doing 2.1.11 → 2.1.15
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/.irbrc +1 -0
- data/.yardoc/checksums +15 -13
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/CHANGELOG.md +44 -1
- data/Gemfile.lock +9 -2
- data/README.md +56 -19
- data/bin/doing +215 -76
- data/docs/doc/Array.html +117 -3
- 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 +1 -1
- data/docs/doc/Doing/Completion.html +1 -1
- data/docs/doc/Doing/Configuration.html +7 -4
- data/docs/doc/Doing/Errors/DoingNoTraceError.html +1 -1
- data/docs/doc/Doing/Errors/DoingRuntimeError.html +1 -1
- data/docs/doc/Doing/Errors/DoingStandardError.html +1 -1
- data/docs/doc/Doing/Errors/EmptyInput.html +1 -1
- data/docs/doc/Doing/Errors/NoResults.html +1 -1
- data/docs/doc/Doing/Errors/PluginException.html +1 -1
- data/docs/doc/Doing/Errors/UserCancelled.html +1 -1
- data/docs/doc/Doing/Errors/WrongCommand.html +1 -1
- data/docs/doc/Doing/Errors.html +1 -1
- data/docs/doc/Doing/Hooks.html +1 -1
- data/docs/doc/Doing/Item.html +337 -14
- data/docs/doc/Doing/Items.html +66 -2
- data/docs/doc/Doing/LogAdapter.html +1 -1
- data/docs/doc/Doing/Note.html +2 -2
- data/docs/doc/Doing/Pager.html +1 -1
- data/docs/doc/Doing/Plugins.html +1 -1
- data/docs/doc/Doing/Prompt.html +35 -1
- data/docs/doc/Doing/Section.html +1 -1
- data/docs/doc/Doing/TemplateString.html +2 -2
- data/docs/doc/Doing/Util/Backup.html +84 -1
- data/docs/doc/Doing/Util.html +1 -1
- data/docs/doc/Doing/WWID.html +180 -35
- data/docs/doc/Doing.html +3 -3
- 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 +279 -0
- 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 +767 -115
- data/docs/doc/Symbol.html +1 -1
- data/docs/doc/Time.html +1 -1
- data/docs/doc/_index.html +14 -9
- data/docs/doc/class_list.html +1 -1
- data/docs/doc/file.README.html +41 -15
- data/docs/doc/index.html +41 -15
- data/docs/doc/method_list.html +407 -279
- data/docs/doc/top-level-namespace.html +2 -2
- data/docs/index.md +56 -19
- data/doing.gemspec +2 -0
- data/doing.rdoc +244 -45
- data/example_plugin.rb +2 -4
- data/lib/completion/_doing.zsh +31 -27
- data/lib/completion/doing.bash +50 -39
- data/lib/completion/doing.fish +35 -6
- data/lib/doing/array_chronify.rb +57 -0
- data/lib/doing/configuration.rb +4 -1
- data/lib/doing/item.rb +176 -0
- data/lib/doing/log_adapter.rb +1 -1
- data/lib/doing/numeric_chronify.rb +40 -0
- data/lib/doing/plugins/export/dayone_export.rb +1 -1
- data/lib/doing/plugins/export/json_export.rb +2 -2
- data/lib/doing/plugins/export/template_export.rb +47 -90
- data/lib/doing/plugins/import/calendar_import.rb +13 -1
- data/lib/doing/plugins/import/doing_import.rb +12 -1
- data/lib/doing/plugins/import/timing_import.rb +13 -1
- data/lib/doing/prompt.rb +13 -1
- data/lib/doing/string.rb +97 -33
- data/lib/doing/string_chronify.rb +83 -13
- data/lib/doing/time.rb +6 -6
- data/lib/doing/util_backup.rb +1 -1
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +88 -93
- data/lib/doing.rb +31 -27
- data/lib/examples/plugins/say_export.rb +1 -4
- metadata +46 -2
data/bin/doing
CHANGED
|
@@ -27,6 +27,7 @@ autocomplete_commands true
|
|
|
27
27
|
|
|
28
28
|
REGEX_BOOL = /^(?:and|all|any|or|not|none|p(?:at(?:tern)?)?)$/i
|
|
29
29
|
REGEX_SORT_ORDER = /^(?:a(?:sc)?|d(?:esc)?)$/i
|
|
30
|
+
REGEX_VALUE_QUERY = /^(?:!)?@?(?:\S+) +(?:!?[<>=][=*]?|[$*^]=) +(?:.*?)$/
|
|
30
31
|
|
|
31
32
|
InvalidExportType = Class.new(RuntimeError)
|
|
32
33
|
MissingConfigFile = Class.new(RuntimeError)
|
|
@@ -69,6 +70,12 @@ if settings.dig('plugins', 'command_path')
|
|
|
69
70
|
commands_from File.expand_path(settings.dig('plugins', 'command_path'))
|
|
70
71
|
end
|
|
71
72
|
|
|
73
|
+
class TagArray < Array; end
|
|
74
|
+
|
|
75
|
+
accept TagArray do |value|
|
|
76
|
+
value.gsub(/[, ]+/, ' ').split(' ').map { |tag| tag.sub(/^@/, '')}.map(&:strip)
|
|
77
|
+
end
|
|
78
|
+
|
|
72
79
|
program_desc 'A CLI for a What Was I Doing system'
|
|
73
80
|
program_long_desc %(Doing uses a TaskPaper-like formatting to keep a plain text
|
|
74
81
|
record of what you've been doing, complete with tag-based time tracking. The
|
|
@@ -110,7 +117,7 @@ switch %i[q quiet], default_value: false, negatable: false
|
|
|
110
117
|
desc 'Verbose output'
|
|
111
118
|
switch %i[debug], default_value: false, negatable: false
|
|
112
119
|
|
|
113
|
-
desc 'Use a specific configuration file. Deprecated, set $DOING_CONFIG instead
|
|
120
|
+
desc 'Use a specific configuration file. Deprecated, set $DOING_CONFIG instead'
|
|
114
121
|
flag [:config_file], default_value: config.config_file
|
|
115
122
|
|
|
116
123
|
desc 'Specify a different doing_file'
|
|
@@ -120,7 +127,7 @@ flag %i[f doing_file]
|
|
|
120
127
|
|
|
121
128
|
# @@again @@resume
|
|
122
129
|
desc 'Repeat last entry as new entry'
|
|
123
|
-
long_desc 'This command is designed to allow multiple time intervals to be created for an entry by duplicating it with a new start (and end, eventually) time
|
|
130
|
+
long_desc 'This command is designed to allow multiple time intervals to be created for an entry by duplicating it with a new start (and end, eventually) time'
|
|
124
131
|
command %i[again resume] do |c|
|
|
125
132
|
c.example 'doing resume', desc: 'Duplicate the most recent entry with a new start time, removing any @done tag'
|
|
126
133
|
c.example 'doing again', desc: 'again is an alias for resume'
|
|
@@ -136,15 +143,19 @@ command %i[again resume] do |c|
|
|
|
136
143
|
c.arg_name 'SECTION_NAME'
|
|
137
144
|
c.flag [:in]
|
|
138
145
|
|
|
139
|
-
c.desc 'Repeat last entry matching tags. Combine multiple tags with a comma. Wildcards allowed (*, ?)
|
|
146
|
+
c.desc 'Repeat last entry matching tags. Combine multiple tags with a comma. Wildcards allowed (*, ?)'
|
|
140
147
|
c.arg_name 'TAG'
|
|
141
|
-
c.flag [:tag]
|
|
148
|
+
c.flag [:tag], type: TagArray
|
|
142
149
|
|
|
143
150
|
c.desc 'Repeat last entry matching search. Surround with
|
|
144
151
|
slashes for regex (e.g. "/query/"), start with a single quote for exact match ("\'query").'
|
|
145
152
|
c.arg_name 'QUERY'
|
|
146
153
|
c.flag [:search]
|
|
147
154
|
|
|
155
|
+
c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
|
|
156
|
+
c.arg_name 'QUERY'
|
|
157
|
+
c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
|
|
158
|
+
|
|
148
159
|
# c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
|
|
149
160
|
# c.switch [:fuzzy], default_value: false, negatable: false
|
|
150
161
|
|
|
@@ -158,23 +169,26 @@ command %i[again resume] do |c|
|
|
|
158
169
|
c.arg_name 'TYPE'
|
|
159
170
|
c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
|
|
160
171
|
|
|
161
|
-
c.desc 'Boolean used to combine multiple tags. Use PATTERN to parse + and - as booleans
|
|
172
|
+
c.desc 'Boolean used to combine multiple tags. Use PATTERN to parse + and - as booleans'
|
|
162
173
|
c.arg_name 'BOOLEAN'
|
|
163
174
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
|
164
175
|
|
|
165
176
|
c.desc "Edit duplicated entry with #{Doing::Util.default_editor} before adding"
|
|
166
177
|
c.switch %i[e editor], negatable: false, default_value: false
|
|
167
178
|
|
|
168
|
-
c.desc '
|
|
179
|
+
c.desc 'Add a note'
|
|
169
180
|
c.arg_name 'TEXT'
|
|
170
181
|
c.flag %i[n note]
|
|
171
182
|
|
|
183
|
+
c.desc 'Prompt for note via multi-line input'
|
|
184
|
+
c.switch %i[ask], negatable: false, default_value: false
|
|
185
|
+
|
|
172
186
|
c.desc 'Select item to resume from a menu of matching entries'
|
|
173
187
|
c.switch %i[i interactive], negatable: false, default_value: false
|
|
174
188
|
|
|
175
189
|
c.action do |_global_options, options, _args|
|
|
176
190
|
options[:fuzzy] = false
|
|
177
|
-
tags = options[:tag].nil? ? [] : options[:tag]
|
|
191
|
+
tags = options[:tag].nil? ? [] : options[:tag]
|
|
178
192
|
|
|
179
193
|
options[:case] = options[:case].normalize_case
|
|
180
194
|
|
|
@@ -184,6 +198,11 @@ command %i[again resume] do |c|
|
|
|
184
198
|
options[:search] = search
|
|
185
199
|
end
|
|
186
200
|
|
|
201
|
+
note = Doing::Note.new(options[:note])
|
|
202
|
+
note.add(Doing::Prompt.request_lines(prompt: 'Add a note')) if options[:ask]
|
|
203
|
+
|
|
204
|
+
options[:note] = note
|
|
205
|
+
|
|
187
206
|
opts = options.dup
|
|
188
207
|
|
|
189
208
|
opts[:tag] = tags
|
|
@@ -196,7 +215,7 @@ end
|
|
|
196
215
|
|
|
197
216
|
# @@cancel
|
|
198
217
|
desc 'End last X entries with no time tracked'
|
|
199
|
-
long_desc 'Adds @done tag without datestamp so no elapsed time is recorded. Alias for `doing finish --no-date
|
|
218
|
+
long_desc 'Adds @done tag without datestamp so no elapsed time is recorded. Alias for `doing finish --no-date`'
|
|
200
219
|
arg_name 'COUNT'
|
|
201
220
|
command :cancel do |c|
|
|
202
221
|
c.example 'doing cancel', desc: 'Cancel the last entry'
|
|
@@ -209,11 +228,11 @@ command :cancel do |c|
|
|
|
209
228
|
c.arg_name 'NAME'
|
|
210
229
|
c.flag %i[s section]
|
|
211
230
|
|
|
212
|
-
c.desc 'Cancel the last X entries containing TAG. Separate multiple tags with comma (--tag=tag1,tag2). Wildcards allowed (*, ?)
|
|
231
|
+
c.desc 'Cancel the last X entries containing TAG. Separate multiple tags with comma (--tag=tag1,tag2). Wildcards allowed (*, ?)'
|
|
213
232
|
c.arg_name 'TAG'
|
|
214
|
-
c.flag [:tag]
|
|
233
|
+
c.flag [:tag], type: TagArray
|
|
215
234
|
|
|
216
|
-
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans
|
|
235
|
+
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans'
|
|
217
236
|
c.arg_name 'BOOLEAN'
|
|
218
237
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
|
219
238
|
|
|
@@ -221,6 +240,10 @@ command :cancel do |c|
|
|
|
221
240
|
c.arg_name 'QUERY'
|
|
222
241
|
c.flag [:search]
|
|
223
242
|
|
|
243
|
+
c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
|
|
244
|
+
c.arg_name 'QUERY'
|
|
245
|
+
c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
|
|
246
|
+
|
|
224
247
|
# c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
|
|
225
248
|
# c.switch [:fuzzy], default_value: false, negatable: false
|
|
226
249
|
|
|
@@ -251,7 +274,7 @@ command :cancel do |c|
|
|
|
251
274
|
if options[:tag].nil?
|
|
252
275
|
tags = []
|
|
253
276
|
else
|
|
254
|
-
tags = options[:tag]
|
|
277
|
+
tags = options[:tag]
|
|
255
278
|
end
|
|
256
279
|
|
|
257
280
|
raise InvalidArgument, 'Only one argument allowed' if args.length > 1
|
|
@@ -285,7 +308,8 @@ command :cancel do |c|
|
|
|
285
308
|
tag: tags,
|
|
286
309
|
tag_bool: options[:bool].normalize_bool,
|
|
287
310
|
tags: ['done'],
|
|
288
|
-
unfinished: options[:unfinished]
|
|
311
|
+
unfinished: options[:unfinished],
|
|
312
|
+
val: options[:val]
|
|
289
313
|
}
|
|
290
314
|
|
|
291
315
|
wwid.tag_last(opts)
|
|
@@ -293,7 +317,7 @@ command :cancel do |c|
|
|
|
293
317
|
end
|
|
294
318
|
|
|
295
319
|
# @@done @@did
|
|
296
|
-
desc 'Add a completed item with @done(date). No argument finishes last entry
|
|
320
|
+
desc 'Add a completed item with @done(date). No argument finishes last entry'
|
|
297
321
|
long_desc 'Use this command to add an entry after you\'ve already finished it. It will be immediately marked as @done.
|
|
298
322
|
You can modify the start and end times of the entry using the --back, --took, and --at flags, making it an easy
|
|
299
323
|
way to add entries in post and maintain accurate (albeit manual) time tracking.'
|
|
@@ -326,7 +350,7 @@ command %i[done did] do |c|
|
|
|
326
350
|
If used without the --back option, the start date will be moved back to allow
|
|
327
351
|
the completion date to be the current time.)
|
|
328
352
|
c.arg_name 'INTERVAL'
|
|
329
|
-
c.flag %i[t took]
|
|
353
|
+
c.flag %i[t took for]
|
|
330
354
|
|
|
331
355
|
c.desc 'Section'
|
|
332
356
|
c.arg_name 'NAME'
|
|
@@ -339,6 +363,9 @@ command %i[done did] do |c|
|
|
|
339
363
|
c.arg_name 'TEXT'
|
|
340
364
|
c.flag %i[n note]
|
|
341
365
|
|
|
366
|
+
c.desc 'Prompt for note via multi-line input'
|
|
367
|
+
c.switch %i[ask], negatable: false, default_value: false
|
|
368
|
+
|
|
342
369
|
c.desc 'Finish last entry not already marked @done'
|
|
343
370
|
c.switch %i[u unfinished], negatable: false, default_value: false
|
|
344
371
|
|
|
@@ -374,6 +401,8 @@ command %i[done did] do |c|
|
|
|
374
401
|
end
|
|
375
402
|
|
|
376
403
|
if options[:date]
|
|
404
|
+
finish_date = wwid.verify_duration(date, finish_date) unless options[:took]
|
|
405
|
+
|
|
377
406
|
donedate = finish_date.strftime('%F %R')
|
|
378
407
|
end
|
|
379
408
|
|
|
@@ -385,6 +414,7 @@ command %i[done did] do |c|
|
|
|
385
414
|
|
|
386
415
|
note = Doing::Note.new
|
|
387
416
|
note.add(options[:note]) if options[:note]
|
|
417
|
+
note.add(Doing::Prompt.request_lines(prompt: 'Add a note')) if options[:ask]
|
|
388
418
|
|
|
389
419
|
if options[:editor]
|
|
390
420
|
raise MissingEditor, 'No EDITOR variable defined in environment' if Doing::Util.default_editor.nil?
|
|
@@ -439,7 +469,6 @@ command %i[done did] do |c|
|
|
|
439
469
|
if options[:remove]
|
|
440
470
|
wwid.tag_last({ tags: ['done'], count: 1, section: section, remove: true })
|
|
441
471
|
else
|
|
442
|
-
note = options[:note] ? Doing::Note.new(options[:note]) : nil
|
|
443
472
|
opt = {
|
|
444
473
|
archive: options[:archive],
|
|
445
474
|
back: finish_date,
|
|
@@ -520,7 +549,7 @@ command :finish do |c|
|
|
|
520
549
|
|
|
521
550
|
c.desc 'Set the completed date to the start date plus XX[hmd]'
|
|
522
551
|
c.arg_name 'INTERVAL'
|
|
523
|
-
c.flag %i[t took]
|
|
552
|
+
c.flag %i[t took for]
|
|
524
553
|
|
|
525
554
|
c.desc %(Set finish date to specific date/time (natural langauge parsed, e.g. --at=1:30pm). If used, ignores --back.)
|
|
526
555
|
c.arg_name 'DATE_STRING'
|
|
@@ -529,12 +558,16 @@ command :finish do |c|
|
|
|
529
558
|
c.desc 'Finish the last X entries containing TAG.
|
|
530
559
|
Separate multiple tags with comma (--tag=tag1,tag2), combine with --bool. Wildcards allowed (*, ?).'
|
|
531
560
|
c.arg_name 'TAG'
|
|
532
|
-
c.flag [:tag]
|
|
561
|
+
c.flag [:tag], type: TagArray
|
|
533
562
|
|
|
534
563
|
c.desc 'Finish the last X entries matching search filter, surround with slashes for regex (e.g. "/query.*/"), start with single quote for exact match ("\'query")'
|
|
535
564
|
c.arg_name 'QUERY'
|
|
536
565
|
c.flag [:search]
|
|
537
566
|
|
|
567
|
+
c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
|
|
568
|
+
c.arg_name 'QUERY'
|
|
569
|
+
c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
|
|
570
|
+
|
|
538
571
|
# c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
|
|
539
572
|
# c.switch [:fuzzy], default_value: false, negatable: false
|
|
540
573
|
|
|
@@ -548,7 +581,7 @@ command :finish do |c|
|
|
|
548
581
|
c.arg_name 'TYPE'
|
|
549
582
|
c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
|
|
550
583
|
|
|
551
|
-
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans
|
|
584
|
+
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans'
|
|
552
585
|
c.arg_name 'BOOLEAN'
|
|
553
586
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
|
554
587
|
|
|
@@ -604,7 +637,7 @@ command :finish do |c|
|
|
|
604
637
|
if options[:tag].nil?
|
|
605
638
|
tags = []
|
|
606
639
|
else
|
|
607
|
-
tags = options[:tag]
|
|
640
|
+
tags = options[:tag]
|
|
608
641
|
end
|
|
609
642
|
|
|
610
643
|
raise InvalidArgument, 'Only one argument allowed' if args.length > 1
|
|
@@ -641,7 +674,8 @@ command :finish do |c|
|
|
|
641
674
|
tag_bool: options[:bool].normalize_bool,
|
|
642
675
|
tags: ['done'],
|
|
643
676
|
took: options[:took],
|
|
644
|
-
unfinished: options[:unfinished]
|
|
677
|
+
unfinished: options[:unfinished],
|
|
678
|
+
val: options[:val]
|
|
645
679
|
}
|
|
646
680
|
|
|
647
681
|
wwid.tag_last(opts)
|
|
@@ -666,6 +700,9 @@ command :later do |c|
|
|
|
666
700
|
c.arg_name 'TEXT'
|
|
667
701
|
c.flag %i[n note]
|
|
668
702
|
|
|
703
|
+
c.desc 'Prompt for note via multi-line input'
|
|
704
|
+
c.switch %i[ask], negatable: false, default_value: false
|
|
705
|
+
|
|
669
706
|
c.action do |_global_options, options, args|
|
|
670
707
|
if options[:back]
|
|
671
708
|
date = options[:back].chronify(guess: :begin)
|
|
@@ -674,11 +711,16 @@ command :later do |c|
|
|
|
674
711
|
date = Time.now
|
|
675
712
|
end
|
|
676
713
|
|
|
714
|
+
ask_note = options[:ask] ? Doing::Prompt.request_lines(prompt: 'Add a note') : ''
|
|
715
|
+
|
|
677
716
|
if options[:editor] || (args.empty? && $stdin.stat.size.zero?)
|
|
678
717
|
raise MissingEditor, 'No EDITOR variable defined in environment' if Doing::Util.default_editor.nil?
|
|
679
718
|
|
|
680
719
|
input += date.strftime('%F %R | ')
|
|
681
720
|
input += args.empty? ? '' : args.join(' ')
|
|
721
|
+
input += "\n#{options[:note]}" if options[:note]
|
|
722
|
+
input += "\n#{ask_note}" unless ask_note.empty?
|
|
723
|
+
|
|
682
724
|
input = wwid.fork_editor(input).strip
|
|
683
725
|
raise EmptyInput, 'No content' unless input && !input.empty?
|
|
684
726
|
|
|
@@ -691,6 +733,7 @@ command :later do |c|
|
|
|
691
733
|
d, title, note = wwid.format_input(args.join(' '))
|
|
692
734
|
date = d.nil? ? date : d
|
|
693
735
|
note.add(options[:note]) if options[:note]
|
|
736
|
+
note.add(ask_note) unless ask_note.empty?
|
|
694
737
|
wwid.add_item(title.cap_first, 'Later', { note: note, back: date })
|
|
695
738
|
wwid.write(wwid.doing_file)
|
|
696
739
|
elsif $stdin.stat.size.positive?
|
|
@@ -700,6 +743,7 @@ command :later do |c|
|
|
|
700
743
|
date = d
|
|
701
744
|
end
|
|
702
745
|
note.add(options[:note]) if options[:note]
|
|
746
|
+
note.add(ask_note) unless ask_note.empty?
|
|
703
747
|
wwid.add_item(title.cap_first, 'Later', { note: note, back: date })
|
|
704
748
|
wwid.write(wwid.doing_file)
|
|
705
749
|
else
|
|
@@ -739,12 +783,16 @@ command %i[mark flag] do |c|
|
|
|
739
783
|
c.desc 'Flag the last entry containing TAG.
|
|
740
784
|
Separate multiple tags with comma (--tag=tag1,tag2), combine with --bool. Wildcards allowed (*, ?).'
|
|
741
785
|
c.arg_name 'TAG'
|
|
742
|
-
c.flag [:tag]
|
|
786
|
+
c.flag [:tag], type: TagArray
|
|
743
787
|
|
|
744
788
|
c.desc 'Flag the last entry matching search filter, surround with slashes for regex (e.g. "/query.*/"), start with single quote for exact match ("\'query")'
|
|
745
789
|
c.arg_name 'QUERY'
|
|
746
790
|
c.flag [:search]
|
|
747
791
|
|
|
792
|
+
c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
|
|
793
|
+
c.arg_name 'QUERY'
|
|
794
|
+
c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
|
|
795
|
+
|
|
748
796
|
# c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
|
|
749
797
|
# c.switch [:fuzzy], default_value: false, negatable: false
|
|
750
798
|
|
|
@@ -758,7 +806,7 @@ command %i[mark flag] do |c|
|
|
|
758
806
|
c.arg_name 'TYPE'
|
|
759
807
|
c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
|
|
760
808
|
|
|
761
|
-
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans
|
|
809
|
+
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans'
|
|
762
810
|
c.arg_name 'BOOLEAN'
|
|
763
811
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
|
764
812
|
|
|
@@ -780,7 +828,7 @@ command %i[mark flag] do |c|
|
|
|
780
828
|
if options[:tag].nil?
|
|
781
829
|
search_tags = []
|
|
782
830
|
else
|
|
783
|
-
search_tags = options[:tag]
|
|
831
|
+
search_tags = options[:tag]
|
|
784
832
|
end
|
|
785
833
|
|
|
786
834
|
if options[:interactive]
|
|
@@ -862,6 +910,9 @@ command :meanwhile do |c|
|
|
|
862
910
|
c.arg_name 'TEXT'
|
|
863
911
|
c.flag %i[n note]
|
|
864
912
|
|
|
913
|
+
c.desc 'Prompt for note via multi-line input'
|
|
914
|
+
c.switch %i[ask], negatable: false, default_value: false
|
|
915
|
+
|
|
865
916
|
c.action do |_global_options, options, args|
|
|
866
917
|
if options[:back]
|
|
867
918
|
date = options[:back].chronify(guess: :begin)
|
|
@@ -878,10 +929,15 @@ command :meanwhile do |c|
|
|
|
878
929
|
end
|
|
879
930
|
input = ''
|
|
880
931
|
|
|
932
|
+
ask_note = options[:ask] ? Doing::Prompt.request_lines(prompt: 'Add a note') : []
|
|
933
|
+
|
|
881
934
|
if options[:editor]
|
|
882
935
|
raise MissingEditor, 'No EDITOR variable defined in environment' if Doing::Util.default_editor.nil?
|
|
883
936
|
input += date.strftime('%F %R | ')
|
|
884
937
|
input += args.join(' ') unless args.empty?
|
|
938
|
+
input += "\n#{options[:note]}" if options[:note]
|
|
939
|
+
input += "\n#{ask_note}" unless ask_note.empty?
|
|
940
|
+
|
|
885
941
|
input = wwid.fork_editor(input).strip
|
|
886
942
|
elsif !args.empty?
|
|
887
943
|
input = args.join(' ')
|
|
@@ -900,10 +956,9 @@ command :meanwhile do |c|
|
|
|
900
956
|
note = []
|
|
901
957
|
end
|
|
902
958
|
|
|
903
|
-
|
|
904
|
-
note.
|
|
905
|
-
|
|
906
|
-
note = nil
|
|
959
|
+
unless options[:editor]
|
|
960
|
+
note.add(options[:note]) if options[:note]
|
|
961
|
+
note.add(ask_note) unless ask_note.empty?
|
|
907
962
|
end
|
|
908
963
|
|
|
909
964
|
wwid.stop_start('meanwhile', { new_item: input, back: date, section: section, archive: options[:archive], note: note })
|
|
@@ -937,14 +992,18 @@ command :note do |c|
|
|
|
937
992
|
c.desc "Replace/Remove last entry's note (default append)"
|
|
938
993
|
c.switch %i[r remove], negatable: false, default_value: false
|
|
939
994
|
|
|
940
|
-
c.desc 'Add/remove note from last entry matching tag. Wildcards allowed (*, ?)
|
|
995
|
+
c.desc 'Add/remove note from last entry matching tag. Wildcards allowed (*, ?)'
|
|
941
996
|
c.arg_name 'TAG'
|
|
942
|
-
c.flag [:tag]
|
|
997
|
+
c.flag [:tag], type: TagArray
|
|
943
998
|
|
|
944
999
|
c.desc 'Add/remove note from last entry matching search filter, surround with slashes for regex (e.g. "/query.*/"), start with single quote for exact match ("\'query")'
|
|
945
1000
|
c.arg_name 'QUERY'
|
|
946
1001
|
c.flag [:search]
|
|
947
1002
|
|
|
1003
|
+
c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
|
|
1004
|
+
c.arg_name 'QUERY'
|
|
1005
|
+
c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
|
|
1006
|
+
|
|
948
1007
|
# c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
|
|
949
1008
|
# c.switch [:fuzzy], default_value: false, negatable: false
|
|
950
1009
|
|
|
@@ -958,13 +1017,16 @@ command :note do |c|
|
|
|
958
1017
|
c.arg_name 'TYPE'
|
|
959
1018
|
c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
|
|
960
1019
|
|
|
961
|
-
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans
|
|
1020
|
+
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans'
|
|
962
1021
|
c.arg_name 'BOOLEAN'
|
|
963
1022
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
|
964
1023
|
|
|
965
1024
|
c.desc 'Select item for new note from a menu of matching entries'
|
|
966
1025
|
c.switch %i[i interactive], negatable: false, default_value: false
|
|
967
1026
|
|
|
1027
|
+
c.desc 'Prompt for note via multi-line input'
|
|
1028
|
+
c.switch %i[ask], negatable: false, default_value: false
|
|
1029
|
+
|
|
968
1030
|
c.action do |_global_options, options, args|
|
|
969
1031
|
options[:fuzzy] = false
|
|
970
1032
|
if options[:section]
|
|
@@ -991,8 +1053,9 @@ command :note do |c|
|
|
|
991
1053
|
|
|
992
1054
|
last_note = last_entry.note || Doing::Note.new
|
|
993
1055
|
new_note = Doing::Note.new
|
|
1056
|
+
ask_note = options[:ask] ? Doing::Prompt.request_lines(prompt: 'Add a note') : ''
|
|
994
1057
|
|
|
995
|
-
if options[:editor] || (args.empty? && $stdin.stat.size.zero? && !options[:remove])
|
|
1058
|
+
if options[:editor] || (args.empty? && $stdin.stat.size.zero? && !options[:remove] && !options[:ask])
|
|
996
1059
|
raise MissingEditor, 'No EDITOR variable defined in environment' if Doing::Util.default_editor.nil?
|
|
997
1060
|
|
|
998
1061
|
input = !args.empty? ? args.join(' ') : ''
|
|
@@ -1003,7 +1066,9 @@ command :note do |c|
|
|
|
1003
1066
|
prev_input = last_entry.note || Doing::Note.new
|
|
1004
1067
|
end
|
|
1005
1068
|
|
|
1069
|
+
|
|
1006
1070
|
input = prev_input.add(input)
|
|
1071
|
+
input.add(ask_note) unless ask_note.empty?
|
|
1007
1072
|
|
|
1008
1073
|
input = wwid.fork_editor(prev_input.strip_lines.join("\n"), message: nil).strip
|
|
1009
1074
|
note = input
|
|
@@ -1014,9 +1079,12 @@ command :note do |c|
|
|
|
1014
1079
|
elsif $stdin.stat.size.positive?
|
|
1015
1080
|
new_note.add($stdin.read.strip)
|
|
1016
1081
|
else
|
|
1017
|
-
raise EmptyInput, 'You must provide content when adding a note' unless options[:remove]
|
|
1082
|
+
raise EmptyInput, 'You must provide content when adding a note' unless options[:remove] || !ask_note.empty?
|
|
1083
|
+
|
|
1018
1084
|
end
|
|
1019
1085
|
|
|
1086
|
+
new_note.add(ask_note) unless ask_note.empty?
|
|
1087
|
+
|
|
1020
1088
|
if last_note.equal?(new_note)
|
|
1021
1089
|
Doing.logger.debug('Skipped:', 'No note change')
|
|
1022
1090
|
else
|
|
@@ -1062,6 +1130,9 @@ command %i[now next] do |c|
|
|
|
1062
1130
|
c.arg_name 'TEXT'
|
|
1063
1131
|
c.flag %i[n note]
|
|
1064
1132
|
|
|
1133
|
+
c.desc 'Prompt for note via multi-line input'
|
|
1134
|
+
c.switch %i[ask], negatable: false, default_value: false
|
|
1135
|
+
|
|
1065
1136
|
# c.desc "Edit entry with specified app"
|
|
1066
1137
|
# c.arg_name 'editor_app'
|
|
1067
1138
|
# # c.flag [:a, :app]
|
|
@@ -1081,23 +1152,28 @@ command %i[now next] do |c|
|
|
|
1081
1152
|
options[:section] = settings['current_section']
|
|
1082
1153
|
end
|
|
1083
1154
|
|
|
1155
|
+
ask_note = options[:ask] ? Doing::Prompt.request_lines(prompt: 'Add a note') : ''
|
|
1156
|
+
|
|
1084
1157
|
if options[:editor] || (args.empty? && $stdin.stat.size.zero?)
|
|
1085
1158
|
raise MissingEditor, 'No EDITOR variable defined in environment' if Doing::Util.default_editor.nil?
|
|
1086
1159
|
|
|
1087
1160
|
input = date.strftime('%F %R | ')
|
|
1088
1161
|
input += args.join(' ') unless args.empty?
|
|
1162
|
+
input += "\n#{options[:note]}" if options[:note]
|
|
1163
|
+
input += "\n#{ask_note}" unless ask_note.empty?
|
|
1089
1164
|
input = wwid.fork_editor(input).strip
|
|
1090
1165
|
|
|
1091
1166
|
raise EmptyInput, 'No content' if input.empty?
|
|
1092
1167
|
|
|
1093
1168
|
date, title, note = wwid.format_input(input)
|
|
1094
|
-
|
|
1169
|
+
|
|
1095
1170
|
wwid.add_item(title.cap_first, section, { note: note, back: date, timed: options[:finish_last] })
|
|
1096
1171
|
wwid.write(wwid.doing_file)
|
|
1097
1172
|
elsif args.length.positive?
|
|
1098
1173
|
d, title, note = wwid.format_input(args.join(' '))
|
|
1099
1174
|
date = d.nil? ? date : d
|
|
1100
1175
|
note.add(options[:note]) if options[:note]
|
|
1176
|
+
note.add(ask_note) unless ask_note.empty?
|
|
1101
1177
|
wwid.add_item(title.cap_first, section, { note: note, back: date, timed: options[:finish_last] })
|
|
1102
1178
|
wwid.write(wwid.doing_file)
|
|
1103
1179
|
elsif $stdin.stat.size.positive?
|
|
@@ -1108,6 +1184,7 @@ command %i[now next] do |c|
|
|
|
1108
1184
|
date = d
|
|
1109
1185
|
end
|
|
1110
1186
|
note.add(options[:note]) if options[:note]
|
|
1187
|
+
note.add(ask_note) unless ask_note.empty?
|
|
1111
1188
|
wwid.add_item(title.cap_first, section, { note: note, back: date, timed: options[:finish_last] })
|
|
1112
1189
|
wwid.write(wwid.doing_file)
|
|
1113
1190
|
else
|
|
@@ -1135,7 +1212,7 @@ command %i[reset begin] do |c|
|
|
|
1135
1212
|
c.desc 'Resume entry (remove @done)'
|
|
1136
1213
|
c.switch %i[r resume], default_value: true
|
|
1137
1214
|
|
|
1138
|
-
c.desc 'Reset last entry matching tag. Wildcards allowed (*, ?)
|
|
1215
|
+
c.desc 'Reset last entry matching tag. Wildcards allowed (*, ?)'
|
|
1139
1216
|
c.arg_name 'TAG'
|
|
1140
1217
|
c.flag [:tag]
|
|
1141
1218
|
|
|
@@ -1143,6 +1220,10 @@ command %i[reset begin] do |c|
|
|
|
1143
1220
|
c.arg_name 'QUERY'
|
|
1144
1221
|
c.flag [:search]
|
|
1145
1222
|
|
|
1223
|
+
c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
|
|
1224
|
+
c.arg_name 'QUERY'
|
|
1225
|
+
c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
|
|
1226
|
+
|
|
1146
1227
|
# c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
|
|
1147
1228
|
# c.switch [:fuzzy], default_value: false, negatable: false
|
|
1148
1229
|
|
|
@@ -1156,7 +1237,7 @@ command %i[reset begin] do |c|
|
|
|
1156
1237
|
c.arg_name 'TYPE'
|
|
1157
1238
|
c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
|
|
1158
1239
|
|
|
1159
|
-
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
|
|
1240
|
+
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans'
|
|
1160
1241
|
c.arg_name 'BOOLEAN'
|
|
1161
1242
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
|
1162
1243
|
|
|
@@ -1256,13 +1337,21 @@ command :select do |c|
|
|
|
1256
1337
|
|
|
1257
1338
|
c.desc 'Initial search query for filtering. Matching is fuzzy. For exact matching, start query with a single quote, e.g. `--query "\'search"'
|
|
1258
1339
|
c.arg_name 'QUERY'
|
|
1259
|
-
c.flag %i[q query
|
|
1340
|
+
c.flag %i[q query]
|
|
1341
|
+
|
|
1342
|
+
c.desc 'Select from entries matching search filter, surround with slashes for regex (e.g. "/query.*/"), start with single quote for exact match ("\'query")'
|
|
1343
|
+
c.arg_name 'QUERY'
|
|
1344
|
+
c.flag [:search]
|
|
1345
|
+
|
|
1346
|
+
c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
|
|
1347
|
+
c.arg_name 'QUERY'
|
|
1348
|
+
c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
|
|
1260
1349
|
|
|
1261
|
-
c.desc 'Select from entries older than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day
|
|
1350
|
+
c.desc 'Select from entries older than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day'
|
|
1262
1351
|
c.arg_name 'DATE_STRING'
|
|
1263
1352
|
c.flag [:before]
|
|
1264
1353
|
|
|
1265
|
-
c.desc 'Select from entries newer than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day
|
|
1354
|
+
c.desc 'Select from entries newer than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day'
|
|
1266
1355
|
c.arg_name 'DATE_STRING'
|
|
1267
1356
|
c.flag [:after]
|
|
1268
1357
|
|
|
@@ -1287,7 +1376,7 @@ command :select do |c|
|
|
|
1287
1376
|
c.arg_name 'TYPE'
|
|
1288
1377
|
c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
|
|
1289
1378
|
|
|
1290
|
-
c.desc 'Use --no-menu to skip the interactive menu. Use with --query to filter items and act on results automatically. Test with `--output doing` to preview matches
|
|
1379
|
+
c.desc 'Use --no-menu to skip the interactive menu. Use with --query to filter items and act on results automatically. Test with `--output doing` to preview matches'
|
|
1291
1380
|
c.switch %i[menu], negatable: true, default_value: true
|
|
1292
1381
|
|
|
1293
1382
|
c.desc 'Cancel selected items (add @done without timestamp)'
|
|
@@ -1305,7 +1394,7 @@ command :select do |c|
|
|
|
1305
1394
|
c.desc 'Add flag to selected item(s)'
|
|
1306
1395
|
c.switch %i[flag], negatable: false, default_value: false
|
|
1307
1396
|
|
|
1308
|
-
c.desc 'Perform action without confirmation
|
|
1397
|
+
c.desc 'Perform action without confirmation'
|
|
1309
1398
|
c.switch %i[force], negatable: false, default_value: false
|
|
1310
1399
|
|
|
1311
1400
|
c.desc 'Save selected entries to file using --output format'
|
|
@@ -1365,6 +1454,10 @@ command :tag do |c|
|
|
|
1365
1454
|
c.arg_name 'ORIG_TAG'
|
|
1366
1455
|
c.flag %i[rename]
|
|
1367
1456
|
|
|
1457
|
+
c.desc 'Include a value, e.g. @tag(value)'
|
|
1458
|
+
c.arg_name 'VALUE'
|
|
1459
|
+
c.flag %i[v value]
|
|
1460
|
+
|
|
1368
1461
|
c.desc 'Don\'t ask permission to tag all entries when count is 0'
|
|
1369
1462
|
c.switch %i[force], negatable: false, default_value: false
|
|
1370
1463
|
|
|
@@ -1386,12 +1479,16 @@ command :tag do |c|
|
|
|
1386
1479
|
c.desc 'Tag the last X entries containing TAG.
|
|
1387
1480
|
Separate multiple tags with comma (--tag=tag1,tag2), combine with --bool. Wildcards allowed (*, ?).'
|
|
1388
1481
|
c.arg_name 'TAG'
|
|
1389
|
-
c.flag [:tag]
|
|
1482
|
+
c.flag [:tag], type: TagArray
|
|
1390
1483
|
|
|
1391
1484
|
c.desc 'Tag entries matching search filter, surround with slashes for regex (e.g. "/query.*/"), start with single quote for exact match ("\'query")'
|
|
1392
1485
|
c.arg_name 'QUERY'
|
|
1393
1486
|
c.flag [:search]
|
|
1394
1487
|
|
|
1488
|
+
c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
|
|
1489
|
+
c.arg_name 'QUERY'
|
|
1490
|
+
c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
|
|
1491
|
+
|
|
1395
1492
|
# c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
|
|
1396
1493
|
# c.switch [:fuzzy], default_value: false, negatable: false
|
|
1397
1494
|
|
|
@@ -1405,7 +1502,7 @@ command :tag do |c|
|
|
|
1405
1502
|
c.arg_name 'TYPE'
|
|
1406
1503
|
c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
|
|
1407
1504
|
|
|
1408
|
-
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans
|
|
1505
|
+
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans'
|
|
1409
1506
|
c.arg_name 'BOOLEAN'
|
|
1410
1507
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
|
1411
1508
|
|
|
@@ -1428,7 +1525,7 @@ command :tag do |c|
|
|
|
1428
1525
|
if options[:tag].nil?
|
|
1429
1526
|
search_tags = []
|
|
1430
1527
|
else
|
|
1431
|
-
search_tags = options[:tag]
|
|
1528
|
+
search_tags = options[:tag]
|
|
1432
1529
|
end
|
|
1433
1530
|
|
|
1434
1531
|
if options[:autotag]
|
|
@@ -1528,11 +1625,11 @@ command %i[grep search] do |c|
|
|
|
1528
1625
|
c.arg_name 'NAME'
|
|
1529
1626
|
c.flag %i[s section], default_value: 'All'
|
|
1530
1627
|
|
|
1531
|
-
c.desc 'Search entries older than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day
|
|
1628
|
+
c.desc 'Search entries older than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day'
|
|
1532
1629
|
c.arg_name 'DATE_STRING'
|
|
1533
1630
|
c.flag [:before]
|
|
1534
1631
|
|
|
1535
|
-
c.desc 'Search entries newer than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day
|
|
1632
|
+
c.desc 'Search entries newer than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day'
|
|
1536
1633
|
c.arg_name 'DATE_STRING'
|
|
1537
1634
|
c.flag [:after]
|
|
1538
1635
|
|
|
@@ -1591,6 +1688,13 @@ command %i[grep search] do |c|
|
|
|
1591
1688
|
c.desc 'Display an interactive menu of results to perform further operations'
|
|
1592
1689
|
c.switch %i[i interactive], default_value: false, negatable: false
|
|
1593
1690
|
|
|
1691
|
+
c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
|
|
1692
|
+
c.arg_name 'QUERY'
|
|
1693
|
+
c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
|
|
1694
|
+
|
|
1695
|
+
c.desc 'Combine multiple tags or value queries using AND, OR, or NOT'
|
|
1696
|
+
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
|
|
1697
|
+
|
|
1594
1698
|
c.action do |_global_options, options, args|
|
|
1595
1699
|
options[:fuzzy] = false
|
|
1596
1700
|
raise DoingRuntimeError, %(Invalid output type "#{options[:output]}") if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
|
|
@@ -1601,6 +1705,7 @@ command %i[grep search] do |c|
|
|
|
1601
1705
|
section = wwid.guess_section(options[:section]) if options[:section]
|
|
1602
1706
|
|
|
1603
1707
|
options[:case] = options[:case].normalize_case
|
|
1708
|
+
options[:bool] = options[:bool].normalize_bool
|
|
1604
1709
|
|
|
1605
1710
|
search = args.join(' ')
|
|
1606
1711
|
search.sub!(/^'?/, "'") if options[:exact]
|
|
@@ -1639,11 +1744,11 @@ command :last do |c|
|
|
|
1639
1744
|
c.desc "Delete the last entry"
|
|
1640
1745
|
c.switch %i[d delete], negatable: false, default_value: false
|
|
1641
1746
|
|
|
1642
|
-
c.desc 'Tag filter, combine multiple tags with a comma. Wildcards allowed (*, ?)
|
|
1747
|
+
c.desc 'Tag filter, combine multiple tags with a comma. Wildcards allowed (*, ?)'
|
|
1643
1748
|
c.arg_name 'TAG'
|
|
1644
|
-
c.flag [:tag]
|
|
1749
|
+
c.flag [:tag], type: TagArray
|
|
1645
1750
|
|
|
1646
|
-
c.desc 'Tag boolean (AND|OR|NOT). Use PATTERN to parse + and - as booleans
|
|
1751
|
+
c.desc 'Tag boolean (AND|OR|NOT). Use PATTERN to parse + and - as booleans'
|
|
1647
1752
|
c.arg_name 'BOOLEAN'
|
|
1648
1753
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
|
1649
1754
|
|
|
@@ -1651,6 +1756,10 @@ command :last do |c|
|
|
|
1651
1756
|
c.arg_name 'QUERY'
|
|
1652
1757
|
c.flag [:search]
|
|
1653
1758
|
|
|
1759
|
+
c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
|
|
1760
|
+
c.arg_name 'QUERY'
|
|
1761
|
+
c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
|
|
1762
|
+
|
|
1654
1763
|
c.desc 'Show elapsed time if entry is not tagged @done'
|
|
1655
1764
|
c.switch [:duration]
|
|
1656
1765
|
|
|
@@ -1674,7 +1783,7 @@ command :last do |c|
|
|
|
1674
1783
|
if options[:tag].nil?
|
|
1675
1784
|
options[:tag] = []
|
|
1676
1785
|
else
|
|
1677
|
-
options[:tag] = options[:tag]
|
|
1786
|
+
options[:tag] = options[:tag]
|
|
1678
1787
|
options[:bool] = options[:bool].normalize_bool
|
|
1679
1788
|
end
|
|
1680
1789
|
|
|
@@ -1685,12 +1794,14 @@ command :last do |c|
|
|
|
1685
1794
|
if options[:editor]
|
|
1686
1795
|
wwid.edit_last(section: options[:section],
|
|
1687
1796
|
options: {
|
|
1688
|
-
search: search,
|
|
1797
|
+
search: options[:search],
|
|
1689
1798
|
fuzzy: options[:fuzzy],
|
|
1690
1799
|
case: options[:case],
|
|
1691
|
-
tag:
|
|
1800
|
+
tag: options[:tag],
|
|
1692
1801
|
tag_bool: options[:bool],
|
|
1693
|
-
not: options[:not]
|
|
1802
|
+
not: options[:not],
|
|
1803
|
+
val: options[:val],
|
|
1804
|
+
bool: options[:bool]
|
|
1694
1805
|
})
|
|
1695
1806
|
else
|
|
1696
1807
|
last = wwid.last(times: true, section: options[:section],
|
|
@@ -1702,7 +1813,9 @@ command :last do |c|
|
|
|
1702
1813
|
negate: options[:not],
|
|
1703
1814
|
tag: options[:tag],
|
|
1704
1815
|
tag_bool: options[:bool],
|
|
1705
|
-
delete: options[:delete]
|
|
1816
|
+
delete: options[:delete],
|
|
1817
|
+
bool: options[:bool],
|
|
1818
|
+
val: options[:val]
|
|
1706
1819
|
})
|
|
1707
1820
|
Doing::Pager::page last.strip if last
|
|
1708
1821
|
end
|
|
@@ -1798,11 +1911,15 @@ command :show do |c|
|
|
|
1798
1911
|
c.example 'doing show Ideas @doing --from "mon to fri"', desc: 'Show entries tagged @doing from the Ideas section added between monday and friday of the current week.'
|
|
1799
1912
|
c.example 'doing show --interactive Later @doing', desc: 'Create a menu from entries from the Later section tagged @doing to perform batch actions'
|
|
1800
1913
|
|
|
1801
|
-
c.desc 'Tag filter, combine multiple tags with a comma. Use `--tag pick` for a menu of available tags. Wildcards allowed (*, ?). Added for compatibility with other commands
|
|
1914
|
+
c.desc 'Tag filter, combine multiple tags with a comma. Use `--tag pick` for a menu of available tags. Wildcards allowed (*, ?). Added for compatibility with other commands'
|
|
1802
1915
|
c.arg_name 'TAG'
|
|
1803
|
-
c.flag [:tag]
|
|
1916
|
+
c.flag [:tag], type: TagArray
|
|
1917
|
+
|
|
1918
|
+
c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
|
|
1919
|
+
c.arg_name 'QUERY'
|
|
1920
|
+
c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
|
|
1804
1921
|
|
|
1805
|
-
c.desc 'Tag boolean (AND,OR,NOT). Use PATTERN to parse + and - as booleans
|
|
1922
|
+
c.desc 'Tag boolean (AND,OR,NOT). Use PATTERN to parse + and - as booleans'
|
|
1806
1923
|
c.arg_name 'BOOLEAN'
|
|
1807
1924
|
c.flag %i[b bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
|
1808
1925
|
|
|
@@ -1814,11 +1931,11 @@ command :show do |c|
|
|
|
1814
1931
|
c.arg_name 'AGE'
|
|
1815
1932
|
c.flag %i[a age], default_value: 'newest'
|
|
1816
1933
|
|
|
1817
|
-
c.desc 'Show entries older than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day
|
|
1934
|
+
c.desc 'Show entries older than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day'
|
|
1818
1935
|
c.arg_name 'DATE_STRING'
|
|
1819
1936
|
c.flag [:before]
|
|
1820
1937
|
|
|
1821
|
-
c.desc 'Show entries newer than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day
|
|
1938
|
+
c.desc 'Show entries newer than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day'
|
|
1822
1939
|
c.arg_name 'DATE_STRING'
|
|
1823
1940
|
c.flag [:after]
|
|
1824
1941
|
|
|
@@ -1929,7 +2046,7 @@ command :show do |c|
|
|
|
1929
2046
|
section ||= 'All'
|
|
1930
2047
|
end
|
|
1931
2048
|
|
|
1932
|
-
tags.concat(options[:tag]
|
|
2049
|
+
tags.concat(options[:tag]) if options[:tag]
|
|
1933
2050
|
|
|
1934
2051
|
options[:times] = true if options[:totals]
|
|
1935
2052
|
|
|
@@ -2012,7 +2129,7 @@ command :tags do |c|
|
|
|
2012
2129
|
c.arg_name 'ORDER'
|
|
2013
2130
|
c.flag %i[o order], must_match: REGEX_SORT_ORDER, default_value: 'asc'
|
|
2014
2131
|
|
|
2015
|
-
c.desc 'Get tags for entries matching tags. Combine multiple tags with a comma. Wildcards allowed (*, ?)
|
|
2132
|
+
c.desc 'Get tags for entries matching tags. Combine multiple tags with a comma. Wildcards allowed (*, ?)'
|
|
2016
2133
|
c.arg_name 'TAG'
|
|
2017
2134
|
c.flag [:tag]
|
|
2018
2135
|
|
|
@@ -2021,6 +2138,10 @@ command :tags do |c|
|
|
|
2021
2138
|
c.arg_name 'QUERY'
|
|
2022
2139
|
c.flag [:search]
|
|
2023
2140
|
|
|
2141
|
+
c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
|
|
2142
|
+
c.arg_name 'QUERY'
|
|
2143
|
+
c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
|
|
2144
|
+
|
|
2024
2145
|
# c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
|
|
2025
2146
|
# c.switch [:fuzzy], default_value: false, negatable: false
|
|
2026
2147
|
|
|
@@ -2034,7 +2155,7 @@ command :tags do |c|
|
|
|
2034
2155
|
c.arg_name 'TYPE'
|
|
2035
2156
|
c.flag [:case], must_match: /^[csi]/, default_value: settings.dig('search', 'case')
|
|
2036
2157
|
|
|
2037
|
-
c.desc 'Boolean used to combine multiple tags. Use PATTERN to parse + and - as booleans
|
|
2158
|
+
c.desc 'Boolean used to combine multiple tags. Use PATTERN to parse + and - as booleans'
|
|
2038
2159
|
c.arg_name 'BOOLEAN'
|
|
2039
2160
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
|
2040
2161
|
|
|
@@ -2291,11 +2412,15 @@ command :view do |c|
|
|
|
2291
2412
|
c.desc 'Include colors in output'
|
|
2292
2413
|
c.switch [:color], default_value: true, negatable: true
|
|
2293
2414
|
|
|
2294
|
-
c.desc 'Tag filter, combine multiple tags with a comma. Wildcards allowed (*, ?)
|
|
2415
|
+
c.desc 'Tag filter, combine multiple tags with a comma. Wildcards allowed (*, ?)'
|
|
2295
2416
|
c.arg_name 'TAG'
|
|
2296
2417
|
c.flag [:tag]
|
|
2297
2418
|
|
|
2298
|
-
c.desc '
|
|
2419
|
+
c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
|
|
2420
|
+
c.arg_name 'QUERY'
|
|
2421
|
+
c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
|
|
2422
|
+
|
|
2423
|
+
c.desc 'Tag boolean (AND,OR,NOT). Use PATTERN to parse + and - as booleans'
|
|
2299
2424
|
c.arg_name 'BOOLEAN'
|
|
2300
2425
|
c.flag %i[b bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
|
2301
2426
|
|
|
@@ -2324,11 +2449,11 @@ command :view do |c|
|
|
|
2324
2449
|
c.arg_name 'DIRECTION'
|
|
2325
2450
|
c.flag [:tag_order], must_match: REGEX_SORT_ORDER
|
|
2326
2451
|
|
|
2327
|
-
c.desc 'View entries older than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day
|
|
2452
|
+
c.desc 'View entries older than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day'
|
|
2328
2453
|
c.arg_name 'DATE_STRING'
|
|
2329
2454
|
c.flag [:before]
|
|
2330
2455
|
|
|
2331
|
-
c.desc 'View entries newer than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day
|
|
2456
|
+
c.desc 'View entries newer than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day'
|
|
2332
2457
|
c.arg_name 'DATE_STRING'
|
|
2333
2458
|
c.flag [:after]
|
|
2334
2459
|
|
|
@@ -2935,11 +3060,11 @@ command %i[archive move] do |c|
|
|
|
2935
3060
|
c.desc 'Label moved items with @from(SECTION_NAME)'
|
|
2936
3061
|
c.switch [:label], default_value: true, negatable: true
|
|
2937
3062
|
|
|
2938
|
-
c.desc 'Tag filter, combine multiple tags with a comma. Wildcards allowed (*, ?). Added for compatibility with other commands
|
|
3063
|
+
c.desc 'Tag filter, combine multiple tags with a comma. Wildcards allowed (*, ?). Added for compatibility with other commands'
|
|
2939
3064
|
c.arg_name 'TAG'
|
|
2940
|
-
c.flag [:tag]
|
|
3065
|
+
c.flag [:tag], type: TagArray
|
|
2941
3066
|
|
|
2942
|
-
c.desc 'Tag boolean (AND|OR|NOT). Use PATTERN to parse + and - as booleans
|
|
3067
|
+
c.desc 'Tag boolean (AND|OR|NOT). Use PATTERN to parse + and - as booleans'
|
|
2943
3068
|
c.arg_name 'BOOLEAN'
|
|
2944
3069
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
|
2945
3070
|
|
|
@@ -2947,6 +3072,10 @@ command %i[archive move] do |c|
|
|
|
2947
3072
|
c.arg_name 'QUERY'
|
|
2948
3073
|
c.flag [:search]
|
|
2949
3074
|
|
|
3075
|
+
c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
|
|
3076
|
+
c.arg_name 'QUERY'
|
|
3077
|
+
c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
|
|
3078
|
+
|
|
2950
3079
|
# c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
|
|
2951
3080
|
# c.switch [:fuzzy], default_value: false, negatable: false
|
|
2952
3081
|
|
|
@@ -2982,7 +3111,7 @@ command %i[archive move] do |c|
|
|
|
2982
3111
|
|
|
2983
3112
|
raise InvalidArgument, '--keep and --count can not be used together' if options[:keep] && options[:count]
|
|
2984
3113
|
|
|
2985
|
-
tags.concat(options[:tag]
|
|
3114
|
+
tags.concat(options[:tag]) if options[:tag]
|
|
2986
3115
|
|
|
2987
3116
|
search = nil
|
|
2988
3117
|
|
|
@@ -3042,7 +3171,7 @@ command :import do |c|
|
|
|
3042
3171
|
|
|
3043
3172
|
c.desc 'Tag all imported entries'
|
|
3044
3173
|
c.arg_name 'TAGS'
|
|
3045
|
-
c.flag
|
|
3174
|
+
c.flag %i[t tag]
|
|
3046
3175
|
|
|
3047
3176
|
c.desc 'Autotag entries'
|
|
3048
3177
|
c.switch :autotag, negatable: true, default_value: true
|
|
@@ -3077,6 +3206,12 @@ command :import do |c|
|
|
|
3077
3206
|
options[:section] = wwid.guess_section(options[:section]) || options[:section].cap_first
|
|
3078
3207
|
end
|
|
3079
3208
|
|
|
3209
|
+
if options[:search]
|
|
3210
|
+
search = options[:search]
|
|
3211
|
+
search.sub!(/^'?/, "'") if options[:exact]
|
|
3212
|
+
options[:search] = search
|
|
3213
|
+
end
|
|
3214
|
+
|
|
3080
3215
|
if options[:from]
|
|
3081
3216
|
date_string = options[:from]
|
|
3082
3217
|
if date_string =~ / (to|through|thru|(un)?til|-+) /
|
|
@@ -3085,7 +3220,7 @@ command :import do |c|
|
|
|
3085
3220
|
finish = dates[2].chronify(guess: :end)
|
|
3086
3221
|
else
|
|
3087
3222
|
start = date_string.chronify(guess: :begin)
|
|
3088
|
-
finish =
|
|
3223
|
+
finish = date_string.chronify(guess: :end)
|
|
3089
3224
|
end
|
|
3090
3225
|
raise InvalidTimeExpression, 'Unrecognized date string' unless start
|
|
3091
3226
|
dates = [start, finish]
|
|
@@ -3122,11 +3257,11 @@ command :rotate do |c|
|
|
|
3122
3257
|
c.arg_name 'SECTION_NAME'
|
|
3123
3258
|
c.flag %i[s section], default_value: 'All'
|
|
3124
3259
|
|
|
3125
|
-
c.desc 'Tag filter, combine multiple tags with a comma. Wildcards allowed (*, ?). Added for compatibility with other commands
|
|
3260
|
+
c.desc 'Tag filter, combine multiple tags with a comma. Wildcards allowed (*, ?). Added for compatibility with other commands'
|
|
3126
3261
|
c.arg_name 'TAG'
|
|
3127
3262
|
c.flag [:tag]
|
|
3128
3263
|
|
|
3129
|
-
c.desc 'Tag boolean (AND|OR|NOT). Use PATTERN to parse + and - as booleans
|
|
3264
|
+
c.desc 'Tag boolean (AND|OR|NOT). Use PATTERN to parse + and - as booleans'
|
|
3130
3265
|
c.arg_name 'BOOLEAN'
|
|
3131
3266
|
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
|
3132
3267
|
|
|
@@ -3134,6 +3269,10 @@ command :rotate do |c|
|
|
|
3134
3269
|
c.arg_name 'QUERY'
|
|
3135
3270
|
c.flag [:search]
|
|
3136
3271
|
|
|
3272
|
+
c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
|
|
3273
|
+
c.arg_name 'QUERY'
|
|
3274
|
+
c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
|
|
3275
|
+
|
|
3137
3276
|
# c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
|
|
3138
3277
|
# c.switch [:fuzzy], default_value: false, negatable: false
|
|
3139
3278
|
|
|
@@ -3357,7 +3496,7 @@ command :undo do |c|
|
|
|
3357
3496
|
c.arg_name 'COUNT'
|
|
3358
3497
|
c.flag %i[p prune], type: Integer
|
|
3359
3498
|
|
|
3360
|
-
c.desc 'Redo last undo. Note: you cannot undo a redo
|
|
3499
|
+
c.desc 'Redo last undo. Note: you cannot undo a redo'
|
|
3361
3500
|
c.switch %i[r redo]
|
|
3362
3501
|
|
|
3363
3502
|
c.action do |_global_options, options, args|
|
|
@@ -3384,7 +3523,7 @@ command :undo do |c|
|
|
|
3384
3523
|
end
|
|
3385
3524
|
|
|
3386
3525
|
# @@redo
|
|
3387
|
-
long_desc 'Shortcut for `doing undo -r`, reverses the last undo command. You cannot undo a redo
|
|
3526
|
+
long_desc 'Shortcut for `doing undo -r`, reverses the last undo command. You cannot undo a redo'
|
|
3388
3527
|
arg_name 'COUNT'
|
|
3389
3528
|
command :redo do |c|
|
|
3390
3529
|
c.desc 'Specify alternate doing file'
|