doing 2.1.39 → 2.1.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -0
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/bin/commands/config.rb +43 -34
- data/bin/commands/done.rb +1 -18
- data/bin/commands/finish.rb +30 -25
- data/bin/commands/grep.rb +3 -14
- data/bin/commands/last.rb +2 -8
- data/bin/commands/meanwhile.rb +13 -6
- data/bin/commands/on.rb +3 -16
- data/bin/commands/recent.rb +2 -8
- data/bin/commands/reset.rb +24 -1
- data/bin/commands/select.rb +1 -1
- data/bin/commands/show.rb +6 -17
- data/bin/commands/since.rb +1 -12
- data/bin/commands/today.rb +2 -13
- data/bin/commands/view.rb +1 -1
- data/bin/commands/yesterday.rb +2 -13
- data/bin/doing +15 -8
- data/docs/doc/Array.html +1 -1
- data/docs/doc/BooleanTermParser/Clause.html +1 -1
- data/docs/doc/BooleanTermParser/Operator.html +1 -1
- data/docs/doc/BooleanTermParser/Query.html +1 -1
- data/docs/doc/BooleanTermParser/QueryParser.html +1 -1
- data/docs/doc/BooleanTermParser/QueryTransformer.html +1 -1
- data/docs/doc/BooleanTermParser.html +1 -1
- data/docs/doc/Doing/Color.html +166 -20
- data/docs/doc/Doing/Completion.html +1 -1
- data/docs/doc/Doing/Configuration.html +1 -1
- data/docs/doc/Doing/Errors/DoingNoTraceError.html +7 -3
- data/docs/doc/Doing/Errors/DoingRuntimeError.html +7 -3
- data/docs/doc/Doing/Errors/DoingStandardError.html +1 -1
- data/docs/doc/Doing/Errors/EmptyInput.html +10 -2
- data/docs/doc/Doing/Errors/HistoryLimitError.html +194 -0
- data/docs/doc/Doing/Errors/InvalidPlugin.html +194 -0
- data/docs/doc/Doing/Errors/MissingBackupFile.html +194 -0
- data/docs/doc/Doing/Errors/NoResults.html +10 -2
- data/docs/doc/Doing/Errors/PluginException.html +1 -1
- data/docs/doc/Doing/Errors/UserCancelled.html +10 -2
- data/docs/doc/Doing/Errors/WrongCommand.html +10 -2
- data/docs/doc/Doing/Errors.html +9 -9
- data/docs/doc/Doing/Hooks.html +1 -1
- data/docs/doc/Doing/Item.html +90 -1615
- data/docs/doc/Doing/Items.html +121 -5
- data/docs/doc/Doing/Logger.html +1 -1
- data/docs/doc/Doing/Note.html +1 -1
- data/docs/doc/Doing/Pager.html +1 -1
- data/docs/doc/Doing/Plugins.html +1 -1
- data/docs/doc/Doing/Prompt.html +2 -2
- data/docs/doc/Doing/Section.html +1 -1
- data/docs/doc/Doing/TemplateString.html +2 -2
- data/docs/doc/Doing/Types.html +1 -1
- data/docs/doc/Doing/Util/Backup.html +5 -5
- data/docs/doc/Doing/Util.html +1 -1
- data/docs/doc/Doing/WWID.html +197 -4033
- data/docs/doc/Doing.html +2 -2
- data/docs/doc/FalseClass.html +1 -1
- data/docs/doc/GLI/Commands/Help.html +1 -1
- data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
- data/docs/doc/GLI/Commands.html +1 -1
- data/docs/doc/GLI.html +1 -1
- data/docs/doc/Hash.html +1 -1
- data/docs/doc/Object.html +1 -1
- data/docs/doc/PhraseParser/Operator.html +1 -1
- data/docs/doc/PhraseParser/PhraseClause.html +1 -1
- data/docs/doc/PhraseParser/Query.html +1 -1
- data/docs/doc/PhraseParser/QueryParser.html +1 -1
- data/docs/doc/PhraseParser/QueryTransformer.html +1 -1
- data/docs/doc/PhraseParser/TermClause.html +1 -1
- data/docs/doc/PhraseParser.html +1 -1
- data/docs/doc/Status.html +1 -1
- data/docs/doc/String.html +1 -1
- data/docs/doc/Symbol.html +1 -1
- data/docs/doc/Time.html +1 -1
- data/docs/doc/TrueClass.html +1 -1
- data/docs/doc/_index.html +26 -5
- data/docs/doc/class_list.html +1 -1
- data/docs/doc/file.README.html +2 -2
- data/docs/doc/index.html +2 -2
- data/docs/doc/method_list.html +293 -773
- data/docs/doc/top-level-namespace.html +3 -3
- data/docs/index.md +1 -1
- data/doing.rdoc +49 -7
- data/lib/completion/_doing.zsh +5 -5
- data/lib/completion/doing.bash +8 -8
- data/lib/completion/doing.fish +7 -2
- data/lib/doing/add_options.rb +31 -1
- data/lib/doing/chronify/array.rb +64 -22
- data/lib/doing/colors.rb +77 -30
- data/lib/doing/completion.rb +4 -5
- data/lib/doing/errors.rb +51 -35
- data/lib/doing/hooks.rb +3 -3
- data/lib/doing/item/dates.rb +112 -0
- data/lib/doing/item/query.rb +433 -0
- data/lib/doing/item/state.rb +59 -0
- data/lib/doing/item/tags.rb +87 -0
- data/lib/doing/item.rb +6 -667
- data/lib/doing/items.rb +38 -13
- data/lib/doing/plugin_manager.rb +3 -3
- data/lib/doing/plugins/export/template_export.rb +4 -4
- data/lib/doing/plugins/import/cal_to_json.scpt +0 -0
- data/lib/doing/util_backup.rb +6 -8
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid/display.rb +399 -0
- data/lib/doing/wwid/editor.rb +214 -0
- data/lib/doing/wwid/filetools.rb +186 -0
- data/lib/doing/wwid/filter.rb +218 -0
- data/lib/doing/wwid/guess.rb +87 -0
- data/lib/doing/wwid/interactive.rb +385 -0
- data/lib/doing/wwid/modify.rb +618 -0
- data/lib/doing/wwid/tags.rb +54 -0
- data/lib/doing/wwid/timers.rb +345 -0
- data/lib/doing/wwid/wwidutil.rb +104 -0
- data/lib/doing/wwid.rb +31 -2317
- metadata +19 -2
data/lib/doing/colors.rb
CHANGED
|
@@ -2,9 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
# Cribbed from <https://github.com/flori/term-ansicolor>
|
|
4
4
|
module Doing
|
|
5
|
-
# Terminal color functions
|
|
5
|
+
# Terminal output color functions.
|
|
6
6
|
module Color
|
|
7
|
-
#
|
|
7
|
+
# All available color names. Available as methods and string extensions.
|
|
8
|
+
#
|
|
9
|
+
# @example Use a color as a method. Color reset will be added to end of string.
|
|
10
|
+
# Color.yellow('This text is yellow') => "\e[33mThis text is yellow\e[0m"
|
|
11
|
+
#
|
|
12
|
+
# @example Use a color as a string extension. Color reset added automatically.
|
|
13
|
+
# 'This text is green'.green => "\e[1;32mThis text is green\e[0m"
|
|
14
|
+
#
|
|
15
|
+
# @example Send a text string as a color
|
|
16
|
+
# Color.send('red') => "\e[31m"
|
|
8
17
|
ATTRIBUTES = [
|
|
9
18
|
[:clear, 0], # String#clear is already used to empty string in Ruby 1.9
|
|
10
19
|
[:reset, 0], # synonym for :clear
|
|
@@ -66,7 +75,7 @@ module Doing
|
|
|
66
75
|
[:redacted, '0;30;40'],
|
|
67
76
|
[:alert, '1;31;43'],
|
|
68
77
|
[:error, '1;37;41'],
|
|
69
|
-
[:default,
|
|
78
|
+
[:default, '0;39']
|
|
70
79
|
].map(&:freeze).freeze
|
|
71
80
|
|
|
72
81
|
ATTRIBUTE_NAMES = ATTRIBUTES.transpose.first
|
|
@@ -119,24 +128,60 @@ module Doing
|
|
|
119
128
|
end
|
|
120
129
|
|
|
121
130
|
class << self
|
|
122
|
-
# Returns true
|
|
131
|
+
# Returns true if the coloring function of this module
|
|
123
132
|
# is switched on, false otherwise.
|
|
124
133
|
def coloring?
|
|
125
134
|
@coloring
|
|
126
135
|
end
|
|
127
136
|
|
|
128
|
-
# Turns the coloring on or off globally, so you can easily do
|
|
129
|
-
# this for example:
|
|
130
|
-
# Doing::Color::coloring = STDOUT.isatty
|
|
131
137
|
attr_writer :coloring
|
|
132
138
|
|
|
139
|
+
##
|
|
140
|
+
## Enables colored output
|
|
141
|
+
##
|
|
142
|
+
## @example Turn color on or off based on TTY
|
|
143
|
+
## Doing::Color.coloring = STDOUT.isatty
|
|
133
144
|
def coloring
|
|
134
145
|
@coloring ||= true
|
|
135
146
|
end
|
|
147
|
+
|
|
148
|
+
##
|
|
149
|
+
## Convert a template string to a colored string.
|
|
150
|
+
## Colors are specified with single letters inside
|
|
151
|
+
## curly braces. Uppercase changes background color.
|
|
152
|
+
##
|
|
153
|
+
## w: white, k: black, g: green, l: blue, y: yellow, c: cyan,
|
|
154
|
+
## m: magenta, r: red, b: bold, u: underline, i: italic,
|
|
155
|
+
## x: reset (remove background, color, emphasis)
|
|
156
|
+
##
|
|
157
|
+
## @example Convert a templated string
|
|
158
|
+
## Color.template('{Rwb}Warning:{x} {w}you look a little {g}ill{x}')
|
|
159
|
+
##
|
|
160
|
+
## @param input [String, Array] The template
|
|
161
|
+
## string. If this is an array, the
|
|
162
|
+
## elements will be joined with a
|
|
163
|
+
## space.
|
|
164
|
+
##
|
|
165
|
+
## @return [String] Colorized string
|
|
166
|
+
##
|
|
167
|
+
def template(input)
|
|
168
|
+
input = input.join(' ') if input.is_a? Array
|
|
169
|
+
fmt = input.gsub(/\{(\w+)\}/) do
|
|
170
|
+
Regexp.last_match(1).split('').map { |c| "%<#{c}>s" }.join('')
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
colors = { w: white, k: black, g: green, l: blue,
|
|
174
|
+
y: yellow, c: cyan, m: magenta, r: red,
|
|
175
|
+
W: bgwhite, K: bgblack, G: bggreen, L: bgblue,
|
|
176
|
+
Y: bgyellow, C: bgcyan, M: bgmagenta, R: bgred,
|
|
177
|
+
b: bold, u: underline, i: italic, x: reset }
|
|
178
|
+
|
|
179
|
+
format(fmt, colors)
|
|
180
|
+
end
|
|
136
181
|
end
|
|
137
182
|
|
|
138
183
|
ATTRIBUTES.each do |c, v|
|
|
139
|
-
|
|
184
|
+
new_method = <<-EOSCRIPT
|
|
140
185
|
def #{c}(string = nil)
|
|
141
186
|
result = ''
|
|
142
187
|
result << "\e[#{v}m" if Doing::Color.coloring?
|
|
@@ -152,33 +197,37 @@ module Doing
|
|
|
152
197
|
result << "\e[0m" if Doing::Color.coloring?
|
|
153
198
|
result
|
|
154
199
|
end
|
|
155
|
-
|
|
200
|
+
EOSCRIPT
|
|
201
|
+
|
|
202
|
+
module_eval(new_method)
|
|
203
|
+
|
|
204
|
+
next unless c =~ /bold/
|
|
156
205
|
|
|
157
206
|
# Accept brightwhite in addition to boldwhite
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
return result #only switch on
|
|
171
|
-
end
|
|
172
|
-
result << "\e[0m" if Doing::Color.coloring?
|
|
173
|
-
result
|
|
207
|
+
new_method = <<-EOSCRIPT
|
|
208
|
+
def #{c.to_s.sub(/bold/, 'bright')}(string = nil)
|
|
209
|
+
result = ''
|
|
210
|
+
result << "\e[#{v}m" if Doing::Color.coloring?
|
|
211
|
+
if block_given?
|
|
212
|
+
result << yield
|
|
213
|
+
elsif string.respond_to?(:to_str)
|
|
214
|
+
result << string.to_str
|
|
215
|
+
elsif respond_to?(:to_str)
|
|
216
|
+
result << to_str
|
|
217
|
+
else
|
|
218
|
+
return result #only switch on
|
|
174
219
|
end
|
|
175
|
-
|
|
176
|
-
|
|
220
|
+
result << "\e[0m" if Doing::Color.coloring?
|
|
221
|
+
result
|
|
222
|
+
end
|
|
223
|
+
EOSCRIPT
|
|
224
|
+
|
|
225
|
+
module_eval(new_method)
|
|
177
226
|
end
|
|
178
227
|
|
|
179
228
|
# Regular expression that is used to scan for ANSI-sequences while
|
|
180
229
|
# uncoloring strings.
|
|
181
|
-
COLORED_REGEXP = /\e\[(?:(?:[349]|10)[0-7]|[0-9])?m
|
|
230
|
+
COLORED_REGEXP = /\e\[(?:(?:[349]|10)[0-7]|[0-9])?m/.freeze
|
|
182
231
|
|
|
183
232
|
# Returns an uncolored version of the string, that is all
|
|
184
233
|
# ANSI-sequences are stripped from the string.
|
|
@@ -194,8 +243,6 @@ module Doing
|
|
|
194
243
|
end
|
|
195
244
|
end
|
|
196
245
|
|
|
197
|
-
module_function
|
|
198
|
-
|
|
199
246
|
# Returns an array of all Doing::Color attributes as symbols.
|
|
200
247
|
def attributes
|
|
201
248
|
ATTRIBUTE_NAMES
|
data/lib/doing/completion.rb
CHANGED
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
require 'tty-progressbar'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
require 'bash_completion'
|
|
5
|
+
require_relative 'completion/string'
|
|
6
|
+
require_relative 'completion/fish_completion'
|
|
7
|
+
require_relative 'completion/zsh_completion'
|
|
8
|
+
require_relative 'completion/bash_completion'
|
|
10
9
|
|
|
11
10
|
module Doing
|
|
12
11
|
# Completion script generator
|
data/lib/doing/errors.rb
CHANGED
|
@@ -2,19 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
module Doing
|
|
4
4
|
module Errors
|
|
5
|
-
class
|
|
6
|
-
def initialize(msg =
|
|
5
|
+
class DoingNoTraceError < ::StandardError
|
|
6
|
+
def initialize(msg = nil, level: nil, topic: 'Error:', exit_code: 1)
|
|
7
|
+
level ||= :error
|
|
7
8
|
Doing.logger.output_results
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
if msg
|
|
10
|
+
Doing.logger.log_now(level, topic, msg)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
Process.exit exit_code
|
|
10
14
|
end
|
|
11
15
|
end
|
|
12
16
|
|
|
13
|
-
class
|
|
17
|
+
class UserCancelled < DoingNoTraceError
|
|
18
|
+
def initialize(msg = 'Cancelled', topic = 'Exited:')
|
|
19
|
+
super(msg, level: :warn, topic: topic, exit_code: 1)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class EmptyInput < DoingNoTraceError
|
|
14
24
|
def initialize(msg = 'No input', topic = 'Exited:')
|
|
15
|
-
|
|
16
|
-
Doing.logger.log_now(:warn, topic, msg)
|
|
17
|
-
Process.exit 1
|
|
25
|
+
super(msg, level: :warn, topic: topic, exit_code: 6)
|
|
18
26
|
end
|
|
19
27
|
end
|
|
20
28
|
|
|
@@ -22,44 +30,47 @@ module Doing
|
|
|
22
30
|
def initialize(msg = '')
|
|
23
31
|
Doing.logger.output_results
|
|
24
32
|
|
|
25
|
-
super
|
|
33
|
+
super(msg)
|
|
26
34
|
end
|
|
27
35
|
end
|
|
28
36
|
|
|
29
|
-
class WrongCommand <
|
|
37
|
+
class WrongCommand < DoingNoTraceError
|
|
30
38
|
def initialize(msg = 'wrong command', topic: 'Error:')
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
super(msg)
|
|
39
|
+
super(msg, level: :warn, topic: topic, exit_code: 2)
|
|
34
40
|
end
|
|
35
41
|
end
|
|
36
42
|
|
|
37
43
|
class DoingRuntimeError < ::RuntimeError
|
|
38
|
-
def initialize(msg = 'Runtime Error', topic: 'Error:')
|
|
44
|
+
def initialize(msg = 'Runtime Error', exit_code = nil, topic: 'Error:')
|
|
39
45
|
Doing.logger.output_results
|
|
40
46
|
Doing.logger.log_now(:error, topic, msg)
|
|
41
|
-
|
|
47
|
+
|
|
48
|
+
Process.exit exit_code if exit_code
|
|
42
49
|
end
|
|
43
50
|
end
|
|
44
51
|
|
|
45
|
-
class NoResults <
|
|
52
|
+
class NoResults < DoingNoTraceError
|
|
46
53
|
def initialize(msg = 'No results', topic = 'Exited:')
|
|
47
|
-
|
|
48
|
-
Doing.logger.log_now(:warn, topic, msg)
|
|
49
|
-
Process.exit 0
|
|
54
|
+
super(msg, level: :warn, topic: topic, exit_code: 0)
|
|
50
55
|
|
|
51
56
|
end
|
|
52
57
|
end
|
|
53
58
|
|
|
54
|
-
class
|
|
55
|
-
def initialize(msg
|
|
56
|
-
level
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
Doing.logger.log_now(level, topic, msg)
|
|
60
|
-
end
|
|
59
|
+
class HistoryLimitError < DoingNoTraceError
|
|
60
|
+
def initialize(msg, exit_code = 24)
|
|
61
|
+
super(msg, level: :error, topic: 'History:', exit_code: exit_code)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
61
64
|
|
|
62
|
-
|
|
65
|
+
class MissingBackupFile < DoingNoTraceError
|
|
66
|
+
def initialize(msg, exit_code = 26)
|
|
67
|
+
super(msg, level: :error, topic: 'History:', exit_code: exit_code)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
class InvalidPlugin < DoingRuntimeError
|
|
72
|
+
def initialize(kind = 'output', msg = nil)
|
|
73
|
+
super(%(Invalid #{kind} type (#{msg})), 128, topic: 'Invalid:')
|
|
63
74
|
end
|
|
64
75
|
end
|
|
65
76
|
|
|
@@ -75,6 +86,10 @@ module Doing
|
|
|
75
86
|
'Import plugin'
|
|
76
87
|
when /^e/
|
|
77
88
|
'Export plugin'
|
|
89
|
+
when /^h/
|
|
90
|
+
'Hook'
|
|
91
|
+
when /^u/
|
|
92
|
+
'Unrecognized'
|
|
78
93
|
else
|
|
79
94
|
type.to_s
|
|
80
95
|
end
|
|
@@ -82,7 +97,8 @@ module Doing
|
|
|
82
97
|
msg = "(#{@type}: #{@plugin}) #{msg}"
|
|
83
98
|
|
|
84
99
|
Doing.logger.log_now(:error, 'Plugin:', msg)
|
|
85
|
-
|
|
100
|
+
|
|
101
|
+
super(msg)
|
|
86
102
|
end
|
|
87
103
|
end
|
|
88
104
|
|
|
@@ -90,17 +106,17 @@ module Doing
|
|
|
90
106
|
InvalidPluginType = Class.new(PluginException)
|
|
91
107
|
PluginUncallable = Class.new(PluginException)
|
|
92
108
|
|
|
93
|
-
InvalidArgument = Class.new(
|
|
94
|
-
MissingArgument = Class.new(
|
|
95
|
-
MissingFile = Class.new(
|
|
96
|
-
MissingEditor = Class.new(
|
|
109
|
+
InvalidArgument = Class.new(DoingNoTraceError)
|
|
110
|
+
MissingArgument = Class.new(DoingNoTraceError)
|
|
111
|
+
MissingFile = Class.new(DoingNoTraceError)
|
|
112
|
+
MissingEditor = Class.new(DoingNoTraceError)
|
|
97
113
|
NonInteractive = Class.new(StandardError)
|
|
98
114
|
|
|
99
|
-
NoEntryError = Class.new(
|
|
115
|
+
NoEntryError = Class.new(DoingNoTraceError)
|
|
100
116
|
|
|
101
117
|
InvalidTimeExpression = Class.new(DoingRuntimeError)
|
|
102
|
-
InvalidSection = Class.new(
|
|
103
|
-
InvalidView = Class.new(
|
|
118
|
+
InvalidSection = Class.new(DoingNoTraceError)
|
|
119
|
+
InvalidView = Class.new(DoingNoTraceError)
|
|
104
120
|
|
|
105
121
|
ItemNotFound = Class.new(DoingRuntimeError)
|
|
106
122
|
# FatalException = Class.new(::RuntimeError)
|
data/lib/doing/hooks.rb
CHANGED
|
@@ -15,7 +15,7 @@ module Doing
|
|
|
15
15
|
post_entry_removed: [], # wwid, entry.dup
|
|
16
16
|
pre_export: [], # wwid, format, entries
|
|
17
17
|
pre_write: [], # wwid, file
|
|
18
|
-
post_write: [] #
|
|
18
|
+
post_write: [] # file
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
# map of all hooks and their priorities
|
|
@@ -40,10 +40,10 @@ module Doing
|
|
|
40
40
|
# register a single hook to be called later, internal API
|
|
41
41
|
def self.register_one(event, priority, &block)
|
|
42
42
|
unless @registry[event]
|
|
43
|
-
raise Doing::Errors::HookUnavailable
|
|
43
|
+
raise Doing::Errors::HookUnavailable.new("Invalid hook. Doing only supports #{@registry.keys.inspect}", 'hook', event)
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
raise Doing::Errors::PluginUncallable
|
|
46
|
+
raise Doing::Errors::PluginUncallable.new('Hooks must respond to :call', 'hook', event) unless block.respond_to? :call
|
|
47
47
|
|
|
48
48
|
Doing.logger.debug('Hook Manager:', "Registered #{event} hook") if ENV['DOING_PLUGIN_DEBUG']
|
|
49
49
|
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
module Doing
|
|
2
|
+
class Item
|
|
3
|
+
# def date=(new_date)
|
|
4
|
+
# @date = new_date.is_a?(Time) ? new_date : Time.parse(new_date)
|
|
5
|
+
# end
|
|
6
|
+
|
|
7
|
+
## If the entry doesn't have a @done date, return the elapsed time
|
|
8
|
+
def duration
|
|
9
|
+
return nil unless should_time? && should_finish?
|
|
10
|
+
|
|
11
|
+
return nil if @title =~ /(?<=^| )@done\b/
|
|
12
|
+
|
|
13
|
+
return Time.now - @date
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
##
|
|
17
|
+
## Get the difference between the item's start date and
|
|
18
|
+
## the value of its @done tag (if present)
|
|
19
|
+
##
|
|
20
|
+
## @return Interval in seconds
|
|
21
|
+
##
|
|
22
|
+
def interval
|
|
23
|
+
@interval ||= calc_interval
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
## Get the value of the item's @done tag
|
|
28
|
+
##
|
|
29
|
+
## @return [Time] @done value
|
|
30
|
+
##
|
|
31
|
+
def end_date
|
|
32
|
+
@end_date ||= Time.parse(Regexp.last_match(1)) if @title =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def calculate_end_date(opt)
|
|
36
|
+
if opt[:took]
|
|
37
|
+
if @date + opt[:took] > Time.now
|
|
38
|
+
@date = Time.now - opt[:took]
|
|
39
|
+
Time.now
|
|
40
|
+
else
|
|
41
|
+
@date + opt[:took]
|
|
42
|
+
end
|
|
43
|
+
elsif opt[:back]
|
|
44
|
+
if opt[:back].is_a? Integer
|
|
45
|
+
@date + opt[:back]
|
|
46
|
+
else
|
|
47
|
+
@date + (opt[:back] - @date)
|
|
48
|
+
end
|
|
49
|
+
else
|
|
50
|
+
Time.now
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
##
|
|
55
|
+
## Test if two items occur at the same time (same start date and equal duration)
|
|
56
|
+
##
|
|
57
|
+
## @param item_b [Item] The item to compare
|
|
58
|
+
##
|
|
59
|
+
## @return [Boolean] is equal?
|
|
60
|
+
##
|
|
61
|
+
def same_time?(item_b)
|
|
62
|
+
date == item_b.date ? interval == item_b.interval : false
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
##
|
|
66
|
+
## Test if the interval between start date and @done
|
|
67
|
+
## value overlaps with another item's
|
|
68
|
+
##
|
|
69
|
+
## @param item_b [Item] The item to compare
|
|
70
|
+
##
|
|
71
|
+
## @return [Boolean] overlaps?
|
|
72
|
+
##
|
|
73
|
+
def overlapping_time?(item_b)
|
|
74
|
+
return true if same_time?(item_b)
|
|
75
|
+
|
|
76
|
+
start_a = date
|
|
77
|
+
a_interval = interval
|
|
78
|
+
end_a = a_interval ? start_a + a_interval.to_i : start_a
|
|
79
|
+
start_b = item_b.date
|
|
80
|
+
b_interval = item_b.interval
|
|
81
|
+
end_b = b_interval ? start_b + b_interval.to_i : start_b
|
|
82
|
+
(start_a >= start_b && start_a <= end_b) || (end_a >= start_b && end_a <= end_b) || (start_a < start_b && end_a > end_b)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
##
|
|
86
|
+
## Updates the title of the Item by expanding natural
|
|
87
|
+
## language dates within configured date tags (tags
|
|
88
|
+
## whose value is expected to be a date)
|
|
89
|
+
##
|
|
90
|
+
## @param additional_tags An array of additional
|
|
91
|
+
## tag names to consider
|
|
92
|
+
## dates
|
|
93
|
+
##
|
|
94
|
+
def expand_date_tags(additional_tags = nil)
|
|
95
|
+
@title.expand_date_tags(additional_tags)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def calc_interval
|
|
101
|
+
return nil unless should_time? && should_finish?
|
|
102
|
+
|
|
103
|
+
done = end_date
|
|
104
|
+
return nil if done.nil?
|
|
105
|
+
|
|
106
|
+
start = @date
|
|
107
|
+
|
|
108
|
+
t = (done - start).to_i
|
|
109
|
+
t.positive? ? t : nil
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|