doing 2.1.17 → 2.1.22
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardoc/checksums +15 -14
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/CHANGELOG.md +117 -53
- data/Gemfile.lock +11 -11
- data/README.md +1 -1
- data/Rakefile +12 -4
- data/bin/doing +161 -205
- data/docs/doc/Array.html +9 -37
- data/docs/doc/BooleanTermParser/Clause.html +3 -3
- data/docs/doc/BooleanTermParser/Operator.html +3 -3
- data/docs/doc/BooleanTermParser/Query.html +3 -3
- data/docs/doc/BooleanTermParser/QueryParser.html +3 -3
- data/docs/doc/BooleanTermParser/QueryTransformer.html +3 -3
- data/docs/doc/BooleanTermParser.html +3 -3
- data/docs/doc/Doing/Color.html +3 -3
- data/docs/doc/Doing/Completion.html +3 -3
- data/docs/doc/Doing/Configuration.html +4 -3
- data/docs/doc/Doing/Errors/DoingNoTraceError.html +3 -3
- data/docs/doc/Doing/Errors/DoingRuntimeError.html +3 -3
- data/docs/doc/Doing/Errors/DoingStandardError.html +3 -3
- data/docs/doc/Doing/Errors/EmptyInput.html +3 -3
- data/docs/doc/Doing/Errors/NoResults.html +3 -3
- data/docs/doc/Doing/Errors/PluginException.html +3 -3
- data/docs/doc/Doing/Errors/UserCancelled.html +3 -3
- data/docs/doc/Doing/Errors/WrongCommand.html +3 -3
- data/docs/doc/Doing/Errors.html +3 -3
- data/docs/doc/Doing/Hooks.html +3 -3
- data/docs/doc/Doing/Item.html +3 -3
- data/docs/doc/Doing/Items.html +3 -3
- data/docs/doc/Doing/LogAdapter.html +3 -3
- data/docs/doc/Doing/Note.html +3 -3
- data/docs/doc/Doing/Pager.html +3 -3
- data/docs/doc/Doing/Plugins.html +3 -3
- data/docs/doc/Doing/Prompt.html +7 -7
- data/docs/doc/Doing/Section.html +3 -3
- data/docs/doc/Doing/TemplateString.html +4 -4
- data/docs/doc/Doing/Util/Backup.html +3 -3
- data/docs/doc/Doing/Util.html +3 -3
- data/docs/doc/Doing/WWID.html +66 -8
- data/docs/doc/Doing.html +6 -6
- data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +3 -3
- data/docs/doc/GLI/Commands.html +3 -3
- data/docs/doc/GLI.html +3 -3
- data/docs/doc/Hash.html +78 -6
- data/docs/doc/Numeric.html +3 -3
- data/docs/doc/PhraseParser/Operator.html +3 -3
- data/docs/doc/PhraseParser/PhraseClause.html +3 -3
- data/docs/doc/PhraseParser/Query.html +3 -3
- data/docs/doc/PhraseParser/QueryParser.html +3 -3
- data/docs/doc/PhraseParser/QueryTransformer.html +3 -3
- data/docs/doc/PhraseParser/TermClause.html +3 -3
- data/docs/doc/PhraseParser.html +3 -3
- data/docs/doc/Status.html +3 -3
- data/docs/doc/String.html +156 -17
- data/docs/doc/Symbol.html +3 -3
- data/docs/doc/Time.html +3 -3
- data/docs/doc/_index.html +23 -16
- data/docs/doc/class_list.html +1 -1
- data/docs/doc/file.README.html +4 -4
- data/docs/doc/frames.html +1 -1
- data/docs/doc/index.html +4 -4
- data/docs/doc/method_list.html +331 -283
- data/docs/doc/top-level-namespace.html +3 -3
- data/doing.gemspec +1 -1
- data/doing.rdoc +26 -12
- data/lib/completion/_doing.zsh +5 -5
- data/lib/completion/doing.bash +8 -8
- data/lib/completion/doing.fish +93 -15
- data/lib/doing/array.rb +5 -4
- data/lib/doing/array_chronify.rb +4 -3
- data/lib/doing/completion/fish_completion.rb +80 -11
- data/lib/doing/configuration.rb +2 -1
- data/lib/doing/hash.rb +22 -4
- data/lib/doing/item.rb +2 -2
- data/lib/doing/items.rb +3 -1
- data/lib/doing/log_adapter.rb +1 -1
- data/lib/doing/pager.rb +2 -2
- data/lib/doing/plugins/export/dayone_export.rb +1 -1
- data/lib/doing/plugins/export/markdown_export.rb +1 -1
- data/lib/doing/plugins/export/template_export.rb +8 -2
- data/lib/doing/prompt.rb +4 -2
- data/lib/doing/string.rb +25 -2
- data/lib/doing/string_chronify.rb +55 -17
- data/lib/doing/template_string.rb +7 -0
- data/lib/doing/types.rb +23 -0
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +71 -50
- data/lib/doing.rb +1 -0
- data/lib/examples/commands/later.rb +32 -0
- data/lib/helpers/threaded_tests.rb +273 -0
- metadata +9 -6
data/bin/doing
CHANGED
@@ -25,12 +25,7 @@ version Doing::VERSION
|
|
25
25
|
hide_commands_without_desc true
|
26
26
|
autocomplete_commands true
|
27
27
|
|
28
|
-
|
29
|
-
REGEX_SORT_ORDER = /^(?:a(?:sc)?|d(?:esc)?)$/i
|
30
|
-
REGEX_VALUE_QUERY = /^(?:!)?@?(?:\S+) +(?:!?[<>=][=*]?|[$*^]=) +(?:.*?)$/
|
31
|
-
|
32
|
-
InvalidExportType = Class.new(RuntimeError)
|
33
|
-
MissingConfigFile = Class.new(RuntimeError)
|
28
|
+
include Doing::Types
|
34
29
|
|
35
30
|
colors = Doing::Color
|
36
31
|
wwid = Doing::WWID.new
|
@@ -70,7 +65,42 @@ if settings.dig('plugins', 'command_path')
|
|
70
65
|
commands_from File.expand_path(settings.dig('plugins', 'command_path'))
|
71
66
|
end
|
72
67
|
|
73
|
-
|
68
|
+
accept DateBeginString do |value|
|
69
|
+
if value =~ REGEX_TIME
|
70
|
+
res = value
|
71
|
+
else
|
72
|
+
res = value.chronify(guess: :begin, future: false)
|
73
|
+
end
|
74
|
+
raise InvalidTimeExpression, 'Invalid start date' unless res
|
75
|
+
|
76
|
+
res
|
77
|
+
end
|
78
|
+
|
79
|
+
accept DateEndString do |value|
|
80
|
+
if value =~ REGEX_TIME
|
81
|
+
res = value
|
82
|
+
else
|
83
|
+
res = value.chronify(guess: :end, future: false)
|
84
|
+
end
|
85
|
+
raise InvalidTimeExpression, 'Invalid end date' unless res
|
86
|
+
|
87
|
+
res
|
88
|
+
end
|
89
|
+
|
90
|
+
accept DateRangeString do |value|
|
91
|
+
start, finish = value.split_date_range
|
92
|
+
raise InvalidTimeExpression, 'Invalid range' unless start
|
93
|
+
|
94
|
+
finish ||= Time.now
|
95
|
+
[start, finish]
|
96
|
+
end
|
97
|
+
|
98
|
+
accept DateIntervalString do |value|
|
99
|
+
res = value.chronify_qty
|
100
|
+
raise InvalidTimeExpression, 'Invalid time quantity' unless res
|
101
|
+
|
102
|
+
res
|
103
|
+
end
|
74
104
|
|
75
105
|
accept TagArray do |value|
|
76
106
|
value.gsub(/[, ]+/, ' ').split(' ').map { |tag| tag.sub(/^@/, '')}.map(&:strip)
|
@@ -97,7 +127,7 @@ desc 'Use a pager when output is longer than screen'
|
|
97
127
|
switch %i[p pager], default_value: settings['paginate']
|
98
128
|
|
99
129
|
desc 'Answer yes/no menus with default option'
|
100
|
-
switch [:default], default_value: false
|
130
|
+
switch [:default], default_value: false, negatable: false
|
101
131
|
|
102
132
|
desc 'Answer all yes/no menus with yes'
|
103
133
|
switch [:yes], negatable: false
|
@@ -143,6 +173,10 @@ command %i[again resume] do |c|
|
|
143
173
|
c.arg_name 'SECTION_NAME'
|
144
174
|
c.flag [:in]
|
145
175
|
|
176
|
+
c.desc 'Backdate start date by interval or set to time [4pm|20m|2h|"yesterday noon"]'
|
177
|
+
c.arg_name 'DATE_STRING'
|
178
|
+
c.flag %i[b back started], type: DateBeginString
|
179
|
+
|
146
180
|
c.desc 'Repeat last entry matching tags. Combine multiple tags with a comma. Wildcards allowed (*, ?)'
|
147
181
|
c.arg_name 'TAG'
|
148
182
|
c.flag [:tag], type: TagArray
|
@@ -198,6 +232,13 @@ command %i[again resume] do |c|
|
|
198
232
|
options[:search] = search
|
199
233
|
end
|
200
234
|
|
235
|
+
if options[:back]
|
236
|
+
date = options[:back]
|
237
|
+
raise InvalidTimeExpression, 'Unable to parse date string for --back' if date.nil?
|
238
|
+
else
|
239
|
+
date = Time.now
|
240
|
+
end
|
241
|
+
|
201
242
|
note = Doing::Note.new(options[:note])
|
202
243
|
note.add(Doing::Prompt.read_lines(prompt: 'Add a note')) if options[:ask]
|
203
244
|
|
@@ -208,6 +249,7 @@ command %i[again resume] do |c|
|
|
208
249
|
opts[:tag] = tags
|
209
250
|
opts[:tag_bool] = options[:bool].normalize_bool
|
210
251
|
opts[:interactive] = options[:interactive]
|
252
|
+
opts[:date] = date
|
211
253
|
|
212
254
|
wwid.repeat_last(opts)
|
213
255
|
end
|
@@ -321,7 +363,7 @@ desc 'Add a completed item with @done(date). No argument finishes last entry'
|
|
321
363
|
long_desc 'Use this command to add an entry after you\'ve already finished it. It will be immediately marked as @done.
|
322
364
|
You can modify the start and end times of the entry using the --back, --took, and --at flags, making it an easy
|
323
365
|
way to add entries in post and maintain accurate (albeit manual) time tracking.'
|
324
|
-
arg_name 'ENTRY'
|
366
|
+
arg_name 'ENTRY', optional: true
|
325
367
|
command %i[done did] do |c|
|
326
368
|
c.example 'doing done', desc: 'Tag the last entry @done'
|
327
369
|
c.example 'doing done I already finished this', desc: 'Add a new entry and immediately mark it @done'
|
@@ -340,24 +382,24 @@ command %i[done did] do |c|
|
|
340
382
|
c.desc %(Set finish date to specific date/time (natural langauge parsed, e.g. --at=1:30pm).
|
341
383
|
Used with --took, backdates start date)
|
342
384
|
c.arg_name 'DATE_STRING'
|
343
|
-
c.flag %i[at finished]
|
385
|
+
c.flag %i[at finished], type: DateEndString
|
344
386
|
|
345
387
|
c.desc 'Backdate start date by interval or set to time [4pm|20m|2h|"yesterday noon"]'
|
346
388
|
c.arg_name 'DATE_STRING'
|
347
|
-
c.flag %i[b back started]
|
389
|
+
c.flag %i[b back started], type: DateBeginString
|
348
390
|
|
349
391
|
c.desc %(
|
350
392
|
Start and end times as a date/time range `doing done --from "1am to 8am"`.
|
351
393
|
Overrides other date flags.
|
352
394
|
)
|
353
395
|
c.arg_name 'TIME_RANGE'
|
354
|
-
c.flag [:from]
|
396
|
+
c.flag [:from], must_match: REGEX_RANGE
|
355
397
|
|
356
398
|
c.desc %(Set completion date to start date plus interval (XX[mhd] or HH:MM).
|
357
399
|
If used without the --back option, the start date will be moved back to allow
|
358
400
|
the completion date to be the current time.)
|
359
401
|
c.arg_name 'INTERVAL'
|
360
|
-
c.flag %i[t took for]
|
402
|
+
c.flag %i[t took for], type: DateIntervalString
|
361
403
|
|
362
404
|
c.desc 'Section'
|
363
405
|
c.arg_name 'NAME'
|
@@ -385,23 +427,27 @@ command %i[done did] do |c|
|
|
385
427
|
donedate = nil
|
386
428
|
|
387
429
|
if options[:from]
|
388
|
-
|
430
|
+
options[:from] = options[:from].split(/#{REGEX_RANGE_INDICATOR}/).map do |time|
|
431
|
+
time =~ REGEX_TIME ? "today #{time.sub(/(?mi)(^.*?(?=\d+)|(?<=[ap]m).*?$)/, '')}" : time
|
432
|
+
end.join(' to ').split_date_range
|
433
|
+
date, finish_date = options[:from]
|
389
434
|
finish_date ||= Time.now
|
390
435
|
else
|
391
436
|
if options[:took]
|
392
|
-
took = options[:took]
|
437
|
+
took = options[:took]
|
393
438
|
raise InvalidTimeExpression, 'Unable to parse date string for --took' if took.nil?
|
394
439
|
end
|
395
440
|
|
396
441
|
if options[:back]
|
397
|
-
date = options[:back]
|
442
|
+
date = options[:back]
|
398
443
|
raise InvalidTimeExpression, 'Unable to parse date string for --back' if date.nil?
|
399
444
|
else
|
400
445
|
date = options[:took] ? Time.now - took : Time.now
|
401
446
|
end
|
402
447
|
|
403
448
|
if options[:at]
|
404
|
-
finish_date = options[:at]
|
449
|
+
finish_date = options[:at]
|
450
|
+
finish_date = finish_date.chronify(guess: :begin) if finish_date.is_a? String
|
405
451
|
raise InvalidTimeExpression, 'Unable to parse date string for --at' if finish_date.nil?
|
406
452
|
|
407
453
|
if options[:took]
|
@@ -417,6 +463,7 @@ command %i[done did] do |c|
|
|
417
463
|
end
|
418
464
|
|
419
465
|
if options[:date]
|
466
|
+
date = date.chronify(guess: :begin, context: :today) if date =~ REGEX_TIME
|
420
467
|
finish_date = wwid.verify_duration(date, finish_date) unless options[:took] || options[:from]
|
421
468
|
|
422
469
|
donedate = finish_date.strftime('%F %R')
|
@@ -528,7 +575,7 @@ command %i[done did] do |c|
|
|
528
575
|
wwid.content.push(new_entry)
|
529
576
|
Doing::Hooks.trigger :post_entry_added, wwid, new_entry.dup
|
530
577
|
wwid.write(wwid.doing_file)
|
531
|
-
Doing.logger.info('
|
578
|
+
Doing.logger.info('New entry:', %(added "#{new_entry.date.relative_date}: #{new_entry.title}" to #{section}))
|
532
579
|
elsif $stdin.stat.size.positive?
|
533
580
|
note = Doing::Note.new(options[:note])
|
534
581
|
d, title, note = wwid.format_input($stdin.read.strip)
|
@@ -553,7 +600,7 @@ command %i[done did] do |c|
|
|
553
600
|
Doing::Hooks.trigger :post_entry_added, wwid, new_entry.dup
|
554
601
|
|
555
602
|
wwid.write(wwid.doing_file)
|
556
|
-
Doing.logger.info('
|
603
|
+
Doing.logger.info('New entry:', %(added "#{new_entry.date.relative_date}: #{new_entry.title}" to #{section}))
|
557
604
|
else
|
558
605
|
raise EmptyInput, 'You must provide content when creating a new entry'
|
559
606
|
end
|
@@ -563,7 +610,7 @@ end
|
|
563
610
|
# @@finish
|
564
611
|
desc 'Mark last X entries as @done'
|
565
612
|
long_desc 'Marks the last X entries with a @done tag and current date. Does not alter already completed entries.'
|
566
|
-
arg_name 'COUNT'
|
613
|
+
arg_name 'COUNT', optional: true
|
567
614
|
command :finish do |c|
|
568
615
|
c.example 'doing finish', desc: 'Mark the last entry @done'
|
569
616
|
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'
|
@@ -574,15 +621,15 @@ command :finish do |c|
|
|
574
621
|
|
575
622
|
c.desc 'Backdate completed date to date string [4pm|20m|2h|yesterday noon]'
|
576
623
|
c.arg_name 'DATE_STRING'
|
577
|
-
c.flag %i[b back]
|
624
|
+
c.flag %i[b back started], type: DateBeginString
|
578
625
|
|
579
626
|
c.desc 'Set the completed date to the start date plus XX[hmd]'
|
580
627
|
c.arg_name 'INTERVAL'
|
581
|
-
c.flag %i[t took for]
|
628
|
+
c.flag %i[t took for], type: DateIntervalString
|
582
629
|
|
583
630
|
c.desc %(Set finish date to specific date/time (natural langauge parsed, e.g. --at=1:30pm). If used, ignores --back.)
|
584
631
|
c.arg_name 'DATE_STRING'
|
585
|
-
c.flag [
|
632
|
+
c.flag %i[at finished], type: DateEndString
|
586
633
|
|
587
634
|
c.desc 'Finish the last X entries containing TAG.
|
588
635
|
Separate multiple tags with comma (--tag=tag1,tag2), combine with --bool. Wildcards allowed (*, ?).'
|
@@ -639,7 +686,7 @@ command :finish do |c|
|
|
639
686
|
options[:fuzzy] = false
|
640
687
|
unless options[:auto]
|
641
688
|
if options[:took]
|
642
|
-
took = options[:took]
|
689
|
+
took = options[:took]
|
643
690
|
raise InvalidTimeExpression, 'Unable to parse date string for --took' if took.nil?
|
644
691
|
end
|
645
692
|
|
@@ -648,12 +695,13 @@ command :finish do |c|
|
|
648
695
|
raise InvalidArgument, '--search and --tag can not be used together' if options[:search] && options[:tag]
|
649
696
|
|
650
697
|
if options[:at]
|
651
|
-
finish_date = options[:at]
|
698
|
+
finish_date = options[:at]
|
699
|
+
finish_date = finish_date.chronify(guess: :begin) if finish_date.is_a? String
|
652
700
|
raise InvalidTimeExpression, 'Unable to parse date string for --at' if finish_date.nil?
|
653
701
|
|
654
702
|
date = options[:took] ? finish_date - took : finish_date
|
655
703
|
elsif options[:back]
|
656
|
-
date = options[:back]
|
704
|
+
date = options[:back]
|
657
705
|
|
658
706
|
raise InvalidTimeExpression, 'Unable to parse date string' if date.nil?
|
659
707
|
else
|
@@ -661,8 +709,6 @@ command :finish do |c|
|
|
661
709
|
end
|
662
710
|
end
|
663
711
|
|
664
|
-
options[:took] = options[:took].chronify_qty if options[:took]
|
665
|
-
|
666
712
|
if options[:tag].nil?
|
667
713
|
tags = []
|
668
714
|
else
|
@@ -711,92 +757,6 @@ command :finish do |c|
|
|
711
757
|
end
|
712
758
|
end
|
713
759
|
|
714
|
-
# @@later
|
715
|
-
desc 'Add an item to the Later section'
|
716
|
-
arg_name 'ENTRY'
|
717
|
-
command :later do |c|
|
718
|
-
c.example 'doing later "Something I\'ll think about tomorrow"', desc: 'Add an entry to the Later section'
|
719
|
-
c.example 'doing later -e', desc: 'Open $EDITOR to create an entry and optional note'
|
720
|
-
|
721
|
-
c.desc "Edit entry with #{Doing::Util.default_editor}"
|
722
|
-
c.switch %i[e editor], negatable: false, default_value: false
|
723
|
-
|
724
|
-
c.desc 'Backdate start time to date string [4pm|20m|2h|yesterday noon]'
|
725
|
-
c.arg_name 'DATE_STRING'
|
726
|
-
c.flag %i[b back]
|
727
|
-
|
728
|
-
c.desc 'Note'
|
729
|
-
c.arg_name 'TEXT'
|
730
|
-
c.flag %i[n note]
|
731
|
-
|
732
|
-
c.desc 'Prompt for note via multi-line input'
|
733
|
-
c.switch %i[ask], negatable: false, default_value: false
|
734
|
-
|
735
|
-
c.action do |_global_options, options, args|
|
736
|
-
if options[:back]
|
737
|
-
date = options[:back].chronify(guess: :begin)
|
738
|
-
raise InvalidTimeExpression, 'Unable to parse date string' if date.nil?
|
739
|
-
else
|
740
|
-
date = Time.now
|
741
|
-
end
|
742
|
-
|
743
|
-
ask_note = options[:ask] && !options[:editor] && args.count.positive? ? Doing::Prompt.read_lines(prompt: 'Add a note') : ''
|
744
|
-
|
745
|
-
if options[:editor]
|
746
|
-
raise MissingEditor, 'No EDITOR variable defined in environment' if Doing::Util.default_editor.nil?
|
747
|
-
|
748
|
-
input = ''
|
749
|
-
input += date.strftime('%F %R | ')
|
750
|
-
input += args.empty? ? '' : args.join(' ')
|
751
|
-
input += "\n#{options[:note]}" if options[:note]
|
752
|
-
input += "\n#{ask_note}" unless ask_note.empty?
|
753
|
-
|
754
|
-
input = wwid.fork_editor(input).strip
|
755
|
-
|
756
|
-
d, title, note = wwid.format_input(input)
|
757
|
-
raise EmptyInput, 'No content' if title.empty?
|
758
|
-
|
759
|
-
note.add(options[:note]) if options[:note]
|
760
|
-
if ask_note.empty? && options[:ask]
|
761
|
-
ask_note = Doing::Prompt.read_lines(prompt: 'Add a note')
|
762
|
-
note.add(ask_note) unless ask_note.empty?
|
763
|
-
end
|
764
|
-
|
765
|
-
date = d.nil? ? date : d
|
766
|
-
wwid.add_item(title.cap_first, 'Later', { note: note, back: date })
|
767
|
-
wwid.write(wwid.doing_file)
|
768
|
-
elsif !args.empty?
|
769
|
-
d, title, note = wwid.format_input(args.join(' '))
|
770
|
-
date = d.nil? ? date : d
|
771
|
-
note.add(options[:note]) if options[:note]
|
772
|
-
note.add(ask_note) unless ask_note.empty?
|
773
|
-
wwid.add_item(title.cap_first, 'Later', { note: note, back: date })
|
774
|
-
wwid.write(wwid.doing_file)
|
775
|
-
elsif $stdin.stat.size.positive?
|
776
|
-
d, title, note = wwid.format_input($stdin.read)
|
777
|
-
unless d.nil?
|
778
|
-
Doing.logger.debug('Parser:', 'Date detected in input, overriding command line values')
|
779
|
-
date = d
|
780
|
-
end
|
781
|
-
note.add(options[:note]) if options[:note]
|
782
|
-
note.add(ask_note) unless ask_note.empty?
|
783
|
-
wwid.add_item(title.cap_first, 'Later', { note: note, back: date })
|
784
|
-
wwid.write(wwid.doing_file)
|
785
|
-
else
|
786
|
-
title = Doing::Prompt.read_line(prompt: 'Entry content')
|
787
|
-
raise EmptyInput, 'You must provide content when creating a new entry' if title.strip.empty?
|
788
|
-
|
789
|
-
note = Doing::Note.new
|
790
|
-
res = Doing::Prompt.yn('Add a note', default_response: false)
|
791
|
-
ask_note = res ? Doing::Prompt.read_lines(prompt: 'Enter note') : []
|
792
|
-
note.add(ask_note)
|
793
|
-
|
794
|
-
wwid.add_item(title.cap_first, 'Later', { note: note, back: date })
|
795
|
-
wwid.write(wwid.doing_file)
|
796
|
-
end
|
797
|
-
end
|
798
|
-
end
|
799
|
-
|
800
760
|
# @@mark @@flag
|
801
761
|
desc 'Mark last entry as flagged'
|
802
762
|
command %i[mark flag] do |c|
|
@@ -930,7 +890,7 @@ long_desc 'The @meanwhile tag allows you to have long-running entries that encom
|
|
930
890
|
This command makes it easy to start and stop these overarching entries. Just run `doing meanwhile Starting work on this
|
931
891
|
big project` to start a @meanwhile entry, add other entries as you work on the project, then use `doing meanwhile` by
|
932
892
|
itself to mark the entry as @done.'
|
933
|
-
arg_name 'ENTRY'
|
893
|
+
arg_name 'ENTRY', optional: true
|
934
894
|
command :meanwhile do |c|
|
935
895
|
c.example 'doing meanwhile "Long task that will have others after it before it\'s done"', desc: 'Add a new long-running entry, completing any current @meanwhile entry'
|
936
896
|
c.example 'doing meanwhile', desc: 'Finish any open @meanwhile entry'
|
@@ -949,7 +909,7 @@ command :meanwhile do |c|
|
|
949
909
|
|
950
910
|
c.desc 'Backdate start date for new entry to date string [4pm|20m|2h|yesterday noon]'
|
951
911
|
c.arg_name 'DATE_STRING'
|
952
|
-
c.flag %i[b back]
|
912
|
+
c.flag %i[b back started], type: DateBeginString
|
953
913
|
|
954
914
|
c.desc 'Note'
|
955
915
|
c.arg_name 'TEXT'
|
@@ -960,7 +920,7 @@ command :meanwhile do |c|
|
|
960
920
|
|
961
921
|
c.action do |_global_options, options, args|
|
962
922
|
if options[:back]
|
963
|
-
date = options[:back]
|
923
|
+
date = options[:back]
|
964
924
|
|
965
925
|
raise InvalidTimeExpression, 'Unable to parse date string' if date.nil?
|
966
926
|
else
|
@@ -1020,7 +980,7 @@ long_desc %(
|
|
1020
980
|
|
1021
981
|
Use -e to load the last entry in a text editor where you can append a note.
|
1022
982
|
)
|
1023
|
-
arg_name 'NOTE_TEXT'
|
983
|
+
arg_name 'NOTE_TEXT', optional: true
|
1024
984
|
command :note do |c|
|
1025
985
|
c.example 'doing note', desc: 'Open the last entry in $EDITOR to append a note'
|
1026
986
|
c.example 'doing note "Just a quick annotation"', desc: 'Add a quick note to the last entry'
|
@@ -1088,7 +1048,6 @@ command :note do |c|
|
|
1088
1048
|
options[:search] = search
|
1089
1049
|
end
|
1090
1050
|
|
1091
|
-
|
1092
1051
|
last_entry = wwid.last_entry(options)
|
1093
1052
|
|
1094
1053
|
unless last_entry
|
@@ -1098,37 +1057,37 @@ command :note do |c|
|
|
1098
1057
|
|
1099
1058
|
last_note = last_entry.note || Doing::Note.new
|
1100
1059
|
new_note = Doing::Note.new
|
1101
|
-
ask_note = options[:ask] ? Doing::Prompt.read_lines(prompt: 'Add a note') : ''
|
1102
1060
|
|
1103
|
-
if
|
1104
|
-
|
1061
|
+
if $stdin.stat.size.positive?
|
1062
|
+
new_note.add($stdin.read.strip)
|
1063
|
+
end
|
1105
1064
|
|
1106
|
-
|
1065
|
+
unless args.empty?
|
1066
|
+
new_note.add(args.join(' '))
|
1067
|
+
end
|
1068
|
+
|
1069
|
+
if options[:editor]
|
1070
|
+
raise MissingEditor, 'No EDITOR variable defined in environment' if Doing::Util.default_editor.nil?
|
1107
1071
|
|
1108
1072
|
if options[:remove]
|
1109
|
-
|
1073
|
+
input = Doing::Note.new
|
1110
1074
|
else
|
1111
|
-
|
1075
|
+
input = last_entry.note || Doing::Note.new
|
1112
1076
|
end
|
1113
1077
|
|
1078
|
+
input.add(new_note)
|
1114
1079
|
|
1115
|
-
|
1116
|
-
input.add(ask_note) unless ask_note.empty?
|
1117
|
-
|
1118
|
-
input = wwid.fork_editor(prev_input.strip_lines.join("\n"), message: nil).strip
|
1119
|
-
note = input
|
1080
|
+
new_note = Doing::Note.new(wwid.fork_editor(input.strip_lines.join("\n"), message: nil).strip)
|
1120
1081
|
options[:remove] = true
|
1121
|
-
|
1122
|
-
elsif !args.empty?
|
1123
|
-
new_note.add(args.join(' '))
|
1124
|
-
elsif $stdin.stat.size.positive?
|
1125
|
-
new_note.add($stdin.read.strip)
|
1126
|
-
else
|
1127
|
-
raise EmptyInput, 'You must provide content when adding a note' unless options[:remove] || !ask_note.empty?
|
1082
|
+
end
|
1128
1083
|
|
1084
|
+
if (new_note.empty? && !options[:remove]) || options[:ask]
|
1085
|
+
$stderr.puts last_note unless last_note.empty?
|
1086
|
+
$stderr.puts new_note unless new_note.empty?
|
1087
|
+
new_note.add(Doing::Prompt.read_lines(prompt: 'Add a note'))
|
1129
1088
|
end
|
1130
1089
|
|
1131
|
-
|
1090
|
+
raise EmptyInput, 'You must provide content when adding a note' unless options[:remove] || !new_note.empty?
|
1132
1091
|
|
1133
1092
|
if last_note.equal?(new_note)
|
1134
1093
|
Doing.logger.debug('Skipped:', 'No note change')
|
@@ -1169,7 +1128,7 @@ command %i[now next] do |c|
|
|
1169
1128
|
|
1170
1129
|
c.desc 'Backdate start time [4pm|20m|2h|"yesterday noon"]'
|
1171
1130
|
c.arg_name 'DATE_STRING'
|
1172
|
-
c.flag %i[b back started]
|
1131
|
+
c.flag %i[b back started], type: DateBeginString
|
1173
1132
|
|
1174
1133
|
c.desc 'Timed entry, marks last entry in section as @done'
|
1175
1134
|
c.switch %i[f finish_last], negatable: false, default_value: false
|
@@ -1187,7 +1146,7 @@ command %i[now next] do |c|
|
|
1187
1146
|
|
1188
1147
|
c.action do |_global_options, options, args|
|
1189
1148
|
if options[:back]
|
1190
|
-
date = options[:back]
|
1149
|
+
date = options[:back]
|
1191
1150
|
|
1192
1151
|
raise InvalidTimeExpression.new('unable to parse date string', topic: 'Parser:') if date.nil?
|
1193
1152
|
else
|
@@ -1211,7 +1170,7 @@ command %i[now next] do |c|
|
|
1211
1170
|
input += "\n#{ask_note}" unless ask_note.empty?
|
1212
1171
|
input = wwid.fork_editor(input).strip
|
1213
1172
|
|
1214
|
-
|
1173
|
+
d, title, note = wwid.format_input(input)
|
1215
1174
|
raise EmptyInput, 'No content' if title.strip.empty?
|
1216
1175
|
|
1217
1176
|
if ask_note.empty? && options[:ask]
|
@@ -1219,6 +1178,7 @@ command %i[now next] do |c|
|
|
1219
1178
|
note.add(ask_note) unless ask_note.empty?
|
1220
1179
|
end
|
1221
1180
|
|
1181
|
+
date = d.nil? ? date : d
|
1222
1182
|
wwid.add_item(title.cap_first, section, { note: note, back: date, timed: options[:finish_last] })
|
1223
1183
|
wwid.write(wwid.doing_file)
|
1224
1184
|
elsif args.length.positive?
|
@@ -1265,7 +1225,7 @@ desc 'Reset the start time of an entry'
|
|
1265
1225
|
long_desc 'Update the start time of the last entry or the last entry matching a tag/search filter.
|
1266
1226
|
If no argument is provided, the start time will be reset to the current time.
|
1267
1227
|
If a date string is provided as an argument, the start time will be set to the parsed result.'
|
1268
|
-
arg_name 'DATE_STRING'
|
1228
|
+
arg_name 'DATE_STRING', optional: true
|
1269
1229
|
command %i[reset begin] do |c|
|
1270
1230
|
c.example 'doing reset', desc: 'Reset the start time of the last entry to the current time'
|
1271
1231
|
c.example 'doing reset --tag project1', desc: 'Reset the start time of the most recent entry tagged @project1 to the current time'
|
@@ -1279,6 +1239,9 @@ command %i[reset begin] do |c|
|
|
1279
1239
|
c.desc 'Resume entry (remove @done)'
|
1280
1240
|
c.switch %i[r resume], default_value: true
|
1281
1241
|
|
1242
|
+
c.desc 'Change start date but do not remove @done (shortcut for --no-resume)'
|
1243
|
+
c.switch [:n]
|
1244
|
+
|
1282
1245
|
c.desc 'Reset last entry matching tag. Wildcards allowed (*, ?)'
|
1283
1246
|
c.arg_name 'TAG'
|
1284
1247
|
c.flag [:tag]
|
@@ -1416,11 +1379,11 @@ command :select do |c|
|
|
1416
1379
|
|
1417
1380
|
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'
|
1418
1381
|
c.arg_name 'DATE_STRING'
|
1419
|
-
c.flag [:before]
|
1382
|
+
c.flag [:before], type: DateBeginString
|
1420
1383
|
|
1421
1384
|
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'
|
1422
1385
|
c.arg_name 'DATE_STRING'
|
1423
|
-
c.flag [:after]
|
1386
|
+
c.flag [:after], type: DateEndString
|
1424
1387
|
|
1425
1388
|
c.desc %(
|
1426
1389
|
Date range to show, or a single day to filter date on.
|
@@ -1431,7 +1394,7 @@ command :select do |c|
|
|
1431
1394
|
by time of day.
|
1432
1395
|
)
|
1433
1396
|
c.arg_name 'DATE_OR_RANGE'
|
1434
|
-
c.flag [:from]
|
1397
|
+
c.flag [:from], type: DateRangeString
|
1435
1398
|
|
1436
1399
|
c.desc 'Force exact search string matching (case sensitive)'
|
1437
1400
|
c.switch %i[x exact], default_value: config.exact_match?, negatable: config.exact_match?
|
@@ -1698,11 +1661,11 @@ command %i[grep search] do |c|
|
|
1698
1661
|
|
1699
1662
|
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'
|
1700
1663
|
c.arg_name 'DATE_STRING'
|
1701
|
-
c.flag [:before]
|
1664
|
+
c.flag [:before], type: DateBeginString
|
1702
1665
|
|
1703
1666
|
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'
|
1704
1667
|
c.arg_name 'DATE_STRING'
|
1705
|
-
c.flag [:after]
|
1668
|
+
c.flag [:after], type: DateEndString
|
1706
1669
|
|
1707
1670
|
c.desc %(
|
1708
1671
|
Date range to show, or a single day to filter date on.
|
@@ -1713,7 +1676,7 @@ command %i[grep search] do |c|
|
|
1713
1676
|
by time of day.
|
1714
1677
|
)
|
1715
1678
|
c.arg_name 'DATE_OR_RANGE'
|
1716
|
-
c.flag [:from]
|
1679
|
+
c.flag [:from], type: DateRangeString
|
1717
1680
|
|
1718
1681
|
c.desc "Output to export format (#{Doing::Plugins.plugin_names(type: :export)})"
|
1719
1682
|
c.arg_name 'FORMAT'
|
@@ -2011,11 +1974,11 @@ command :show do |c|
|
|
2011
1974
|
|
2012
1975
|
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'
|
2013
1976
|
c.arg_name 'DATE_STRING'
|
2014
|
-
c.flag [:before]
|
1977
|
+
c.flag [:before], type: DateBeginString
|
2015
1978
|
|
2016
1979
|
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'
|
2017
1980
|
c.arg_name 'DATE_STRING'
|
2018
|
-
c.flag [:after]
|
1981
|
+
c.flag [:after], type: DateEndString
|
2019
1982
|
|
2020
1983
|
c.desc %(
|
2021
1984
|
Date range to show, or a single day to filter date on.
|
@@ -2027,7 +1990,7 @@ command :show do |c|
|
|
2027
1990
|
)
|
2028
1991
|
|
2029
1992
|
c.arg_name 'DATE_OR_RANGE'
|
2030
|
-
c.flag [:from]
|
1993
|
+
c.flag [:from], type: DateRangeString
|
2031
1994
|
|
2032
1995
|
c.desc 'Search filter, surround with slashes for regex (/query/), start with single quote for exact match ("\'query")'
|
2033
1996
|
c.arg_name 'QUERY'
|
@@ -2322,8 +2285,8 @@ command :today do |c|
|
|
2322
2285
|
c.desc %(
|
2323
2286
|
Time range to show `doing today --from "12pm to 4pm"`
|
2324
2287
|
)
|
2325
|
-
c.arg_name '
|
2326
|
-
c.flag [:from]
|
2288
|
+
c.arg_name 'TIME_RANGE'
|
2289
|
+
c.flag [:from], type: DateRangeString
|
2327
2290
|
|
2328
2291
|
c.action do |_global_options, options, _args|
|
2329
2292
|
raise DoingRuntimeError, %(Invalid output type "#{options[:output]}") if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
|
@@ -2336,7 +2299,7 @@ command :today do |c|
|
|
2336
2299
|
end
|
2337
2300
|
end
|
2338
2301
|
|
2339
|
-
#
|
2302
|
+
# @@on
|
2340
2303
|
desc 'List entries for a date'
|
2341
2304
|
long_desc %(Date argument can be natural language. "thursday" would be interpreted as "last thursday,"
|
2342
2305
|
and "2d" would be interpreted as "two days ago." If you use "to" or "through" between two dates,
|
@@ -2375,16 +2338,11 @@ command :on do |c|
|
|
2375
2338
|
|
2376
2339
|
raise MissingArgument, 'Missing date argument' if args.empty?
|
2377
2340
|
|
2378
|
-
date_string = args.join(' ')
|
2379
|
-
|
2380
|
-
|
2381
|
-
dates = date_string.split(/ (to|through|thru) /)
|
2382
|
-
start = dates[0].chronify(guess: :begin)
|
2383
|
-
finish = dates[2].chronify(guess: :end)
|
2384
|
-
else
|
2385
|
-
start = date_string.chronify(guess: :begin)
|
2386
|
-
finish = false
|
2341
|
+
date_string = args.join(' ').strip
|
2342
|
+
if date_string =~ /^tod(?:ay)?/i
|
2343
|
+
date_string = 'today to tomorrow 12am'
|
2387
2344
|
end
|
2345
|
+
start, finish = date_string.split_date_range
|
2388
2346
|
|
2389
2347
|
raise InvalidTimeExpression, 'Unrecognized date string' unless start
|
2390
2348
|
|
@@ -2536,11 +2494,11 @@ command :view do |c|
|
|
2536
2494
|
|
2537
2495
|
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'
|
2538
2496
|
c.arg_name 'DATE_STRING'
|
2539
|
-
c.flag [:before]
|
2497
|
+
c.flag [:before], type: DateBeginString
|
2540
2498
|
|
2541
2499
|
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'
|
2542
2500
|
c.arg_name 'DATE_STRING'
|
2543
|
-
c.flag [:after]
|
2501
|
+
c.flag [:after], type: DateEndString
|
2544
2502
|
|
2545
2503
|
c.desc %(
|
2546
2504
|
Date range to show, or a single day to filter date on.
|
@@ -2551,7 +2509,7 @@ command :view do |c|
|
|
2551
2509
|
by time of day.
|
2552
2510
|
)
|
2553
2511
|
c.arg_name 'DATE_OR_RANGE'
|
2554
|
-
c.flag [:from]
|
2512
|
+
c.flag [:from], type: DateRangeString
|
2555
2513
|
|
2556
2514
|
c.desc 'Only show items with recorded time intervals (override view settings)'
|
2557
2515
|
c.switch [:only_timed], default_value: false, negatable: false
|
@@ -2588,17 +2546,17 @@ command :view do |c|
|
|
2588
2546
|
view = wwid.get_view(title)
|
2589
2547
|
|
2590
2548
|
if view
|
2591
|
-
page_title = view
|
2549
|
+
page_title = view['title'] || title.cap_first
|
2592
2550
|
only_timed = if (view.key?('only_timed') && view['only_timed']) || options[:only_timed]
|
2593
2551
|
true
|
2594
2552
|
else
|
2595
2553
|
false
|
2596
2554
|
end
|
2597
2555
|
|
2598
|
-
template = view
|
2599
|
-
date_format = view
|
2556
|
+
template = view['template'] || nil
|
2557
|
+
date_format = view['date_format'] || nil
|
2600
2558
|
|
2601
|
-
tags_color = view
|
2559
|
+
tags_color = view['tags_color'] || nil
|
2602
2560
|
tag_filter = false
|
2603
2561
|
if options[:tag]
|
2604
2562
|
tag_filter = { 'tags' => [], 'bool' => 'OR' }
|
@@ -2628,19 +2586,19 @@ command :view do |c|
|
|
2628
2586
|
section = if options[:section]
|
2629
2587
|
section
|
2630
2588
|
else
|
2631
|
-
view
|
2589
|
+
view['section'] || settings['current_section']
|
2632
2590
|
end
|
2633
|
-
order = view
|
2591
|
+
order = view['order']&.normalize_order || 'asc'
|
2634
2592
|
|
2635
2593
|
totals = if options[:totals]
|
2636
2594
|
true
|
2637
2595
|
else
|
2638
|
-
view
|
2596
|
+
view['totals'] || false
|
2639
2597
|
end
|
2640
2598
|
tag_order = if options[:tag_order]
|
2641
2599
|
options[:tag_order].normalize_order
|
2642
2600
|
else
|
2643
|
-
view
|
2601
|
+
view['tag_order']&.normalize_order || 'asc'
|
2644
2602
|
end
|
2645
2603
|
|
2646
2604
|
options[:times] = true if totals
|
@@ -2669,7 +2627,6 @@ command :view do |c|
|
|
2669
2627
|
|
2670
2628
|
opts = options.dup
|
2671
2629
|
opts[:age] = options[:age].normalize_age(:newest)
|
2672
|
-
opts[:view_template] = title
|
2673
2630
|
opts[:count] = count
|
2674
2631
|
opts[:format] = date_format
|
2675
2632
|
opts[:highlight] = options[:color]
|
@@ -2686,6 +2643,7 @@ command :view do |c|
|
|
2686
2643
|
opts[:tags_color] = tags_color
|
2687
2644
|
opts[:template] = template
|
2688
2645
|
opts[:totals] = totals
|
2646
|
+
opts[:view_template] = title
|
2689
2647
|
|
2690
2648
|
Doing::Pager.page wwid.list_section(opts)
|
2691
2649
|
elsif title.instance_of?(FalseClass)
|
@@ -2735,11 +2693,9 @@ command :yesterday do |c|
|
|
2735
2693
|
c.arg_name 'TIME_STRING'
|
2736
2694
|
c.flag [:after]
|
2737
2695
|
|
2738
|
-
c.desc
|
2739
|
-
Time range to show, e.g. `doing yesterday --from "1am to 8am"`
|
2740
|
-
)
|
2696
|
+
c.desc 'Time range to show, e.g. `doing yesterday --from "1am to 8am"`'
|
2741
2697
|
c.arg_name 'TIME_RANGE'
|
2742
|
-
c.flag [:from]
|
2698
|
+
c.flag [:from], must_match: REGEX_TIME_RANGE
|
2743
2699
|
|
2744
2700
|
c.desc 'Tag sort direction (asc|desc)'
|
2745
2701
|
c.arg_name 'DIRECTION'
|
@@ -2751,9 +2707,9 @@ command :yesterday do |c|
|
|
2751
2707
|
options[:sort_tags] = options[:tag_sort] =~ /^n/i
|
2752
2708
|
|
2753
2709
|
if options[:from]
|
2754
|
-
options[:from] = options[:from].split(/
|
2710
|
+
options[:from] = options[:from].split(/#{REGEX_RANGE_INDICATOR}/).map do |time|
|
2755
2711
|
"yesterday #{time.sub(/(?mi)(^.*?(?=\d+)|(?<=[ap]m).*?$)/, '')}"
|
2756
|
-
end.join(' to ')
|
2712
|
+
end.join(' to ').split_date_range
|
2757
2713
|
end
|
2758
2714
|
|
2759
2715
|
opt = {
|
@@ -2991,8 +2947,7 @@ command :config do |c|
|
|
2991
2947
|
value = options[:remove] ? nil : args.pop
|
2992
2948
|
keypath = args.join('.')
|
2993
2949
|
real_path = config.resolve_key_path(keypath, create: true)
|
2994
|
-
|
2995
|
-
old_value = settings.dig(*real_path) || nil
|
2950
|
+
old_value = settings.dig(*real_path)
|
2996
2951
|
old_type = old_value&.class.to_s || nil
|
2997
2952
|
|
2998
2953
|
if old_value.is_a?(Hash) && !options[:remove]
|
@@ -3018,7 +2973,6 @@ command :config do |c|
|
|
3018
2973
|
else
|
3019
2974
|
current_value = cfg.dig(*real_path)
|
3020
2975
|
cfg.deep_set(real_path, value.set_type(old_type))
|
3021
|
-
|
3022
2976
|
$stderr.puts "#{' Key path:'.yellow} #{real_path.join('->').boldwhite}"
|
3023
2977
|
$stderr.puts "#{'Inherited:'.yellow} #{(old_value ? old_value.to_s : 'empty').boldwhite}"
|
3024
2978
|
$stderr.puts "#{' Current:'.yellow} #{ (current_value ? current_value.to_s : 'empty').boldwhite }"
|
@@ -3178,7 +3132,7 @@ command %i[archive move] do |c|
|
|
3178
3132
|
c.desc 'Archive entries older than date
|
3179
3133
|
(Flexible date format, e.g. 1/27/2021, 2020-07-19, or Monday 3pm)'
|
3180
3134
|
c.arg_name 'DATE_STRING'
|
3181
|
-
c.flag [:before]
|
3135
|
+
c.flag [:before], type: DateEndString
|
3182
3136
|
|
3183
3137
|
c.action do |_global_options, options, args|
|
3184
3138
|
options[:fuzzy] = false
|
@@ -3269,11 +3223,11 @@ command :import do |c|
|
|
3269
3223
|
# TODO: Allow time range filtering
|
3270
3224
|
c.desc 'Import entries older than date'
|
3271
3225
|
c.arg_name 'DATE_STRING'
|
3272
|
-
c.flag [:before]
|
3226
|
+
c.flag [:before], type: DateBeginString
|
3273
3227
|
|
3274
3228
|
c.desc 'Import entries newer than date'
|
3275
3229
|
c.arg_name 'DATE_STRING'
|
3276
|
-
c.flag [:after]
|
3230
|
+
c.flag [:after], type: DateEndString
|
3277
3231
|
|
3278
3232
|
c.desc %(
|
3279
3233
|
Date range to import. Date range argument should be quoted. Date specifications can be natural language.
|
@@ -3281,7 +3235,7 @@ command :import do |c|
|
|
3281
3235
|
Has no effect unless the import plugin has implemented date range filtering.
|
3282
3236
|
)
|
3283
3237
|
c.arg_name 'DATE_OR_RANGE'
|
3284
|
-
c.flag %i[f from]
|
3238
|
+
c.flag %i[f from], type: DateRangeString
|
3285
3239
|
|
3286
3240
|
c.desc 'Allow entries that overlap existing times'
|
3287
3241
|
c.switch [:overlap], negatable: true
|
@@ -3299,24 +3253,19 @@ command :import do |c|
|
|
3299
3253
|
end
|
3300
3254
|
|
3301
3255
|
if options[:from]
|
3302
|
-
|
3303
|
-
|
3304
|
-
|
3305
|
-
|
3306
|
-
|
3307
|
-
|
3308
|
-
|
3309
|
-
finish = date_string.chronify(guess: :end)
|
3310
|
-
end
|
3311
|
-
raise InvalidTimeExpression, 'Unrecognized date string' unless start
|
3312
|
-
dates = [start, finish]
|
3256
|
+
options[:date_filter] = options[:from]
|
3257
|
+
|
3258
|
+
raise InvalidTimeExpression, 'Unrecognized date string' unless options[:date_filter][0]
|
3259
|
+
elsif options[:before] || options[:after]
|
3260
|
+
options[:date_filter] = [nil, nil]
|
3261
|
+
options[:date_filter][1] = options[:before] || Time.now + (1 << 64)
|
3262
|
+
options[:date_filter][0] = options[:after] || Time.now - (1 << 64)
|
3313
3263
|
end
|
3314
3264
|
|
3315
3265
|
options[:case] = options[:case].normalize_case
|
3316
3266
|
|
3317
3267
|
if options[:type] =~ Doing::Plugins.plugin_regex(type: :import)
|
3318
3268
|
options[:no_overlap] = !options[:overlap]
|
3319
|
-
options[:date_filter] = dates
|
3320
3269
|
wwid.import(args, options)
|
3321
3270
|
wwid.write(wwid.doing_file)
|
3322
3271
|
else
|
@@ -3667,9 +3616,9 @@ command :commands_accepting do |c|
|
|
3667
3616
|
end
|
3668
3617
|
|
3669
3618
|
if o[:column]
|
3670
|
-
puts cmds
|
3619
|
+
puts cmds.sort
|
3671
3620
|
else
|
3672
|
-
puts "Commands accepting --#{option}: #{cmds.join(', ')}"
|
3621
|
+
puts "Commands accepting --#{option}: #{cmds.sort.join(', ')}"
|
3673
3622
|
end
|
3674
3623
|
end
|
3675
3624
|
end
|
@@ -3700,7 +3649,7 @@ pre do |global, _command, _options, _args|
|
|
3700
3649
|
Doing::Pager.paginate = global[:pager]
|
3701
3650
|
|
3702
3651
|
$stdout.puts "doing v#{Doing::VERSION}" if global[:version]
|
3703
|
-
unless
|
3652
|
+
unless $stdout.isatty
|
3704
3653
|
Doing::Color.coloring = global[:pager] ? global[:color] : false
|
3705
3654
|
else
|
3706
3655
|
Doing::Color.coloring = global[:color]
|
@@ -3714,7 +3663,9 @@ pre do |global, _command, _options, _args|
|
|
3714
3663
|
end
|
3715
3664
|
|
3716
3665
|
on_error do |exception|
|
3717
|
-
if exception.kind_of?(
|
3666
|
+
if exception.kind_of?(GLI::UnknownCommand)
|
3667
|
+
exit run(['now'].concat(ARGV))
|
3668
|
+
elsif exception.kind_of?(SystemExit)
|
3718
3669
|
false
|
3719
3670
|
else
|
3720
3671
|
# Doing.logger.error('Fatal:', exception)
|
@@ -3748,7 +3699,12 @@ around do |global, command, options, arguments, code|
|
|
3748
3699
|
Doing::Prompt.force_answer = false
|
3749
3700
|
Doing.config.force_answer = false
|
3750
3701
|
else
|
3751
|
-
Doing::Prompt.default_answer =
|
3702
|
+
Doing::Prompt.default_answer = if $stdout.isatty
|
3703
|
+
global[:default]
|
3704
|
+
else
|
3705
|
+
true
|
3706
|
+
end
|
3707
|
+
|
3752
3708
|
Doing.config.force_answer = global[:default] ? true : false
|
3753
3709
|
end
|
3754
3710
|
|