doing 1.0.67 → 1.0.72
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +26 -3
- data/bin/doing +72 -7
- data/lib/doing/helpers.rb +1 -0
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +208 -9
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8ab378bf9ba26ec5c6f852afa702d74bd8323bb9e4aca92e3e94b081c578b637
|
4
|
+
data.tar.gz: 1c868eb6ac0dbb438f69679abfcb2fc587465ce9848c4da607f537b8c98d60ca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 257898f624de2463259c5b49e46bc1687edf56f428aa16d297d212554efabbff82f59f0ae98da9772fc1aa30673623d70a2903326dca6ffd510d6afec846ff43
|
7
|
+
data.tar.gz: f635bc6bbb42de40a4f5bdcd1abd1d4caeec1a94af7553f1bcff1d0fffcda6898c248941a38f7abfba807721a18d39fd1632d0ec228c56b940c502f036ac7f19
|
data/README.md
CHANGED
@@ -25,11 +25,9 @@ While I'm working, I have hourly reminders to record what I'm working on, and I
|
|
25
25
|
|
26
26
|
If there's something I want to look at later but doesn't need to be added to a task list or tracker, I can type `doing later check out the pinboard bookmarks from macdrifter`. When I get back to my computer --- or just need a refresher after a distraction --- I can type `doing last` to see what the last thing on my plate was. I can also type `doing recent` (or just `doing`) to get a list of the last few entries. `doing today` gives me everything since midnight for the current day, making it easy to see what I've accomplished over a sleepless night.
|
27
27
|
|
28
|
-
_Side note:_ I actually use the library behind this utility as part of another script that mirrors entries in [Day One](http://dayoneapp.com) that have the tag `wwid`. I can use the hourly writing reminders and enter my stuff in the quick entry popup. Someday I'll get around to cleaning that up and putting it out there.
|
29
|
-
|
30
28
|
## Installation
|
31
29
|
|
32
|
-
The current version of `doing` is <!--VER-->1.0.
|
30
|
+
The current version of `doing` is <!--VER-->1.0.70<!--END VER-->.
|
33
31
|
|
34
32
|
$ [sudo] gem install doing
|
35
33
|
|
@@ -464,6 +462,7 @@ You can also include a `--no-date` switch to add `@done` without a finish date,
|
|
464
462
|
|
465
463
|
By default `doing finish` works on a single entry, the last entry or the most recent entry matching a `--tag` or `--search` query. Specifying `doing finish 10` would finish any unfinished entries within the last 10 entries. In the case of `--tag` or `--search` queries, the count serves as the maximum number of matches doing will act on, sorted in reverse date order (most recent first). A count of 0 will disable the limit entirely, acting on all matching entries.
|
466
464
|
|
465
|
+
Both `finish` and `cancel` accept `--unfinished` as an argument. This causes them to act on the last entry not already marked @done, no matter how far back it's dated or how many @done entries come after it. You can use `doing finish --unfinished X -s SECTION` to finish the last X unfinished entries in SECTION.
|
467
466
|
|
468
467
|
##### Tagging and Autotagging
|
469
468
|
|
@@ -618,6 +617,30 @@ Now you can run `doing import --type timing -s SECTION PATH`, where SECTION is t
|
|
618
617
|
# Import to default section (Currently) and prefix entries with '[Imported]'
|
619
618
|
doing import --prefix="[Imported]" "~/Desktop/All Activities.json"
|
620
619
|
|
620
|
+
#### Interactive Usage
|
621
|
+
|
622
|
+
If you have `fzf` installed (<https://github.com/junegunn/fzf>), you can use `doing select` to get a menu of all your items (or items in a given section) which can be searched with fuzzy matching. The menu allows multiple selections to be acted on directly.
|
623
|
+
|
624
|
+
To use the menu, type a search string or use the arrow keys to navigate up and down. Press tab on an entry you'd like to perform an action on. A marker will show up on the left indicating the entry is selected. Repeat the process and select as many entries as needed. When you hit Return, the selection will be passed back to doing.
|
625
|
+
|
626
|
+
Doing can perform several functions with this menu. Not all of doing's features are available, but the core functionality you'd need is there, plus you can open all selected entries in your editor, make changes to them, and when you save and close the entries are updated accordingly. This allows editing of everything from timestamps to tags to notes.
|
627
|
+
|
628
|
+
Run `doing help select` for a list of options:
|
629
|
+
|
630
|
+
-a, --archive - Archive selected items
|
631
|
+
-c, --cancel - Cancel selected items (add @done without timestamp)
|
632
|
+
-d, --delete - Delete selected items
|
633
|
+
-e, --editor - Edit selected item(s)
|
634
|
+
-f, --finish - Add @done with current time to selected item(s)
|
635
|
+
--flag - Add flag to selected item(s)
|
636
|
+
-m, --move=SECTION - Move selected items to section (default: none)
|
637
|
+
-s, --section=SECTION - Select from a specific section (default: none)
|
638
|
+
-t, --tag=TAG - Tag selected entries (default: none)
|
639
|
+
|
640
|
+
For example, `doing select -d -a` would present the menu, and then mark selected entries as @done (with timestamp) and move them to the Archive section.
|
641
|
+
|
642
|
+
Multiple actions can be performed at once by combining options. You can also combine the `--editor` switch with any other options. Other actions will be performed first, then the entries --- with any modifications performed --- will be presented in the editor for tweaking.
|
643
|
+
|
621
644
|
---
|
622
645
|
|
623
646
|
## Extras
|
data/bin/doing
CHANGED
@@ -245,7 +245,7 @@ command :template do |c|
|
|
245
245
|
c.action do |_global_options, options, args|
|
246
246
|
raise 'No type specified, use `doing template [HAML|CSS]`' if args.empty?
|
247
247
|
|
248
|
-
case
|
248
|
+
case args[0]
|
249
249
|
when /html|haml/i
|
250
250
|
$stdout.puts wwid.haml_template
|
251
251
|
when /css/i
|
@@ -256,6 +256,51 @@ command :template do |c|
|
|
256
256
|
end
|
257
257
|
end
|
258
258
|
|
259
|
+
desc 'Display an interactive menu to perform operations (requires fzf)'
|
260
|
+
long_desc 'Requires that `fzf` be installed and available in your path. <https://github.com/junegunn/fzf>
|
261
|
+
|
262
|
+
List all entries and select with typeahead fuzzy matching. Multiple selections are allowed, hit tab to add the highlighted entry to the selection. Return processes the selected entries.'
|
263
|
+
command :select do |c|
|
264
|
+
c.desc 'Select from a specific section'
|
265
|
+
c.arg_name 'SECTION'
|
266
|
+
c.flag %i[s section]
|
267
|
+
|
268
|
+
c.desc 'Tag selected entries'
|
269
|
+
c.arg_name 'TAG'
|
270
|
+
c.flag %i[t tag]
|
271
|
+
|
272
|
+
# c.desc 'Add @done to selected item(s), using start time of next item as the finish time'
|
273
|
+
# c.switch %i[a auto], negatable: false, default_value: false
|
274
|
+
|
275
|
+
c.desc 'Archive selected items'
|
276
|
+
c.switch %i[a archive], negatable: false, default_value: false
|
277
|
+
|
278
|
+
c.desc 'Move selected items to section'
|
279
|
+
c.arg_name 'SECTION'
|
280
|
+
c.flag %i[m move]
|
281
|
+
|
282
|
+
c.desc 'Cancel selected items (add @done without timestamp)'
|
283
|
+
c.switch %i[c cancel], negatable: false, default_value: false
|
284
|
+
|
285
|
+
c.desc 'Delete selected items'
|
286
|
+
c.switch %i[d delete], negatable: false, default_value: false
|
287
|
+
|
288
|
+
c.desc 'Edit selected item(s)'
|
289
|
+
c.switch %i[e editor], negatable: false, default_value: false
|
290
|
+
|
291
|
+
c.desc 'Add @done with current time to selected item(s)'
|
292
|
+
c.switch %i[f finish], negatable: false, default_value: false
|
293
|
+
|
294
|
+
c.desc 'Add flag to selected item(s)'
|
295
|
+
c.switch %i[flag], negatable: false, default_value: false
|
296
|
+
|
297
|
+
c.action do |_global_options, options, args|
|
298
|
+
section = options[:section] || 'All'
|
299
|
+
edit = options[:editor]
|
300
|
+
wwid.interactive(options)
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
259
304
|
desc 'Add an item to the Later section'
|
260
305
|
arg_name 'ENTRY'
|
261
306
|
command :later do |c|
|
@@ -368,7 +413,7 @@ command %i[done did] do |c|
|
|
368
413
|
|
369
414
|
date = options[:took] ? finish_date - took : finish_date
|
370
415
|
elsif options[:took]
|
371
|
-
finish_date =
|
416
|
+
finish_date = date + took
|
372
417
|
elsif options[:back]
|
373
418
|
finish_date = date
|
374
419
|
else
|
@@ -446,6 +491,9 @@ command :cancel do |c|
|
|
446
491
|
c.arg_name 'BOOLEAN'
|
447
492
|
c.flag [:bool], must_match: /(?:and|all|any|or|not|none)/i, default_value: 'AND'
|
448
493
|
|
494
|
+
c.desc 'Cancel last entry (or entries) not already marked @done'
|
495
|
+
c.switch %i[u unfinished], negatable: false, default_value: false
|
496
|
+
|
449
497
|
c.action do |_global_options, options, args|
|
450
498
|
section = wwid.guess_section(options[:s]) || options[:s].cap_first
|
451
499
|
|
@@ -478,7 +526,8 @@ command :cancel do |c|
|
|
478
526
|
sequential: false,
|
479
527
|
tag: tags,
|
480
528
|
tag_bool: options[:bool],
|
481
|
-
tags: ['done']
|
529
|
+
tags: ['done'],
|
530
|
+
unfinished: options[:unfinished]
|
482
531
|
}
|
483
532
|
wwid.tag_last(opts)
|
484
533
|
end
|
@@ -512,6 +561,9 @@ command :finish do |c|
|
|
512
561
|
c.arg_name 'BOOLEAN'
|
513
562
|
c.flag [:bool], must_match: /(?:and|all|any|or|not|none)/i, default_value: 'AND'
|
514
563
|
|
564
|
+
c.desc 'Finish last entry (or entries) not already marked @done'
|
565
|
+
c.switch %i[u unfinished], negatable: false, default_value: false
|
566
|
+
|
515
567
|
c.desc %(Auto-generate finish dates from next entry's start time.
|
516
568
|
Automatically generate completion dates 1 minute before next start date.
|
517
569
|
--auto overrides the --date and --back parameters.)
|
@@ -574,7 +626,8 @@ command :finish do |c|
|
|
574
626
|
sequential: options[:auto],
|
575
627
|
tag: tags,
|
576
628
|
tag_bool: options[:bool],
|
577
|
-
tags: ['done']
|
629
|
+
tags: ['done'],
|
630
|
+
unfinished: options[:unfinished]
|
578
631
|
}
|
579
632
|
wwid.tag_last(opts)
|
580
633
|
end
|
@@ -648,6 +701,9 @@ command :tag do |c|
|
|
648
701
|
c.desc 'Remove given tag(s)'
|
649
702
|
c.switch %i[r remove], negatable: false, default_value: false
|
650
703
|
|
704
|
+
c.desc 'Tag last entry (or entries) not marked @done'
|
705
|
+
c.switch %i[u unfinished], negatable: false, default_value: false
|
706
|
+
|
651
707
|
c.desc 'Autotag entries based on autotag configuration in ~/.doingrc'
|
652
708
|
c.switch %i[a autotag], negatable: false, default_value: false
|
653
709
|
|
@@ -691,7 +747,8 @@ command :tag do |c|
|
|
691
747
|
date: options[:date],
|
692
748
|
remove: options[:r],
|
693
749
|
section: section,
|
694
|
-
tags: tags
|
750
|
+
tags: tags,
|
751
|
+
unfinished: options[:unfinished]
|
695
752
|
}
|
696
753
|
wwid.tag_last(opts)
|
697
754
|
end
|
@@ -706,9 +763,17 @@ command [:mark, :flag] do |c|
|
|
706
763
|
c.desc 'Remove mark'
|
707
764
|
c.switch %i[r remove], negatable: false, default_value: false
|
708
765
|
|
766
|
+
c.desc 'Mark last entry not marked @done'
|
767
|
+
c.switch %i[u unfinished], negatable: false, default_value: false
|
768
|
+
|
709
769
|
c.action do |_global_options, options, _args|
|
710
770
|
mark = wwid.config['marker_tag'] || 'flagged'
|
711
|
-
wwid.tag_last({
|
771
|
+
wwid.tag_last({
|
772
|
+
remove: options[:r],
|
773
|
+
section: options[:s],
|
774
|
+
tags: [mark],
|
775
|
+
unfinished: options[:unfinished]
|
776
|
+
})
|
712
777
|
end
|
713
778
|
end
|
714
779
|
|
@@ -737,7 +802,7 @@ command :show do |c|
|
|
737
802
|
|
738
803
|
c.desc 'Sort order (asc/desc)'
|
739
804
|
c.arg_name 'ORDER'
|
740
|
-
c.flag %i[s sort], must_match: /^
|
805
|
+
c.flag %i[s sort], must_match: /^[ad].*/i, default_value: 'ASC'
|
741
806
|
|
742
807
|
c.desc %(
|
743
808
|
Date range to show, or a single day to filter date on.
|
data/lib/doing/helpers.rb
CHANGED
data/lib/doing/version.rb
CHANGED
data/lib/doing/wwid.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'deep_merge'
|
4
4
|
require 'open3'
|
5
5
|
require 'pp'
|
6
|
+
require 'shellwords'
|
6
7
|
|
7
8
|
##
|
8
9
|
## @brief Main "What Was I Doing" methods
|
@@ -318,8 +319,8 @@ class WWID
|
|
318
319
|
|
319
320
|
note = input_lines.length > 1 ? input_lines[1..-1] : []
|
320
321
|
# If title line ends in a parenthetical, use that as the note
|
321
|
-
if note.empty? && title =~ /\(.*?\)$/
|
322
|
-
title.sub!(/\((.*?)\)$/) do
|
322
|
+
if note.empty? && title =~ /\s+\(.*?\)$/
|
323
|
+
title.sub!(/\s+\((.*?)\)$/) do
|
323
324
|
m = Regexp.last_match
|
324
325
|
note.push(m[1])
|
325
326
|
''
|
@@ -765,6 +766,129 @@ class WWID
|
|
765
766
|
all_items.max_by { |item| item['date'] }
|
766
767
|
end
|
767
768
|
|
769
|
+
|
770
|
+
##
|
771
|
+
## @brief Display an interactive menu of entries
|
772
|
+
##
|
773
|
+
## @param opt (Hash) Additional options
|
774
|
+
##
|
775
|
+
def interactive(opt = {})
|
776
|
+
raise "Select command requires that fzf be installed" unless exec_available('fzf')
|
777
|
+
|
778
|
+
section = opt[:section] ? guess_section(opt[:section]) : 'All'
|
779
|
+
|
780
|
+
|
781
|
+
if section =~ /^all$/i
|
782
|
+
combined = { 'items' => [] }
|
783
|
+
@content.each do |_k, v|
|
784
|
+
combined['items'] += v['items']
|
785
|
+
end
|
786
|
+
items = combined['items'].dup.sort_by { |item| item['date'] }.reverse
|
787
|
+
else
|
788
|
+
items = @content[section]['items']
|
789
|
+
end
|
790
|
+
|
791
|
+
|
792
|
+
options = items.map.with_index do |item, i|
|
793
|
+
out = [
|
794
|
+
i,
|
795
|
+
') ',
|
796
|
+
item['date'],
|
797
|
+
' | ',
|
798
|
+
item['title'],
|
799
|
+
]
|
800
|
+
if opt[:section] =~ /^all/i
|
801
|
+
out.concat([
|
802
|
+
' (',
|
803
|
+
item['section'],
|
804
|
+
') '
|
805
|
+
])
|
806
|
+
end
|
807
|
+
out.join('')
|
808
|
+
end
|
809
|
+
|
810
|
+
res = `echo #{Shellwords.escape(options.join("\n"))}|fzf -m`
|
811
|
+
selected = []
|
812
|
+
res.split(/\n/).each do |item|
|
813
|
+
idx = item.match(/^(\d+)\)/)[1].to_i
|
814
|
+
selected.push(items[idx])
|
815
|
+
end
|
816
|
+
|
817
|
+
if selected.empty?
|
818
|
+
@results.push("No selection")
|
819
|
+
return
|
820
|
+
end
|
821
|
+
|
822
|
+
if opt[:delete]
|
823
|
+
res = yn("Delete #{selected.size} items?", default_response: 'y')
|
824
|
+
if res
|
825
|
+
selected.each {|item| delete_item(item) }
|
826
|
+
write(@doing_file)
|
827
|
+
end
|
828
|
+
return
|
829
|
+
end
|
830
|
+
|
831
|
+
if opt[:flag]
|
832
|
+
tag = @config['marker_tag'] || 'flagged'
|
833
|
+
selected.map! {|item| tag_item(item, tag, date: false) }
|
834
|
+
end
|
835
|
+
|
836
|
+
if opt[:finish] || opt[:cancel]
|
837
|
+
tag = 'done'
|
838
|
+
selected.map! {|item| tag_item(item, tag, date: !opt[:cancel])}
|
839
|
+
end
|
840
|
+
|
841
|
+
if opt[:tag]
|
842
|
+
tag = opt[:tag]
|
843
|
+
selected.map! {|item| tag_item(item, tag, date: false)}
|
844
|
+
end
|
845
|
+
|
846
|
+
if opt[:archive] || opt[:move]
|
847
|
+
section = opt[:archive] ? 'Archive' : guess_section(opt[:move])
|
848
|
+
selected.map! {|item| move_item(item, section) }
|
849
|
+
end
|
850
|
+
|
851
|
+
write(@doing_file)
|
852
|
+
|
853
|
+
if opt[:editor]
|
854
|
+
|
855
|
+
editable_items = []
|
856
|
+
|
857
|
+
selected.each do |item|
|
858
|
+
editable = "#{item['date']} | #{item['title']}"
|
859
|
+
old_note = item['note'] ? item['note'].map(&:strip).join("\n") : nil
|
860
|
+
editable += "\n#{old_note}" unless old_note.nil?
|
861
|
+
editable_items << editable
|
862
|
+
end
|
863
|
+
|
864
|
+
new_items = fork_editor(editable_items.join("\n---\n") + "\n\n# You may delete entries, but leave all --- lines in place").split(/\n---\n/)
|
865
|
+
|
866
|
+
new_items.each_with_index do |new_item, i|
|
867
|
+
input_lines = new_item.split(/[\n\r]+/).delete_if {|line| line =~ /^#/ || line =~ /^\s*$/ }
|
868
|
+
title = input_lines[0]&.strip
|
869
|
+
if title.nil? || title =~ /^---$/ || title.strip.empty?
|
870
|
+
delete_item(selected[i])
|
871
|
+
else
|
872
|
+
note = input_lines.length > 1 ? input_lines[1..-1] : []
|
873
|
+
|
874
|
+
note.map!(&:strip)
|
875
|
+
note.delete_if { |line| line =~ /^\s*$/ || line =~ /^#/ }
|
876
|
+
|
877
|
+
date = title.match(/^([\d\-: ]+) \| /)[1]
|
878
|
+
title.sub!(/^([\d\-: ]+) \| /, '')
|
879
|
+
|
880
|
+
item = selected[i].dup
|
881
|
+
item['title'] = title
|
882
|
+
item['note'] = note
|
883
|
+
item['date'] = Time.parse(date)
|
884
|
+
update_item(selected[i], item)
|
885
|
+
end
|
886
|
+
end
|
887
|
+
|
888
|
+
write(@doing_file)
|
889
|
+
end
|
890
|
+
end
|
891
|
+
|
768
892
|
##
|
769
893
|
## @brief Tag the last entry or X entries
|
770
894
|
##
|
@@ -781,6 +905,7 @@ class WWID
|
|
781
905
|
opt[:autotag] ||= false
|
782
906
|
opt[:back] ||= false
|
783
907
|
opt[:took] ||= nil
|
908
|
+
opt[:unfinished] ||= false
|
784
909
|
|
785
910
|
sec_arr = []
|
786
911
|
|
@@ -816,10 +941,11 @@ class WWID
|
|
816
941
|
items.map! do |item|
|
817
942
|
break if idx == count
|
818
943
|
|
944
|
+
finished = opt[:unfinished] && item.has_tags?('done', :and)
|
819
945
|
tag_match = opt[:tag].nil? || opt[:tag].empty? ? true : item.has_tags?(opt[:tag], opt[:tag_bool])
|
820
946
|
search_match = opt[:search].nil? || opt[:search].empty? ? true : item.matches_search?(opt[:search])
|
821
947
|
|
822
|
-
if tag_match && search_match
|
948
|
+
if tag_match && search_match && !finished
|
823
949
|
if opt[:autotag]
|
824
950
|
new_title = autotag(item['title']) if @auto_tag
|
825
951
|
if new_title == item['title']
|
@@ -832,12 +958,6 @@ class WWID
|
|
832
958
|
if opt[:sequential]
|
833
959
|
done_date = next_start - 1
|
834
960
|
next_start = item['date']
|
835
|
-
elsif opt[:back]
|
836
|
-
if opt[:back].is_a? Integer
|
837
|
-
done_date = item['date'] + opt[:back]
|
838
|
-
else
|
839
|
-
done_date = item['date'] + (opt[:back] - item['date'])
|
840
|
-
end
|
841
961
|
elsif opt[:took]
|
842
962
|
if item['date'] + opt[:took] > Time.now
|
843
963
|
item['date'] = Time.now - opt[:took]
|
@@ -845,6 +965,12 @@ class WWID
|
|
845
965
|
else
|
846
966
|
done_date = item['date'] + opt[:took]
|
847
967
|
end
|
968
|
+
elsif opt[:back]
|
969
|
+
if opt[:back].is_a? Integer
|
970
|
+
done_date = item['date'] + opt[:back]
|
971
|
+
else
|
972
|
+
done_date = item['date'] + (opt[:back] - item['date'])
|
973
|
+
end
|
848
974
|
else
|
849
975
|
done_date = Time.now
|
850
976
|
end
|
@@ -902,6 +1028,71 @@ class WWID
|
|
902
1028
|
write(@doing_file)
|
903
1029
|
end
|
904
1030
|
|
1031
|
+
def move_item(item, section)
|
1032
|
+
old_section = item['section']
|
1033
|
+
new_item = item.dup
|
1034
|
+
new_item['section'] = section
|
1035
|
+
|
1036
|
+
section_items = @content[old_section]['items']
|
1037
|
+
section_items.delete(item)
|
1038
|
+
@content[old_section]['items'] = section_items
|
1039
|
+
|
1040
|
+
archive_items = @content[section]['items']
|
1041
|
+
archive_items.push(new_item)
|
1042
|
+
# archive_items = archive_items.sort_by { |item| item['date'] }
|
1043
|
+
@content[section]['items'] = archive_items
|
1044
|
+
|
1045
|
+
@results.push("Entry moved to #{section}: #{new_item['title']}")
|
1046
|
+
return new_item
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
##
|
1050
|
+
## @brief Delete an item from the index
|
1051
|
+
##
|
1052
|
+
## @param old_item
|
1053
|
+
##
|
1054
|
+
def delete_item(old_item)
|
1055
|
+
section = old_item['section']
|
1056
|
+
|
1057
|
+
section_items = @content[section]['items']
|
1058
|
+
deleted = section_items.delete(old_item)
|
1059
|
+
@results.push("Entry deleted: #{deleted['title']}")
|
1060
|
+
@content[section]['items'] = section_items
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
##
|
1064
|
+
## @brief Tag an item from the index
|
1065
|
+
##
|
1066
|
+
## @param old_item (Item) The item to tag
|
1067
|
+
## @param tag (string) The tag to apply
|
1068
|
+
## @param date (Boolean) Include timestamp?
|
1069
|
+
##
|
1070
|
+
def tag_item(old_item, tag, date: false)
|
1071
|
+
title = old_item['title'].dup
|
1072
|
+
done_date = Time.now
|
1073
|
+
if title !~ /@#{tag}/
|
1074
|
+
title.chomp!
|
1075
|
+
if date
|
1076
|
+
title += " @#{tag}(#{done_date.strftime('%F %R')})"
|
1077
|
+
else
|
1078
|
+
title += " @#{tag}"
|
1079
|
+
end
|
1080
|
+
new_item = old_item.dup
|
1081
|
+
new_item['title'] = title
|
1082
|
+
update_item(old_item, new_item)
|
1083
|
+
return new_item
|
1084
|
+
else
|
1085
|
+
@results.push(%(Item already @#{tag}: "#{title}" in #{old_item['section']}))
|
1086
|
+
return old_item
|
1087
|
+
end
|
1088
|
+
end
|
1089
|
+
|
1090
|
+
##
|
1091
|
+
## @brief Update an item in the index with a modified item
|
1092
|
+
##
|
1093
|
+
## @param old_item The old item
|
1094
|
+
## @param new_item The new item
|
1095
|
+
##
|
905
1096
|
def update_item(old_item, new_item)
|
906
1097
|
section = old_item['section']
|
907
1098
|
|
@@ -2003,4 +2194,12 @@ EOS
|
|
2003
2194
|
minutes = (minutes % 60).to_i
|
2004
2195
|
[days, hours, minutes]
|
2005
2196
|
end
|
2197
|
+
|
2198
|
+
def exec_available(cli)
|
2199
|
+
if File.exists?(File.expand_path(cli))
|
2200
|
+
File.executable?(File.expand_path(cli))
|
2201
|
+
else
|
2202
|
+
system "which #{cli}", :out => File::NULL, :err => File::NULL
|
2203
|
+
end
|
2204
|
+
end
|
2006
2205
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: doing
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.72
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brett Terpstra
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|