doing 2.1.19 → 2.1.21
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/.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>
|