doing 2.1.19 → 2.1.21
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardoc/checksums +9 -8
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/CHANGELOG.md +49 -0
- data/Gemfile.lock +11 -11
- data/README.md +1 -1
- data/Rakefile +10 -4
- data/bin/doing +123 -167
- data/docs/doc/Array.html +3 -3
- 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 +3 -3
- 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 +4 -4
- 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 +3 -3
- 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 +94 -17
- data/docs/doc/Symbol.html +3 -3
- data/docs/doc/Time.html +3 -3
- data/docs/doc/_index.html +4 -4
- 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 +300 -276
- data/docs/doc/top-level-namespace.html +94 -3
- data/doing.gemspec +1 -1
- data/doing.rdoc +15 -6
- data/lib/completion/_doing.zsh +5 -5
- data/lib/completion/doing.bash +8 -8
- data/lib/completion/doing.fish +93 -15
- data/lib/doing/completion/fish_completion.rb +80 -11
- data/lib/doing/configuration.rb +1 -0
- data/lib/doing/hash.rb +1 -1
- data/lib/doing/items.rb +3 -1
- data/lib/doing/pager.rb +1 -1
- data/lib/doing/plugins/export/dayone_export.rb +1 -1
- data/lib/doing/plugins/export/markdown_export.rb +1 -1
- data/lib/doing/string.rb +11 -0
- data/lib/doing/string_chronify.rb +55 -17
- data/lib/doing/types.rb +19 -0
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +69 -42
- data/lib/examples/commands/later.rb +32 -0
- data/lib/helpers/threaded_tests.rb +250 -0
- metadata +9 -6
data/bin/doing
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
$LOAD_PATH.unshift File.join(__dir__, '..', 'lib')
|
5
5
|
require 'gli'
|
6
6
|
require 'doing'
|
7
|
+
require 'doing/types'
|
7
8
|
require 'tempfile'
|
8
9
|
require 'pp'
|
9
10
|
|
@@ -25,12 +26,13 @@ version Doing::VERSION
|
|
25
26
|
hide_commands_without_desc true
|
26
27
|
autocomplete_commands true
|
27
28
|
|
28
|
-
REGEX_BOOL = /^(?:and|all|any|or|not|none|p(?:at(?:tern)?)?)$/i
|
29
|
-
REGEX_SORT_ORDER = /^(?:a(?:sc)?|d(?:esc)?)$/i
|
30
|
-
REGEX_VALUE_QUERY = /^(?:!)?@?(?:\S+) +(?:!?[<>=][=*]?|[$*^]=) +(?:.*?)$/
|
31
|
-
|
32
29
|
InvalidExportType = Class.new(RuntimeError)
|
33
30
|
MissingConfigFile = Class.new(RuntimeError)
|
31
|
+
TagArray = Class.new(Array)
|
32
|
+
DateBeginString = Class.new(DateTime)
|
33
|
+
DateEndString = Class.new(DateTime)
|
34
|
+
DateRangeString = Class.new(Array)
|
35
|
+
DateIntervalString = Class.new(DateTime)
|
34
36
|
|
35
37
|
colors = Doing::Color
|
36
38
|
wwid = Doing::WWID.new
|
@@ -70,7 +72,42 @@ if settings.dig('plugins', 'command_path')
|
|
70
72
|
commands_from File.expand_path(settings.dig('plugins', 'command_path'))
|
71
73
|
end
|
72
74
|
|
73
|
-
|
75
|
+
accept DateBeginString do |value|
|
76
|
+
if value =~ REGEX_TIME
|
77
|
+
res = value
|
78
|
+
else
|
79
|
+
res = value.chronify(guess: :begin, future: false)
|
80
|
+
end
|
81
|
+
raise InvalidTimeExpression, 'Invalid start date' unless res
|
82
|
+
|
83
|
+
res
|
84
|
+
end
|
85
|
+
|
86
|
+
accept DateEndString do |value|
|
87
|
+
if value =~ REGEX_TIME
|
88
|
+
res = value
|
89
|
+
else
|
90
|
+
res = value.chronify(guess: :end, future: false)
|
91
|
+
end
|
92
|
+
raise InvalidTimeExpression, 'Invalid end date' unless res
|
93
|
+
|
94
|
+
res
|
95
|
+
end
|
96
|
+
|
97
|
+
accept DateRangeString do |value|
|
98
|
+
start, finish = value.split_date_range
|
99
|
+
raise InvalidTimeExpression, 'Invalid range' unless start
|
100
|
+
|
101
|
+
finish ||= Time.now
|
102
|
+
[start, finish]
|
103
|
+
end
|
104
|
+
|
105
|
+
accept DateIntervalString do |value|
|
106
|
+
res = value.chronify_qty
|
107
|
+
raise InvalidTimeExpression, 'Invalid time quantity' unless res
|
108
|
+
|
109
|
+
res
|
110
|
+
end
|
74
111
|
|
75
112
|
accept TagArray do |value|
|
76
113
|
value.gsub(/[, ]+/, ' ').split(' ').map { |tag| tag.sub(/^@/, '')}.map(&:strip)
|
@@ -143,6 +180,10 @@ command %i[again resume] do |c|
|
|
143
180
|
c.arg_name 'SECTION_NAME'
|
144
181
|
c.flag [:in]
|
145
182
|
|
183
|
+
c.desc 'Backdate start date by interval or set to time [4pm|20m|2h|"yesterday noon"]'
|
184
|
+
c.arg_name 'DATE_STRING'
|
185
|
+
c.flag %i[b back started], type: DateBeginString
|
186
|
+
|
146
187
|
c.desc 'Repeat last entry matching tags. Combine multiple tags with a comma. Wildcards allowed (*, ?)'
|
147
188
|
c.arg_name 'TAG'
|
148
189
|
c.flag [:tag], type: TagArray
|
@@ -198,6 +239,13 @@ command %i[again resume] do |c|
|
|
198
239
|
options[:search] = search
|
199
240
|
end
|
200
241
|
|
242
|
+
if options[:back]
|
243
|
+
date = options[:back]
|
244
|
+
raise InvalidTimeExpression, 'Unable to parse date string for --back' if date.nil?
|
245
|
+
else
|
246
|
+
date = Time.now
|
247
|
+
end
|
248
|
+
|
201
249
|
note = Doing::Note.new(options[:note])
|
202
250
|
note.add(Doing::Prompt.read_lines(prompt: 'Add a note')) if options[:ask]
|
203
251
|
|
@@ -208,6 +256,7 @@ command %i[again resume] do |c|
|
|
208
256
|
opts[:tag] = tags
|
209
257
|
opts[:tag_bool] = options[:bool].normalize_bool
|
210
258
|
opts[:interactive] = options[:interactive]
|
259
|
+
opts[:date] = date
|
211
260
|
|
212
261
|
wwid.repeat_last(opts)
|
213
262
|
end
|
@@ -340,24 +389,24 @@ command %i[done did] do |c|
|
|
340
389
|
c.desc %(Set finish date to specific date/time (natural langauge parsed, e.g. --at=1:30pm).
|
341
390
|
Used with --took, backdates start date)
|
342
391
|
c.arg_name 'DATE_STRING'
|
343
|
-
c.flag %i[at finished]
|
392
|
+
c.flag %i[at finished], type: DateEndString
|
344
393
|
|
345
394
|
c.desc 'Backdate start date by interval or set to time [4pm|20m|2h|"yesterday noon"]'
|
346
395
|
c.arg_name 'DATE_STRING'
|
347
|
-
c.flag %i[b back started]
|
396
|
+
c.flag %i[b back started], type: DateBeginString
|
348
397
|
|
349
398
|
c.desc %(
|
350
399
|
Start and end times as a date/time range `doing done --from "1am to 8am"`.
|
351
400
|
Overrides other date flags.
|
352
401
|
)
|
353
402
|
c.arg_name 'TIME_RANGE'
|
354
|
-
c.flag [:from]
|
403
|
+
c.flag [:from], must_match: REGEX_RANGE
|
355
404
|
|
356
405
|
c.desc %(Set completion date to start date plus interval (XX[mhd] or HH:MM).
|
357
406
|
If used without the --back option, the start date will be moved back to allow
|
358
407
|
the completion date to be the current time.)
|
359
408
|
c.arg_name 'INTERVAL'
|
360
|
-
c.flag %i[t took for]
|
409
|
+
c.flag %i[t took for], type: DateIntervalString
|
361
410
|
|
362
411
|
c.desc 'Section'
|
363
412
|
c.arg_name 'NAME'
|
@@ -385,23 +434,27 @@ command %i[done did] do |c|
|
|
385
434
|
donedate = nil
|
386
435
|
|
387
436
|
if options[:from]
|
388
|
-
|
437
|
+
options[:from] = options[:from].split(/#{REGEX_RANGE_INDICATOR}/).map do |time|
|
438
|
+
time =~ REGEX_TIME ? "today #{time.sub(/(?mi)(^.*?(?=\d+)|(?<=[ap]m).*?$)/, '')}" : time
|
439
|
+
end.join(' to ').split_date_range
|
440
|
+
date, finish_date = options[:from]
|
389
441
|
finish_date ||= Time.now
|
390
442
|
else
|
391
443
|
if options[:took]
|
392
|
-
took = options[:took]
|
444
|
+
took = options[:took]
|
393
445
|
raise InvalidTimeExpression, 'Unable to parse date string for --took' if took.nil?
|
394
446
|
end
|
395
447
|
|
396
448
|
if options[:back]
|
397
|
-
date = options[:back]
|
449
|
+
date = options[:back]
|
398
450
|
raise InvalidTimeExpression, 'Unable to parse date string for --back' if date.nil?
|
399
451
|
else
|
400
452
|
date = options[:took] ? Time.now - took : Time.now
|
401
453
|
end
|
402
454
|
|
403
455
|
if options[:at]
|
404
|
-
finish_date = options[:at]
|
456
|
+
finish_date = options[:at]
|
457
|
+
finish_date = finish_date.chronify(guess: :begin) if finish_date.is_a? String
|
405
458
|
raise InvalidTimeExpression, 'Unable to parse date string for --at' if finish_date.nil?
|
406
459
|
|
407
460
|
if options[:took]
|
@@ -417,6 +470,7 @@ command %i[done did] do |c|
|
|
417
470
|
end
|
418
471
|
|
419
472
|
if options[:date]
|
473
|
+
date = date.chronify(guess: :begin, context: :today) if date =~ REGEX_TIME
|
420
474
|
finish_date = wwid.verify_duration(date, finish_date) unless options[:took] || options[:from]
|
421
475
|
|
422
476
|
donedate = finish_date.strftime('%F %R')
|
@@ -528,7 +582,7 @@ command %i[done did] do |c|
|
|
528
582
|
wwid.content.push(new_entry)
|
529
583
|
Doing::Hooks.trigger :post_entry_added, wwid, new_entry.dup
|
530
584
|
wwid.write(wwid.doing_file)
|
531
|
-
Doing.logger.info('
|
585
|
+
Doing.logger.info('New entry:', %(added "#{new_entry.date.relative_date}: #{new_entry.title}" to #{section}))
|
532
586
|
elsif $stdin.stat.size.positive?
|
533
587
|
note = Doing::Note.new(options[:note])
|
534
588
|
d, title, note = wwid.format_input($stdin.read.strip)
|
@@ -553,7 +607,7 @@ command %i[done did] do |c|
|
|
553
607
|
Doing::Hooks.trigger :post_entry_added, wwid, new_entry.dup
|
554
608
|
|
555
609
|
wwid.write(wwid.doing_file)
|
556
|
-
Doing.logger.info('
|
610
|
+
Doing.logger.info('New entry:', %(added "#{new_entry.date.relative_date}: #{new_entry.title}" to #{section}))
|
557
611
|
else
|
558
612
|
raise EmptyInput, 'You must provide content when creating a new entry'
|
559
613
|
end
|
@@ -574,15 +628,15 @@ command :finish do |c|
|
|
574
628
|
|
575
629
|
c.desc 'Backdate completed date to date string [4pm|20m|2h|yesterday noon]'
|
576
630
|
c.arg_name 'DATE_STRING'
|
577
|
-
c.flag %i[b back]
|
631
|
+
c.flag %i[b back started], type: DateBeginString
|
578
632
|
|
579
633
|
c.desc 'Set the completed date to the start date plus XX[hmd]'
|
580
634
|
c.arg_name 'INTERVAL'
|
581
|
-
c.flag %i[t took for]
|
635
|
+
c.flag %i[t took for], type: DateIntervalString
|
582
636
|
|
583
637
|
c.desc %(Set finish date to specific date/time (natural langauge parsed, e.g. --at=1:30pm). If used, ignores --back.)
|
584
638
|
c.arg_name 'DATE_STRING'
|
585
|
-
c.flag [
|
639
|
+
c.flag %i[at finished], type: DateEndString
|
586
640
|
|
587
641
|
c.desc 'Finish the last X entries containing TAG.
|
588
642
|
Separate multiple tags with comma (--tag=tag1,tag2), combine with --bool. Wildcards allowed (*, ?).'
|
@@ -639,7 +693,7 @@ command :finish do |c|
|
|
639
693
|
options[:fuzzy] = false
|
640
694
|
unless options[:auto]
|
641
695
|
if options[:took]
|
642
|
-
took = options[:took]
|
696
|
+
took = options[:took]
|
643
697
|
raise InvalidTimeExpression, 'Unable to parse date string for --took' if took.nil?
|
644
698
|
end
|
645
699
|
|
@@ -648,12 +702,13 @@ command :finish do |c|
|
|
648
702
|
raise InvalidArgument, '--search and --tag can not be used together' if options[:search] && options[:tag]
|
649
703
|
|
650
704
|
if options[:at]
|
651
|
-
finish_date = options[:at]
|
705
|
+
finish_date = options[:at]
|
706
|
+
finish_date = finish_date.chronify(guess: :begin) if finish_date.is_a? String
|
652
707
|
raise InvalidTimeExpression, 'Unable to parse date string for --at' if finish_date.nil?
|
653
708
|
|
654
709
|
date = options[:took] ? finish_date - took : finish_date
|
655
710
|
elsif options[:back]
|
656
|
-
date = options[:back]
|
711
|
+
date = options[:back]
|
657
712
|
|
658
713
|
raise InvalidTimeExpression, 'Unable to parse date string' if date.nil?
|
659
714
|
else
|
@@ -661,8 +716,6 @@ command :finish do |c|
|
|
661
716
|
end
|
662
717
|
end
|
663
718
|
|
664
|
-
options[:took] = options[:took].chronify_qty if options[:took]
|
665
|
-
|
666
719
|
if options[:tag].nil?
|
667
720
|
tags = []
|
668
721
|
else
|
@@ -711,92 +764,6 @@ command :finish do |c|
|
|
711
764
|
end
|
712
765
|
end
|
713
766
|
|
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
767
|
# @@mark @@flag
|
801
768
|
desc 'Mark last entry as flagged'
|
802
769
|
command %i[mark flag] do |c|
|
@@ -949,7 +916,7 @@ command :meanwhile do |c|
|
|
949
916
|
|
950
917
|
c.desc 'Backdate start date for new entry to date string [4pm|20m|2h|yesterday noon]'
|
951
918
|
c.arg_name 'DATE_STRING'
|
952
|
-
c.flag %i[b back]
|
919
|
+
c.flag %i[b back started], type: DateBeginString
|
953
920
|
|
954
921
|
c.desc 'Note'
|
955
922
|
c.arg_name 'TEXT'
|
@@ -960,7 +927,7 @@ command :meanwhile do |c|
|
|
960
927
|
|
961
928
|
c.action do |_global_options, options, args|
|
962
929
|
if options[:back]
|
963
|
-
date = options[:back]
|
930
|
+
date = options[:back]
|
964
931
|
|
965
932
|
raise InvalidTimeExpression, 'Unable to parse date string' if date.nil?
|
966
933
|
else
|
@@ -1169,7 +1136,7 @@ command %i[now next] do |c|
|
|
1169
1136
|
|
1170
1137
|
c.desc 'Backdate start time [4pm|20m|2h|"yesterday noon"]'
|
1171
1138
|
c.arg_name 'DATE_STRING'
|
1172
|
-
c.flag %i[b back started]
|
1139
|
+
c.flag %i[b back started], type: DateBeginString
|
1173
1140
|
|
1174
1141
|
c.desc 'Timed entry, marks last entry in section as @done'
|
1175
1142
|
c.switch %i[f finish_last], negatable: false, default_value: false
|
@@ -1187,7 +1154,7 @@ command %i[now next] do |c|
|
|
1187
1154
|
|
1188
1155
|
c.action do |_global_options, options, args|
|
1189
1156
|
if options[:back]
|
1190
|
-
date = options[:back]
|
1157
|
+
date = options[:back]
|
1191
1158
|
|
1192
1159
|
raise InvalidTimeExpression.new('unable to parse date string', topic: 'Parser:') if date.nil?
|
1193
1160
|
else
|
@@ -1211,7 +1178,7 @@ command %i[now next] do |c|
|
|
1211
1178
|
input += "\n#{ask_note}" unless ask_note.empty?
|
1212
1179
|
input = wwid.fork_editor(input).strip
|
1213
1180
|
|
1214
|
-
|
1181
|
+
d, title, note = wwid.format_input(input)
|
1215
1182
|
raise EmptyInput, 'No content' if title.strip.empty?
|
1216
1183
|
|
1217
1184
|
if ask_note.empty? && options[:ask]
|
@@ -1219,6 +1186,7 @@ command %i[now next] do |c|
|
|
1219
1186
|
note.add(ask_note) unless ask_note.empty?
|
1220
1187
|
end
|
1221
1188
|
|
1189
|
+
date = d.nil? ? date : d
|
1222
1190
|
wwid.add_item(title.cap_first, section, { note: note, back: date, timed: options[:finish_last] })
|
1223
1191
|
wwid.write(wwid.doing_file)
|
1224
1192
|
elsif args.length.positive?
|
@@ -1416,11 +1384,11 @@ command :select do |c|
|
|
1416
1384
|
|
1417
1385
|
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
1386
|
c.arg_name 'DATE_STRING'
|
1419
|
-
c.flag [:before]
|
1387
|
+
c.flag [:before], type: DateBeginString
|
1420
1388
|
|
1421
1389
|
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
1390
|
c.arg_name 'DATE_STRING'
|
1423
|
-
c.flag [:after]
|
1391
|
+
c.flag [:after], type: DateEndString
|
1424
1392
|
|
1425
1393
|
c.desc %(
|
1426
1394
|
Date range to show, or a single day to filter date on.
|
@@ -1431,7 +1399,7 @@ command :select do |c|
|
|
1431
1399
|
by time of day.
|
1432
1400
|
)
|
1433
1401
|
c.arg_name 'DATE_OR_RANGE'
|
1434
|
-
c.flag [:from]
|
1402
|
+
c.flag [:from], type: DateRangeString
|
1435
1403
|
|
1436
1404
|
c.desc 'Force exact search string matching (case sensitive)'
|
1437
1405
|
c.switch %i[x exact], default_value: config.exact_match?, negatable: config.exact_match?
|
@@ -1698,11 +1666,11 @@ command %i[grep search] do |c|
|
|
1698
1666
|
|
1699
1667
|
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
1668
|
c.arg_name 'DATE_STRING'
|
1701
|
-
c.flag [:before]
|
1669
|
+
c.flag [:before], type: DateBeginString
|
1702
1670
|
|
1703
1671
|
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
1672
|
c.arg_name 'DATE_STRING'
|
1705
|
-
c.flag [:after]
|
1673
|
+
c.flag [:after], type: DateEndString
|
1706
1674
|
|
1707
1675
|
c.desc %(
|
1708
1676
|
Date range to show, or a single day to filter date on.
|
@@ -1713,7 +1681,7 @@ command %i[grep search] do |c|
|
|
1713
1681
|
by time of day.
|
1714
1682
|
)
|
1715
1683
|
c.arg_name 'DATE_OR_RANGE'
|
1716
|
-
c.flag [:from]
|
1684
|
+
c.flag [:from], type: DateRangeString
|
1717
1685
|
|
1718
1686
|
c.desc "Output to export format (#{Doing::Plugins.plugin_names(type: :export)})"
|
1719
1687
|
c.arg_name 'FORMAT'
|
@@ -2011,11 +1979,11 @@ command :show do |c|
|
|
2011
1979
|
|
2012
1980
|
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
1981
|
c.arg_name 'DATE_STRING'
|
2014
|
-
c.flag [:before]
|
1982
|
+
c.flag [:before], type: DateBeginString
|
2015
1983
|
|
2016
1984
|
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
1985
|
c.arg_name 'DATE_STRING'
|
2018
|
-
c.flag [:after]
|
1986
|
+
c.flag [:after], type: DateEndString
|
2019
1987
|
|
2020
1988
|
c.desc %(
|
2021
1989
|
Date range to show, or a single day to filter date on.
|
@@ -2027,7 +1995,7 @@ command :show do |c|
|
|
2027
1995
|
)
|
2028
1996
|
|
2029
1997
|
c.arg_name 'DATE_OR_RANGE'
|
2030
|
-
c.flag [:from]
|
1998
|
+
c.flag [:from], type: DateRangeString
|
2031
1999
|
|
2032
2000
|
c.desc 'Search filter, surround with slashes for regex (/query/), start with single quote for exact match ("\'query")'
|
2033
2001
|
c.arg_name 'QUERY'
|
@@ -2322,8 +2290,8 @@ command :today do |c|
|
|
2322
2290
|
c.desc %(
|
2323
2291
|
Time range to show `doing today --from "12pm to 4pm"`
|
2324
2292
|
)
|
2325
|
-
c.arg_name '
|
2326
|
-
c.flag [:from]
|
2293
|
+
c.arg_name 'TIME_RANGE'
|
2294
|
+
c.flag [:from], type: DateRangeString
|
2327
2295
|
|
2328
2296
|
c.action do |_global_options, options, _args|
|
2329
2297
|
raise DoingRuntimeError, %(Invalid output type "#{options[:output]}") if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
|
@@ -2336,7 +2304,7 @@ command :today do |c|
|
|
2336
2304
|
end
|
2337
2305
|
end
|
2338
2306
|
|
2339
|
-
#
|
2307
|
+
# @@on
|
2340
2308
|
desc 'List entries for a date'
|
2341
2309
|
long_desc %(Date argument can be natural language. "thursday" would be interpreted as "last thursday,"
|
2342
2310
|
and "2d" would be interpreted as "two days ago." If you use "to" or "through" between two dates,
|
@@ -2375,16 +2343,11 @@ command :on do |c|
|
|
2375
2343
|
|
2376
2344
|
raise MissingArgument, 'Missing date argument' if args.empty?
|
2377
2345
|
|
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
|
2346
|
+
date_string = args.join(' ').strip
|
2347
|
+
if date_string =~ /^tod(?:ay)?/i
|
2348
|
+
date_string = 'today to tomorrow 12am'
|
2387
2349
|
end
|
2350
|
+
start, finish = date_string.split_date_range
|
2388
2351
|
|
2389
2352
|
raise InvalidTimeExpression, 'Unrecognized date string' unless start
|
2390
2353
|
|
@@ -2536,11 +2499,11 @@ command :view do |c|
|
|
2536
2499
|
|
2537
2500
|
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
2501
|
c.arg_name 'DATE_STRING'
|
2539
|
-
c.flag [:before]
|
2502
|
+
c.flag [:before], type: DateBeginString
|
2540
2503
|
|
2541
2504
|
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
2505
|
c.arg_name 'DATE_STRING'
|
2543
|
-
c.flag [:after]
|
2506
|
+
c.flag [:after], type: DateEndString
|
2544
2507
|
|
2545
2508
|
c.desc %(
|
2546
2509
|
Date range to show, or a single day to filter date on.
|
@@ -2551,7 +2514,7 @@ command :view do |c|
|
|
2551
2514
|
by time of day.
|
2552
2515
|
)
|
2553
2516
|
c.arg_name 'DATE_OR_RANGE'
|
2554
|
-
c.flag [:from]
|
2517
|
+
c.flag [:from], type: DateRangeString
|
2555
2518
|
|
2556
2519
|
c.desc 'Only show items with recorded time intervals (override view settings)'
|
2557
2520
|
c.switch [:only_timed], default_value: false, negatable: false
|
@@ -2669,7 +2632,6 @@ command :view do |c|
|
|
2669
2632
|
|
2670
2633
|
opts = options.dup
|
2671
2634
|
opts[:age] = options[:age].normalize_age(:newest)
|
2672
|
-
opts[:view_template] = title
|
2673
2635
|
opts[:count] = count
|
2674
2636
|
opts[:format] = date_format
|
2675
2637
|
opts[:highlight] = options[:color]
|
@@ -2686,6 +2648,7 @@ command :view do |c|
|
|
2686
2648
|
opts[:tags_color] = tags_color
|
2687
2649
|
opts[:template] = template
|
2688
2650
|
opts[:totals] = totals
|
2651
|
+
opts[:view_template] = title
|
2689
2652
|
|
2690
2653
|
Doing::Pager.page wwid.list_section(opts)
|
2691
2654
|
elsif title.instance_of?(FalseClass)
|
@@ -2735,11 +2698,9 @@ command :yesterday do |c|
|
|
2735
2698
|
c.arg_name 'TIME_STRING'
|
2736
2699
|
c.flag [:after]
|
2737
2700
|
|
2738
|
-
c.desc
|
2739
|
-
Time range to show, e.g. `doing yesterday --from "1am to 8am"`
|
2740
|
-
)
|
2701
|
+
c.desc 'Time range to show, e.g. `doing yesterday --from "1am to 8am"`'
|
2741
2702
|
c.arg_name 'TIME_RANGE'
|
2742
|
-
c.flag [:from]
|
2703
|
+
c.flag [:from], must_match: REGEX_TIME_RANGE
|
2743
2704
|
|
2744
2705
|
c.desc 'Tag sort direction (asc|desc)'
|
2745
2706
|
c.arg_name 'DIRECTION'
|
@@ -2751,9 +2712,9 @@ command :yesterday do |c|
|
|
2751
2712
|
options[:sort_tags] = options[:tag_sort] =~ /^n/i
|
2752
2713
|
|
2753
2714
|
if options[:from]
|
2754
|
-
options[:from] = options[:from].split(/
|
2715
|
+
options[:from] = options[:from].split(/#{REGEX_RANGE_INDICATOR}/).map do |time|
|
2755
2716
|
"yesterday #{time.sub(/(?mi)(^.*?(?=\d+)|(?<=[ap]m).*?$)/, '')}"
|
2756
|
-
end.join(' to ')
|
2717
|
+
end.join(' to ').split_date_range
|
2757
2718
|
end
|
2758
2719
|
|
2759
2720
|
opt = {
|
@@ -2991,8 +2952,7 @@ command :config do |c|
|
|
2991
2952
|
value = options[:remove] ? nil : args.pop
|
2992
2953
|
keypath = args.join('.')
|
2993
2954
|
real_path = config.resolve_key_path(keypath, create: true)
|
2994
|
-
|
2995
|
-
old_value = settings.dig(*real_path) || nil
|
2955
|
+
old_value = settings.dig(*real_path)
|
2996
2956
|
old_type = old_value&.class.to_s || nil
|
2997
2957
|
|
2998
2958
|
if old_value.is_a?(Hash) && !options[:remove]
|
@@ -3018,7 +2978,6 @@ command :config do |c|
|
|
3018
2978
|
else
|
3019
2979
|
current_value = cfg.dig(*real_path)
|
3020
2980
|
cfg.deep_set(real_path, value.set_type(old_type))
|
3021
|
-
|
3022
2981
|
$stderr.puts "#{' Key path:'.yellow} #{real_path.join('->').boldwhite}"
|
3023
2982
|
$stderr.puts "#{'Inherited:'.yellow} #{(old_value ? old_value.to_s : 'empty').boldwhite}"
|
3024
2983
|
$stderr.puts "#{' Current:'.yellow} #{ (current_value ? current_value.to_s : 'empty').boldwhite }"
|
@@ -3178,7 +3137,7 @@ command %i[archive move] do |c|
|
|
3178
3137
|
c.desc 'Archive entries older than date
|
3179
3138
|
(Flexible date format, e.g. 1/27/2021, 2020-07-19, or Monday 3pm)'
|
3180
3139
|
c.arg_name 'DATE_STRING'
|
3181
|
-
c.flag [:before]
|
3140
|
+
c.flag [:before], type: DateEndString
|
3182
3141
|
|
3183
3142
|
c.action do |_global_options, options, args|
|
3184
3143
|
options[:fuzzy] = false
|
@@ -3269,11 +3228,11 @@ command :import do |c|
|
|
3269
3228
|
# TODO: Allow time range filtering
|
3270
3229
|
c.desc 'Import entries older than date'
|
3271
3230
|
c.arg_name 'DATE_STRING'
|
3272
|
-
c.flag [:before]
|
3231
|
+
c.flag [:before], type: DateBeginString
|
3273
3232
|
|
3274
3233
|
c.desc 'Import entries newer than date'
|
3275
3234
|
c.arg_name 'DATE_STRING'
|
3276
|
-
c.flag [:after]
|
3235
|
+
c.flag [:after], type: DateEndString
|
3277
3236
|
|
3278
3237
|
c.desc %(
|
3279
3238
|
Date range to import. Date range argument should be quoted. Date specifications can be natural language.
|
@@ -3281,7 +3240,7 @@ command :import do |c|
|
|
3281
3240
|
Has no effect unless the import plugin has implemented date range filtering.
|
3282
3241
|
)
|
3283
3242
|
c.arg_name 'DATE_OR_RANGE'
|
3284
|
-
c.flag %i[f from]
|
3243
|
+
c.flag %i[f from], type: DateRangeString
|
3285
3244
|
|
3286
3245
|
c.desc 'Allow entries that overlap existing times'
|
3287
3246
|
c.switch [:overlap], negatable: true
|
@@ -3299,24 +3258,19 @@ command :import do |c|
|
|
3299
3258
|
end
|
3300
3259
|
|
3301
3260
|
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]
|
3261
|
+
options[:date_filter] = options[:from]
|
3262
|
+
|
3263
|
+
raise InvalidTimeExpression, 'Unrecognized date string' unless options[:date_filter][0]
|
3264
|
+
elsif options[:before] || options[:after]
|
3265
|
+
options[:date_filter] = [nil, nil]
|
3266
|
+
options[:date_filter][1] = options[:before] || Time.now + (1 << 64)
|
3267
|
+
options[:date_filter][0] = options[:after] || Time.now - (1 << 64)
|
3313
3268
|
end
|
3314
3269
|
|
3315
3270
|
options[:case] = options[:case].normalize_case
|
3316
3271
|
|
3317
3272
|
if options[:type] =~ Doing::Plugins.plugin_regex(type: :import)
|
3318
3273
|
options[:no_overlap] = !options[:overlap]
|
3319
|
-
options[:date_filter] = dates
|
3320
3274
|
wwid.import(args, options)
|
3321
3275
|
wwid.write(wwid.doing_file)
|
3322
3276
|
else
|
@@ -3667,9 +3621,9 @@ command :commands_accepting do |c|
|
|
3667
3621
|
end
|
3668
3622
|
|
3669
3623
|
if o[:column]
|
3670
|
-
puts cmds
|
3624
|
+
puts cmds.sort
|
3671
3625
|
else
|
3672
|
-
puts "Commands accepting --#{option}: #{cmds.join(', ')}"
|
3626
|
+
puts "Commands accepting --#{option}: #{cmds.sort.join(', ')}"
|
3673
3627
|
end
|
3674
3628
|
end
|
3675
3629
|
end
|
@@ -3714,7 +3668,9 @@ pre do |global, _command, _options, _args|
|
|
3714
3668
|
end
|
3715
3669
|
|
3716
3670
|
on_error do |exception|
|
3717
|
-
if exception.kind_of?(
|
3671
|
+
if exception.kind_of?(GLI::UnknownCommand)
|
3672
|
+
exit run(['now'].concat(ARGV))
|
3673
|
+
elsif exception.kind_of?(SystemExit)
|
3718
3674
|
false
|
3719
3675
|
else
|
3720
3676
|
# Doing.logger.error('Fatal:', exception)
|
data/docs/doc/Array.html
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
<title>
|
7
7
|
Class: Array
|
8
8
|
|
9
|
-
— Documentation by YARD 0.9.
|
9
|
+
— Documentation by YARD 0.9.27
|
10
10
|
|
11
11
|
</title>
|
12
12
|
|
@@ -654,9 +654,9 @@ minutes]</p>
|
|
654
654
|
</div>
|
655
655
|
|
656
656
|
<div id="footer">
|
657
|
-
Generated on
|
657
|
+
Generated on Thu Jan 20 12:10:33 2022 by
|
658
658
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
659
|
-
0.9.
|
659
|
+
0.9.27 (ruby-3.0.1).
|
660
660
|
</div>
|
661
661
|
|
662
662
|
</div>
|