doing 1.0.49 → 1.0.54

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -3
  3. data/bin/doing +180 -160
  4. data/lib/doing/version.rb +1 -1
  5. data/lib/doing/wwid.rb +87 -37
  6. metadata +8 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 18f254e337c39ad92b9f2e7aa7a30797432c642af248387a448cf1673675ea7a
4
- data.tar.gz: 4cd5f972401da1b668b0ae8402d7d463d35c6d0d7d6e3d5de2ad3d2de907ab25
3
+ metadata.gz: 1f1fda3219bcf3e27c6816ff77efe53b168d4c2ecf5d8c17653fd4dc6f95a1dd
4
+ data.tar.gz: 17a4dc1ea548c201e22335d0055fd383f6ceac611c2f0d71f1ae5900e7cd1087
5
5
  SHA512:
6
- metadata.gz: e598cbe3377bda1a868015ea87f14b147b9d77fe02d5b663157b101e6ce988417344b6bf1731fdcb140ba91627e7cc3ab6520ee098811369128f8aa8756eab65
7
- data.tar.gz: 8b32c6b73ceab01561163c28b4bc401293daf13d1fdf64ffd7966a907221941010d12b495fbfed2874ecf75f40612287d55ef7804fac3fd88029f4db1f0b1a82
6
+ metadata.gz: b2fb4ddc3f092a01134e157e84ea86ce44b5be6714c074b17bed647b8b1341fa43a5514311cfd387e662a744d307a624a57ec242caa3e651d57dc6875e572b08
7
+ data.tar.gz: f7e2eb609ce0eda0e2ca51205609b77cc44bf7c3d6dc12f25eb5bb8f06c50322d8d89d789998509d542dd7a90b3b29e1d3c82f5e021cf501850666ccc45243d0
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **A command line tool for remembering what you were doing and tracking what you've done.**
4
4
 
5
- _If you're one of the rare people like me who find this useful, feel free to [buy me some coffee](http://brettterpstra.com/donate)._
5
+ _If you're one of the rare people like me who find this useful, feel free to [buy me some coffee](http://brettterpstra.com/donate/)._
6
6
 
7
7
 
8
8
  ## Contents
