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/lib/doing/items.rb
CHANGED
@@ -131,7 +131,9 @@ module Doing
|
|
131
131
|
out = []
|
132
132
|
@sections.each do |section|
|
133
133
|
out.push(section.original)
|
134
|
-
in_section(section.title).
|
134
|
+
items = in_section(section.title).sort_by { |i| i.date }
|
135
|
+
items.reverse! if Doing.config.settings['doing_file_sort'].normalize_order == 'desc'
|
136
|
+
items.each { |item| out.push(item.to_s)}
|
135
137
|
end
|
136
138
|
|
137
139
|
out.join("\n")
|
data/lib/doing/pager.rb
CHANGED
@@ -75,7 +75,7 @@ module Doing
|
|
75
75
|
note = i.note.map { |line| line.strip.link_urls(format: :markdown) } if i.note
|
76
76
|
end
|
77
77
|
|
78
|
-
title = "#{title} @
|
78
|
+
title = "#{title} @section(#{i.section})" unless variables[:is_single]
|
79
79
|
|
80
80
|
tags.concat(i.tag_array).sort!.uniq!
|
81
81
|
flagged = day_flagged = true if i.tags?(wwid.config['marker_tag'])
|
@@ -48,7 +48,7 @@ module Doing
|
|
48
48
|
note = i.note.map { |line| line.strip.link_urls(format: :markdown) } if i.note
|
49
49
|
end
|
50
50
|
|
51
|
-
title = "#{title} @
|
51
|
+
title = "#{title} @section(#{i.section})" unless variables[:is_single]
|
52
52
|
|
53
53
|
interval = wwid.get_interval(i, record: true) if i.title =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
|
54
54
|
interval ||= false
|
data/lib/doing/string.rb
CHANGED
@@ -685,6 +685,15 @@ module Doing
|
|
685
685
|
end
|
686
686
|
end
|
687
687
|
|
688
|
+
def to_bool
|
689
|
+
case self
|
690
|
+
when /^[yt1]/i
|
691
|
+
true
|
692
|
+
else
|
693
|
+
false
|
694
|
+
end
|
695
|
+
end
|
696
|
+
|
688
697
|
##
|
689
698
|
## Convert a string value to an appropriate type. If
|
690
699
|
## kind is not specified, '[one, two]' becomes an Array,
|
@@ -704,6 +713,8 @@ module Doing
|
|
704
713
|
gsub(/^\[ *| *\]$/, '').split(/ *, */)
|
705
714
|
when /^i/i
|
706
715
|
to_i
|
716
|
+
when /^(fa|tr)/i
|
717
|
+
to_bool
|
707
718
|
when /^f/i
|
708
719
|
to_f
|
709
720
|
when /^sy/i
|
@@ -26,12 +26,12 @@ module Doing
|
|
26
26
|
##
|
27
27
|
def chronify(**options)
|
28
28
|
now = Time.now
|
29
|
-
raise InvalidTimeExpression, "Invalid time expression #{inspect}" if to_s.strip == ''
|
29
|
+
raise Errors::InvalidTimeExpression, "Invalid time expression #{inspect}" if to_s.strip == ''
|
30
30
|
|
31
31
|
secs_ago = if match(/^(\d+)$/)
|
32
32
|
# plain number, assume minutes
|
33
33
|
Regexp.last_match(1).to_i * 60
|
34
|
-
elsif (m = match(/^(?:(?<day>\d+)d)?(?:(?<hour>\d+)h)?(?:(?<min>\d+)m)?$/i))
|
34
|
+
elsif (m = match(/^(?:(?<day>\d+)d)? *(?:(?<hour>\d+)h)? *(?:(?<min>\d+)m)?$/i))
|
35
35
|
# day/hour/minute format e.g. 1d2h30m
|
36
36
|
[[m['day'], 24 * 3600],
|
37
37
|
[m['hour'], 3600],
|
@@ -39,14 +39,23 @@ module Doing
|
|
39
39
|
end
|
40
40
|
|
41
41
|
if secs_ago
|
42
|
-
now - secs_ago
|
42
|
+
res = now - secs_ago
|
43
|
+
Doing.logger.debug('Parser:', %(date/time string "#{self}" interpreted as #{res} (#{secs_ago} seconds ago)))
|
43
44
|
else
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
date_string = dup
|
46
|
+
date_string = 'today' if date_string.match(REGEX_DAY) && now.strftime('%a') =~ /^#{Regexp.last_match(1)}/i
|
47
|
+
date_string = "#{options[:context].to_s} #{date_string}" if date_string =~ REGEX_TIME && options[:context]
|
48
|
+
|
49
|
+
res = Chronic.parse(date_string, {
|
50
|
+
guess: options.fetch(:guess, :begin),
|
51
|
+
context: options.fetch(:future, false) ? :future : :past,
|
52
|
+
ambiguous_time_range: 8
|
53
|
+
})
|
54
|
+
|
55
|
+
Doing.logger.debug('Parser:', %(date/time string "#{self}" interpreted as #{res}))
|
49
56
|
end
|
57
|
+
|
58
|
+
res
|
50
59
|
end
|
51
60
|
|
52
61
|
##
|
@@ -152,6 +161,10 @@ module Doing
|
|
152
161
|
end
|
153
162
|
end
|
154
163
|
|
164
|
+
def is_range?
|
165
|
+
self =~ / (to|through|thru|(un)?til|-+) /
|
166
|
+
end
|
167
|
+
|
155
168
|
##
|
156
169
|
## Splits a range string and returns an array of
|
157
170
|
## DateTime objects as [start, end]. If only one date is
|
@@ -163,20 +176,45 @@ module Doing
|
|
163
176
|
## "mon 3pm to mon 5pm".split_date_range
|
164
177
|
##
|
165
178
|
def split_date_range
|
179
|
+
time_rx = /^(\d{1,2}+(:\d{1,2}+)?( *(am|pm))?|midnight|noon)$/
|
180
|
+
range_rx = / (to|through|thru|(?:un)?til|-+) /
|
181
|
+
|
166
182
|
date_string = dup
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
183
|
+
|
184
|
+
if date_string.is_range?
|
185
|
+
# Do we want to differentiate between "to" and "through"?
|
186
|
+
# inclusive = date_string =~ / (through|thru|-+) / ? true : false
|
187
|
+
inclusive = true
|
188
|
+
|
189
|
+
dates = date_string.split(range_rx)
|
190
|
+
if dates[0].strip =~ time_rx && dates[-1].strip =~ time_rx
|
191
|
+
start = dates[0].strip
|
192
|
+
finish = dates[-1].strip
|
193
|
+
else
|
194
|
+
start = dates[0].chronify(guess: :begin, future: false)
|
195
|
+
finish = dates[-1].chronify(guess: inclusive ? :end : :begin, future: false)
|
196
|
+
end
|
197
|
+
|
198
|
+
raise Errors::InvalidTimeExpression, 'Unrecognized date string' if start.nil? || finish.nil?
|
199
|
+
|
172
200
|
else
|
173
|
-
|
174
|
-
|
201
|
+
if date_string.strip =~ time_rx
|
202
|
+
start = date_string.strip
|
203
|
+
finish = nil
|
204
|
+
else
|
205
|
+
start = date_string.strip.chronify(guess: :begin, future: false)
|
206
|
+
finish = date_string.strip.chronify(guess: :end)
|
207
|
+
end
|
208
|
+
raise Errors::InvalidTimeExpression, 'Unrecognized date string' unless start
|
209
|
+
|
175
210
|
end
|
176
211
|
|
177
|
-
raise InvalidTimeExpression, 'Unrecognized date string' unless start
|
178
212
|
|
179
|
-
|
213
|
+
if start.is_a? String
|
214
|
+
Doing.logger.debug('Parser:', "--from string interpreted as time span, from #{start || '12am'} to #{finish || '11:59pm'}")
|
215
|
+
else
|
216
|
+
Doing.logger.debug('Parser:', "date range interpreted as #{start.strftime('%F %R')} -- #{finish ? finish.strftime('%F %R') : 'now'}")
|
217
|
+
end
|
180
218
|
[start, finish]
|
181
219
|
end
|
182
220
|
end
|
data/lib/doing/types.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
REGEX_BOOL = /^(?:and|all|any|or|not|none|p(?:at(?:tern)?)?)$/i
|
4
|
+
REGEX_SORT_ORDER = /^(?:a(?:sc)?|d(?:esc)?)$/i
|
5
|
+
REGEX_VALUE_QUERY = /^(?:!)?@?(?:\S+) +(?:!?[<>=][=*]?|[$*^]=) +(?:.*?)$/
|
6
|
+
REGEX_CLOCK = '(?:\d{1,2}+(?::\d{1,2}+)?(?: *(?:am|pm))?|midnight|noon)'
|
7
|
+
REGEX_TIME = /^#{REGEX_CLOCK}$/i
|
8
|
+
REGEX_DAY = /^(mon|tue|wed|thur?|fri|sat|sun)(\w+(day)?)?$/i
|
9
|
+
REGEX_RANGE_INDICATOR = ' +(?:to|through|thru|(?:un)?til|-+) +'
|
10
|
+
REGEX_RANGE = /^\S+#{REGEX_RANGE_INDICATOR}+\S+/i
|
11
|
+
REGEX_TIME_RANGE = /^#{REGEX_CLOCK}#{REGEX_RANGE_INDICATOR}#{REGEX_CLOCK}$/i
|
12
|
+
|
13
|
+
InvalidExportType = Class.new(RuntimeError)
|
14
|
+
MissingConfigFile = Class.new(RuntimeError)
|
15
|
+
TagArray = Class.new(Array)
|
16
|
+
DateBeginString = Class.new(DateTime)
|
17
|
+
DateEndString = Class.new(DateTime)
|
18
|
+
DateRangeString = Class.new(Array)
|
19
|
+
DateIntervalString = Class.new(DateTime)
|
data/lib/doing/version.rb
CHANGED
data/lib/doing/wwid.rb
CHANGED
@@ -305,6 +305,28 @@ module Doing
|
|
305
305
|
view
|
306
306
|
end
|
307
307
|
|
308
|
+
def add_with_editor(**options)
|
309
|
+
raise MissingEditor, 'No EDITOR variable defined in environment' if Util.default_editor.nil?
|
310
|
+
|
311
|
+
input = options[:date].strftime('%F %R | ')
|
312
|
+
input += options[:title]
|
313
|
+
input += "\n#{options[:note]}" if options[:note]
|
314
|
+
input = fork_editor(input).strip
|
315
|
+
|
316
|
+
d, title, note = format_input(input)
|
317
|
+
raise EmptyInput, 'No content' if title.empty?
|
318
|
+
|
319
|
+
if options[:ask]
|
320
|
+
ask_note = Doing::Prompt.read_lines(prompt: 'Add a note')
|
321
|
+
note.add(ask_note) unless ask_note.empty?
|
322
|
+
end
|
323
|
+
|
324
|
+
date = d.nil? ? options[:date] : d
|
325
|
+
finish = options[:finish_last] || false
|
326
|
+
add_item(title.cap_first, options[:section], { note: note, back: date, timed: finish })
|
327
|
+
write(@doing_file)
|
328
|
+
end
|
329
|
+
|
308
330
|
##
|
309
331
|
## Adds an entry
|
310
332
|
##
|
@@ -356,7 +378,7 @@ module Doing
|
|
356
378
|
|
357
379
|
@content.push(entry)
|
358
380
|
# logger.count(:added, level: :debug)
|
359
|
-
logger.info('New entry:', %(added "#{entry.title}" to #{section}))
|
381
|
+
logger.info('New entry:', %(added "#{entry.date.relative_date}: #{entry.title}" to #{section}))
|
360
382
|
|
361
383
|
Hooks.trigger :post_entry_added, self, entry.dup
|
362
384
|
end
|
@@ -454,7 +476,8 @@ module Doing
|
|
454
476
|
opt ||= {}
|
455
477
|
if item.should_finish?
|
456
478
|
if item.should_time?
|
457
|
-
item.
|
479
|
+
finish_date = verify_duration(item.date, Time.now, title: item.title)
|
480
|
+
item.title.tag!('done', value: finish_date.strftime('%F %R'))
|
458
481
|
else
|
459
482
|
item.title.tag!('done')
|
460
483
|
end
|
@@ -484,7 +507,7 @@ module Doing
|
|
484
507
|
end
|
485
508
|
|
486
509
|
# @content.update_item(original, item)
|
487
|
-
add_item(title, section, { note: note, back: opt[:date], timed:
|
510
|
+
add_item(title, section, { note: note, back: opt[:date], timed: false })
|
488
511
|
end
|
489
512
|
|
490
513
|
##
|
@@ -633,42 +656,25 @@ module Doing
|
|
633
656
|
|
634
657
|
opt[:time_filter] = [nil, nil]
|
635
658
|
if opt[:from] && !opt[:date_filter]
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
if dates[0].strip =~ time_rx && dates[-1].strip =~ time_rx
|
641
|
-
time_start = dates[0].strip
|
642
|
-
time_end = dates[-1].strip
|
643
|
-
else
|
644
|
-
start = dates[0].chronify(guess: :begin)
|
645
|
-
finish = dates[-1].chronify(guess: :end)
|
646
|
-
end
|
647
|
-
when time_rx
|
648
|
-
time_start = date_string
|
649
|
-
time_end = nil
|
650
|
-
else
|
651
|
-
start = date_string.chronify(guess: :begin)
|
652
|
-
finish = false
|
659
|
+
if opt[:from][0].is_a?(String) && opt[:from][0] =~ time_rx
|
660
|
+
time_start, time_end = opt[:from]
|
661
|
+
elsif opt[:from].is_a?(Time)
|
662
|
+
start, finish = opt[:from]
|
653
663
|
end
|
654
664
|
|
655
665
|
if time_start
|
656
666
|
opt[:time_filter] = [time_start, time_end]
|
657
|
-
Doing.logger.debug('Parser:', "--from string interpreted as time span, from #{time_start ? time_start : '12am'} to #{time_end ? time_end : '11:59pm'}")
|
658
667
|
else
|
659
|
-
|
660
|
-
|
661
|
-
opt[:date_filter] = [start, finish]
|
662
|
-
Doing.logger.debug('Parser:', "--from string interpreted as #{start.strftime('%F %R')} -- #{finish ? finish.strftime('%F %R') : 'now'}")
|
668
|
+
opt[:date_filter] = opt[:from]
|
663
669
|
end
|
664
670
|
end
|
665
671
|
|
666
|
-
if opt[:before] =~ time_rx
|
672
|
+
if opt[:before].is_a?(String) && opt[:before] =~ time_rx
|
667
673
|
opt[:time_filter][1] = opt[:before]
|
668
674
|
opt[:before] = nil
|
669
675
|
end
|
670
676
|
|
671
|
-
if opt[:after] =~ time_rx
|
677
|
+
if opt[:after].is_a?(String) && opt[:after] =~ time_rx
|
672
678
|
opt[:time_filter][0] = opt[:after]
|
673
679
|
opt[:after] = nil
|
674
680
|
end
|
@@ -734,7 +740,7 @@ module Doing
|
|
734
740
|
start_time = start_string.chronify(guess: :begin)
|
735
741
|
|
736
742
|
end_string = if opt[:time_filter][1].nil?
|
737
|
-
"#{item.date.next_day.strftime('%Y-%m-%d')} 12am"
|
743
|
+
"#{item.date.to_datetime.next_day.strftime('%Y-%m-%d')} 12am"
|
738
744
|
else
|
739
745
|
"#{item.date.strftime('%Y-%m-%d')} #{opt[:time_filter][1]}"
|
740
746
|
end
|
@@ -753,22 +759,26 @@ module Doing
|
|
753
759
|
end
|
754
760
|
|
755
761
|
if keep && opt[:before]
|
756
|
-
|
757
|
-
if
|
758
|
-
cutoff = "#{item.date.strftime('%Y-%m-%d')} #{
|
762
|
+
before = opt[:before]
|
763
|
+
if before =~ time_rx
|
764
|
+
cutoff = "#{item.date.strftime('%Y-%m-%d')} #{before}".chronify(guess: :begin)
|
765
|
+
elsif before.is_a?(String)
|
766
|
+
cutoff = before.chronify(guess: :begin)
|
759
767
|
else
|
760
|
-
cutoff =
|
768
|
+
cutoff = before
|
761
769
|
end
|
762
770
|
keep = cutoff && item.date <= cutoff
|
763
771
|
keep = opt[:not] ? !keep : keep
|
764
772
|
end
|
765
773
|
|
766
774
|
if keep && opt[:after]
|
767
|
-
|
768
|
-
if
|
769
|
-
cutoff = "#{item.date.strftime('%Y-%m-%d')} #{
|
775
|
+
after = opt[:after]
|
776
|
+
if after =~ time_rx
|
777
|
+
cutoff = "#{item.date.strftime('%Y-%m-%d')} #{after}".chronify(guess: :end)
|
778
|
+
elsif after.is_a?(String)
|
779
|
+
cutoff = after.chronify(guess: :end)
|
770
780
|
else
|
771
|
-
cutoff =
|
781
|
+
cutoff = after
|
772
782
|
end
|
773
783
|
keep = cutoff && item.date >= cutoff
|
774
784
|
keep = opt[:not] ? !keep : keep
|
@@ -934,6 +944,7 @@ module Doing
|
|
934
944
|
actions = [
|
935
945
|
'add tag',
|
936
946
|
'remove tag',
|
947
|
+
'autotag',
|
937
948
|
'cancel',
|
938
949
|
'delete',
|
939
950
|
'finish',
|
@@ -960,6 +971,8 @@ module Doing
|
|
960
971
|
opt[:resume] = true
|
961
972
|
when /reset/
|
962
973
|
opt[:reset] = true
|
974
|
+
when /autotag/
|
975
|
+
opt[:autotag] = true
|
963
976
|
when /(add|remove) tag/
|
964
977
|
type = action =~ /^add/ ? 'add' : 'remove'
|
965
978
|
raise InvalidArgument, "'add tag' and 'remove tag' can not be used together" if opt[:tag]
|
@@ -1071,6 +1084,21 @@ module Doing
|
|
1071
1084
|
end
|
1072
1085
|
end
|
1073
1086
|
|
1087
|
+
if opt[:autotag]
|
1088
|
+
items.map! do |i|
|
1089
|
+
new_title = autotag(i.title)
|
1090
|
+
if new_title == i.title
|
1091
|
+
logger.count(:skipped, level: :debug, message: '%count unchaged %items')
|
1092
|
+
# logger.debug('Autotag:', 'No changes')
|
1093
|
+
else
|
1094
|
+
logger.count(:added_tags)
|
1095
|
+
logger.write(items.count == 1 ? :info : :debug, 'Tagged:', new_title)
|
1096
|
+
i.title = new_title
|
1097
|
+
Hooks.trigger :post_entry_updated, self, i
|
1098
|
+
end
|
1099
|
+
end
|
1100
|
+
end
|
1101
|
+
|
1074
1102
|
if opt[:tag]
|
1075
1103
|
tag = opt[:tag]
|
1076
1104
|
items.map! do |i|
|
@@ -1098,10 +1126,7 @@ module Doing
|
|
1098
1126
|
|
1099
1127
|
return unless opt[:output]
|
1100
1128
|
|
1101
|
-
items.
|
1102
|
-
i.title = "#{i.title} @project(#{i.section})"
|
1103
|
-
i
|
1104
|
-
end
|
1129
|
+
items.each { |i| i.title = "#{i.title} @section(#{i.section})" }
|
1105
1130
|
|
1106
1131
|
export_items = Items.new
|
1107
1132
|
export_items.concat(items)
|
@@ -1138,6 +1163,8 @@ module Doing
|
|
1138
1163
|
def verify_duration(date, finish_date, title: nil)
|
1139
1164
|
max_elapsed = @config.dig('interaction', 'confirm_longer_than') || 0
|
1140
1165
|
max_elapsed = max_elapsed.chronify_qty if max_elapsed.is_a?(String)
|
1166
|
+
date = date.chronify(guess: :end, context: :today) if finish_date.is_a?(String)
|
1167
|
+
|
1141
1168
|
elapsed = finish_date - date
|
1142
1169
|
|
1143
1170
|
if max_elapsed.positive? && (elapsed > max_elapsed)
|
@@ -1316,7 +1343,7 @@ module Doing
|
|
1316
1343
|
##
|
1317
1344
|
## @return [Item] the next chronological item in the index
|
1318
1345
|
##
|
1319
|
-
def next_item(item, options)
|
1346
|
+
def next_item(item, options = {})
|
1320
1347
|
options ||= {}
|
1321
1348
|
items = filter_items(Items.new, opt: options)
|
1322
1349
|
|
@@ -1747,7 +1774,7 @@ module Doing
|
|
1747
1774
|
opt[:sort_tags] ||= false
|
1748
1775
|
section = guess_section(section)
|
1749
1776
|
# :date_filter expects an array with start and end date
|
1750
|
-
dates =
|
1777
|
+
dates = dates.split_date_range if dates.instance_of?(String)
|
1751
1778
|
|
1752
1779
|
list_section({
|
1753
1780
|
section: section,
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Example command that calls an existing command (tag) with
|
4
|
+
# preset options
|
5
|
+
desc 'Add an item to the Later section'
|
6
|
+
arg_name 'ENTRY'
|
7
|
+
command :later do |c|
|
8
|
+
c.example 'doing later "Something I\'ll think about tomorrow"', desc: 'Add an entry to the Later section'
|
9
|
+
c.example 'doing later -e', desc: 'Open $EDITOR to create an entry and optional note'
|
10
|
+
|
11
|
+
c.desc "Edit entry with #{Doing::Util.default_editor}"
|
12
|
+
c.switch %i[e editor], negatable: false, default_value: false
|
13
|
+
|
14
|
+
c.desc 'Backdate start time to date string [4pm|20m|2h|yesterday noon]'
|
15
|
+
c.arg_name 'DATE_STRING'
|
16
|
+
c.flag %i[b back started], type: DateBeginString
|
17
|
+
|
18
|
+
c.desc 'Note'
|
19
|
+
c.arg_name 'TEXT'
|
20
|
+
c.flag %i[n note]
|
21
|
+
|
22
|
+
c.desc 'Prompt for note via multi-line input'
|
23
|
+
c.switch %i[ask], negatable: false, default_value: false
|
24
|
+
|
25
|
+
c.action do |global_options, options, args|
|
26
|
+
cmd = commands[:now]
|
27
|
+
options[:section] = 'Later'
|
28
|
+
options[:finish_last] = false
|
29
|
+
action = cmd.send(:get_action, nil)
|
30
|
+
action.call(global_options, options, args)
|
31
|
+
end
|
32
|
+
end
|