doing 2.0.25 → 2.1.0pre
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 +18 -15
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/CHANGELOG.md +28 -0
- data/Gemfile.lock +8 -1
- data/README.md +1 -1
- data/Rakefile +23 -4
- data/bin/doing +205 -127
- data/doc/Array.html +354 -1
- data/doc/Doing/Color.html +104 -92
- data/doc/Doing/Completion.html +216 -0
- data/doc/Doing/Configuration.html +340 -5
- data/doc/Doing/Content.html +229 -0
- data/doc/Doing/Errors/DoingNoTraceError.html +1 -1
- data/doc/Doing/Errors/DoingRuntimeError.html +1 -1
- data/doc/Doing/Errors/DoingStandardError.html +1 -1
- data/doc/Doing/Errors/EmptyInput.html +1 -1
- data/doc/Doing/Errors/NoResults.html +1 -1
- data/doc/Doing/Errors/PluginException.html +1 -1
- data/doc/Doing/Errors/UserCancelled.html +1 -1
- data/doc/Doing/Errors/WrongCommand.html +1 -1
- data/doc/Doing/Errors.html +1 -1
- data/doc/Doing/Hooks.html +1 -1
- data/doc/Doing/Item.html +337 -49
- data/doc/Doing/Items.html +444 -35
- data/doc/Doing/LogAdapter.html +139 -51
- data/doc/Doing/Note.html +253 -22
- data/doc/Doing/Pager.html +74 -36
- data/doc/Doing/Plugins.html +1 -1
- data/doc/Doing/Prompt.html +674 -0
- data/doc/Doing/Section.html +354 -0
- data/doc/Doing/Util.html +57 -1
- data/doc/Doing/WWID.html +477 -670
- data/doc/Doing/WWIDFile.html +398 -0
- data/doc/Doing.html +5 -5
- data/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
- data/doc/GLI/Commands.html +1 -1
- data/doc/GLI.html +1 -1
- data/doc/Hash.html +97 -1
- data/doc/Status.html +37 -3
- data/doc/String.html +599 -23
- data/doc/Symbol.html +3 -3
- data/doc/Time.html +1 -1
- data/doc/_index.html +22 -1
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +8 -2
- data/doc/index.html +8 -2
- data/doc/method_list.html +453 -173
- data/doc/top-level-namespace.html +1 -1
- data/doing.gemspec +3 -0
- data/doing.rdoc +40 -12
- data/example_plugin.rb +3 -3
- data/lib/completion/_doing.zsh +1 -1
- data/lib/completion/doing.bash +8 -8
- data/lib/completion/doing.fish +1 -1
- data/lib/doing/array.rb +36 -0
- data/lib/doing/colors.rb +70 -66
- data/lib/doing/completion.rb +6 -0
- data/lib/doing/configuration.rb +69 -28
- data/lib/doing/hash.rb +37 -0
- data/lib/doing/item.rb +77 -12
- data/lib/doing/items.rb +125 -0
- data/lib/doing/log_adapter.rb +55 -3
- data/lib/doing/note.rb +53 -1
- data/lib/doing/pager.rb +49 -38
- data/lib/doing/plugins/export/markdown_export.rb +4 -4
- data/lib/doing/plugins/export/template_export.rb +2 -2
- data/lib/doing/plugins/import/calendar_import.rb +4 -4
- data/lib/doing/plugins/import/doing_import.rb +5 -7
- data/lib/doing/plugins/import/timing_import.rb +3 -3
- data/lib/doing/prompt.rb +206 -0
- data/lib/doing/section.rb +30 -0
- data/lib/doing/string.rb +103 -27
- data/lib/doing/util.rb +14 -6
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +306 -621
- data/lib/doing.rb +6 -2
- data/lib/examples/plugins/capture_thing_import.rb +162 -0
- metadata +73 -5
- data/lib/doing/wwidfile.rb +0 -117
data/bin/doing
CHANGED
@@ -35,8 +35,10 @@ colors = Doing::Color
|
|
35
35
|
wwid = Doing::WWID.new
|
36
36
|
|
37
37
|
Doing.logger.log_level = :info
|
38
|
+
env_log_level = nil
|
38
39
|
|
39
40
|
if ENV['DOING_LOG_LEVEL'] || ENV['DOING_DEBUG'] || ENV['DOING_QUIET'] || ENV['DOING_VERBOSE'] || ENV['DOING_PLUGIN_DEBUG']
|
41
|
+
env_log_level = true
|
40
42
|
# Quiet always wins
|
41
43
|
if ENV['DOING_QUIET'] && ENV['DOING_QUIET'].truthy?
|
42
44
|
Doing.logger.log_level = :error
|
@@ -82,6 +84,12 @@ switch %i[p pager], default_value: settings['paginate']
|
|
82
84
|
desc 'Answer yes/no menus with default option'
|
83
85
|
switch [:default], default_value: false
|
84
86
|
|
87
|
+
desc 'Answer all yes/no menus with yes'
|
88
|
+
switch [:yes], negatable: false
|
89
|
+
|
90
|
+
desc 'Answer all yes/no menus with no'
|
91
|
+
switch [:no], negatable: false
|
92
|
+
|
85
93
|
desc 'Exclude auto tags and default tags'
|
86
94
|
switch %i[x noauto], default_value: false, negatable: false
|
87
95
|
|
@@ -121,9 +129,9 @@ command %i[now next] do |c|
|
|
121
129
|
c.desc "Edit entry with #{Doing::Util.default_editor}"
|
122
130
|
c.switch %i[e editor], negatable: false, default_value: false
|
123
131
|
|
124
|
-
c.desc 'Backdate start time [4pm|20m|2h|yesterday noon]'
|
132
|
+
c.desc 'Backdate start time [4pm|20m|2h|"yesterday noon"]'
|
125
133
|
c.arg_name 'DATE_STRING'
|
126
|
-
c.flag %i[b back]
|
134
|
+
c.flag %i[b back started]
|
127
135
|
|
128
136
|
c.desc 'Timed entry, marks last entry in section as @done'
|
129
137
|
c.switch %i[f finish_last], negatable: false, default_value: false
|
@@ -151,29 +159,34 @@ command %i[now next] do |c|
|
|
151
159
|
options[:section] = settings['current_section']
|
152
160
|
end
|
153
161
|
|
154
|
-
if options[:
|
162
|
+
if options[:editor] || (args.empty? && $stdin.stat.size.zero?)
|
155
163
|
raise MissingEditor, 'No EDITOR variable defined in environment' if Doing::Util.default_editor.nil?
|
156
164
|
|
157
|
-
input = ''
|
165
|
+
input = date.strftime('%F %R | ')
|
158
166
|
input += args.join(' ') unless args.empty?
|
159
167
|
input = wwid.fork_editor(input).strip
|
160
168
|
|
161
169
|
raise EmptyInput, 'No content' if input.empty?
|
162
170
|
|
163
|
-
title, note = wwid.format_input(input)
|
164
|
-
note.
|
165
|
-
wwid.add_item(title.cap_first, section, { note: note, back: date, timed: options[:
|
171
|
+
date, title, note = wwid.format_input(input)
|
172
|
+
note.add(options[:note]) if options[:note]
|
173
|
+
wwid.add_item(title.cap_first, section, { note: note, back: date, timed: options[:finish_last] })
|
166
174
|
wwid.write(wwid.doing_file)
|
167
175
|
elsif args.length.positive?
|
168
|
-
title, note = wwid.format_input(args.join(' '))
|
169
|
-
|
170
|
-
|
176
|
+
d, title, note = wwid.format_input(args.join(' '))
|
177
|
+
date = d.nil? ? date : d
|
178
|
+
note.add(options[:note]) if options[:note]
|
179
|
+
wwid.add_item(title.cap_first, section, { note: note, back: date, timed: options[:finish_last] })
|
171
180
|
wwid.write(wwid.doing_file)
|
172
181
|
elsif $stdin.stat.size.positive?
|
173
|
-
input = $stdin.read
|
174
|
-
title, note = wwid.format_input(input)
|
175
|
-
|
176
|
-
|
182
|
+
input = $stdin.read.strip
|
183
|
+
d, title, note = wwid.format_input(input)
|
184
|
+
unless d.nil?
|
185
|
+
Doing.logger.debug('Parser:', 'Date detected in input, overriding command line values')
|
186
|
+
date = d
|
187
|
+
end
|
188
|
+
note.add(options[:note]) if options[:note]
|
189
|
+
wwid.add_item(title.cap_first, section, { note: note, back: date, timed: options[:finish_last] })
|
177
190
|
wwid.write(wwid.doing_file)
|
178
191
|
else
|
179
192
|
raise EmptyInput, 'You must provide content when creating a new entry'
|
@@ -238,14 +251,13 @@ command %i[reset begin] do |c|
|
|
238
251
|
items = wwid.filter_items([], opt: options)
|
239
252
|
|
240
253
|
if options[:interactive]
|
241
|
-
last_entry =
|
254
|
+
last_entry = Doing::Prompt.choose_from_items(items, include_section: options[:section].nil?,
|
242
255
|
menu: true,
|
243
256
|
header: '',
|
244
257
|
prompt: 'Select an entry to start/reset > ',
|
245
258
|
multiple: false,
|
246
259
|
sort: false,
|
247
|
-
show_if_single: true
|
248
|
-
}, include_section: options[:section].nil? )
|
260
|
+
show_if_single: true)
|
249
261
|
else
|
250
262
|
last_entry = items.last
|
251
263
|
end
|
@@ -344,7 +356,7 @@ command :note do |c|
|
|
344
356
|
last_note = last_entry.note || Doing::Note.new
|
345
357
|
new_note = Doing::Note.new
|
346
358
|
|
347
|
-
if options[:
|
359
|
+
if options[:editor] || (args.empty? && $stdin.stat.size.zero? && !options[:remove])
|
348
360
|
raise MissingEditor, 'No EDITOR variable defined in environment' if Doing::Util.default_editor.nil?
|
349
361
|
|
350
362
|
input = !args.empty? ? args.join(' ') : ''
|
@@ -357,14 +369,14 @@ command :note do |c|
|
|
357
369
|
|
358
370
|
input = prev_input.add(input)
|
359
371
|
|
360
|
-
input = wwid.fork_editor(
|
361
|
-
|
372
|
+
input = wwid.fork_editor(prev_input.strip_lines.join("\n"), message: nil).strip
|
373
|
+
note = input
|
362
374
|
options[:remove] = true
|
363
375
|
new_note.add(note)
|
364
376
|
elsif !args.empty?
|
365
377
|
new_note.add(args.join(' '))
|
366
378
|
elsif $stdin.stat.size.positive?
|
367
|
-
new_note.add($stdin.read)
|
379
|
+
new_note.add($stdin.read.strip)
|
368
380
|
else
|
369
381
|
raise EmptyInput, 'You must provide content when adding a note' unless options[:remove]
|
370
382
|
end
|
@@ -423,31 +435,35 @@ command :meanwhile do |c|
|
|
423
435
|
end
|
424
436
|
input = ''
|
425
437
|
|
426
|
-
if options[:
|
438
|
+
if options[:editor]
|
427
439
|
raise MissingEditor, 'No EDITOR variable defined in environment' if Doing::Util.default_editor.nil?
|
428
|
-
|
440
|
+
input += date.strftime('%F %R | ')
|
429
441
|
input += args.join(' ') unless args.empty?
|
430
442
|
input = wwid.fork_editor(input).strip
|
431
443
|
elsif !args.empty?
|
432
444
|
input = args.join(' ')
|
433
445
|
elsif $stdin.stat.size.positive?
|
434
|
-
input = $stdin.read
|
446
|
+
input = $stdin.read.strip
|
435
447
|
end
|
436
448
|
|
437
449
|
if input && !input.empty?
|
438
|
-
input, note = wwid.format_input(input)
|
450
|
+
d, input, note = wwid.format_input(input)
|
451
|
+
unless d.nil?
|
452
|
+
Doing.logger.debug('Parser:', 'Date detected in input, overriding command line values')
|
453
|
+
date = d
|
454
|
+
end
|
439
455
|
else
|
440
456
|
input = nil
|
441
457
|
note = []
|
442
458
|
end
|
443
459
|
|
444
|
-
if options[:
|
445
|
-
note.push(options[:
|
460
|
+
if options[:note]
|
461
|
+
note.push(options[:note])
|
446
462
|
elsif note.empty?
|
447
463
|
note = nil
|
448
464
|
end
|
449
465
|
|
450
|
-
wwid.stop_start('meanwhile', { new_item: input, back: date, section: section, archive: options[:
|
466
|
+
wwid.stop_start('meanwhile', { new_item: input, back: date, section: section, archive: options[:archive], note: note })
|
451
467
|
wwid.write(wwid.doing_file)
|
452
468
|
end
|
453
469
|
end
|
@@ -465,11 +481,11 @@ command :template do |c|
|
|
465
481
|
c.switch %i[l list], negatable: false
|
466
482
|
|
467
483
|
c.desc 'List in single column for completion'
|
468
|
-
c.switch %i[c]
|
484
|
+
c.switch %i[c column]
|
469
485
|
|
470
486
|
c.action do |_global_options, options, args|
|
471
|
-
if options[:list] || options[:
|
472
|
-
if options[:
|
487
|
+
if options[:list] || options[:column]
|
488
|
+
if options[:column]
|
473
489
|
$stdout.print Doing::Plugins.plugin_templates.join("\n")
|
474
490
|
else
|
475
491
|
$stdout.puts "Available templates: #{Doing::Plugins.plugin_templates.join(', ')}"
|
@@ -478,7 +494,7 @@ command :template do |c|
|
|
478
494
|
end
|
479
495
|
|
480
496
|
if args.empty?
|
481
|
-
type =
|
497
|
+
type = Doing::Prompt.choose_from(Doing::Plugins.plugin_templates, sorted: false, prompt: 'Select template type > ')
|
482
498
|
else
|
483
499
|
type = args[0]
|
484
500
|
end
|
@@ -613,22 +629,29 @@ command :later do |c|
|
|
613
629
|
if options[:editor] || (args.empty? && $stdin.stat.size.zero?)
|
614
630
|
raise MissingEditor, 'No EDITOR variable defined in environment' if Doing::Util.default_editor.nil?
|
615
631
|
|
616
|
-
input
|
632
|
+
input += date.strftime('%F %R | ')
|
633
|
+
input += args.empty? ? '' : args.join(' ')
|
617
634
|
input = wwid.fork_editor(input).strip
|
618
635
|
raise EmptyInput, 'No content' unless input && !input.empty?
|
619
636
|
|
620
|
-
title, note = wwid.format_input(input)
|
621
|
-
|
637
|
+
d, title, note = wwid.format_input(input)
|
638
|
+
date = d.nil? ? date : d
|
639
|
+
note.add(options[:note]) if options[:note]
|
622
640
|
wwid.add_item(title.cap_first, 'Later', { note: note, back: date })
|
623
641
|
wwid.write(wwid.doing_file)
|
624
642
|
elsif !args.empty?
|
625
|
-
title, note = wwid.format_input(args.join(' '))
|
626
|
-
|
643
|
+
d, title, note = wwid.format_input(args.join(' '))
|
644
|
+
date = d.nil? ? date : d
|
645
|
+
note.add(options[:note]) if options[:note]
|
627
646
|
wwid.add_item(title.cap_first, 'Later', { note: note, back: date })
|
628
647
|
wwid.write(wwid.doing_file)
|
629
648
|
elsif $stdin.stat.size.positive?
|
630
|
-
title, note = wwid.format_input($stdin.read)
|
631
|
-
|
649
|
+
d, title, note = wwid.format_input($stdin.read)
|
650
|
+
unless d.nil?
|
651
|
+
Doing.logger.debug('Parser:', 'Date detected in input, overriding command line values')
|
652
|
+
date = d
|
653
|
+
end
|
654
|
+
note.add(options[:note]) if options[:note]
|
632
655
|
wwid.add_item(title.cap_first, 'Later', { note: note, back: date })
|
633
656
|
wwid.write(wwid.doing_file)
|
634
657
|
else
|
@@ -659,9 +682,9 @@ command %i[done did] do |c|
|
|
659
682
|
c.arg_name 'DATE_STRING'
|
660
683
|
c.flag [:at]
|
661
684
|
|
662
|
-
c.desc 'Backdate start date by interval [4pm|20m|2h|yesterday noon]'
|
685
|
+
c.desc 'Backdate start date by interval or set to time [4pm|20m|2h|"yesterday noon"]'
|
663
686
|
c.arg_name 'DATE_STRING'
|
664
|
-
c.flag %i[b back]
|
687
|
+
c.flag %i[b back started]
|
665
688
|
|
666
689
|
c.desc %(Set completion date to start date plus interval (XX[mhd] or HH:MM).
|
667
690
|
If used without the --back option, the start date will be moved back to allow
|
@@ -710,8 +733,6 @@ command %i[done did] do |c|
|
|
710
733
|
date = options[:took] ? finish_date - took : finish_date
|
711
734
|
elsif options[:took]
|
712
735
|
finish_date = date + took
|
713
|
-
elsif options[:back]
|
714
|
-
finish_date = date
|
715
736
|
else
|
716
737
|
finish_date = Time.now
|
717
738
|
end
|
@@ -743,16 +764,17 @@ command %i[done did] do |c|
|
|
743
764
|
|
744
765
|
old_entry = last_entry.dup
|
745
766
|
last_entry.note.add(note)
|
746
|
-
input = [last_entry.title, last_entry.note.
|
767
|
+
input = ["#{last_entry.date.strftime('%F %R | ')}#{last_entry.title}", last_entry.note.strip_lines.join("\n")].join("\n")
|
747
768
|
else
|
748
769
|
is_new = true
|
749
|
-
input = [args.join(' '), note.
|
770
|
+
input = ["#{date.strftime('%F %R | ')}#{args.join(' ')}", note.strip_lines.join("\n")].join("\n")
|
750
771
|
end
|
751
772
|
|
752
773
|
input = wwid.fork_editor(input).strip
|
753
774
|
raise EmptyInput, 'No content' unless input && !input.empty?
|
754
775
|
|
755
|
-
title, note = wwid.format_input(input)
|
776
|
+
d, title, note = wwid.format_input(input)
|
777
|
+
date = d.nil? ? date : d
|
756
778
|
new_entry = Doing::Item.new(date, title, section, note)
|
757
779
|
if new_entry.should_finish?
|
758
780
|
if new_entry.should_time?
|
@@ -763,23 +785,23 @@ command %i[done did] do |c|
|
|
763
785
|
end
|
764
786
|
|
765
787
|
if (is_new)
|
766
|
-
wwid.content
|
788
|
+
wwid.content.push(new_entry)
|
767
789
|
else
|
768
|
-
wwid.update_item(old_entry, new_entry)
|
790
|
+
wwid.content.update_item(old_entry, new_entry)
|
769
791
|
end
|
770
792
|
|
771
|
-
if options[:
|
793
|
+
if options[:archive]
|
772
794
|
wwid.move_item(new_entry, 'Archive', label: true)
|
773
795
|
end
|
774
796
|
|
775
797
|
wwid.write(wwid.doing_file)
|
776
798
|
elsif args.empty? && $stdin.stat.size.zero?
|
777
|
-
if options[:
|
799
|
+
if options[:remove]
|
778
800
|
wwid.tag_last({ tags: ['done'], count: 1, section: section, remove: true })
|
779
801
|
else
|
780
802
|
note = options[:note] ? Doing::Note.new(options[:note]) : nil
|
781
803
|
opt = {
|
782
|
-
archive: options[:
|
804
|
+
archive: options[:archive],
|
783
805
|
back: finish_date,
|
784
806
|
count: 1,
|
785
807
|
date: options[:date],
|
@@ -793,9 +815,10 @@ command %i[done did] do |c|
|
|
793
815
|
end
|
794
816
|
elsif !args.empty?
|
795
817
|
note = Doing::Note.new(options[:note])
|
796
|
-
title, new_note = wwid.format_input([args.join(' '), note.
|
818
|
+
d, title, new_note = wwid.format_input([args.join(' '), note.strip_lines.join("\n")].join("\n"))
|
819
|
+
date = d.nil? ? date : d
|
797
820
|
title.chomp!
|
798
|
-
section = 'Archive' if options[:
|
821
|
+
section = 'Archive' if options[:archive]
|
799
822
|
new_entry = Doing::Item.new(date, title, section, new_note)
|
800
823
|
if new_entry.should_finish?
|
801
824
|
if new_entry.should_time?
|
@@ -804,13 +827,17 @@ command %i[done did] do |c|
|
|
804
827
|
new_entry.tag('done')
|
805
828
|
end
|
806
829
|
end
|
807
|
-
wwid.content
|
830
|
+
wwid.content.push(new_entry)
|
808
831
|
wwid.write(wwid.doing_file)
|
809
832
|
Doing.logger.info('Entry Added:', new_entry.title)
|
810
833
|
elsif $stdin.stat.size.positive?
|
811
|
-
title, note = wwid.format_input($stdin.read)
|
834
|
+
d, title, note = wwid.format_input($stdin.read.strip)
|
835
|
+
unless d.nil?
|
836
|
+
Doing.logger.debug('Parser:', 'Date detected in input, overriding command line values')
|
837
|
+
date = d
|
838
|
+
end
|
812
839
|
note.add(options[:note]) if options[:note]
|
813
|
-
section = options[:
|
840
|
+
section = options[:archive] ? 'Archive' : section
|
814
841
|
new_entry = Doing::Item.new(date, title, section, note)
|
815
842
|
|
816
843
|
if new_entry.should_finish?
|
@@ -821,7 +848,7 @@ command %i[done did] do |c|
|
|
821
848
|
end
|
822
849
|
end
|
823
850
|
|
824
|
-
wwid.content
|
851
|
+
wwid.content.push(new_entry)
|
825
852
|
wwid.write(wwid.doing_file)
|
826
853
|
Doing.logger.info('Entry Added:', new_entry.title)
|
827
854
|
else
|
@@ -907,7 +934,7 @@ command :cancel do |c|
|
|
907
934
|
end
|
908
935
|
|
909
936
|
opts = {
|
910
|
-
archive: options[:
|
937
|
+
archive: options[:archive],
|
911
938
|
case: options[:case].normalize_case,
|
912
939
|
count: count,
|
913
940
|
date: false,
|
@@ -1279,15 +1306,15 @@ command :tag do |c|
|
|
1279
1306
|
end
|
1280
1307
|
|
1281
1308
|
|
1282
|
-
question = if options[:
|
1309
|
+
question = if options[:aarchive]
|
1283
1310
|
"Are you sure you want to autotag all records#{section_q}"
|
1284
|
-
elsif options[:
|
1311
|
+
elsif options[:remove]
|
1285
1312
|
"Are you sure you want to remove #{tags.join(' and ')} from all records#{section_q}"
|
1286
1313
|
else
|
1287
1314
|
"Are you sure you want to add #{tags.join(' and ')} to all records#{section_q}"
|
1288
1315
|
end
|
1289
1316
|
|
1290
|
-
res =
|
1317
|
+
res = Doing::Prompt.yn(question, default_response: false)
|
1291
1318
|
|
1292
1319
|
raise UserCancelled unless res
|
1293
1320
|
end
|
@@ -1408,7 +1435,7 @@ command [:mark, :flag] do |c|
|
|
1408
1435
|
"Are you sure you want to flag all records#{section_q}"
|
1409
1436
|
end
|
1410
1437
|
|
1411
|
-
res =
|
1438
|
+
res = Doing::Prompt.yn(question, default_response: false)
|
1412
1439
|
|
1413
1440
|
exit_now! 'Cancelled' unless res
|
1414
1441
|
end
|
@@ -1598,7 +1625,6 @@ command :show do |c|
|
|
1598
1625
|
end
|
1599
1626
|
|
1600
1627
|
opt = options.dup
|
1601
|
-
|
1602
1628
|
opt[:sort_tags] = options[:tag_sort] =~ /^n/i
|
1603
1629
|
opt[:count] = options[:count].to_i
|
1604
1630
|
opt[:date_filter] = dates
|
@@ -1729,7 +1755,7 @@ command :recent do |c|
|
|
1729
1755
|
c.switch %i[i interactive], negatable: false, default_value: false
|
1730
1756
|
|
1731
1757
|
c.action do |global_options, options, args|
|
1732
|
-
section = wwid.guess_section(options[:
|
1758
|
+
section = wwid.guess_section(options[:section]) || options[:section].cap_first
|
1733
1759
|
|
1734
1760
|
unless global_options[:version]
|
1735
1761
|
if settings['templates']['recent'].key?('count')
|
@@ -1744,7 +1770,7 @@ command :recent do |c|
|
|
1744
1770
|
count = args.empty? ? config_count : args[0].to_i
|
1745
1771
|
end
|
1746
1772
|
|
1747
|
-
options[:
|
1773
|
+
options[:times] = true if options[:totals]
|
1748
1774
|
options[:sort_tags] = options[:tag_sort] =~ /^n/i
|
1749
1775
|
|
1750
1776
|
template = settings['templates']['recent'].deep_merge(settings['templates']['default'])
|
@@ -1753,7 +1779,7 @@ command :recent do |c|
|
|
1753
1779
|
opts = {
|
1754
1780
|
sort_tags: options[:sort_tags],
|
1755
1781
|
tags_color: tags_color,
|
1756
|
-
times: options[:
|
1782
|
+
times: options[:times],
|
1757
1783
|
totals: options[:totals],
|
1758
1784
|
interactive: options[:interactive]
|
1759
1785
|
}
|
@@ -1802,7 +1828,7 @@ command :today do |c|
|
|
1802
1828
|
c.action do |_global_options, options, _args|
|
1803
1829
|
raise DoingRuntimeError, %(Invalid output type "#{options[:output]}") if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
|
1804
1830
|
|
1805
|
-
options[:
|
1831
|
+
options[:times] = true if options[:totals]
|
1806
1832
|
options[:sort_tags] = options[:tag_sort] =~ /^n/i
|
1807
1833
|
opt = {
|
1808
1834
|
after: options[:after],
|
@@ -1863,14 +1889,14 @@ command :on do |c|
|
|
1863
1889
|
|
1864
1890
|
raise InvalidTimeExpression, 'Unrecognized date string' unless start
|
1865
1891
|
|
1866
|
-
message = "
|
1892
|
+
message = "date interpreted as #{start}"
|
1867
1893
|
message += " to #{finish}" if finish
|
1868
|
-
Doing.logger.debug(message)
|
1894
|
+
Doing.logger.debug('Interpreter:', message)
|
1869
1895
|
|
1870
|
-
options[:
|
1896
|
+
options[:times] = true if options[:totals]
|
1871
1897
|
options[:sort_tags] = options[:tag_sort] =~ /^n/i
|
1872
1898
|
|
1873
|
-
Doing::Pager.page wwid.list_date([start, finish], options[:
|
1899
|
+
Doing::Pager.page wwid.list_date([start, finish], options[:section], options[:times], options[:output],
|
1874
1900
|
{ totals: options[:totals], sort_tags: options[:sort_tags] }).chomp
|
1875
1901
|
end
|
1876
1902
|
end
|
@@ -1918,12 +1944,12 @@ command :since do |c|
|
|
1918
1944
|
|
1919
1945
|
raise InvalidTimeExpression, 'Unrecognized date string' unless start
|
1920
1946
|
|
1921
|
-
Doing.logger.debug("
|
1947
|
+
Doing.logger.debug('Interpreter:', "date interpreted as #{start} through the current time")
|
1922
1948
|
|
1923
|
-
options[:
|
1949
|
+
options[:times] = true if options[:totals]
|
1924
1950
|
options[:sort_tags] = options[:tag_sort] =~ /^n/i
|
1925
1951
|
|
1926
|
-
Doing::Pager.page wwid.list_date([start, finish], options[:
|
1952
|
+
Doing::Pager.page wwid.list_date([start, finish], options[:section], options[:times], options[:output],
|
1927
1953
|
{ totals: options[:totals], sort_tags: options[:sort_tags] }).chomp
|
1928
1954
|
end
|
1929
1955
|
end
|
@@ -2053,9 +2079,9 @@ command :last do |c|
|
|
2053
2079
|
end
|
2054
2080
|
|
2055
2081
|
if options[:editor]
|
2056
|
-
wwid.edit_last(section: options[:
|
2082
|
+
wwid.edit_last(section: options[:section], options: { search: search, fuzzy: options[:fuzzy], case: options[:case], tag: tags, tag_bool: options[:bool], not: options[:not] })
|
2057
2083
|
else
|
2058
|
-
Doing::Pager::page wwid.last(times: true, section: options[:
|
2084
|
+
Doing::Pager::page wwid.last(times: true, section: options[:section],
|
2059
2085
|
options: { search: search, fuzzy: options[:fuzzy], case: options[:case], negate: options[:not], tag: tags, tag_bool: options[:bool] }).strip
|
2060
2086
|
end
|
2061
2087
|
end
|
@@ -2067,8 +2093,8 @@ command :sections do |c|
|
|
2067
2093
|
c.switch %i[c column], negatable: false, default_value: false
|
2068
2094
|
|
2069
2095
|
c.action do |_global_options, options, _args|
|
2070
|
-
joiner = options[:
|
2071
|
-
print wwid.
|
2096
|
+
joiner = options[:column] ? "\n" : "\t"
|
2097
|
+
print wwid.content.section_titles.join(joiner)
|
2072
2098
|
end
|
2073
2099
|
end
|
2074
2100
|
|
@@ -2089,7 +2115,7 @@ command :add_section do |c|
|
|
2089
2115
|
c.action do |_global_options, _options, args|
|
2090
2116
|
raise InvalidArgument, "Section #{args[0]} already exists" if wwid.sections.include?(args[0])
|
2091
2117
|
|
2092
|
-
wwid.add_section(args.join(' ').cap_first)
|
2118
|
+
wwid.content.add_section(args.join(' ').cap_first, log: true)
|
2093
2119
|
wwid.write(wwid.doing_file)
|
2094
2120
|
end
|
2095
2121
|
end
|
@@ -2247,6 +2273,7 @@ command :view do |c|
|
|
2247
2273
|
rescue WrongCommand => exception
|
2248
2274
|
cmd = commands[:show]
|
2249
2275
|
options[:sort] = 'asc'
|
2276
|
+
options[:tag_order] = 'asc'
|
2250
2277
|
action = cmd.send(:get_action, nil)
|
2251
2278
|
return action.call(global_options, options, args)
|
2252
2279
|
end
|
@@ -2289,12 +2316,9 @@ command :view do |c|
|
|
2289
2316
|
# If the -o/--output flag was specified, override any default in the view template
|
2290
2317
|
options[:output] ||= view.key?('output_format') ? view['output_format'] : 'template'
|
2291
2318
|
|
2292
|
-
count =
|
2293
|
-
|
2294
|
-
|
2295
|
-
view.key?('count') ? view['count'] : 10
|
2296
|
-
end
|
2297
|
-
section = if options[:s]
|
2319
|
+
count = options[:count] ? options[:count] : view.key?('count') ? view['count'] : 10
|
2320
|
+
|
2321
|
+
section = if options[:section]
|
2298
2322
|
section
|
2299
2323
|
else
|
2300
2324
|
view.key?('section') ? view['section'] : settings['current_section']
|
@@ -2312,7 +2336,7 @@ command :view do |c|
|
|
2312
2336
|
view.key?('tag_order') ? view['tag_order'].normalize_order : 'asc'
|
2313
2337
|
end
|
2314
2338
|
|
2315
|
-
options[:
|
2339
|
+
options[:times] = true if totals
|
2316
2340
|
output_format = options[:output]&.downcase || 'template'
|
2317
2341
|
|
2318
2342
|
options[:sort_tags] = if options[:tag_sort]
|
@@ -2386,7 +2410,7 @@ command :views do |c|
|
|
2386
2410
|
c.switch %i[c column], default_value: false
|
2387
2411
|
|
2388
2412
|
c.action do |_global_options, options, _args|
|
2389
|
-
joiner = options[:
|
2413
|
+
joiner = options[:column] ? "\n" : "\t"
|
2390
2414
|
print wwid.views.join(joiner)
|
2391
2415
|
end
|
2392
2416
|
end
|
@@ -2552,6 +2576,10 @@ end
|
|
2552
2576
|
desc 'Open the "doing" file in an editor'
|
2553
2577
|
long_desc "`doing open` defaults to using the editor_app setting in #{config.config_file} (#{settings.key?('editor_app') ? settings['editor_app'] : 'not set'})."
|
2554
2578
|
command :open do |c|
|
2579
|
+
c.desc 'Open with editor command (e.g. vim, mate)'
|
2580
|
+
c.arg_name 'COMMAND'
|
2581
|
+
c.flag %i[e editor]
|
2582
|
+
|
2555
2583
|
if `uname` =~ /Darwin/
|
2556
2584
|
c.desc 'Open with app name'
|
2557
2585
|
c.arg_name 'APP_NAME'
|
@@ -2567,11 +2595,17 @@ command :open do |c|
|
|
2567
2595
|
params.delete_if do |k, v|
|
2568
2596
|
k.instance_of?(String) || v.nil? || v == false
|
2569
2597
|
end
|
2570
|
-
|
2598
|
+
|
2599
|
+
if options[:editor]
|
2600
|
+
raise MissingEditor, "Editor #{options[:editor]} not found" unless Doing::Util.exec_available(options[:editor])
|
2601
|
+
|
2602
|
+
editor = TTY::Which.which(options[:editor])
|
2603
|
+
system %(#{editor} "#{File.expand_path(wwid.doing_file)}")
|
2604
|
+
elsif `uname` =~ /Darwin/
|
2571
2605
|
if options[:app]
|
2572
|
-
system %(open -a "#{options[:
|
2606
|
+
system %(open -a "#{options[:app]}" "#{File.expand_path(wwid.doing_file)}")
|
2573
2607
|
elsif options[:bundle_id]
|
2574
|
-
system %(open -b "#{options[:
|
2608
|
+
system %(open -b "#{options[:bundle_id]}" "#{File.expand_path(wwid.doing_file)}")
|
2575
2609
|
elsif Doing::Util.find_default_editor('doing_file')
|
2576
2610
|
editor = Doing::Util.find_default_editor('doing_file')
|
2577
2611
|
if Doing::Util.exec_available(editor)
|
@@ -2615,6 +2649,16 @@ command :config do |c|
|
|
2615
2649
|
c.desc 'DEPRECATED'
|
2616
2650
|
c.switch %i[u update]
|
2617
2651
|
|
2652
|
+
c.desc 'List configuration paths, including .doingrc files in the current and parent directories'
|
2653
|
+
c.long_desc 'Config files are listed in order of precedence (if there are multiple configs detected).
|
2654
|
+
Values defined in the top item in the list will override values in configutations below it.'
|
2655
|
+
c.command :list do |list|
|
2656
|
+
list.action do |global, options, args|
|
2657
|
+
puts config.additional_configs.join("\n")
|
2658
|
+
puts config.config_file
|
2659
|
+
end
|
2660
|
+
end
|
2661
|
+
|
2618
2662
|
c.desc 'Open config file in editor'
|
2619
2663
|
c.command :edit do |edit|
|
2620
2664
|
edit.example 'doing config edit', desc: 'Open a config file in the default editor'
|
@@ -2627,14 +2671,14 @@ command :config do |c|
|
|
2627
2671
|
if `uname` =~ /Darwin/
|
2628
2672
|
edit.desc 'Application to use'
|
2629
2673
|
edit.arg_name 'APP_NAME'
|
2630
|
-
edit.flag [
|
2674
|
+
edit.flag %i[a app]
|
2631
2675
|
|
2632
2676
|
edit.desc 'Application bundle id to use'
|
2633
2677
|
edit.arg_name 'BUNDLE_ID'
|
2634
|
-
edit.flag [
|
2678
|
+
edit.flag %i[b bundle_id]
|
2635
2679
|
|
2636
2680
|
edit.desc "Use the config_editor_app defined in ~/.config/doing/config.yml (#{settings.key?('config_editor_app') ? settings['config_editor_app'] : 'config_editor_app not set'})"
|
2637
|
-
edit.switch [
|
2681
|
+
edit.switch %i[x default]
|
2638
2682
|
end
|
2639
2683
|
|
2640
2684
|
edit.action do |global, options, args|
|
@@ -2656,7 +2700,7 @@ command :config do |c|
|
|
2656
2700
|
config_file = config.choose_config
|
2657
2701
|
|
2658
2702
|
if `uname` =~ /Darwin/
|
2659
|
-
if options[:
|
2703
|
+
if options[:default]
|
2660
2704
|
editor = Doing::Util.find_default_editor('config')
|
2661
2705
|
if editor
|
2662
2706
|
if Doing::Util.exec_available(editor)
|
@@ -2667,14 +2711,14 @@ command :config do |c|
|
|
2667
2711
|
else
|
2668
2712
|
raise InvalidArgument, 'No viable editor found in config or environment.'
|
2669
2713
|
end
|
2670
|
-
elsif options[:
|
2671
|
-
if options[:
|
2672
|
-
`open -a "#{options[:
|
2673
|
-
elsif options[:
|
2674
|
-
`open -b #{options[:
|
2714
|
+
elsif options[:app] || options[:bundle_id]
|
2715
|
+
if options[:app]
|
2716
|
+
`open -a "#{options[:app]}" "#{config_file}"`
|
2717
|
+
elsif options[:bundle_id]
|
2718
|
+
`open -b #{options[:bundle_id]} "#{config_file}"`
|
2675
2719
|
end
|
2676
2720
|
else
|
2677
|
-
editor = options[:
|
2721
|
+
editor = options[:editor] || Doing::Util.find_default_editor('config')
|
2678
2722
|
|
2679
2723
|
raise MissingEditor, 'No viable editor defined in config or environment' unless editor
|
2680
2724
|
|
@@ -2685,7 +2729,7 @@ command :config do |c|
|
|
2685
2729
|
end
|
2686
2730
|
end
|
2687
2731
|
else
|
2688
|
-
editor = options[:
|
2732
|
+
editor = options[:editor] || Doing::Util.default_editor
|
2689
2733
|
raise MissingEditor, 'No EDITOR variable defined in environment' unless editor && Doing::Util.exec_available(editor)
|
2690
2734
|
|
2691
2735
|
system %(#{editor} "#{config_file}")
|
@@ -2725,16 +2769,33 @@ command :config do |c|
|
|
2725
2769
|
|
2726
2770
|
keypath = args.join('.')
|
2727
2771
|
cfg = config.value_for_key(keypath)
|
2772
|
+
real_path = config.resolve_key_path(keypath)
|
2728
2773
|
|
2729
2774
|
if cfg
|
2730
|
-
|
2731
|
-
|
2732
|
-
|
2733
|
-
|
2734
|
-
|
2735
|
-
|
2736
|
-
|
2737
|
-
|
2775
|
+
val = cfg.map {|k, v| v }[0]
|
2776
|
+
if real_path.count.positive?
|
2777
|
+
nested_cfg = {}
|
2778
|
+
nested_cfg.deep_set(real_path, val)
|
2779
|
+
else
|
2780
|
+
nested_cfg = val
|
2781
|
+
end
|
2782
|
+
|
2783
|
+
if options[:output] =~ /^r/
|
2784
|
+
if val.is_a?(Hash)
|
2785
|
+
$stdout.puts YAML.dump(val)
|
2786
|
+
elsif val.is_a?(Array)
|
2787
|
+
$stdout.puts val.join(', ')
|
2788
|
+
else
|
2789
|
+
$stdout.puts val.to_s
|
2790
|
+
end
|
2791
|
+
else
|
2792
|
+
$stdout.puts case options[:output]
|
2793
|
+
when /^j/
|
2794
|
+
JSON.pretty_generate(val)
|
2795
|
+
else
|
2796
|
+
YAML.dump(nested_cfg)
|
2797
|
+
end
|
2798
|
+
end
|
2738
2799
|
else
|
2739
2800
|
Doing.logger.log_now(:error, 'Config:', "Key #{keypath} not found")
|
2740
2801
|
end
|
@@ -2749,46 +2810,55 @@ command :config do |c|
|
|
2749
2810
|
set.example 'doing config set timer_format human', desc: 'Set the value of timer_format to "human"'
|
2750
2811
|
set.example 'doing config set plug.plugpath ~/my_plugins', desc: 'Key path is fuzzy matched: set the value of plugins->plugin_path'
|
2751
2812
|
|
2813
|
+
set.desc 'Delete specified key'
|
2814
|
+
set.switch %i[r remove], default_value: false, negatable: false
|
2815
|
+
|
2752
2816
|
set.action do |_global, options, args|
|
2753
|
-
if args.count < 2
|
2817
|
+
if args.count < 2 && !options[:remove]
|
2754
2818
|
raise InvalidArgument, 'config set requires at least two arguments, key path and value'
|
2755
2819
|
|
2756
2820
|
end
|
2757
2821
|
|
2758
|
-
value = args.pop
|
2822
|
+
value = options[:remove] ? nil : args.pop
|
2759
2823
|
keypath = args.join('.')
|
2760
2824
|
old_value = config.value_for_key(keypath).map { |k, v| v.to_s }
|
2761
2825
|
real_path = config.resolve_key_path(keypath)
|
2762
2826
|
raise InvalidArgument, 'Invalid key path' if real_path.empty?
|
2763
2827
|
|
2764
|
-
key = real_path.last
|
2765
|
-
real_path[0...-1].inject(config.settings, :fetch)[key] = value
|
2766
|
-
|
2767
2828
|
config_file = config.choose_config
|
2829
|
+
cfg = YAML.safe_load_file(config_file) || {}
|
2768
2830
|
|
2769
|
-
|
2770
|
-
|
2771
|
-
|
2772
|
-
|
2773
|
-
|
2831
|
+
$stderr.puts "Updating #{config_file}".yellow
|
2832
|
+
|
2833
|
+
if options[:remove]
|
2834
|
+
cfg.deep_set(real_path, nil)
|
2835
|
+
$stderr.puts "#{'Deleting key:'.yellow} #{real_path.join('->').boldwhite}"
|
2836
|
+
else
|
2837
|
+
old_value = cfg.dig(*real_path) || 'empty'
|
2838
|
+
cfg.deep_set(real_path, value.set_type)
|
2839
|
+
$stderr.puts "#{'Key path:'.yellow} #{real_path.join('->').boldwhite}"
|
2840
|
+
$stderr.puts "#{'Previous:'.yellow} #{old_value.to_s.boldwhite}"
|
2841
|
+
$stderr.puts "#{' New:'.yellow} #{value.set_type.to_s.boldwhite}"
|
2842
|
+
end
|
2843
|
+
|
2844
|
+
res = Doing::Prompt.yn('Update selected config', default_response: true)
|
2774
2845
|
|
2775
2846
|
raise UserCancelled, 'Cancelled' unless res
|
2776
2847
|
|
2777
|
-
Doing.
|
2778
|
-
Doing::Util.write_to_file(config_file, YAML.dump(config.settings), backup: true)
|
2848
|
+
Doing::Util.write_to_file(config_file, YAML.dump(cfg), backup: true)
|
2779
2849
|
Doing.logger.warn('Config:', "#{config_file} updated")
|
2780
2850
|
end
|
2781
2851
|
end
|
2782
2852
|
end
|
2783
2853
|
|
2784
|
-
desc 'Undo the last change to the
|
2854
|
+
desc 'Undo the last change to the Doing file'
|
2785
2855
|
command :undo do |c|
|
2786
2856
|
c.desc 'Specify alternate doing file'
|
2787
2857
|
c.arg_name 'PATH'
|
2788
2858
|
c.flag %i[f file], default_value: wwid.doing_file
|
2789
2859
|
|
2790
2860
|
c.action do |_global_options, options, _args|
|
2791
|
-
file = options[:
|
2861
|
+
file = options[:file] || wwid.doing_file
|
2792
2862
|
wwid.restore_backup(file)
|
2793
2863
|
end
|
2794
2864
|
end
|
@@ -2895,9 +2965,9 @@ pre do |global, _command, _options, _args|
|
|
2895
2965
|
|
2896
2966
|
$stdout.puts "doing v#{Doing::VERSION}" if global[:version]
|
2897
2967
|
unless STDOUT.isatty
|
2898
|
-
Doing::Color
|
2968
|
+
Doing::Color.coloring = global[:pager] ? global[:color] : false
|
2899
2969
|
else
|
2900
|
-
Doing::Color
|
2970
|
+
Doing::Color.coloring = global[:color]
|
2901
2971
|
end
|
2902
2972
|
|
2903
2973
|
# Return true to proceed; false to abort and not call the
|
@@ -2925,13 +2995,21 @@ end
|
|
2925
2995
|
|
2926
2996
|
around do |global, command, options, arguments, code|
|
2927
2997
|
# Doing.logger.debug('Pager:', "Global: #{global[:pager]}, Config: #{settings['paginate']}, Pager: #{Doing::Pager.paginate}")
|
2928
|
-
|
2998
|
+
if env_log_level.nil?
|
2999
|
+
Doing.logger.adjust_verbosity(global)
|
3000
|
+
end
|
2929
3001
|
|
2930
3002
|
if global[:stdout]
|
2931
3003
|
Doing.logger.logdev = $stdout
|
2932
3004
|
end
|
2933
3005
|
|
2934
|
-
|
3006
|
+
if global[:yes]
|
3007
|
+
Doing::Prompt.force_answer = true
|
3008
|
+
elsif global[:no]
|
3009
|
+
Doing::Prompt.force_answer = false
|
3010
|
+
else
|
3011
|
+
Doing::Prompt.default_answer = global[:default]
|
3012
|
+
end
|
2935
3013
|
|
2936
3014
|
if global[:config_file] && global[:config_file] != config.config_file
|
2937
3015
|
Doing.logger.warn(format('%sWARNING:%s %sThe use of --config_file is deprecated, please set the environment variable DOING_CONFIG instead.', colors.flamingo, colors.default, colors.boldred))
|