@@ -17,6 +17,7 @@ _If you're one of the rare people like me who find this useful, feel free to [bu
17
17
  - [Changelog](#changelog)
18
18
 
19
19
  <!-- end toc -->
20
+ <!--README-->
20
21
 
21
22
  ## What and why
22
23
 
@@ -413,6 +414,8 @@ When used with `doing done`, `--back` and `--took` allow time intervals to be ac
413
414
 
414
415
  All of these commands accept a `-e` argument. This opens your command line editor (as defined in the environment variable `$EDITOR`). Add your entry, save the temp file, and close it. The new entry is added. Anything after the first line is included as a note on the entry.
415
416
 
417
+ `doing again` (or `doing resume`) will duplicate the last @done entry (most recently completed) with a new start date (and without the @done tag). To resume the last entry matching specific tags, use `--tag=TAG`. You can specify multiple tags by separating with a comma. Multiple tags are combined with 'AND' by default (all tags must exist on the entry to match), but you can use `--bool=` to set it to 'OR' or 'NOT'. By default the new entry will be added to the same section as the matching entry, but you can specify a section with `--in=SECTION`.
418
+
416
419
  `doing meanwhile` is a special command for creating and finishing tasks that may have other entries come before they're complete. When you create an entry with `doing meanwhile [entry text]`, it will automatically complete the last _@meanwhile_ item (dated _@done_ tag) and add the _@meanwhile_ tag to the new item. This allows time tracking on a more general basis, and still lets you keep track of the smaller things you do while working on an overarching project. The `meanwhile` command accepts `--back [time]` and will backdate the _@done_ tag and start date of the new task at the same time. Running `meanwhile` with no arguments will simply complete the last _@meanwhile_ task.
417
420
 
418
421
  See `doing help meanwhile` for more options.
@@ -420,6 +423,7 @@ See `doing help meanwhile` for more options.
420
423
  #### Modifying entries:
421
424
 
422
425
  finish - Mark last X entries as @done
426
+ cancel - Mark last X entries as @done without completion date
423
427
  tag - Tag last entry
424
428
  note - Add a note to the last entry
425
429
 
@@ -431,6 +435,16 @@ See `doing help meanwhile` for more options.
431
435
 
432
436
  As mentioned above, `finish` also accepts `--back "2 hours"` (sets the finish date from time now minus interval) or `--took 30m` (sets the finish date to time started plus interval) so you can accurately add times to completed tasks, even if you don't do it in the moment.
433
437
 
438
+ Both `done` and `finish` accept an `--archive` switch which immediately moves the completed entries to the Archive section with a `@from(Project)` tag.
439
+
440
+ You can finish the last entry containing a specific tag or combination of tags using the `--tag` flag. Multiple tags are separated by commas. By default tags are combined with an AND boolean, meaning the entry must contain all specified tags to be considered. For example, to finish the last entry containing both "@work" and "@project1", you would use:
441
+
442
+ doing finish --tag=work,project1
443
+
444
+ You can change the boolean using `--bool=OR` (last entry containing any of the specified tags) or `--bool=NOT` (last entry containing none of the tags).
445
+
446
+ You can also include a `--no-date` switch to add `@done` without a finish date, meaning no time is tracked for the task. `doing cancel` is an alias for this. Like `finish`, `cancel` accepts a count to act on the last X entries, as well as `--archive` and `--section` options. `cancel` also accepts the `--tag` and `--bool` flags for tag filtering.
447
+
434
448
 
435
449
  ##### Tagging and Autotagging
436
450
 
@@ -565,11 +579,16 @@ __Fish:__ See the file [`doing.fish`](https://github.com/ttscoff/doing/blob/mast
565
579
 
566
580
  The LaunchBar action requires that `doing` be available in `/usr/local/bin/doing`. If it's not (because you're using RVM or similar), you'll need to symlink it there. Running the action with Return will show the latest 9 items from Currently, along with any time intervals recorded, and includes a submenu of Timers for each tag.
567
581
 
568
- Pressing Spacebar and typing allows you to add a new entry to currently. You an also trigger a custom show command by typing "show [section/tag]" and hitting return.
582
+ Pressing Spacebar and typing allows you to add a new entry to currently. You an also trigger a custom show command by typing "show [section/tag]" and hitting return. Include any command line flags at the end of the string, and if you add text in parenthesis, it will be processed as a note on the entry.
569
583
 
570
584
  Point of interest, the LaunchBar Action makes use of the `-o json` flag for outputting JSON to the action's script for parsing.
571
585
 
586
+ <!--GITHUB-->
572
587
  See <https://brettterpstra.com/projects/doing/> for the download.
588
+ <!--JEKYLL
589
+ {% download 117 %}
590
+ -->
591
+ <!--END GITHUB-->
573
592
 
574
593
  Evan Lovely has [created an Alfred workflow as well](http://www.evanlovely.com/blog/technology/alfred-for-terpstras-doing/).
575
594
 
@@ -610,7 +629,9 @@ Please try not to email me directly about GitHub projects.
610
629
 
611
630
  Feel free to [poke around](http://github.com/ttscoff/doing/), I'll try to add more comments in the future (and retroactively).
612
631
 
613
- {% donate doing now sending coffee money to Brett. %}
632
+ <!--END README-->
633
+
634
+ PayPal link: [paypal.me/ttscoff](https://paypal.me/ttscoff)
614
635
 
615
636
  ## Changelog
616
637
 
data/bin/doing CHANGED
@@ -36,23 +36,20 @@ default_command :recent
36
36
  # sort_help :manually
37
37
 
38
38
  desc 'Output notes if included in the template'
39
- default_value true
40
- switch [:notes], :default_value => true, :negatable => true
39
+ switch [:notes], default_value: true, negatable: true
41
40
 
42
41
  desc 'Send results report to STDOUT instead of STDERR'
43
- default_value false
44
- switch [:stdout], :default_value => false, :negatable => false
42
+ switch [:stdout], default_value: false, negatable: false
45
43
 
46
44
  desc 'Exclude auto tags and default tags'
47
- switch [:x, :noauto], :default_value => false
45
+ switch [:x, :noauto], default_value: false
48
46
 
49
47
  desc 'Use a specific configuration file'
50
- default_value false
51
48
  flag [:config_file]
52
49
 
53
50
 
54
51
  # desc 'Wrap notes at X chars (0 for no wrap)'
55
- # flag [:w, :wrapwidth], :must_match => /^\d+$/, :type => Integer
52
+ # flag [:w, :wrapwidth], must_match: /^\d+$/, type: Integer
56
53
 
57
54
  desc 'Specify a different doing_file'
58
55
  flag [:f, :doing_file]
@@ -62,8 +59,7 @@ arg_name 'entry'
62
59
  command [:now, :next] do |c|
63
60
  c.desc 'Section'
64
61
  c.arg_name 'section_name'
65
- c.default_value wwid.current_section
66
- c.flag [:s, :section], :default_value => wwid.current_section
62
+ c.flag [:s, :section], default_value: wwid.current_section
67
63
 
68
64
  c.desc "Edit entry with #{ENV['EDITOR']}"
69
65
  c.switch [:e, :editor]
@@ -72,8 +68,7 @@ command [:now, :next] do |c|
72
68
  c.flag [:b, :back]
73
69
 
74
70
  c.desc 'Timed entry, marks last entry in section as @done'
75
- c.default_value false
76
- c.switch [:f, :finish_last], :negatable => false, :default_value => false
71
+ c.switch [:f, :finish_last], negatable: false, default_value: false
77
72
 
78
73
  c.desc 'Note'
79
74
  c.arg_name 'note_text'
@@ -81,8 +76,7 @@ command [:now, :next] do |c|
81
76
 
82
77
  # c.desc "Edit entry with specified app"
83
78
  # c.arg_name 'editor_app'
84
- # c.default_value wwid.config.has_key?('editor_app') && wwid.config['editor_app'] ? wwid.config['editor_app'] : false
85
- # c.flag [:a, :app]
79
+ # # c.flag [:a, :app]
86
80
 
87
81
  c.action do |global_options,options,args|
88
82
  if options[:back]
@@ -103,7 +97,7 @@ command [:now, :next] do |c|
103
97
  if input
104
98
  title, note = wwid.format_input(input)
105
99
  note.push(options[:n]) if options[:n]
106
- wwid.add_item(title.cap_first, section, {:note => note, :back => date, :timed => options[:f]})
100
+ wwid.add_item(title.cap_first, section, {note: note, back: date, timed: options[:f]})
107
101
  wwid.write(wwid.doing_file)
108
102
  else
109
103
  raise "No content"
@@ -112,12 +106,12 @@ command [:now, :next] do |c|
112
106
  if args.length > 0
113
107
  title, note = wwid.format_input(args.join(" "))
114
108
  note.push(options[:n]) if options[:n]
115
- wwid.add_item(title.cap_first, section, {:note => note, :back => date, :timed => options[:f]})
109
+ wwid.add_item(title.cap_first, section, {note: note, back: date, timed: options[:f]})
116
110
  wwid.write(wwid.doing_file)
117
111
  elsif STDIN.stat.size > 0
118
112
  title, note = wwid.format_input(STDIN.read)
119
113
  note.push(options[:n]) if options[:n]
120
- wwid.add_item(title.cap_first, section, {:note => note, :back => date, :timed => options[:f]})
114
+ wwid.add_item(title.cap_first, section, {note: note, back: date, timed: options[:f]})
121
115
  wwid.write(wwid.doing_file)
122
116
  else
123
117
  raise "You must provide content when creating a new entry"
@@ -136,14 +130,13 @@ arg_name 'note_text'
136
130
  command :note do |c|
137
131
  c.desc 'Section'
138
132
  c.arg_name 'section_name'
139
- c.default_value wwid.current_section
140
- c.flag [:s, :section], :default_value => "All"
133
+ c.flag [:s, :section], default_value: "All"
141
134
 
142
135
  c.desc "Edit entry with #{ENV['EDITOR']}"
143
- c.switch [:e, :editor], :negatable => false, :default_value => false
136
+ c.switch [:e, :editor], negatable: false, default_value: false
144
137
 
145
138
  c.desc "Replace/Remove last entry's note (default append)"
146
- c.switch [:r, :remove], :negatable => false, :default_value => false
139
+ c.switch [:r, :remove], negatable: false, default_value: false
147
140
 
148
141
  c.action do |global_options,options,args|
149
142
  section = wwid.guess_section(options[:s]) || options[:s].cap_first
@@ -196,14 +189,13 @@ arg_name 'entry'
196
189
  command :meanwhile do |c|
197
190
  c.desc 'Section'
198
191
  c.arg_name 'section_name'
199
- c.default_value wwid.current_section
200
- c.flag [:s, :section], :default_value => wwid.current_section
192
+ c.flag [:s, :section], default_value: wwid.current_section
201
193
 
202
194
  c.desc "Edit entry with #{ENV['EDITOR']}"
203
195
  c.switch [:e, :editor]
204
196
 
205
197
  c.desc "Archive previous @meanwhile entry"
206
- c.switch [:a, :archive], :default_value => false
198
+ c.switch [:a, :archive], default_value: false
207
199
 
208
200
  c.desc 'Backdate start date for new entry to date string [4pm|20m|2h|yesterday noon]'
209
201
  c.flag [:b, :back]
@@ -238,7 +230,7 @@ command :meanwhile do |c|
238
230
  input = false unless input && input.length > 0
239
231
 
240
232
  note = options[:n] ? options[:n] : false
241
- wwid.stop_start("meanwhile",{:new_item => input, :back => date, :section => section, :archive => options[:a], :note => note})
233
+ wwid.stop_start('meanwhile', {new_item: input, back: date, section: section, archive: options[:a], note: note})
242
234
  wwid.write(wwid.doing_file)
243
235
  end
244
236
  end
@@ -276,7 +268,6 @@ command :later do |c|
276
268
 
277
269
  c.desc "Edit entry with specified app"
278
270
  c.arg_name 'editor_app'
279
- c.default_value wwid.config.has_key?('editor_app') && wwid.config['editor_app'] ? wwid.config['editor_app'] : false
280
271
  c.flag [:a, :app]
281
272
 
282
273
  c.desc 'Backdate start time to date string [4pm|20m|2h|yesterday noon]'
@@ -302,7 +293,7 @@ command :later do |c|
302
293
  if input
303
294
  title, note = wwid.format_input(input)
304
295
  note.push(options[:n]) if options[:n]
305
- wwid.add_item(title.cap_first, "Later", {:note => note, :back => date})
296
+ wwid.add_item(title.cap_first, "Later", {note: note, back: date})
306
297
  wwid.write(wwid.doing_file)
307
298
  else
308
299
  raise "No content"
@@ -311,12 +302,12 @@ command :later do |c|
311
302
  if args.length > 0
312
303
  title, note = wwid.format_input(args.join(" "))
313
304
  note.push(options[:n]) if options[:n]
314
- wwid.add_item(title.cap_first, "Later", {:note => note, :back => date})
305
+ wwid.add_item(title.cap_first, "Later", {note: note, back: date})
315
306
  wwid.write(wwid.doing_file)
316
307
  elsif STDIN.stat.size > 0
317
308
  title, note = wwid.format_input(STDIN.read)
318
309
  note.push(options[:n]) if options[:n]
319
- wwid.add_item(title.cap_first, "Later", {:note => note, :back => date})
310
+ wwid.add_item(title.cap_first, "Later", {note: note, back: date})
320
311
  wwid.write(wwid.doing_file)
321
312
  else
322
313
  raise "You must provide content when creating a new entry"
@@ -329,16 +320,13 @@ desc 'Add a completed item with @done(date). No argument finishes last entry.'
329
320
  arg_name 'entry'
330
321
  command [:done, :did] do |c|
331
322
  c.desc 'Remove @done tag'
332
- c.default_value false
333
- c.switch [:r, :remove], :negatable => false, :default_value => false
323
+ c.switch [:r, :remove], negatable: false, default_value: false
334
324
 
335
325
  c.desc 'Include date'
336
- c.default_value true
337
- c.switch [:date], :negatable => true, :default_value => true
326
+ c.switch [:date], negatable: true, default_value: true
338
327
 
339
328
  c.desc 'Immediately archive the entry'
340
- c.default_value false
341
- c.switch [:a, :archive], :negatable => false, :default_value => false
329
+ c.switch [:a, :archive], negatable: false, default_value: false
342
330
 
343
331
  c.desc 'Set finish date to specific date/time (natural langauge parsed, e.g. --at=1:30pm). If used, ignores --back. Used with --took, backdates start date'
344
332
  c.flag [:at]
@@ -350,16 +338,14 @@ command [:done, :did] do |c|
350
338
  c.flag [:t, :took]
351
339
 
352
340
  c.desc 'Section'
353
- c.default_value wwid.current_section
354
- c.flag [:s, :section], :default_value => wwid.current_section
341
+ c.flag [:s, :section], default_value: wwid.current_section
355
342
 
356
343
  c.desc "Edit entry with #{ENV['EDITOR']}"
357
344
  c.switch [:e, :editor]
358
345
 
359
346
  # c.desc "Edit entry with specified app"
360
347
  # c.arg_name 'editor_app'
361
- # c.default_value wwid.config.has_key?('editor_app') && wwid.config['editor_app'] ? wwid.config['editor_app'] : false
362
- # c.flag [:a, :app]
348
+ # # c.flag [:a, :app]
363
349
 
364
350
  c.action do |global_options,options,args|
365
351
  took = 0
@@ -390,7 +376,7 @@ command [:done, :did] do |c|
390
376
  end
391
377
 
392
378
  section = wwid.guess_section(options[:s]) || options[:s].cap_first
393
- donedate = options[:d] ? "(#{finish_date.strftime('%F %R')})" : ""
379
+ donedate = options[:date] ? "(#{finish_date.strftime('%F %R')})" : ""
394
380
 
395
381
  if options[:e]
396
382
  raise "No EDITOR variable defined in environment" if ENV['EDITOR'].nil?
@@ -401,16 +387,16 @@ command [:done, :did] do |c|
401
387
  title, note = wwid.format_input(input)
402
388
  title += " @done#{donedate}"
403
389
  section = "Archive" if options[:a]
404
- wwid.add_item(title.cap_first, section.cap_first, {:note => note, :back => date})
390
+ wwid.add_item(title.cap_first, section.cap_first, {note: note, back: date})
405
391
  wwid.write(wwid.doing_file)
406
392
  else
407
393
  raise "No content"
408
394
  end
409
395
  elsif args.length == 0 && STDIN.stat.size == 0
410
396
  if options[:r]
411
- wwid.tag_last({:tags => ["done"], :count => 1, :section => section, :remove => true })
397
+ wwid.tag_last({tags: ["done"], count: 1, section: section, remove: true })
412
398
  else
413
- wwid.tag_last({:tags => ["done"], :count => 1, :section => section, :archive => options[:a], :back => finish_date, :date => options[:date]})
399
+ wwid.tag_last({tags: ["done"], count: 1, section: section, archive: options[:a], back: finish_date, date: options[:date]})
414
400
  end
415
401
  else
416
402
  if args.length > 0
@@ -418,13 +404,13 @@ command [:done, :did] do |c|
418
404
  title.chomp!
419
405
  title += " @done#{donedate}"
420
406
  section = "Archive" if options[:a]
421
- wwid.add_item(title.cap_first, section.cap_first, {:note => note, :back => date})
407
+ wwid.add_item(title.cap_first, section.cap_first, {note: note, back: date})
422
408
  wwid.write(wwid.doing_file)
423
409
  elsif STDIN.stat.size > 0
424
410
  title, note = wwid.format_input(STDIN.read)
425
411
  title += " @done#{donedate}"
426
412
  section = options[:a] ? "Archive" : section
427
- wwid.add_item(title.cap_first, section.cap_first, {:note => note, :back => date})
413
+ wwid.add_item(title.cap_first, section.cap_first, {note: note, back: date})
428
414
  wwid.write(wwid.doing_file)
429
415
  else
430
416
  raise "You must provide content when creating a new entry"
@@ -433,12 +419,51 @@ command [:done, :did] do |c|
433
419
  end
434
420
  end
435
421
 
422
+ desc 'End last X entries with no time tracked'
423
+ long_desc 'Adds @done tag without datestamp so no elapsed time is recorded. Alias for `doing finish --no-date`.'
424
+ arg_name 'count'
425
+ command :cancel do |c|
426
+ c.desc 'Archive entries'
427
+ c.switch [:a, :archive], negatable: false, default_value: false
428
+
429
+ c.desc 'Section'
430
+ c.flag [:s, :section], default_value: wwid.current_section
431
+
432
+ c.desc 'Cancel the last X entries containing TAG. Separate multiple tags with comma (--tag=tag2,tag2)'
433
+ c.flag [:tag]
434
+
435
+ c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
436
+ c.flag [:bool], must_match: /^(and|or|not)$/i, default_value: 'AND'
437
+
438
+
439
+ c.action do |global_options,options,args|
440
+
441
+ section = wwid.guess_section(options[:s]) || options[:s].cap_first
442
+
443
+ if options[:tag].nil?
444
+ tags = []
445
+ else
446
+ tags = options[:tag].split(/ *, */).map {|t| t.strip.sub(/^@/, '') }
447
+ options[:bool] = options[:bool] =~ /^(and|or|not)$/i ? options[:bool].upcase : 'AND'
448
+ end
449
+
450
+ if args.length > 1
451
+ raise "Only one argument allowed"
452
+ elsif args.length == 0 || args[0] =~ /\d+/
453
+ count = args[0] ? args[0].to_i : 1
454
+ wwid.tag_last({tags: ["done"], count: count, section: section, archive: options[:a], sequential: false, date: false, tag: tags, tag_bool: options[:bool] })
455
+ else
456
+ raise "Invalid argument (specify number of recent items to mark @done)"
457
+ end
458
+ end
459
+ end
460
+
436
461
  desc 'Mark last X entries as @done'
437
462
  long_desc 'Marks the last X entries with a @done tag and current date. Does not alter already completed entries.'
438
463
  arg_name 'count'
439
464
  command :finish do |c|
440
465
  c.desc 'Include date'
441
- c.switch [:date], :negatable => true, :default_value => true
466
+ c.switch [:date], negatable: true, default_value: true
442
467
 
443
468
  c.desc 'Backdate completed date to date string [4pm|20m|2h|yesterday noon]'
444
469
  c.flag [:b, :back]
@@ -446,17 +471,20 @@ command :finish do |c|
446
471
  c.desc 'Set the completed date to the start date plus XX[hmd]'
447
472
  c.flag [:t, :took]
448
473
 
474
+ c.desc 'Finish the last X entries containing TAG. Separate multiple tags with comma (--tag=tag2,tag2)'
475
+ c.flag [:tag]
476
+
477
+ c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
478
+ c.flag [:bool], must_match: /^(and|or|not)$/i, default_value: 'AND'
479
+
449
480
  c.desc 'Auto-generate finish dates from next entry\'s start time. Automatically generate completion dates 1 minute before next start date. --auto overrides the --date and --back parameters.'
450
- c.default_value false
451
- c.switch [:auto], :negatable => false, :default_value => false
481
+ c.switch [:auto], negatable: false, default_value: false
452
482
 
453
483
  c.desc 'Archive entries'
454
- c.default_value false
455
- c.switch [:a, :archive], :negatable => false, :default_value => false
484
+ c.switch [:a, :archive], negatable: false, default_value: false
456
485
 
457
486
  c.desc 'Section'
458
- c.default_value wwid.current_section
459
- c.flag [:s, :section], :default_value => wwid.current_section
487
+ c.flag [:s, :section], default_value: wwid.current_section
460
488
 
461
489
  c.action do |global_options,options,args|
462
490
 
@@ -476,11 +504,18 @@ command :finish do |c|
476
504
  end
477
505
  end
478
506
 
507
+ if options[:tag].nil?
508
+ tags = []
509
+ else
510
+ tags = options[:tag].split(/ *, */).map {|t| t.strip.sub(/^@/, '') }
511
+ options[:bool] = options[:bool] =~ /^(and|or|not)$/i ? options[:bool].upcase : 'AND'
512
+ end
513
+
479
514
  if args.length > 1
480
515
  raise "Only one argument allowed"
481
516
  elsif args.length == 0 || args[0] =~ /\d+/
482
517
  count = args[0] ? args[0].to_i : 1
483
- wwid.tag_last({:tags => ["done"], :count => count, :section => section, :archive => options[:a], :sequential => options[:auto], :date => options[:date], :back => date })
518
+ wwid.tag_last({ tags: ["done"],count: count,section: section,archive: options[:a],sequential: options[:auto],date: options[:date], back: date, tag: options[:tag], tag_bool: options[:bool] })
484
519
  else
485
520
  raise "Invalid argument (specify number of recent items to mark @done)"
486
521
  end
@@ -491,14 +526,24 @@ desc 'Repeat last entry as new entry'
491
526
  arg_name 'section'
492
527
  command [:again, :resume] do |c|
493
528
  c.desc 'Section'
494
- c.flag [:s, :section], :default_value => "All"
529
+ c.flag [:s, :section], default_value: "All"
530
+
531
+ c.desc 'Add new entry to section (default: same section as repeated entry)'
532
+ c.flag [:in]
533
+
534
+ c.desc 'Repeat last entry matching tags. Combine multiple tags with a comma.'
535
+ c.flag [:tag]
536
+
537
+ c.desc 'Boolean used to combine multiple tags'
538
+ c.flag [:bool], must_match: /^(and|or|not)$/i, default_value: 'ALL'
495
539
 
496
540
  c.desc 'Note'
497
541
  c.arg_name 'note_text'
498
542
  c.flag [:n, :note]
499
543
 
500
544
  c.action do |global_options, options, args|
501
- wwid.restart_last({ section: options[:s], note: options[:n] })
545
+ tags = options[:tag].nil? ? [] : options[:tag].split(/ *, */).map {|t| t.sub(/^@/, '').strip }
546
+ wwid.restart_last({ section: options[:s], note: options[:n], tag: tags, tag_bool: options[:bool], in: options[:in] })
502
547
  end
503
548
  end
504
549
 
@@ -506,23 +551,19 @@ desc 'Tag last entry'
506
551
  arg_name 'tag1 [tag2...]'
507
552
  command :tag do |c|
508
553
  c.desc 'Section'
509
- c.flag [:s, :section], :default_value => "All"
554
+ c.flag [:s, :section], default_value: 'All'
510
555
 
511
556
  c.desc 'How many recent entries to tag (0 for all)'
512
- c.default_value 1
513
- c.flag [:c, :count], :default_value => 1
557
+ c.flag [:c, :count], default_value: 1
514
558
 
515
559
  c.desc 'Include current date/time with tag'
516
- c.default_value false
517
- c.switch [:d, :date], :negatable => false, :default_value => false
560
+ c.switch [:d, :date], negatable: false, default_value: false
518
561
 
519
562
  c.desc 'Remove given tag(s)'
520
- c.default_value false
521
- c.switch [:r, :remove], :negatable => false, :default_value => false
563
+ c.switch [:r, :remove], negatable: false, default_value: false
522
564
 
523
565
  c.desc 'Autotag entries based on autotag configuration in ~/.doingrc'
524
- c.default_value false
525
- c.switch [:a, :autotag], :negatable => false, :default_value => false
566
+ c.switch [:a, :autotag], negatable: false, default_value: false
526
567
 
527
568
  c.action do |global_options,options,args|
528
569
  if args.length == 0 && !options[:a]
@@ -563,7 +604,7 @@ command :tag do |c|
563
604
  end
564
605
  end
565
606
 
566
- wwid.tag_last({:tags => tags, :count => count, :section => section, :date => options[:date], :remove => options[:r], :autotag => options[:a]})
607
+ wwid.tag_last({tags: tags, count: count, section: section, date: options[:date], remove: options[:r], autotag: options[:a]})
567
608
  end
568
609
  end
569
610
  end
@@ -571,17 +612,15 @@ end
571
612
  desc 'Mark last entry as highlighted'
572
613
  command [:mark, :flag] do |c|
573
614
  c.desc 'Section'
574
- c.default_value wwid.current_section
575
- c.flag [:s, :section], :default_value => wwid.current_section
615
+ c.flag [:s, :section], default_value: wwid.current_section
576
616
 
577
617
  c.desc 'Remove mark'
578
- c.default_value false
579
- c.switch [:r, :remove], :negatable => false, :default_value => false
618
+ c.switch [:r, :remove], negatable: false, default_value: false
580
619
 
581
620
 
582
621
  c.action do |global_options,options,args|
583
622
  mark = wwid.config['marker_tag'] || "flagged"
584
- wwid.tag_last({:tags => [mark], :section => options[:s], :remove => options[:r]})
623
+ wwid.tag_last({tags: [mark], section: options[:s], remove: options[:r]})
585
624
  end
586
625
  end
587
626
 
@@ -589,21 +628,20 @@ desc 'List all entries'
589
628
  long_desc 'The argument can be a section name, @tag(s) or both. "pick" or "choose" as an argument will offer a section menu.'
590
629
  arg_name '[section|@tags]'
591
630
  command :show do |c|
631
+ c.desc 'Tag filter, combine multiple tags with a comma. Added for compatibility with other commands.'
632
+ c.flag [:tag]
633
+
592
634
  c.desc 'Tag boolean (AND,OR,NONE)'
593
- c.default_value "OR"
594
- c.flag [:b, :bool], :default_value => "OR"
635
+ c.flag [:b, :bool], must_match: /^(and|or|not)$/i, default_value: 'OR'
595
636
 
596
637
  c.desc 'Max count to show'
597
- c.default_value 0
598
- c.flag [:c, :count], :default_value => 0
638
+ c.flag [:c, :count], default_value: 0
599
639
 
600
640
  c.desc 'Age (oldest/newest)'
601
- c.default_value 'newest'
602
- c.flag [:a, :age], :default_value => 'newest'
641
+ c.flag [:a, :age], default_value: 'newest'
603
642
 
604
643
  c.desc 'Sort order (asc/desc)'
605
- c.default_value 'asc'
606
- c.flag [:s, :sort], :default_value => 'asc'
644
+ c.flag [:s, :sort], default_value: 'asc'
607
645
 
608
646
  c.desc %{
609
647
  Date range to show, or a single day to filter date on.
@@ -613,23 +651,20 @@ command :show do |c|
613
651
  c.flag [:f, :from]
614
652
 
615
653
  c.desc 'Show time intervals on @done tasks'
616
- c.default_value true
617
- c.switch [:t, :times], :default_value => true
654
+ c.switch [:t, :times], default_value: true
618
655
 
619
656
  c.desc 'Show intervals with totals at the end of output'
620
- c.default_value false
621
- c.switch [:totals], :default_value => false, :negatable => true
657
+ c.switch [:totals], default_value: false, negatable: true
622
658
 
623
659
  c.desc 'Sort tags by (name|time)'
624
660
  default = 'time'
625
661
  if wwid.config.has_key?('tag_sort')
626
662
  default = wwid.config['tag_sort']
627
663
  end
628
- c.flag [:tag_sort], :default_value => default
664
+ c.flag [:tag_sort], default_value: default
629
665
 
630
666
  c.desc 'Only show items with recorded time intervals'
631
- c.default_value false
632
- c.switch [:only_timed], :default_value => false, :negatable => false
667
+ c.switch [:only_timed], default_value: false, negatable: false
633
668
 
634
669
  c.desc 'Output to export format (csv|html|json)'
635
670
  c.flag [:o, :output]
@@ -666,6 +701,8 @@ command :show do |c|
666
701
  section = wwid.current_section
667
702
  end
668
703
 
704
+ tags.concat(options[:tag].split(/ *, */).map {|t| t.sub(/^@/, '').strip }) if options[:tag]
705
+
669
706
  unless tags.empty?
670
707
  tag_filter = {
671
708
  'tags' => tags,
@@ -684,14 +721,14 @@ command :show do |c|
684
721
  finish = false
685
722
  end
686
723
  exit_now! "Unrecognized date string" unless start
687
- dates = [start,finish]
724
+ dates = [start, finish]
688
725
  end
689
726
 
690
727
  options[:t] = true if options[:totals]
691
728
 
692
729
  options[:sort_tags] = options[:tag_sort] =~ /^n/i
693
730
 
694
- puts wwid.list_section({:section => section, :date_filter => dates, :count => options[:c].to_i, :tag_filter => tag_filter, :age => options[:a], :order => options[:s], :output => options[:output], :times => options[:t], :totals => options[:totals], :sort_tags => options[:sort_tags], :highlight => true, :only_timed => options[:only_timed]})
731
+ puts wwid.list_section({section: section, date_filter: dates, count: options[:c].to_i, tag_filter: tag_filter, age: options[:a], order: options[:s], output: options[:output], times: options[:t], totals: options[:totals], sort_tags: options[:sort_tags], highlight: true, only_timed: options[:only_timed]})
695
732
 
696
733
  end
697
734
  end
@@ -706,30 +743,26 @@ EODESC
706
743
  arg_name 'search_pattern'
707
744
  command [:grep, :search] do |c|
708
745
  c.desc 'Section'
709
- c.default_value "all"
710
- c.flag [:s, :section], :default_value => "All"
746
+ c.flag [:s, :section], default_value: "All"
711
747
 
712
748
  c.desc 'Output to export format (csv|html|json)'
713
749
  c.flag [:o, :output]
714
750
 
715
751
  c.desc 'Show time intervals on @done tasks'
716
- c.default_value true
717
- c.switch [:t, :times], :default_value => true
752
+ c.switch [:t, :times], default_value: true
718
753
 
719
754
  c.desc 'Show intervals with totals at the end of output'
720
- c.default_value false
721
- c.switch [:totals], :default_value => false, :negatable => true
755
+ c.switch [:totals], default_value: false, negatable: true
722
756
 
723
757
  c.desc 'Sort tags by (name|time)'
724
758
  default = 'time'
725
759
  if wwid.config.has_key?('tag_sort')
726
760
  default = wwid.config['tag_sort']
727
761
  end
728
- c.flag [:tag_sort], :default_value => default
762
+ c.flag [:tag_sort], default_value: default
729
763
 
730
764
  c.desc 'Only show items with recorded time intervals'
731
- c.default_value false
732
- c.switch [:only_timed], :default_value => false, :negatable => false
765
+ c.switch [:only_timed], default_value: false, negatable: false
733
766
 
734
767
  c.action do |global_options,options,args|
735
768
 
@@ -738,7 +771,7 @@ command [:grep, :search] do |c|
738
771
  options[:t] = true if options[:totals]
739
772
  options[:sort_tags] = options[:tag_sort] =~ /^n/i
740
773
 
741
- puts wwid.list_section({:search => args.join(' '), :section => section, :output => options[:output], :times => options[:t], :highlight => true, :totals => options[:totals], :only_timed => options[:only_timed], :sort_tags => options[:sort_tags]})
774
+ puts wwid.list_section({search: args.join(' '), section: section, output: options[:output], times: options[:t], highlight: true, totals: options[:totals], only_timed: options[:only_timed], sort_tags: options[:sort_tags]})
742
775
 
743
776
  end
744
777
  end
@@ -748,23 +781,20 @@ default_value 10
748
781
  arg_name 'count'
749
782
  command :recent do |c|
750
783
  c.desc 'Section'
751
- c.default_value "All"
752
- c.flag [:s, :section], :default_value => "All"
784
+ c.flag [:s, :section], default_value: "All"
753
785
 
754
786
  c.desc 'Show time intervals on @done tasks'
755
- c.default_value true
756
- c.switch [:t, :times], :default_value => true
787
+ c.switch [:t, :times], default_value: true
757
788
 
758
789
  c.desc 'Show intervals with totals at the end of output'
759
- c.default_value false
760
- c.switch [:totals], :default_value => false, :negatable => true
790
+ c.switch [:totals], default_value: false, negatable: true
761
791
 
762
792
  c.desc 'Sort tags by (name|time)'
763
793
  default = 'time'
764
794
  if wwid.config.has_key?('tag_sort')
765
795
  default = wwid.config['tag_sort']
766
796
  end
767
- c.flag [:tag_sort], :default_value => default
797
+ c.flag [:tag_sort], default_value: default
768
798
 
769
799
  c.action do |global_options,options,args|
770
800
 
@@ -779,7 +809,7 @@ command :recent do |c|
779
809
  options[:t] = true if options[:totals]
780
810
  options[:sort_tags] = options[:tag_sort] =~ /^n/i
781
811
 
782
- puts wwid.recent(count,section.cap_first,{ :times => options[:t], :totals => options[:totals], :sort_tags => options[:sort_tags] })
812
+ puts wwid.recent(count,section.cap_first,{ times: options[:t], totals: options[:totals], sort_tags: options[:sort_tags] })
783
813
 
784
814
  end
785
815
  end
@@ -789,23 +819,20 @@ desc 'List entries from today'
789
819
  command :today do |c|
790
820
  c.desc 'Specify a section'
791
821
  c.arg_name 'section_name'
792
- c.default_value "All"
793
- c.flag [:s, :section], :default_value => 'All'
822
+ c.flag [:s, :section], default_value: 'All'
794
823
 
795
824
  c.desc 'Show time intervals on @done tasks'
796
- c.default_value true
797
- c.switch [:t, :times], :default_value => true
825
+ c.switch [:t, :times], default_value: true
798
826
 
799
827
  c.desc 'Show time totals at the end of output'
800
- c.default_value false
801
- c.switch [:totals], :default_value => false, :negatable => true
828
+ c.switch [:totals], default_value: false, negatable: true
802
829
 
803
830
  c.desc 'Sort tags by (name|time)'
804
831
  default = 'time'
805
832
  if wwid.config.has_key?('tag_sort')
806
833
  default = wwid.config['tag_sort']
807
834
  end
808
- c.flag [:tag_sort], :default_value => default
835
+ c.flag [:tag_sort], default_value: default
809
836
 
810
837
  c.desc 'Output to export format (csv|html|json)'
811
838
  c.flag [:o, :output]
@@ -815,7 +842,7 @@ command :today do |c|
815
842
  options[:t] = true if options[:totals]
816
843
  options[:sort_tags] = options[:tag_sort] =~ /^n/i
817
844
 
818
- puts wwid.today(options[:t],options[:output],{:totals => options[:totals], :section => options[:s], :sort_tags => options[:sort_tags]}).chomp
845
+ puts wwid.today(options[:t], options[:output], {totals: options[:totals], section: options[:s], sort_tags: options[:sort_tags]}).chomp
819
846
 
820
847
  end
821
848
  end
@@ -826,28 +853,26 @@ arg_name 'date_string'
826
853
  command :on do |c|
827
854
  c.desc 'Section'
828
855
  c.arg_name 'section_name'
829
- c.default_value 'All'
830
- c.flag [:s, :section], :default_value => 'All'
856
+ c.flag [:s, :section], default_value: 'All'
831
857
 
832
858
  c.desc 'Show time intervals on @done tasks'
833
- c.default_value true
834
- c.switch [:t, :times], :default_value => true
859
+ c.switch [:t, :times], default_value: true
835
860
 
836
861
  c.desc 'Show time totals at the end of output'
837
- c.default_value false
838
- c.switch [:totals], :default_value => false, :negatable => true
862
+ c.switch [:totals], default_value: false, negatable: true
839
863
 
840
864
  c.desc 'Sort tags by (name|time)'
841
865
  default = 'time'
842
866
  if wwid.config.has_key?('tag_sort')
843
867
  default = wwid.config['tag_sort']
844
868
  end
845
- c.flag [:tag_sort], :default_value => default
869
+ c.flag [:tag_sort], default_value: default
846
870
 
847
871
  c.desc 'Output to export format (csv|html|json)'
848
872
  c.flag [:o, :output]
849
873
 
850
874
  c.action do |global_options,options,args|
875
+ exit_now! "Missing date argument" if args.empty?
851
876
 
852
877
  date_string = args.join(" ")
853
878
 
@@ -869,7 +894,7 @@ command :on do |c|
869
894
  options[:t] = true if options[:totals]
870
895
  options[:sort_tags] = options[:tag_sort] =~ /^n/i
871
896
 
872
- puts wwid.list_date([start, finish], options[:s], options[:t], options[:output], {:totals => options[:totals], :sort_tags => options[:sort_tags]}).chomp
897
+ puts wwid.list_date([start, finish], options[:s], options[:t], options[:output], {totals: options[:totals], sort_tags: options[:sort_tags]}).chomp
873
898
 
874
899
  end
875
900
  end
@@ -878,30 +903,27 @@ desc 'List entries from yesterday'
878
903
  command :yesterday do |c|
879
904
  c.desc 'Specify a section'
880
905
  c.arg_name 'section_name'
881
- c.default_value "All"
882
- c.flag [:s, :section], :default_value => 'All'
906
+ c.flag [:s, :section], default_value: 'All'
883
907
 
884
908
  c.desc 'Output to export format (csv|html|json)'
885
909
  c.flag [:o, :output]
886
910
 
887
911
  c.desc 'Show time intervals on @done tasks'
888
- c.default_value true
889
- c.switch [:t, :times], :default_value => true
912
+ c.switch [:t, :times], default_value: true
890
913
 
891
914
  c.desc 'Show time totals at the end of output'
892
- c.default_value false
893
- c.switch [:totals], :default_value => false, :negatable => true
915
+ c.switch [:totals], default_value: false, negatable: true
894
916
 
895
917
  c.desc 'Sort tags by (name|time)'
896
918
  default = 'time'
897
919
  if wwid.config.has_key?('tag_sort')
898
920
  default = wwid.config['tag_sort']
899
921
  end
900
- c.flag [:tag_sort], :default_value => default
922
+ c.flag [:tag_sort], default_value: default
901
923
 
902
924
  c.action do |global_options, options,args|
903
925
  options[:sort_tags] = options[:tag_sort] =~ /^n/i
904
- puts wwid.yesterday(options[:s],options[:t],options[:o],{:totals => options[:totals], :sort_tags => options[:sort_tags]}).chomp
926
+ puts wwid.yesterday(options[:s], options[:t], options[:o],{ totals: options[:totals], sort_tags: options[:sort_tags] }).chomp
905
927
 
906
928
  end
907
929
  end
@@ -909,7 +931,6 @@ end
909
931
  desc 'Show the last entry'
910
932
  command :last do |c|
911
933
  c.desc 'Specify a section'
912
- c.default_value "All"
913
934
  c.flag [:s, :section]
914
935
 
915
936
  c.action do |global_options,options,args|
@@ -920,8 +941,7 @@ end
920
941
  desc 'List sections'
921
942
  command :sections do |c|
922
943
  c.desc 'List in single column'
923
- c.default_value false
924
- c.switch [:c, :column], :default_value => false
944
+ c.switch [:c, :column], default_value: false
925
945
 
926
946
  c.action do |global_options,options,args|
927
947
  joiner = options[:c] ? "\n" : "\t"
@@ -933,7 +953,7 @@ desc 'Select a section to display from a menu'
933
953
  command :choose do |c|
934
954
  c.action do |global_options,options,args|
935
955
  section = wwid.choose_section
936
- puts wwid.list_section({:section => section.cap_first, :count => 0})
956
+ puts wwid.list_section({ section: section.cap_first, count: 0 })
937
957
  end
938
958
  end
939
959
 
@@ -975,29 +995,29 @@ command :view do |c|
975
995
  c.flag [:s, :section]
976
996
 
977
997
  c.desc 'Count to display (override view settings)'
978
- c.flag [:c, :count], :must_match => /^\d+$/, :type => Integer
998
+ c.flag [:c, :count], must_match: /^\d+$/, type: Integer
979
999
 
980
1000
  c.desc 'Output to export format (csv|html|json)'
981
1001
  c.flag [:o, :output]
982
1002
 
983
1003
  c.desc 'Show time intervals on @done tasks'
984
- c.default_value true
985
- c.switch [:t, :times], :default_value => true
1004
+ c.switch [:t, :times], default_value: true
986
1005
 
987
1006
  c.desc 'Show intervals with totals at the end of output'
988
- c.default_value false
989
- c.switch [:totals], :default_value => false, :negatable => true
1007
+ c.switch [:totals], default_value: false, negatable: true
1008
+
1009
+ c.desc 'Include colors in output'
1010
+ c.switch [:color], default_value: true, negatable: true
990
1011
 
991
1012
  c.desc 'Sort tags by (name|time)'
992
1013
  default = 'time'
993
1014
  if wwid.config.has_key?('tag_sort')
994
1015
  default = wwid.config['tag_sort']
995
1016
  end
996
- c.flag [:tag_sort], :default_value => default
1017
+ c.flag [:tag_sort], default_value: default
997
1018
 
998
1019
  c.desc 'Only show items with recorded time intervals'
999
- c.default_value false
1000
- c.switch [:only_timed], :default_value => false, :negatable => true
1020
+ c.switch [:only_timed], default_value: false, negatable: true
1001
1021
 
1002
1022
  c.action do |global_options,options,args|
1003
1023
  if args.empty?
@@ -1024,7 +1044,7 @@ command :view do |c|
1024
1044
  tag_filter = false
1025
1045
  if view.has_key?('tags')
1026
1046
  unless view['tags'].nil? || view['tags'].empty?
1027
- tag_filter = {'tags' => [], 'bool' => "OR"}
1047
+ tag_filter = {'tags' => [], 'bool' => 'OR'}
1028
1048
  if view['tags'].class == Array
1029
1049
  tag_filter['tags'] = view['tags'].map{|tag| tag.strip }
1030
1050
  else
@@ -1045,7 +1065,7 @@ command :view do |c|
1045
1065
  options[:output].downcase! if options[:output]
1046
1066
  options[:sort_tags] = options[:tag_sort] =~ /^n/i
1047
1067
 
1048
- puts wwid.list_section({:section => section, :count => count, :template => template, :format => format, :order => order, :tag_filter => tag_filter, :output => options[:o], :tags_color => tags_color, :times => options[:t], :highlight => true, :totals => options[:totals], :only_timed => only_timed, :sort_tags => options[:sort_tags] })
1068
+ puts wwid.list_section({section: section, count: count, template: template, format: format, order: order, tag_filter: tag_filter, output: options[:o], tags_color: tags_color, times: options[:t], highlight: options[:color], totals: options[:totals], only_timed: only_timed, sort_tags: options[:sort_tags] })
1049
1069
  else
1050
1070
  if title.class == FalseClass
1051
1071
  exit_now! "Cancelled"
@@ -1059,8 +1079,7 @@ end
1059
1079
  desc 'List available custom views'
1060
1080
  command :views do |c|
1061
1081
  c.desc 'List in single column'
1062
- c.default_value false
1063
- c.switch [:c, :column], :default_value => false
1082
+ c.switch [:c, :column], default_value: false
1064
1083
 
1065
1084
  c.action do |global_options,options,args|
1066
1085
  joiner = options[:c] ? "\n" : "\t"
@@ -1068,21 +1087,21 @@ command :views do |c|
1068
1087
  end
1069
1088
  end
1070
1089
 
1071
- desc 'Move entries in between sections'
1090
+ desc 'Move entries between sections'
1072
1091
  arg_name 'section'
1073
1092
  default_value wwid.current_section
1074
1093
  command :archive do |c|
1075
1094
  c.desc 'Count to keep (ignored if archiving by tag)'
1076
- c.default_value 5
1077
- c.flag [:k, :keep], :default_value => 5, :must_match => /^\d+$/, :type => Integer
1095
+ c.flag [:k, :keep], default_value: 5, must_match: /^\d+$/, type: Integer
1078
1096
 
1079
1097
  c.desc 'Move entries to'
1080
- c.default_value "Archive"
1081
- c.flag [:t, :to], :default_value => "Archive"
1098
+ c.flag [:t, :to], default_value: 'Archive'
1099
+
1100
+ c.desc 'Tag filter, combine multiple tags with a comma. Added for compatibility with other commands.'
1101
+ c.flag [:tag]
1082
1102
 
1083
1103
  c.desc 'Tag boolean'
1084
- c.default_value "AND"
1085
- c.flag [:b, :bool], :default_value => "AND"
1104
+ c.flag [:b, :bool], must_match: /(and|or|not)/i, default_value: 'AND'
1086
1105
 
1087
1106
  c.action do |global_options,options,args|
1088
1107
  if args.length > 0
@@ -1091,13 +1110,16 @@ command :archive do |c|
1091
1110
  tags = args.map {|t| t.sub(/^@/,'').strip }
1092
1111
  else
1093
1112
  section = args[0].cap_first
1094
- tags = args.length > 1 ? args[1..-1].map {|t| t.sub(/^@/,'').strip } : nil
1113
+ tags = args.length > 1 ? args[1..-1].map {|t| t.sub(/^@/, '').strip } : nil
1095
1114
  end
1096
1115
  else
1097
1116
  section = wwid.current_section
1098
- tags = nil
1117
+ tags = []
1099
1118
  end
1100
- wwid.archive(section,options[:k],options[:t],tags,options[:b])
1119
+
1120
+ tags.concat(options[:tag].split(/ *, */).map {|t| t.sub(/^@/, '').strip }) if options[:tag]
1121
+
1122
+ wwid.archive(section, options[:k], options[:t], tags, options[:b])
1101
1123
  end
1102
1124
  end
1103
1125
 
@@ -1113,7 +1135,7 @@ if `uname` =~ /Darwin/
1113
1135
  c.flag [:b]
1114
1136
  end
1115
1137
  c.desc 'open with $EDITOR'
1116
- c.switch [:e], :negatable => false
1138
+ c.switch [:e], negatable: false
1117
1139
 
1118
1140
  c.action do |global_options,options,args|
1119
1141
  params = options.dup
@@ -1150,8 +1172,7 @@ end
1150
1172
  desc 'Edit the configuration file'
1151
1173
  command :config do |c|
1152
1174
  c.desc 'Editor to use'
1153
- c.default_value ENV['EDITOR']
1154
- c.flag [:e, :editor], :default_value => nil
1175
+ c.flag [:e, :editor], default_value: nil
1155
1176
 
1156
1177
  if `uname` =~ /Darwins/
1157
1178
  c.desc 'Application to use'
@@ -1189,8 +1210,7 @@ end
1189
1210
  desc 'Undo the last change to the doing_file'
1190
1211
  command :undo do |c|
1191
1212
  c.desc 'Specify alternate doing file'
1192
- c.default_value wwid.doing_file
1193
- c.flag [:f, :file], :default_value => wwid.doing_file
1213
+ c.flag [:f, :file], default_value: wwid.doing_file
1194
1214
 
1195
1215
  c.action do |global_options,options,args|
1196
1216
  file = options[:f] || wwid.doing_file
@@ -1202,7 +1222,7 @@ end
1202
1222
  pre do |global,command,options,args|
1203
1223
  if global[:config_file]
1204
1224
  wwid.config_file = global[:config_file]
1205
- wwid.configure({:ignore_local => true})
1225
+ wwid.configure({ignore_local: true})
1206
1226
  # wwid.results.push("Override config file #{wwid.config_file}")
1207
1227
  end
1208
1228
 
data/lib/doing/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '1.0.49'
2
+ VERSION = '1.0.54'
3
3
  end
data/lib/doing/wwid.rb CHANGED
@@ -3,6 +3,45 @@
3
3
  require 'deep_merge'
4
4
  require 'open3'
5
5
 
6
+ ##
7
+ ## @brief Hash helpers
8
+ ##
9
+ class Hash
10
+ def has_tags?(tags, bool = 'AND')
11
+ tags = tags.split(/ *, */) if tags.is_a? String
12
+ item = self
13
+ case bool
14
+ when 'AND'
15
+ result = true
16
+ tags.each do |tag|
17
+ unless item['title'] =~ /@#{tag}/
18
+ result = false
19
+ break
20
+ end
21
+ end
22
+ result
23
+ when 'NOT'
24
+ result = true
25
+ tags.each do |tag|
26
+ if item['title'] =~ /@#{tag}/
27
+ result = false
28
+ break
29
+ end
30
+ end
31
+ result
32
+ else
33
+ result = false
34
+ tags.each do |tag|
35
+ if item['title'] =~ /@#{tag}/
36
+ result = true
37
+ break
38
+ end
39
+ end
40
+ result
41
+ end
42
+ end
43
+ end
44
+
6
45
  ##
7
46
  ## @brief String helpers
8
47
  ##
@@ -637,6 +676,8 @@ class WWID
637
676
  def restart_last(opt = {})
638
677
  opt[:section] ||= 'all'
639
678
  opt[:note] ||= []
679
+ opt[:tag] ||= []
680
+ opt[:tag_bool] ||= 'AND'
640
681
 
641
682
  last = last_entry(opt)
642
683
  if last.nil?
@@ -645,8 +686,9 @@ class WWID
645
686
  end
646
687
  # Remove @done tag
647
688
  title = last['title'].sub(/\s*@done(\(.*?\))?/, '').chomp
689
+ section = opt[:in].nil? ? last['section'] : guess_section(opt[:in])
648
690
  @auto_tag = false
649
- add_item(title, last['section'], { note: opt[:note], back: opt[:date], timed: true })
691
+ add_item(title, section, { note: opt[:note], back: opt[:date], timed: true })
650
692
  write(@doing_file)
651
693
  end
652
694
 
@@ -656,6 +698,8 @@ class WWID
656
698
  ## @param opt (Hash) Additional Options
657
699
  ##
658
700
  def last_entry(opt = {})
701
+ opt[:tag] ||= []
702
+ opt[:tag_bool] ||= 'AND'
659
703
  opt[:section] ||= @current_section
660
704
 
661
705
  sec_arr = []
@@ -682,6 +726,8 @@ class WWID
682
726
  all_items.concat(@content[section]['items'].dup) if @content.key?(section)
683
727
  end
684
728
 
729
+ all_items.select! { |item| item.has_tags?(opt[:tag], opt[:tag_bool]) } if !opt[:tag].nil? && opt[:tag].length.positive?
730
+
685
731
  all_items.max_by { |item| item['date'] }
686
732
  end
687
733
 
@@ -728,7 +774,6 @@ class WWID
728
774
  if @content.key?(section)
729
775
 
730
776
  items = @content[section]['items'].dup.sort_by { |item| item['date'] }.reverse
731
-
732
777
  index = 0
733
778
  done_date = Time.now
734
779
  next_start = Time.now
@@ -736,44 +781,48 @@ class WWID
736
781
  items.map! do |item|
737
782
  break if index == count
738
783
 
739
- if opt[:autotag]
740
- new_title = autotag(item['title']) if @auto_tag
741
- if new_title == item['title']
742
- @results.push(%(Autotag: No changes))
743
- else
744
- @results.push("Tags updated: #{new_title}")
745
- item['title'] = new_title
746
- end
747
- else
748
- if opt[:sequential]
749
- done_date = next_start - 1
750
- next_start = item['date']
751
- elsif opt[:back]
752
- done_date = item['date'] + (opt[:back] - item['date'])
784
+ tag_match = !opt[:tag].nil? && opt[:tag].length.positive? ? item.has_tags?(opt[:tag], opt[:tag_bool]) : true
785
+
786
+ if tag_match
787
+ if opt[:autotag]
788
+ new_title = autotag(item['title']) if @auto_tag
789
+ if new_title == item['title']
790
+ @results.push(%(Autotag: No changes))
791
+ else
792
+ @results.push("Tags updated: #{new_title}")
793
+ item['title'] = new_title
794
+ end
753
795
  else
754
- done_date = Time.now
755
- end
796
+ if opt[:sequential]
797
+ done_date = next_start - 1
798
+ next_start = item['date']
799
+ elsif opt[:back]
800
+ done_date = item['date'] + (opt[:back] - item['date'])
801
+ else
802
+ done_date = Time.now
803
+ end
756
804
 
757
- title = item['title']
758
- opt[:tags].each do |tag|
759
- tag.strip!
760
- if opt[:remove] && title =~ /@#{tag}\b/
761
- title.gsub!(/(^| )@#{tag}(\([^)]*\))?/, '')
762
- @results.push(%(Removed @#{tag}: "#{title}" in #{section}))
763
- elsif title !~ /@#{tag}/
764
- title.chomp!
765
- title += if opt[:date]
766
- " @#{tag}(#{done_date.strftime('%F %R')})"
767
- else
768
- " @#{tag}"
769
- end
770
- @results.push(%(Added @#{tag}: "#{title}" in #{section}))
805
+ title = item['title']
806
+ opt[:tags].each do |tag|
807
+ tag.strip!
808
+ if opt[:remove] && title =~ /@#{tag}\b/
809
+ title.gsub!(/(^| )@#{tag}(\([^)]*\))?/, '')
810
+ @results.push(%(Removed @#{tag}: "#{title}" in #{section}))
811
+ elsif title !~ /@#{tag}/
812
+ title.chomp!
813
+ title += if opt[:date]
814
+ " @#{tag}(#{done_date.strftime('%F %R')})"
815
+ else
816
+ " @#{tag}"
817
+ end
818
+ @results.push(%(Added @#{tag}: "#{title}" in #{section}))
819
+ end
771
820
  end
821
+ item['title'] = title
772
822
  end
773
- item['title'] = title
774
- end
775
823
 
776
- index += 1
824
+ index += 1
825
+ end
777
826
 
778
827
  item
779
828
  end
@@ -783,9 +832,10 @@ class WWID
783
832
  if opt[:archive] && section != 'Archive' && (opt[:count]).positive?
784
833
  # concat [count] items from [section] and archive section
785
834
  archived = @content[section]['items'][0..opt[:count] - 1].map do |i|
786
- i['title'].sub(/(?:@from\(.*?\))?(.*)$/, "\\1 @from(#{i['section']})")
835
+ i['title'].sub!(/(?:@from\(.*?\))?(.*)$/, "\\1 @from(#{i['section']})")
836
+ i
787
837
  end.concat(@content['Archive']['items'])
788
- # chop [count] items off of [section] items
838
+ # slice [count] items off of [section] items
789
839
  @content[opt[:section]]['items'] = @content[opt[:section]]['items'][opt[:count]..-1]
790
840
  # overwrite archive section with concatenated array
791
841
  @content['Archive']['items'] = archived
metadata CHANGED
@@ -1,19 +1,22 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: doing
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.49
4
+ version: 1.0.54
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-07-02 00:00:00.000000000 Z
11
+ date: 2021-07-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '13.0'
17
20
  - - ">="
18
21
  - !ruby/object:Gem::Version
19
22
  version: 13.0.1
@@ -21,6 +24,9 @@ dependencies:
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '13.0'
24
30
  - - ">="
25
31
  - !ruby/object:Gem::Version
26
32
  version: 13.0.1