doing 2.1.39 → 2.1.42
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/.yardopts +1 -1
- data/CHANGELOG.md +67 -0
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/Rakefile +4 -4
- data/bin/commands/again.rb +1 -3
- data/bin/commands/changes.rb +50 -34
- data/bin/commands/commands.rb +77 -52
- data/bin/commands/commands_accepting.rb +57 -53
- data/bin/commands/config.rb +45 -36
- data/bin/commands/done.rb +1 -18
- data/bin/commands/finish.rb +90 -59
- data/bin/commands/flag.rb +5 -1
- data/bin/commands/grep.rb +3 -14
- data/bin/commands/last.rb +2 -8
- data/bin/commands/meanwhile.rb +13 -6
- data/bin/commands/now.rb +151 -107
- data/bin/commands/on.rb +8 -18
- 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/tag_dir.rb +49 -15
- data/bin/commands/today.rb +2 -13
- data/bin/commands/undo.rb +4 -6
- data/bin/commands/view.rb +1 -1
- data/bin/commands/yesterday.rb +2 -13
- data/bin/doing +15 -8
- data/{Dockerfile → docker/Dockerfile} +3 -1
- data/{Dockerfile-2.6 → docker/Dockerfile-2.6} +2 -2
- data/{Dockerfile-2.7 → docker/Dockerfile-2.7} +2 -2
- data/{Dockerfile-3.0 → docker/Dockerfile-3.0} +2 -2
- data/{bash_profile → docker/bash_profile} +0 -0
- data/{inputrc → docker/inputrc} +0 -0
- data/docs/doc/Array.html +85 -2
- 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/ArrayNestedHash.html +198 -0
- data/docs/doc/Doing/ArrayTags.html +424 -0
- data/docs/doc/Doing/CSVExport.html +266 -0
- data/docs/doc/Doing/CalendarImport.html +232 -0
- data/docs/doc/Doing/Change.html +617 -0
- data/docs/doc/Doing/Changes.html +468 -0
- data/docs/doc/Doing/ChronifyArray.html +347 -0
- data/docs/doc/Doing/ChronifyNumeric.html +271 -0
- data/docs/doc/Doing/ChronifyString.html +682 -0
- data/docs/doc/Doing/Color.html +167 -21
- data/docs/doc/Doing/Completion/BashCompletions.html +445 -0
- data/docs/doc/Doing/Completion/FishCompletions.html +445 -0
- data/docs/doc/Doing/Completion/StringUtils.html +229 -0
- data/docs/doc/Doing/Completion/ZshCompletions.html +445 -0
- data/docs/doc/Doing/Completion.html +17 -3
- data/docs/doc/Doing/Configuration.html +3 -2
- data/docs/doc/Doing/DayOneRenderer.html +383 -0
- data/docs/doc/Doing/DayoneExport.html +290 -0
- data/docs/doc/Doing/DoingImport.html +391 -0
- data/docs/doc/Doing/Entry.html +381 -0
- 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/HTMLExport.html +256 -0
- data/docs/doc/Doing/Hooks.html +1 -1
- data/docs/doc/Doing/Item.html +179 -1660
- data/docs/doc/Doing/ItemDates.html +564 -0
- data/docs/doc/Doing/ItemQuery.html +614 -0
- data/docs/doc/Doing/ItemState.html +387 -0
- data/docs/doc/Doing/ItemTags.html +498 -0
- data/docs/doc/Doing/Items.html +581 -15
- data/docs/doc/Doing/JSONExport.html +222 -0
- data/docs/doc/Doing/Logger.html +1 -1
- data/docs/doc/Doing/MarkdownExport.html +266 -0
- data/docs/doc/Doing/MarkdownRenderer.html +383 -0
- data/docs/doc/Doing/Note.html +18 -4
- data/docs/doc/Doing/Pager.html +1 -1
- data/docs/doc/Doing/Plugins.html +181 -76
- data/docs/doc/Doing/Prompt.html +32 -683
- data/docs/doc/Doing/PromptChoose.html +484 -0
- data/docs/doc/Doing/PromptFZF.html +391 -0
- data/docs/doc/Doing/PromptInput.html +572 -0
- data/docs/doc/Doing/PromptSTD.html +293 -0
- data/docs/doc/Doing/PromptYN.html +237 -0
- data/docs/doc/Doing/Section.html +58 -2
- data/docs/doc/Doing/StringHighlight.html +533 -0
- data/docs/doc/Doing/StringNormalize.html +929 -0
- data/docs/doc/Doing/StringQuery.html +725 -0
- data/docs/doc/Doing/StringTags.html +884 -0
- data/docs/doc/Doing/StringTransform.html +599 -0
- data/docs/doc/Doing/StringTruncate.html +448 -0
- data/docs/doc/Doing/StringURL.html +409 -0
- data/docs/doc/Doing/SymbolNormalize.html +341 -0
- data/docs/doc/Doing/TaskPaperExport.html +222 -0
- data/docs/doc/Doing/TemplateExport.html +249 -0
- data/docs/doc/Doing/TemplateString.html +102 -3
- data/docs/doc/Doing/TimingImport.html +285 -0
- data/docs/doc/Doing/Types.html +1 -1
- data/docs/doc/Doing/Util/Backup.html +11 -163
- data/docs/doc/Doing/Util.html +67 -10
- data/docs/doc/Doing/Version.html +523 -0
- data/docs/doc/Doing/WWID/WWIDUtil.html +510 -0
- data/docs/doc/Doing/WWID.html +476 -139
- data/docs/doc/Doing/WWIDDisplay.html +865 -0
- data/docs/doc/Doing/WWIDEditor.html +466 -0
- data/docs/doc/Doing/WWIDFileTools.html +359 -0
- data/docs/doc/Doing/WWIDFilter.html +466 -0
- data/docs/doc/Doing/WWIDGuess.html +299 -0
- data/docs/doc/Doing/WWIDInteractive.html +752 -0
- data/docs/doc/Doing/WWIDModify.html +1078 -0
- data/docs/doc/Doing/WWIDTags.html +302 -0
- data/docs/doc/Doing/WWIDTimers.html +359 -0
- data/docs/doc/Doing/WWIDUtil.html +510 -0
- data/docs/doc/Doing.html +9 -6
- 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/Numeric.html +23 -78
- 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 +58 -633
- data/docs/doc/Symbol.html +9 -224
- data/docs/doc/Time.html +119 -13
- data/docs/doc/TrueClass.html +1 -1
- data/docs/doc/_index.html +348 -4
- 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 +1904 -592
- data/docs/doc/top-level-namespace.html +12 -4
- data/docs/index.md +1 -1
- data/doing.rdoc +67 -15
- data/lib/completion/_doing.zsh +6 -6
- data/lib/completion/doing.bash +10 -10
- data/lib/completion/doing.fish +10 -3
- data/lib/doing/add_options.rb +39 -1
- data/lib/doing/array/array.rb +18 -12
- data/lib/doing/array/cleanup.rb +31 -0
- data/lib/doing/array/nested_hash.rb +1 -1
- data/lib/doing/array/tags.rb +6 -5
- data/lib/doing/changelog/changelog.rb +6 -0
- data/lib/doing/chronify/array.rb +65 -25
- data/lib/doing/chronify/chronify.rb +12 -0
- data/lib/doing/chronify/numeric.rb +3 -2
- data/lib/doing/chronify/string.rb +1 -1
- data/lib/doing/colors.rb +77 -30
- data/lib/doing/completion/completion_string.rb +25 -0
- data/lib/doing/completion.rb +4 -5
- data/lib/doing/configuration.rb +7 -3
- data/lib/doing/errors.rb +51 -35
- data/lib/doing/good.rb +8 -0
- data/lib/doing/hooks.rb +3 -3
- data/lib/doing/item/dates.rb +112 -0
- data/lib/doing/item/item.rb +128 -0
- data/lib/doing/{item.rb → item/query.rb} +2 -353
- data/lib/doing/item/state.rb +59 -0
- data/lib/doing/item/tags.rb +87 -0
- data/lib/doing/items/filter.rb +67 -0
- data/lib/doing/items/items.rb +57 -0
- data/lib/doing/items/modify.rb +36 -0
- data/lib/doing/items/sections.rb +83 -0
- data/lib/doing/items/util.rb +74 -0
- data/lib/doing/normalize.rb +10 -2
- data/lib/doing/note.rb +1 -1
- data/lib/doing/pager.rb +9 -3
- data/lib/doing/plugin_manager.rb +33 -8
- data/lib/doing/plugins/export/markdown_export.rb +4 -2
- data/lib/doing/plugins/export/template_export.rb +4 -4
- data/lib/doing/plugins/import/cal_to_json.scpt +0 -0
- data/lib/doing/plugins/import/doing_import.rb +1 -1
- data/lib/doing/prompt/choose.rb +118 -0
- data/lib/doing/prompt/fzf.rb +84 -0
- data/lib/doing/prompt/input.rb +129 -0
- data/lib/doing/prompt/prompt.rb +41 -0
- data/lib/doing/prompt/std.rb +32 -0
- data/lib/doing/prompt/yn.rb +64 -0
- data/lib/doing/section.rb +4 -0
- data/lib/doing/string/highlight.rb +1 -1
- data/lib/doing/string/query.rb +1 -1
- data/lib/doing/string/string.rb +18 -7
- data/lib/doing/string/tags.rb +14 -3
- data/lib/doing/string/transform.rb +7 -1
- data/lib/doing/string/truncate.rb +1 -1
- data/lib/doing/string/url.rb +1 -1
- data/lib/doing/time.rb +19 -1
- data/lib/doing/util.rb +12 -6
- data/lib/doing/util_backup.rb +62 -57
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid/display.rb +396 -0
- data/lib/doing/wwid/editor.rb +214 -0
- data/lib/doing/wwid/filetools.rb +183 -0
- data/lib/doing/wwid/filter.rb +226 -0
- data/lib/doing/wwid/guess.rb +85 -0
- data/lib/doing/wwid/interactive.rb +377 -0
- data/lib/doing/wwid/modify.rb +617 -0
- data/lib/doing/wwid/tags.rb +51 -0
- data/lib/doing/wwid/timers.rb +342 -0
- data/lib/doing/wwid/wwid.rb +121 -0
- data/lib/doing/wwid/wwidutil.rb +101 -0
- data/lib/doing.rb +7 -7
- data/lib/helpers/threaded_tests.rb +1 -0
- metadata +94 -14
- data/lib/doing/changelog.rb +0 -6
- data/lib/doing/completion/string.rb +0 -17
- data/lib/doing/items.rb +0 -196
- data/lib/doing/prompt.rb +0 -330
- data/lib/doing/wwid.rb +0 -2398
data/bin/commands/config.rb
CHANGED
|
@@ -29,7 +29,7 @@ command :config do |c|
|
|
|
29
29
|
c.long_desc 'Config files are listed in order of precedence (if there are multiple configs detected).
|
|
30
30
|
Values defined in the top item in the list will override values in configutations below it.'
|
|
31
31
|
c.command :list do |list|
|
|
32
|
-
list.action do
|
|
32
|
+
list.action do
|
|
33
33
|
puts Doing.config.additional_configs.join("\n")
|
|
34
34
|
puts Doing.config.config_file
|
|
35
35
|
end
|
|
@@ -54,7 +54,8 @@ command :config do |c|
|
|
|
54
54
|
edit.arg_name 'BUNDLE_ID'
|
|
55
55
|
edit.flag %i[b bundle_id]
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
default_editor = Doing.setting('editors.config', 'editors.config not set')
|
|
58
|
+
edit.desc "Use the config editor defined in ~/.config/doing/config.yml (#{default_editor})"
|
|
58
59
|
edit.switch %i[x default], negatable: false
|
|
59
60
|
end
|
|
60
61
|
|
|
@@ -68,10 +69,11 @@ command :config do |c|
|
|
|
68
69
|
end
|
|
69
70
|
action = cmd.send(:get_action, nil)
|
|
70
71
|
action.call(global, options, args)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
|
|
73
|
+
raise DoingNoTraceError.new('--dump and --update are deprecated,
|
|
74
|
+
use `doing config get` and `doing config update`',
|
|
75
|
+
level: :warn,
|
|
76
|
+
topic: 'Deprecated:')
|
|
75
77
|
end
|
|
76
78
|
|
|
77
79
|
config_file = Doing.config.choose_config
|
|
@@ -79,14 +81,12 @@ command :config do |c|
|
|
|
79
81
|
if `uname` =~ /Darwin/
|
|
80
82
|
if options[:default]
|
|
81
83
|
editor = Doing::Util.find_default_editor('config')
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
`open -a "#{editor}" "#{config_file}"`
|
|
87
|
-
end
|
|
84
|
+
raise InvalidArgument, 'No viable editor found in config or environment.' unless editor
|
|
85
|
+
|
|
86
|
+
if Doing::Util.exec_available(editor.split(/ /).first)
|
|
87
|
+
system %(#{editor} "#{config_file}")
|
|
88
88
|
else
|
|
89
|
-
|
|
89
|
+
`open -a "#{editor}" "#{config_file}"`
|
|
90
90
|
end
|
|
91
91
|
elsif options[:app] || options[:bundle_id]
|
|
92
92
|
if options[:app]
|
|
@@ -107,7 +107,10 @@ command :config do |c|
|
|
|
107
107
|
end
|
|
108
108
|
else
|
|
109
109
|
editor = options[:editor] || Doing::Util.default_editor
|
|
110
|
-
|
|
110
|
+
unless editor && Doing::Util.exec_available(editor.split(/ /).first)
|
|
111
|
+
raise MissingEditor, 'No EDITOR variable defined in environment'
|
|
112
|
+
|
|
113
|
+
end
|
|
111
114
|
|
|
112
115
|
system %(#{editor} "#{config_file}")
|
|
113
116
|
end
|
|
@@ -117,8 +120,8 @@ command :config do |c|
|
|
|
117
120
|
# @@config.update @@config.refresh
|
|
118
121
|
c.desc 'Update default config file, adding any missing keys'
|
|
119
122
|
c.command %i[update refresh] do |update|
|
|
120
|
-
update.action do
|
|
121
|
-
Doing.config.configure({rewrite: true, ignore_local: true})
|
|
123
|
+
update.action do
|
|
124
|
+
Doing.config.configure({ rewrite: true, ignore_local: true })
|
|
122
125
|
Doing.logger.warn('Config:', 'config refreshed')
|
|
123
126
|
end
|
|
124
127
|
end
|
|
@@ -126,7 +129,7 @@ command :config do |c|
|
|
|
126
129
|
# @@config.undo
|
|
127
130
|
c.desc 'Undo the last change to a config file'
|
|
128
131
|
c.command :undo do |undo|
|
|
129
|
-
undo.action do
|
|
132
|
+
undo.action do
|
|
130
133
|
config_file = Doing.config.choose_config
|
|
131
134
|
Doing::Util::Backup.restore_last_backup(config_file, count: 1)
|
|
132
135
|
end
|
|
@@ -137,22 +140,24 @@ command :config do |c|
|
|
|
137
140
|
c.arg 'KEY_PATH'
|
|
138
141
|
c.command %i[get dump] do |dump|
|
|
139
142
|
dump.example 'doing config get', desc: 'Output the entire configuration'
|
|
140
|
-
dump.example 'doing config get timer_format --output raw',
|
|
141
|
-
|
|
142
|
-
dump.example 'doing config get
|
|
143
|
+
dump.example 'doing config get timer_format --output raw',
|
|
144
|
+
desc: 'Output the value of timer_format as a plain string'
|
|
145
|
+
dump.example 'doing config get doing_file',
|
|
146
|
+
desc: 'Output the value of the doing_file setting, respecting local configurations'
|
|
147
|
+
dump.example 'doing config get -o json plug.plugpath',
|
|
148
|
+
desc: 'Key path is fuzzy matched: output the value of plugins.plugin_path as JSON'
|
|
143
149
|
|
|
144
150
|
dump.desc 'Format for output (json|yaml|raw)'
|
|
145
151
|
dump.arg_name 'FORMAT'
|
|
146
152
|
dump.flag %i[o output], default_value: 'yaml', must_match: /^(?:y(?:aml)?|j(?:son)?|r(?:aw)?)$/
|
|
147
153
|
|
|
148
154
|
dump.action do |_global, options, args|
|
|
149
|
-
|
|
150
155
|
keypath = args.join('.')
|
|
151
156
|
cfg = Doing.config.value_for_key(keypath)
|
|
152
157
|
real_path = Doing.config.resolve_key_path(keypath)
|
|
153
158
|
|
|
154
159
|
if cfg
|
|
155
|
-
val = cfg.map {|
|
|
160
|
+
val = cfg.map { |_, v| v }[0]
|
|
156
161
|
if real_path.count.positive?
|
|
157
162
|
nested_cfg = {}
|
|
158
163
|
nested_cfg.deep_set(real_path, val)
|
|
@@ -161,13 +166,15 @@ command :config do |c|
|
|
|
161
166
|
end
|
|
162
167
|
|
|
163
168
|
if options[:output] =~ /^r/
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
|
|
170
|
+
$stdout.puts case val
|
|
171
|
+
when Hash
|
|
172
|
+
YAML.dump(val)
|
|
173
|
+
when Array
|
|
174
|
+
val.join(', ')
|
|
175
|
+
else
|
|
176
|
+
val.to_s
|
|
177
|
+
end
|
|
171
178
|
else
|
|
172
179
|
$stdout.puts case options[:output]
|
|
173
180
|
when /^j/
|
|
@@ -188,13 +195,14 @@ command :config do |c|
|
|
|
188
195
|
c.arg 'KEY VALUE'
|
|
189
196
|
c.command :set do |set|
|
|
190
197
|
set.example 'doing config set timer_format human', desc: 'Set the value of timer_format to "human"'
|
|
191
|
-
set.example 'doing config set plug.plugpath ~/my_plugins',
|
|
198
|
+
set.example 'doing config set plug.plugpath ~/my_plugins',
|
|
199
|
+
desc: 'Key path is fuzzy matched: set the value of plugins.plugin_path'
|
|
192
200
|
|
|
193
201
|
set.desc 'Delete specified key'
|
|
194
202
|
set.switch %i[r remove], negatable: false
|
|
195
203
|
|
|
196
204
|
set.desc 'Force update to .doingrc in the current directory'
|
|
197
|
-
set.switch %[local], negatable: false
|
|
205
|
+
set.switch %i[local], negatable: false
|
|
198
206
|
|
|
199
207
|
set.action do |_global, options, args|
|
|
200
208
|
if args.count < 2 && !options[:remove]
|
|
@@ -206,13 +214,14 @@ command :config do |c|
|
|
|
206
214
|
keypath = args.join('.')
|
|
207
215
|
real_path = Doing.config.resolve_key_path(keypath, create: true)
|
|
208
216
|
old_value = Doing.config.settings.dig(*real_path)
|
|
209
|
-
old_type = old_value&.class.to_s
|
|
217
|
+
old_type = old_value.good? ? old_value&.class.to_s : nil
|
|
210
218
|
|
|
211
219
|
if old_value.is_a?(Hash) && !options[:remove]
|
|
212
|
-
Doing.logger.log_now(:warn, 'Config:',
|
|
220
|
+
Doing.logger.log_now(:warn, 'Config:', ['Config key must point to a single value, ',
|
|
221
|
+
"#{real_path.join('.').boldwhite} is a mapping"].join(' '))
|
|
213
222
|
didyou = 'Did you mean:'
|
|
214
|
-
old_value.
|
|
215
|
-
Doing.logger.log_now(:warn,
|
|
223
|
+
old_value.each_key do |k|
|
|
224
|
+
Doing.logger.log_now(:warn, didyou, "#{keypath}.#{k}?")
|
|
216
225
|
didyou = '..........or:'
|
|
217
226
|
end
|
|
218
227
|
raise InvalidArgument, 'Config value is a mapping, can not be set to a single value'
|
|
@@ -226,8 +235,8 @@ command :config do |c|
|
|
|
226
235
|
$stderr.puts "> Config: Updating #{config_file}".yellow
|
|
227
236
|
|
|
228
237
|
if options[:remove]
|
|
229
|
-
cfg.deep_set(real_path, nil)
|
|
230
238
|
$stderr.puts "#{'Deleting key:'.yellow} #{real_path.join('.').boldwhite}"
|
|
239
|
+
cfg.deep_set(real_path, nil)
|
|
231
240
|
else
|
|
232
241
|
current_value = cfg.dig(*real_path)
|
|
233
242
|
cfg.deep_set(real_path, value.set_type(old_type))
|
data/bin/commands/done.rb
CHANGED
|
@@ -19,24 +19,6 @@ command %i[done did] do |c|
|
|
|
19
19
|
c.desc 'Immediately archive the entry'
|
|
20
20
|
c.switch %i[a archive], negatable: false, default_value: false
|
|
21
21
|
|
|
22
|
-
c.desc %(Set finish date to specific date/time (natural langauge parsed, e.g. --at=1:30pm).
|
|
23
|
-
Used with --took, backdates start date)
|
|
24
|
-
c.arg_name 'DATE_STRING'
|
|
25
|
-
c.flag %i[at finished], type: DateEndString
|
|
26
|
-
|
|
27
|
-
c.desc %(
|
|
28
|
-
Start and end times as a date/time range `doing done --from "1am to 8am"`.
|
|
29
|
-
Overrides other date flags.
|
|
30
|
-
)
|
|
31
|
-
c.arg_name 'TIME_RANGE'
|
|
32
|
-
c.flag [:from], must_match: REGEX_RANGE
|
|
33
|
-
|
|
34
|
-
c.desc %(Set completion date to start date plus interval (XX[mhd] or HH:MM).
|
|
35
|
-
If used without the --back option, the start date will be moved back to allow
|
|
36
|
-
the completion date to be the current time.)
|
|
37
|
-
c.arg_name 'INTERVAL'
|
|
38
|
-
c.flag %i[t took for], type: DateIntervalString
|
|
39
|
-
|
|
40
22
|
c.desc 'Section'
|
|
41
23
|
c.arg_name 'NAME'
|
|
42
24
|
c.flag %i[s section]
|
|
@@ -45,6 +27,7 @@ command %i[done did] do |c|
|
|
|
45
27
|
c.switch %i[u unfinished], negatable: false, default_value: false
|
|
46
28
|
|
|
47
29
|
add_options(:add_entry, c)
|
|
30
|
+
add_options(:finish_entry, c)
|
|
48
31
|
|
|
49
32
|
c.action do |global_options, options, args|
|
|
50
33
|
Doing.auto_tag = !options[:noauto]
|
data/bin/commands/finish.rb
CHANGED
|
@@ -1,97 +1,126 @@
|
|
|
1
|
-
#
|
|
2
|
-
desc 'Mark last X entries as @done'
|
|
3
|
-
long_desc 'Marks the last X entries with a @done tag and current date. Does not alter already completed entries.'
|
|
4
|
-
arg_name 'COUNT', optional: true
|
|
5
|
-
command :finish do |c|
|
|
6
|
-
c.example 'doing finish', desc: 'Mark the last entry @done'
|
|
7
|
-
c.example 'doing finish --auto --section Later 10', desc: 'Add @done to any unfinished entries in the last 10 in Later, setting the finish time based on the start time of the task after it'
|
|
8
|
-
c.example 'doing finish --search "a specific entry" --at "yesterday 3pm"', desc: 'Search for an entry containing string and set its @done time to yesterday at 3pm'
|
|
1
|
+
# frozen_string_literal: true
|
|
9
2
|
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
# @@finish
|
|
4
|
+
module Doing
|
|
5
|
+
# finish command methods
|
|
6
|
+
class FinishCommand
|
|
7
|
+
def initialize(wwid)
|
|
8
|
+
@wwid = wwid
|
|
9
|
+
end
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
def add_examples(cmd)
|
|
12
|
+
cmd.example 'doing finish', desc: 'Mark the last entry @done'
|
|
13
|
+
cmd.example 'doing finish --auto --section Later 10', desc: 'Add @done to any unfinished entries in the last 10 in Later, setting the finish time based on the start time of the task after it'
|
|
14
|
+
cmd.example 'doing finish --search "a specific entry" --at "yesterday 3pm"', desc: 'Search for an entry containing string and set its @done time to yesterday at 3pm'
|
|
15
|
+
end
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
def add_options(cmd)
|
|
18
|
+
cmd.desc 'Include date'
|
|
19
|
+
cmd.switch [:date], negatable: true, default_value: true
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
cmd.desc 'Backdate completed date to date string [4pm|20m|2h|yesterday noon]'
|
|
22
|
+
cmd.arg_name 'DATE_STRING'
|
|
23
|
+
cmd.flag %i[b back started], type: DateBeginString
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
cmd.desc 'Overwrite existing @done tag with new date'
|
|
26
|
+
cmd.switch %i[update], negatable: false, default_value: false
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
cmd.desc 'Remove @done tag'
|
|
29
|
+
cmd.switch %i[r remove], negatable: false, default_value: false
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
cmd.desc 'Finish last entry (or entries) not already marked @done'
|
|
32
|
+
cmd.switch %i[u unfinished], negatable: false, default_value: false
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
cmd.desc %(Auto-generate finish dates from next entry's start time.
|
|
35
|
+
Automatically generate completion dates 1 minute before next item (in any section) began.
|
|
36
|
+
--auto overrides the --date and --back parameters.)
|
|
37
|
+
cmd.switch [:auto], negatable: false, default_value: false
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
cmd.desc 'Archive entries'
|
|
40
|
+
cmd.switch %i[a archive], negatable: false, default_value: false
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
cmd.desc 'Section'
|
|
43
|
+
cmd.arg_name 'NAME'
|
|
44
|
+
cmd.flag %i[s section]
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
cmd.desc 'Select item(s) to finish from a menu of matching entries'
|
|
47
|
+
cmd.switch %i[i interactive], negatable: false, default_value: false
|
|
48
|
+
end
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
def handle_from(options)
|
|
51
|
+
options[:from] = options[:from].split(/#{REGEX_RANGE_INDICATOR}/).map do |time|
|
|
52
|
+
time =~ REGEX_TIME ? "today #{time.sub(/(?mi)(^.*?(?=\d+)|(?<=[ap]m).*?$)/, '')}" : time
|
|
53
|
+
end.join(' to ').split_date_range
|
|
54
|
+
start_date, finish_date = options[:from]
|
|
55
|
+
finish_date ||= Time.now
|
|
56
|
+
[start_date, finish_date]
|
|
57
|
+
end
|
|
51
58
|
|
|
52
|
-
|
|
53
|
-
options[:fuzzy] = false
|
|
54
|
-
unless options[:auto]
|
|
59
|
+
def handle_date_options(options)
|
|
55
60
|
if options[:took]
|
|
56
61
|
took = options[:took]
|
|
57
62
|
raise InvalidTimeExpression, 'Unable to parse date string for --took' if took.nil?
|
|
58
|
-
end
|
|
59
63
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
raise InvalidArgument, '--search and --tag can not be used together' if options[:search] && options[:tag]
|
|
64
|
+
end
|
|
63
65
|
|
|
64
66
|
if options[:at]
|
|
65
67
|
finish_date = options[:at]
|
|
66
68
|
finish_date = finish_date.chronify(guess: :begin) if finish_date.is_a? String
|
|
67
69
|
raise InvalidTimeExpression, 'Unable to parse date string for --at' if finish_date.nil?
|
|
68
70
|
|
|
69
|
-
|
|
71
|
+
start_date = options[:took] ? finish_date - took : nil
|
|
70
72
|
elsif options[:back]
|
|
71
|
-
|
|
73
|
+
start_date = options[:back]
|
|
74
|
+
finish_date = options[:took] ? start_date + took : Time.now
|
|
75
|
+
|
|
76
|
+
raise InvalidTimeExpression, 'Unable to parse date string' if start_date.nil?
|
|
72
77
|
|
|
73
|
-
raise InvalidTimeExpression, 'Unable to parse date string' if date.nil?
|
|
74
78
|
else
|
|
75
|
-
|
|
79
|
+
start_date = options[:took] ? Time.now - took : nil
|
|
80
|
+
finish_date = Time.now
|
|
76
81
|
end
|
|
82
|
+
|
|
83
|
+
[start_date, finish_date]
|
|
77
84
|
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
desc 'Mark last X entries as @done'
|
|
89
|
+
long_desc 'Marks the last X entries with a @done tag and current date. Does not alter already completed entries.'
|
|
90
|
+
arg_name 'COUNT', optional: true
|
|
91
|
+
command :finish do |c|
|
|
92
|
+
cmd = Doing::FinishCommand.new(@wwid)
|
|
93
|
+
cmd.add_examples(c)
|
|
94
|
+
cmd.add_options(c)
|
|
95
|
+
add_options(:search, c)
|
|
96
|
+
add_options(:tag_filter, c)
|
|
97
|
+
add_options(:finish_entry, c)
|
|
78
98
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
99
|
+
c.action do |_global_options, options, args|
|
|
100
|
+
options[:fuzzy] = false
|
|
101
|
+
unless options[:auto]
|
|
102
|
+
if options[:from]
|
|
103
|
+
start_date, finish_date = cmd.handle_from(options)
|
|
104
|
+
else
|
|
105
|
+
start_date, finish_date = cmd.handle_date_options(options)
|
|
106
|
+
end
|
|
83
107
|
end
|
|
84
108
|
|
|
109
|
+
tags = options[:tag] || []
|
|
110
|
+
|
|
85
111
|
raise InvalidArgument, 'Only one argument allowed' if args.length > 1
|
|
86
112
|
|
|
87
|
-
|
|
113
|
+
unless args.empty? || args[0] =~ /\d+/
|
|
114
|
+
raise InvalidArgument, 'Invalid argument (specify number of recent items to mark @done)'
|
|
88
115
|
|
|
89
|
-
if options[:interactive]
|
|
90
|
-
count = 0
|
|
91
|
-
else
|
|
92
|
-
count = args[0] ? args[0].to_i : 1
|
|
93
116
|
end
|
|
94
117
|
|
|
118
|
+
count = if options[:interactive]
|
|
119
|
+
0
|
|
120
|
+
else
|
|
121
|
+
args[0] ? args[0].to_i : 1
|
|
122
|
+
end
|
|
123
|
+
|
|
95
124
|
search = nil
|
|
96
125
|
|
|
97
126
|
if options[:search]
|
|
@@ -101,10 +130,11 @@ command :finish do |c|
|
|
|
101
130
|
|
|
102
131
|
opts = {
|
|
103
132
|
archive: options[:archive],
|
|
104
|
-
back:
|
|
133
|
+
back: start_date,
|
|
105
134
|
case: options[:case].normalize_case,
|
|
106
135
|
count: count,
|
|
107
136
|
date: options[:date],
|
|
137
|
+
done_date: finish_date,
|
|
108
138
|
fuzzy: options[:fuzzy],
|
|
109
139
|
interactive: options[:interactive],
|
|
110
140
|
not: options[:not],
|
|
@@ -112,6 +142,7 @@ command :finish do |c|
|
|
|
112
142
|
search: search,
|
|
113
143
|
section: options[:section],
|
|
114
144
|
sequential: options[:auto],
|
|
145
|
+
start_date: start_date,
|
|
115
146
|
tag: tags,
|
|
116
147
|
tag_bool: options[:bool].normalize_bool,
|
|
117
148
|
tags: ['done'],
|
data/bin/commands/flag.rb
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# @@mark @@flag
|
|
2
4
|
desc 'Mark last entry as flagged'
|
|
3
5
|
command %i[mark flag] do |c|
|
|
4
6
|
c.example 'doing flag', desc: 'Add @flagged to the last entry created'
|
|
5
7
|
c.example 'doing mark', desc: 'mark is an alias for flag'
|
|
6
8
|
c.example 'doing flag --tag project1 --count 2', desc: 'Add @flagged to the last 2 entries tagged @project1'
|
|
7
|
-
c.example 'doing flag --interactive --search "/(develop|cod)ing/"',
|
|
9
|
+
c.example 'doing flag --interactive --search "/(develop|cod)ing/"',
|
|
10
|
+
desc: 'Find entries matching regular expression and create a menu allowing multiple selections,
|
|
11
|
+
selected items will be @flagged'
|
|
8
12
|
|
|
9
13
|
c.desc 'Section'
|
|
10
14
|
c.arg_name 'SECTION_NAME'
|
data/bin/commands/grep.rb
CHANGED
|
@@ -16,25 +16,12 @@ command %i[grep search] do |c|
|
|
|
16
16
|
c.arg_name 'NAME'
|
|
17
17
|
c.flag %i[s section], default_value: 'All'
|
|
18
18
|
|
|
19
|
-
c.desc "Output to export format (#{Doing::Plugins.plugin_names(type: :export)})"
|
|
20
|
-
c.arg_name 'FORMAT'
|
|
21
|
-
c.flag %i[o output]
|
|
22
|
-
|
|
23
|
-
c.desc "Output using a template from configuration"
|
|
24
|
-
c.arg_name 'TEMPLATE_KEY'
|
|
25
|
-
c.flag [:config_template], type: TemplateName, default_value: 'default'
|
|
26
|
-
|
|
27
|
-
c.desc 'Override output format with a template string containing %placeholders'
|
|
28
|
-
c.arg_name 'TEMPLATE_STRING'
|
|
29
|
-
c.flag [:template]
|
|
30
|
-
|
|
31
19
|
# c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
|
|
32
20
|
# c.switch [:fuzzy], default_value: false, negatable: false
|
|
33
21
|
|
|
34
22
|
c.desc 'Force exact string matching (case sensitive)'
|
|
35
23
|
c.switch %i[x exact], default_value: Doing.config.exact_match?, negatable: Doing.config.exact_match?
|
|
36
24
|
|
|
37
|
-
|
|
38
25
|
c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
|
|
39
26
|
c.arg_name 'TYPE'
|
|
40
27
|
c.flag [:case], must_match: REGEX_CASE,
|
|
@@ -53,13 +40,15 @@ command %i[grep search] do |c|
|
|
|
53
40
|
c.desc 'Display an interactive menu of results to perform further operations'
|
|
54
41
|
c.switch %i[i interactive], default_value: false, negatable: false
|
|
55
42
|
|
|
43
|
+
add_options(:output_template, c)
|
|
56
44
|
add_options(:tag_filter, c)
|
|
57
45
|
add_options(:date_filter, c)
|
|
58
46
|
add_options(:time_display, c)
|
|
59
47
|
|
|
60
48
|
c.action do |_global_options, options, args|
|
|
61
49
|
options[:fuzzy] = false
|
|
62
|
-
|
|
50
|
+
|
|
51
|
+
raise InvalidPlugin.new('output', options[:output]) if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
|
|
63
52
|
|
|
64
53
|
template = Doing.setting(['templates', options[:config_template]]).deep_merge(Doing.settings)
|
|
65
54
|
tags_color = template.key?('tags_color') ? template['tags_color'] : nil
|
data/bin/commands/last.rb
CHANGED
|
@@ -21,20 +21,13 @@ command :last do |c|
|
|
|
21
21
|
c.desc "Delete the last entry"
|
|
22
22
|
c.switch %i[d delete], negatable: false, default_value: false
|
|
23
23
|
|
|
24
|
-
c.desc "Output using a template from configuration"
|
|
25
|
-
c.arg_name 'TEMPLATE_KEY'
|
|
26
|
-
c.flag [:config_template], type: TemplateName, default_value: 'last'
|
|
27
|
-
|
|
28
|
-
c.desc 'Override output format with a template string containing %placeholders'
|
|
29
|
-
c.arg_name 'TEMPLATE_STRING'
|
|
30
|
-
c.flag [:template]
|
|
31
|
-
|
|
32
24
|
c.desc "Highlight search matches in output. Only affects command line output"
|
|
33
25
|
c.switch %i[h hilite], default_value: Doing.settings.dig('search', 'highlight')
|
|
34
26
|
|
|
35
27
|
c.desc 'Show elapsed time if entry is not tagged @done'
|
|
36
28
|
c.switch [:duration]
|
|
37
29
|
|
|
30
|
+
add_options(:output_template, c, default_template: 'last')
|
|
38
31
|
add_options(:search, c)
|
|
39
32
|
add_options(:tag_filter, c)
|
|
40
33
|
|
|
@@ -69,6 +62,7 @@ command :last do |c|
|
|
|
69
62
|
case: options[:case],
|
|
70
63
|
hilite: options[:hilite],
|
|
71
64
|
negate: options[:not],
|
|
65
|
+
output: options[:output],
|
|
72
66
|
tag: options[:tag],
|
|
73
67
|
tag_bool: options[:bool],
|
|
74
68
|
delete: options[:delete],
|
data/bin/commands/meanwhile.rb
CHANGED
|
@@ -19,6 +19,8 @@ command :meanwhile do |c|
|
|
|
19
19
|
c.switch %i[a archive], negatable: false, default_value: false
|
|
20
20
|
|
|
21
21
|
add_options(:add_entry, c)
|
|
22
|
+
# TODO: Add took and from handling for post-dating meanwhile entries
|
|
23
|
+
# add_options(:add_dated, c)
|
|
22
24
|
|
|
23
25
|
c.action do |global_options, options, args|
|
|
24
26
|
Doing.auto_tag = !options[:noauto]
|
|
@@ -31,17 +33,18 @@ command :meanwhile do |c|
|
|
|
31
33
|
date = Time.now
|
|
32
34
|
end
|
|
33
35
|
|
|
34
|
-
if options[:section]
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
section = if options[:section]
|
|
37
|
+
@wwid.guess_section(options[:section]) || options[:section].cap_first
|
|
38
|
+
else
|
|
39
|
+
Doing.setting('current_section')
|
|
40
|
+
end
|
|
39
41
|
input = ''
|
|
40
42
|
|
|
41
43
|
ask_note = options[:ask] ? Doing::Prompt.read_lines(prompt: 'Add a note') : []
|
|
42
44
|
|
|
43
45
|
if options[:editor]
|
|
44
46
|
raise MissingEditor, 'No EDITOR variable defined in environment' if Doing::Util.default_editor.nil?
|
|
47
|
+
|
|
45
48
|
input += date.strftime('%F %R | ')
|
|
46
49
|
input += args.join(' ') unless args.empty?
|
|
47
50
|
input += "\n#{options[:note]}" if options[:note]
|
|
@@ -70,7 +73,11 @@ command :meanwhile do |c|
|
|
|
70
73
|
note.add(ask_note) if ask_note.good?
|
|
71
74
|
end
|
|
72
75
|
|
|
73
|
-
@wwid.stop_start('meanwhile', { new_item: input,
|
|
76
|
+
@wwid.stop_start('meanwhile', { new_item: input,
|
|
77
|
+
back: date,
|
|
78
|
+
section: section,
|
|
79
|
+
archive: options[:archive],
|
|
80
|
+
note: note })
|
|
74
81
|
@wwid.write(@wwid.doing_file)
|
|
75
82
|
end
|
|
76
83
|
end
|