doing 1.0.46 → 1.0.51

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 +17 -5
  3. data/bin/doing +115 -123
  4. data/lib/doing/version.rb +1 -1
  5. data/lib/doing/wwid.rb +78 -40
  6. metadata +12 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 35a90bfcfe901ff215cddf7ce3f0f19734371c2934c08af6bf0263137320d7cc
4
- data.tar.gz: d791452d6e5235aaf2a04db3e485c57e56a99c84c65f61026f82fa0e6a56b04e
3
+ metadata.gz: 03b16107627feaf0adeafbce9ad45e96fc53df7ba379f59dc72d2970d12642ef
4
+ data.tar.gz: 5cd54e6ba005e985b6c86468831d0b83369c5801916a9e8e15e742c86fcccf53
5
5
  SHA512:
6
- metadata.gz: 2166a9ee774dc475e2f9d13c116ce7e1aaa550b0e454ce7ae47a6b950a855443a0c59d6a24ff87247aac28a88404314011a4d6420190fdf007b236a53dcac3e6
7
- data.tar.gz: f3ebed8c0f2ae40770fca5df63a2a7a680915aa57d0baf0046a2ffb50f3908914bfbb8ba46a38ad943e6fe0fc1bd8d4e92b39761212bf6285dbf70b385544d77
6
+ metadata.gz: 617cd299b816ad12dc042ec76dbd58e5f19dca7098362ad4cc465d70d5c6dfab0e5ca4e05b82cd9535a85638ae490adea4da502ce4b6f0127e25da8f08b0bc6c
7
+ data.tar.gz: c82bb894c5d457d6bde4e6396cb7badffb4db3e6d0d81b75372f98968ec79b9ebfe15548b7040ddb5cc2eb2abfda2e3faaf6ea517c0485878689b50ce1739a79
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
@@ -393,10 +393,11 @@ Note that you can include a tag with synonyms in the whitelist as well to tag it
393
393
 
394
394
  #### Adding entries:
395
395
 
396
- now, did - Add an entry
397
- later - Add an item to the Later section
398
- done - Add a completed item with @done(date). No argument finishes last entry.
399
- meanwhile - Finish any @meanwhile tasks and optionally create a new one
396
+ now, did - Add an entry
397
+ later - Add an item to the Later section
398
+ done - Add a completed item with @done(date). No argument finishes last entry.
399
+ meanwhile - Finish any @meanwhile tasks and optionally create a new one
400
+ again, resume - Duplicate the last entry as new entry (without @done tag)
400
401
 
401
402
  The `doing now` command can accept `-s section_name` to send the new entry straight to a non-default section. It also accepts `--back=AMOUNT` to let you specify a start date in the past using "natural language." For example, `doing now --back=25m ENTRY` or `doing now --back="yesterday 3:30pm" ENTRY`.
402
403
 
@@ -419,6 +420,7 @@ See `doing help meanwhile` for more options.
419
420
  #### Modifying entries:
420
421
 
421
422
  finish - Mark last X entries as @done
423
+ cancel - Mark last X entries as @done without completion date
422
424
  tag - Tag last entry
423
425
  note - Add a note to the last entry
424
426
 
@@ -430,6 +432,16 @@ See `doing help meanwhile` for more options.
430
432
 
431
433
  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.
432
434
 
435
+ Both `done` and `finish` accept an `--archive` switch which immediately moves the completed entries to the Archive section with a `@from(Project)` tag.
436
+
437
+ 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:
438
+
439
+ doing finish --tag=work,project1
440
+
441
+ You can change the boolean using `--tag_bool=OR` (last entry containing any of the specified tags) or `--tag_bool=NOT` (last entry containing none of the tags).
442
+
443
+ 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.
444
+
433
445
 
434
446
  ##### Tagging and Autotagging
435
447
 
data/bin/doing CHANGED
@@ -44,7 +44,7 @@ default_value false
44
44
  switch [:stdout], :default_value => false, :negatable => false
45
45
 
46
46
  desc 'Exclude auto tags and default tags'
47
- switch [:x,:noauto], :default_value => false
47
+ switch [:x, :noauto], :default_value => false
48
48
 
49
49
  desc 'Use a specific configuration file'
50
50
  default_value false
@@ -52,37 +52,34 @@ flag [:config_file]
52
52
 
53
53
 
54
54
  # desc 'Wrap notes at X chars (0 for no wrap)'
55
- # flag [:w,:wrapwidth], :must_match => /^\d+$/, :type => Integer
55
+ # flag [:w, :wrapwidth], :must_match => /^\d+$/, :type => Integer
56
56
 
57
57
  desc 'Specify a different doing_file'
58
58
  flag [:f, :doing_file]
59
59
 
60
60
  desc 'Add an entry'
61
61
  arg_name 'entry'
62
- command [:now,:next] do |c|
62
+ command [:now, :next] do |c|
63
63
  c.desc 'Section'
64
64
  c.arg_name 'section_name'
65
- c.default_value wwid.current_section
66
- c.flag [:s,:section], :default_value => wwid.current_section
65
+ c.flag [:s, :section], :default_value => wwid.current_section
67
66
 
68
67
  c.desc "Edit entry with #{ENV['EDITOR']}"
69
- c.switch [:e,:editor]
68
+ c.switch [:e, :editor]
70
69
 
71
70
  c.desc 'Backdate start time [4pm|20m|2h|yesterday noon]'
72
- c.flag [:back]
71
+ c.flag [:b, :back]
73
72
 
74
73
  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
74
+ c.switch [:f, :finish_last], :negatable => false, :default_value => false
77
75
 
78
76
  c.desc 'Note'
79
77
  c.arg_name 'note_text'
80
- c.flag [:n,:note]
78
+ c.flag [:n, :note]
81
79
 
82
80
  # c.desc "Edit entry with specified app"
83
81
  # 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]
82
+ # # c.flag [:a, :app]
86
83
 
87
84
  c.action do |global_options,options,args|
88
85
  if options[:back]
@@ -136,7 +133,6 @@ arg_name 'note_text'
136
133
  command :note do |c|
137
134
  c.desc 'Section'
138
135
  c.arg_name 'section_name'
139
- c.default_value wwid.current_section
140
136
  c.flag [:s, :section], :default_value => "All"
141
137
 
142
138
  c.desc "Edit entry with #{ENV['EDITOR']}"
@@ -196,7 +192,6 @@ arg_name 'entry'
196
192
  command :meanwhile do |c|
197
193
  c.desc 'Section'
198
194
  c.arg_name 'section_name'
199
- c.default_value wwid.current_section
200
195
  c.flag [:s, :section], :default_value => wwid.current_section
201
196
 
202
197
  c.desc "Edit entry with #{ENV['EDITOR']}"
@@ -206,7 +201,7 @@ command :meanwhile do |c|
206
201
  c.switch [:a, :archive], :default_value => false
207
202
 
208
203
  c.desc 'Backdate start date for new entry to date string [4pm|20m|2h|yesterday noon]'
209
- c.flag [:back]
204
+ c.flag [:b, :back]
210
205
 
211
206
  c.desc 'Note'
212
207
  c.arg_name 'note_text'
@@ -238,7 +233,7 @@ command :meanwhile do |c|
238
233
  input = false unless input && input.length > 0
239
234
 
240
235
  note = options[:n] ? options[:n] : false
241
- wwid.stop_start("meanwhile",{:new_item => input, :back => date, :section => section, :archive => options[:a], :note => note})
236
+ wwid.stop_start('meanwhile', {:new_item => input, :back => date, :section => section, :archive => options[:a], :note => note})
242
237
  wwid.write(wwid.doing_file)
243
238
  end
244
239
  end
@@ -276,11 +271,10 @@ command :later do |c|
276
271
 
277
272
  c.desc "Edit entry with specified app"
278
273
  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
274
  c.flag [:a, :app]
281
275
 
282
276
  c.desc 'Backdate start time to date string [4pm|20m|2h|yesterday noon]'
283
- c.flag [:back]
277
+ c.flag [:b, :back]
284
278
 
285
279
  c.desc 'Note'
286
280
  c.arg_name 'note_text'
@@ -327,17 +321,14 @@ end
327
321
 
328
322
  desc 'Add a completed item with @done(date). No argument finishes last entry.'
329
323
  arg_name 'entry'
330
- command [:done,:did] do |c|
324
+ command [:done, :did] do |c|
331
325
  c.desc 'Remove @done tag'
332
- c.default_value false
333
326
  c.switch [:r, :remove], :negatable => false, :default_value => false
334
327
 
335
328
  c.desc 'Include date'
336
- c.default_value true
337
- c.switch [:d, :date], :negatable => true, :default_value => true
329
+ c.switch [:date], :negatable => true, :default_value => true
338
330
 
339
331
  c.desc 'Immediately archive the entry'
340
- c.default_value false
341
332
  c.switch [:a, :archive], :negatable => false, :default_value => false
342
333
 
343
334
  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'
@@ -350,16 +341,14 @@ command [:done,:did] do |c|
350
341
  c.flag [:t, :took]
351
342
 
352
343
  c.desc 'Section'
353
- c.default_value wwid.current_section
354
- c.flag [:s,:section], :default_value => wwid.current_section
344
+ c.flag [:s, :section], :default_value => wwid.current_section
355
345
 
356
346
  c.desc "Edit entry with #{ENV['EDITOR']}"
357
- c.switch [:e,:editor]
347
+ c.switch [:e, :editor]
358
348
 
359
349
  # c.desc "Edit entry with specified app"
360
350
  # 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]
351
+ # # c.flag [:a, :app]
363
352
 
364
353
  c.action do |global_options,options,args|
365
354
  took = 0
@@ -390,7 +379,7 @@ command [:done,:did] do |c|
390
379
  end
391
380
 
392
381
  section = wwid.guess_section(options[:s]) || options[:s].cap_first
393
- donedate = options[:d] ? "(#{finish_date.strftime('%F %R')})" : ""
382
+ donedate = options[:date] ? "(#{finish_date.strftime('%F %R')})" : ""
394
383
 
395
384
  if options[:e]
396
385
  raise "No EDITOR variable defined in environment" if ENV['EDITOR'].nil?
@@ -410,7 +399,7 @@ command [:done,:did] do |c|
410
399
  if options[:r]
411
400
  wwid.tag_last({:tags => ["done"], :count => 1, :section => section, :remove => true })
412
401
  else
413
- wwid.tag_last({:tags => ["done"], :count => 1, :section => section, :archive => options[:a], :back => finish_date, :date => options[:d]})
402
+ wwid.tag_last({:tags => ["done"], :count => 1, :section => section, :archive => options[:a], :back => finish_date, :date => options[:date]})
414
403
  end
415
404
  else
416
405
  if args.length > 0
@@ -433,31 +422,58 @@ command [:done,:did] do |c|
433
422
  end
434
423
  end
435
424
 
425
+ desc 'End last X entries with no time tracked'
426
+ long_desc 'Adds @done tag without datestamp so no elapsed time is recorded. Alias for `doing finish --no-date`.'
427
+ arg_name 'count'
428
+ command :cancel do |c|
429
+ c.desc 'Archive entries'
430
+ c.switch [:a, :archive], :negatable => false, :default_value => false
431
+
432
+ c.desc 'Section'
433
+ c.flag [:s, :section], :default_value => wwid.current_section
434
+
435
+ c.action do |global_options,options,args|
436
+
437
+ section = wwid.guess_section(options[:s]) || options[:s].cap_first
438
+
439
+ if args.length > 1
440
+ raise "Only one argument allowed"
441
+ elsif args.length == 0 || args[0] =~ /\d+/
442
+ count = args[0] ? args[0].to_i : 1
443
+ wwid.tag_last({:tags => ["done"], :count => count, :section => section, :archive => options[:a], :sequential => false, :date => false })
444
+ else
445
+ raise "Invalid argument (specify number of recent items to mark @done)"
446
+ end
447
+ end
448
+ end
449
+
436
450
  desc 'Mark last X entries as @done'
437
451
  long_desc 'Marks the last X entries with a @done tag and current date. Does not alter already completed entries.'
438
452
  arg_name 'count'
439
453
  command :finish do |c|
440
454
  c.desc 'Include date'
441
- c.default_value true
442
- c.switch [:d,:date], :default_value => true
455
+ c.switch [:date], :negatable => true, :default_value => true
443
456
 
444
457
  c.desc 'Backdate completed date to date string [4pm|20m|2h|yesterday noon]'
445
- c.flag [:b,:back]
458
+ c.flag [:b, :back]
446
459
 
447
460
  c.desc 'Set the completed date to the start date plus XX[hmd]'
448
- c.flag [:t,:took]
461
+ c.flag [:t, :took]
462
+
463
+ c.desc 'Finish the last X entries containing TAG. Separate multiple tags with comma (--tag=tag2,tag2)'
464
+ c.flag [:tag], :default_value => []
465
+
466
+ c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters'
467
+ c.flag [:tag_bool], default_value: 'AND'
449
468
 
450
469
  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.'
451
- c.default_value false
452
470
  c.switch [:auto], :negatable => false, :default_value => false
453
471
 
454
472
  c.desc 'Archive entries'
455
- c.default_value false
456
- c.switch [:a,:archive], :negatable => false, :default_value => false
473
+ c.switch [:a, :archive], :negatable => false, :default_value => false
457
474
 
458
475
  c.desc 'Section'
459
- c.default_value wwid.current_section
460
- c.flag [:s,:section], :default_value => wwid.current_section
476
+ c.flag [:s, :section], :default_value => wwid.current_section
461
477
 
462
478
  c.action do |global_options,options,args|
463
479
 
@@ -477,11 +493,20 @@ command :finish do |c|
477
493
  end
478
494
  end
479
495
 
496
+ if options[:tag]
497
+ options[:tag] = options[:tag].split(/,/).map {|tag| tag.strip.sub(/^@/, '') }
498
+ if options[:tag_bool] =~ /^(and|or|not)$/i
499
+ options[:tag_bool] = options[:tag_bool].upcase
500
+ else
501
+ options[:tag_bool] = 'AND'
502
+ end
503
+ end
504
+
480
505
  if args.length > 1
481
506
  raise "Only one argument allowed"
482
507
  elsif args.length == 0 || args[0] =~ /\d+/
483
508
  count = args[0] ? args[0].to_i : 1
484
- wwid.tag_last({:tags => ["done"], :count => count, :section => section, :archive => options[:a], :sequential => options[:auto], :date => options[:d], :back => date })
509
+ 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[:tag_bool] })
485
510
  else
486
511
  raise "Invalid argument (specify number of recent items to mark @done)"
487
512
  end
@@ -490,13 +515,13 @@ end
490
515
 
491
516
  desc 'Repeat last entry as new entry'
492
517
  arg_name 'section'
493
- command [:again,:resume] do |c|
518
+ command [:again, :resume] do |c|
494
519
  c.desc 'Section'
495
520
  c.flag [:s, :section], :default_value => "All"
496
521
 
497
522
  c.desc 'Note'
498
523
  c.arg_name 'note_text'
499
- c.flag [:n,:note]
524
+ c.flag [:n, :note]
500
525
 
501
526
  c.action do |global_options, options, args|
502
527
  wwid.restart_last({ section: options[:s], note: options[:n] })
@@ -510,19 +535,15 @@ command :tag do |c|
510
535
  c.flag [:s, :section], :default_value => "All"
511
536
 
512
537
  c.desc 'How many recent entries to tag (0 for all)'
513
- c.default_value 1
514
538
  c.flag [:c, :count], :default_value => 1
515
539
 
516
540
  c.desc 'Include current date/time with tag'
517
- c.default_value false
518
541
  c.switch [:d, :date], :negatable => false, :default_value => false
519
542
 
520
543
  c.desc 'Remove given tag(s)'
521
- c.default_value false
522
544
  c.switch [:r, :remove], :negatable => false, :default_value => false
523
545
 
524
546
  c.desc 'Autotag entries based on autotag configuration in ~/.doingrc'
525
- c.default_value false
526
547
  c.switch [:a, :autotag], :negatable => false, :default_value => false
527
548
 
528
549
  c.action do |global_options,options,args|
@@ -557,27 +578,25 @@ command :tag do |c|
557
578
  question = "Are you sure you want to add #{tags.join(" and ")} to all records#{section_q}"
558
579
  end
559
580
 
560
- res = wwid.yn(question,false)
581
+ res = wwid.yn(question, default_response: false)
561
582
 
562
583
  unless res
563
584
  raise "Cancelled"
564
585
  end
565
586
  end
566
587
 
567
- wwid.tag_last({:tags => tags, :count => count, :section => section, :date => options[:d], :remove => options[:r], :autotag => options[:a]})
588
+ wwid.tag_last({:tags => tags, :count => count, :section => section, :date => options[:date], :remove => options[:r], :autotag => options[:a]})
568
589
  end
569
590
  end
570
591
  end
571
592
 
572
593
  desc 'Mark last entry as highlighted'
573
- command [:mark,:flag] do |c|
594
+ command [:mark, :flag] do |c|
574
595
  c.desc 'Section'
575
- c.default_value wwid.current_section
576
- c.flag [:s,:section], :default_value => wwid.current_section
596
+ c.flag [:s, :section], :default_value => wwid.current_section
577
597
 
578
598
  c.desc 'Remove mark'
579
- c.default_value false
580
- c.switch [:r,:remove], :negatable => false, :default_value => false
599
+ c.switch [:r, :remove], :negatable => false, :default_value => false
581
600
 
582
601
 
583
602
  c.action do |global_options,options,args|
@@ -591,32 +610,28 @@ long_desc 'The argument can be a section name, @tag(s) or both. "pick" or "choos
591
610
  arg_name '[section|@tags]'
592
611
  command :show do |c|
593
612
  c.desc 'Tag boolean (AND,OR,NONE)'
594
- c.default_value "OR"
595
- c.flag [:b,:bool], :default_value => "OR"
613
+ c.flag [:b, :bool], :default_value => "OR"
596
614
 
597
615
  c.desc 'Max count to show'
598
- c.default_value 0
599
- c.flag [:c,:count], :default_value => 0
616
+ c.flag [:c, :count], :default_value => 0
600
617
 
601
618
  c.desc 'Age (oldest/newest)'
602
- c.default_value 'newest'
603
- c.flag [:a,:age], :default_value => 'newest'
619
+ c.flag [:a, :age], :default_value => 'newest'
604
620
 
605
621
  c.desc 'Sort order (asc/desc)'
606
- c.default_value 'asc'
607
- c.flag [:s,:sort], :default_value => 'asc'
622
+ c.flag [:s, :sort], :default_value => 'asc'
608
623
 
609
624
  c.desc %{
610
- Date range to show, or a single day to filter date on. Date range argument should be quoted. Date specifications can be natural language. To specify a range, use "to," or "through,". Example `doing show --from "monday to friday"`
625
+ Date range to show, or a single day to filter date on.
626
+ Date range argument should be quoted. Date specifications can be natural language.
627
+ To specify a range, use "to" or "through": `doing show --from "monday to friday"`
611
628
  }
612
- c.flag [:f,:from]
629
+ c.flag [:f, :from]
613
630
 
614
631
  c.desc 'Show time intervals on @done tasks'
615
- c.default_value true
616
- c.switch [:t,:times], :default_value => true
632
+ c.switch [:t, :times], :default_value => true
617
633
 
618
634
  c.desc 'Show intervals with totals at the end of output'
619
- c.default_value false
620
635
  c.switch [:totals], :default_value => false, :negatable => true
621
636
 
622
637
  c.desc 'Sort tags by (name|time)'
@@ -627,11 +642,10 @@ command :show do |c|
627
642
  c.flag [:tag_sort], :default_value => default
628
643
 
629
644
  c.desc 'Only show items with recorded time intervals'
630
- c.default_value false
631
645
  c.switch [:only_timed], :default_value => false, :negatable => false
632
646
 
633
647
  c.desc 'Output to export format (csv|html|json)'
634
- c.flag [:o,:output]
648
+ c.flag [:o, :output]
635
649
  c.action do |global_options,options,args|
636
650
 
637
651
  tag_filter = false
@@ -696,22 +710,24 @@ command :show do |c|
696
710
  end
697
711
 
698
712
  desc 'Search for entries'
699
- long_desc 'Search all sections (or limit to a single section) for entries matching text or regular expression. Normal strings are fuzzy matched, delineate regex with /expression/'
713
+ long_desc <<-'EODESC'
714
+ Search all sections (or limit to a single section) for entries matching text or regular expression. Normal strings are fuzzy matched.
715
+
716
+ To search with regular expressions, single quote the string and surround with slashes: `doing search '/\bm.*?x\b/'`
717
+ EODESC
718
+
700
719
  arg_name 'search_pattern'
701
- command [:grep,:search] do |c|
720
+ command [:grep, :search] do |c|
702
721
  c.desc 'Section'
703
- c.default_value "all"
704
- c.flag [:s,:section], :default_value => "All"
722
+ c.flag [:s, :section], :default_value => "All"
705
723
 
706
724
  c.desc 'Output to export format (csv|html|json)'
707
- c.flag [:o,:output]
725
+ c.flag [:o, :output]
708
726
 
709
727
  c.desc 'Show time intervals on @done tasks'
710
- c.default_value true
711
- c.switch [:t,:times], :default_value => true
728
+ c.switch [:t, :times], :default_value => true
712
729
 
713
730
  c.desc 'Show intervals with totals at the end of output'
714
- c.default_value false
715
731
  c.switch [:totals], :default_value => false, :negatable => true
716
732
 
717
733
  c.desc 'Sort tags by (name|time)'
@@ -722,7 +738,6 @@ command [:grep,:search] do |c|
722
738
  c.flag [:tag_sort], :default_value => default
723
739
 
724
740
  c.desc 'Only show items with recorded time intervals'
725
- c.default_value false
726
741
  c.switch [:only_timed], :default_value => false, :negatable => false
727
742
 
728
743
  c.action do |global_options,options,args|
@@ -742,15 +757,12 @@ default_value 10
742
757
  arg_name 'count'
743
758
  command :recent do |c|
744
759
  c.desc 'Section'
745
- c.default_value "All"
746
- c.flag [:s,:section], :default_value => "All"
760
+ c.flag [:s, :section], :default_value => "All"
747
761
 
748
762
  c.desc 'Show time intervals on @done tasks'
749
- c.default_value true
750
- c.switch [:t,:times], :default_value => true
763
+ c.switch [:t, :times], :default_value => true
751
764
 
752
765
  c.desc 'Show intervals with totals at the end of output'
753
- c.default_value false
754
766
  c.switch [:totals], :default_value => false, :negatable => true
755
767
 
756
768
  c.desc 'Sort tags by (name|time)'
@@ -783,15 +795,12 @@ desc 'List entries from today'
783
795
  command :today do |c|
784
796
  c.desc 'Specify a section'
785
797
  c.arg_name 'section_name'
786
- c.default_value "All"
787
- c.flag [:s,:section], :default_value => 'All'
798
+ c.flag [:s, :section], :default_value => 'All'
788
799
 
789
800
  c.desc 'Show time intervals on @done tasks'
790
- c.default_value true
791
- c.switch [:t,:times], :default_value => true
801
+ c.switch [:t, :times], :default_value => true
792
802
 
793
803
  c.desc 'Show time totals at the end of output'
794
- c.default_value false
795
804
  c.switch [:totals], :default_value => false, :negatable => true
796
805
 
797
806
  c.desc 'Sort tags by (name|time)'
@@ -802,7 +811,7 @@ command :today do |c|
802
811
  c.flag [:tag_sort], :default_value => default
803
812
 
804
813
  c.desc 'Output to export format (csv|html|json)'
805
- c.flag [:o,:output]
814
+ c.flag [:o, :output]
806
815
 
807
816
  c.action do |global_options,options,args|
808
817
 
@@ -820,15 +829,12 @@ arg_name 'date_string'
820
829
  command :on do |c|
821
830
  c.desc 'Section'
822
831
  c.arg_name 'section_name'
823
- c.default_value 'All'
824
- c.flag [:s,:section], :default_value => 'All'
832
+ c.flag [:s, :section], :default_value => 'All'
825
833
 
826
834
  c.desc 'Show time intervals on @done tasks'
827
- c.default_value true
828
- c.switch [:t,:times], :default_value => true
835
+ c.switch [:t, :times], :default_value => true
829
836
 
830
837
  c.desc 'Show time totals at the end of output'
831
- c.default_value false
832
838
  c.switch [:totals], :default_value => false, :negatable => true
833
839
 
834
840
  c.desc 'Sort tags by (name|time)'
@@ -839,7 +845,7 @@ command :on do |c|
839
845
  c.flag [:tag_sort], :default_value => default
840
846
 
841
847
  c.desc 'Output to export format (csv|html|json)'
842
- c.flag [:o,:output]
848
+ c.flag [:o, :output]
843
849
 
844
850
  c.action do |global_options,options,args|
845
851
 
@@ -872,18 +878,15 @@ desc 'List entries from yesterday'
872
878
  command :yesterday do |c|
873
879
  c.desc 'Specify a section'
874
880
  c.arg_name 'section_name'
875
- c.default_value "All"
876
- c.flag [:s,:section], :default_value => 'All'
881
+ c.flag [:s, :section], :default_value => 'All'
877
882
 
878
883
  c.desc 'Output to export format (csv|html|json)'
879
- c.flag [:o,:output]
884
+ c.flag [:o, :output]
880
885
 
881
886
  c.desc 'Show time intervals on @done tasks'
882
- c.default_value true
883
- c.switch [:t,:times], :default_value => true
887
+ c.switch [:t, :times], :default_value => true
884
888
 
885
889
  c.desc 'Show time totals at the end of output'
886
- c.default_value false
887
890
  c.switch [:totals], :default_value => false, :negatable => true
888
891
 
889
892
  c.desc 'Sort tags by (name|time)'
@@ -903,8 +906,7 @@ end
903
906
  desc 'Show the last entry'
904
907
  command :last do |c|
905
908
  c.desc 'Specify a section'
906
- c.default_value "All"
907
- c.flag [:s,:section]
909
+ c.flag [:s, :section]
908
910
 
909
911
  c.action do |global_options,options,args|
910
912
  puts wwid.last(true,options[:s]).strip
@@ -914,8 +916,7 @@ end
914
916
  desc 'List sections'
915
917
  command :sections do |c|
916
918
  c.desc 'List in single column'
917
- c.default_value false
918
- c.switch [:c,:column], :default_value => false
919
+ c.switch [:c, :column], :default_value => false
919
920
 
920
921
  c.action do |global_options,options,args|
921
922
  joiner = options[:c] ? "\n" : "\t"
@@ -966,20 +967,18 @@ desc 'Display a user-created view'
966
967
  arg_name 'view_name'
967
968
  command :view do |c|
968
969
  c.desc 'Section (override view settings)'
969
- c.flag [:s,:section]
970
+ c.flag [:s, :section]
970
971
 
971
972
  c.desc 'Count to display (override view settings)'
972
- c.flag [:c,:count], :must_match => /^\d+$/, :type => Integer
973
+ c.flag [:c, :count], :must_match => /^\d+$/, :type => Integer
973
974
 
974
975
  c.desc 'Output to export format (csv|html|json)'
975
- c.flag [:o,:output]
976
+ c.flag [:o, :output]
976
977
 
977
978
  c.desc 'Show time intervals on @done tasks'
978
- c.default_value true
979
- c.switch [:t,:times], :default_value => true
979
+ c.switch [:t, :times], :default_value => true
980
980
 
981
981
  c.desc 'Show intervals with totals at the end of output'
982
- c.default_value false
983
982
  c.switch [:totals], :default_value => false, :negatable => true
984
983
 
985
984
  c.desc 'Sort tags by (name|time)'
@@ -990,7 +989,6 @@ command :view do |c|
990
989
  c.flag [:tag_sort], :default_value => default
991
990
 
992
991
  c.desc 'Only show items with recorded time intervals'
993
- c.default_value false
994
992
  c.switch [:only_timed], :default_value => false, :negatable => true
995
993
 
996
994
  c.action do |global_options,options,args|
@@ -1053,8 +1051,7 @@ end
1053
1051
  desc 'List available custom views'
1054
1052
  command :views do |c|
1055
1053
  c.desc 'List in single column'
1056
- c.default_value false
1057
- c.switch [:c,:column], :default_value => false
1054
+ c.switch [:c, :column], :default_value => false
1058
1055
 
1059
1056
  c.action do |global_options,options,args|
1060
1057
  joiner = options[:c] ? "\n" : "\t"
@@ -1067,16 +1064,13 @@ arg_name 'section'
1067
1064
  default_value wwid.current_section
1068
1065
  command :archive do |c|
1069
1066
  c.desc 'Count to keep (ignored if archiving by tag)'
1070
- c.default_value 5
1071
- c.flag [:k,:keep], :default_value => 5, :must_match => /^\d+$/, :type => Integer
1067
+ c.flag [:k, :keep], :default_value => 5, :must_match => /^\d+$/, :type => Integer
1072
1068
 
1073
1069
  c.desc 'Move entries to'
1074
- c.default_value "Archive"
1075
- c.flag [:t,:to], :default_value => "Archive"
1070
+ c.flag [:t, :to], :default_value => "Archive"
1076
1071
 
1077
1072
  c.desc 'Tag boolean'
1078
- c.default_value "AND"
1079
- c.flag [:b,:bool], :default_value => "AND"
1073
+ c.flag [:b, :bool], :default_value => "AND"
1080
1074
 
1081
1075
  c.action do |global_options,options,args|
1082
1076
  if args.length > 0
@@ -1144,8 +1138,7 @@ end
1144
1138
  desc 'Edit the configuration file'
1145
1139
  command :config do |c|
1146
1140
  c.desc 'Editor to use'
1147
- c.default_value ENV['EDITOR']
1148
- c.flag [:e,:editor], :default_value => nil
1141
+ c.flag [:e, :editor], :default_value => nil
1149
1142
 
1150
1143
  if `uname` =~ /Darwins/
1151
1144
  c.desc 'Application to use'
@@ -1183,8 +1176,7 @@ end
1183
1176
  desc 'Undo the last change to the doing_file'
1184
1177
  command :undo do |c|
1185
1178
  c.desc 'Specify alternate doing file'
1186
- c.default_value wwid.doing_file
1187
- c.flag [:f,:file], :default_value => wwid.doing_file
1179
+ c.flag [:f, :file], :default_value => wwid.doing_file
1188
1180
 
1189
1181
  c.action do |global_options,options,args|
1190
1182
  file = options[:f] || wwid.doing_file
data/lib/doing/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '1.0.46'
2
+ VERSION = '1.0.51'
3
3
  end
data/lib/doing/wwid.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
3
  require 'deep_merge'
4
+ require 'open3'
4
5
 
5
6
  ##
6
7
  ## @brief String helpers
@@ -644,6 +645,7 @@ class WWID
644
645
  end
645
646
  # Remove @done tag
646
647
  title = last['title'].sub(/\s*@done(\(.*?\))?/, '').chomp
648
+ @auto_tag = false
647
649
  add_item(title, last['section'], { note: opt[:note], back: opt[:date], timed: true })
648
650
  write(@doing_file)
649
651
  end
@@ -726,7 +728,6 @@ class WWID
726
728
  if @content.key?(section)
727
729
 
728
730
  items = @content[section]['items'].dup.sort_by { |item| item['date'] }.reverse
729
-
730
731
  index = 0
731
732
  done_date = Time.now
732
733
  next_start = Time.now
@@ -734,44 +735,80 @@ class WWID
734
735
  items.map! do |item|
735
736
  break if index == count
736
737
 
737
- if opt[:autotag]
738
- new_title = autotag(item['title']) if @auto_tag
739
- if new_title == item['title']
740
- @results.push(%(Autotag: No changes))
741
- else
742
- @results.push("Tags updated: #{new_title}")
743
- item['title'] = new_title
744
- end
745
- else
746
- if opt[:sequential]
747
- done_date = next_start - 1
748
- next_start = item['date']
749
- elsif opt[:back]
750
- done_date = item['date'] + (opt[:back] - item['date'])
738
+ tag_match = if opt[:tag].length.positive?
739
+ case opt[:tag_bool]
740
+ when 'AND'
741
+ result = true
742
+ opt[:tag].each do |tag|
743
+ unless item['title'] =~ /@#{tag}/
744
+ result = false
745
+ break
746
+ end
747
+ end
748
+ result
749
+ when 'NOT'
750
+ result = true
751
+ opt[:tag].each do |tag|
752
+ if item['title'] =~ /@#{tag}/
753
+ result = false
754
+ break
755
+ end
756
+ end
757
+ result
758
+ else
759
+ result = false
760
+ opt[:tag].each do |tag|
761
+ if item['title'] =~ /@#{tag}/
762
+ result = true
763
+ break
764
+ end
765
+ end
766
+ result
767
+ end
768
+ else
769
+ true
770
+ end
771
+
772
+ if tag_match
773
+ if opt[:autotag]
774
+ new_title = autotag(item['title']) if @auto_tag
775
+ if new_title == item['title']
776
+ @results.push(%(Autotag: No changes))
777
+ else
778
+ @results.push("Tags updated: #{new_title}")
779
+ item['title'] = new_title
780
+ end
751
781
  else
752
- done_date = Time.now
753
- end
782
+ if opt[:sequential]
783
+ done_date = next_start - 1
784
+ next_start = item['date']
785
+ elsif opt[:back]
786
+ done_date = item['date'] + (opt[:back] - item['date'])
787
+ else
788
+ done_date = Time.now
789
+ end
754
790
 
755
- title = item['title']
756
- opt[:tags].each do |tag|
757
- tag.strip!
758
- if opt[:remove] && title =~ /@#{tag}\b/
759
- title.gsub!(/(^| )@#{tag}(\([^)]*\))?/, '')
760
- @results.push(%(Removed @#{tag}: "#{title}" in #{section}))
761
- elsif title !~ /@#{tag}/
762
- title.chomp!
763
- title += if opt[:date]
764
- " @#{tag}(#{done_date.strftime('%F %R')})"
765
- else
766
- " @#{tag}"
767
- end
768
- @results.push(%(Added @#{tag}: "#{title}" in #{section}))
791
+ title = item['title']
792
+ opt[:tags].each do |tag|
793
+ tag.strip!
794
+ if opt[:remove] && title =~ /@#{tag}\b/
795
+ title.gsub!(/(^| )@#{tag}(\([^)]*\))?/, '')
796
+ @results.push(%(Removed @#{tag}: "#{title}" in #{section}))
797
+ elsif title !~ /@#{tag}/
798
+ title.chomp!
799
+ title += if opt[:date]
800
+ " @#{tag}(#{done_date.strftime('%F %R')})"
801
+ else
802
+ " @#{tag}"
803
+ end
804
+ @results.push(%(Added @#{tag}: "#{title}" in #{section}))
805
+ end
769
806
  end
807
+ item['title'] = title
770
808
  end
771
- item['title'] = title
772
- end
773
809
 
774
- index += 1
810
+ index += 1
811
+ end
775
812
 
776
813
  item
777
814
  end
@@ -781,9 +818,10 @@ class WWID
781
818
  if opt[:archive] && section != 'Archive' && (opt[:count]).positive?
782
819
  # concat [count] items from [section] and archive section
783
820
  archived = @content[section]['items'][0..opt[:count] - 1].map do |i|
784
- i['title'].sub(/(?:@from\(.*?\))?(.*)$/, "\\1 @from(#{i['section']})")
821
+ i['title'].sub!(/(?:@from\(.*?\))?(.*)$/, "\\1 @from(#{i['section']})")
822
+ i
785
823
  end.concat(@content['Archive']['items'])
786
- # chop [count] items off of [section] items
824
+ # slice [count] items off of [section] items
787
825
  @content[opt[:section]]['items'] = @content[opt[:section]]['items'][opt[:count]..-1]
788
826
  # overwrite archive section with concatenated array
789
827
  @content['Archive']['items'] = archived
@@ -931,10 +969,10 @@ class WWID
931
969
  end
932
970
 
933
971
  if @config.key?('run_after')
934
- script = File.expand_path(@config['run_after'])
935
- if File.exist?(script)
936
- # warn "Running #{script}"
937
- `#{script}`
972
+ stdout, stderr, status = Open3.capture3(@config['run_after'])
973
+ if status.exitstatus.positive?
974
+ warn "Error running #{@config['run_after']}"
975
+ warn stderr
938
976
  end
939
977
  end
940
978
  end
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.46
4
+ version: 1.0.51
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-01 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
@@ -72,20 +78,20 @@ dependencies:
72
78
  requirements:
73
79
  - - "~>"
74
80
  - !ruby/object:Gem::Version
75
- version: '2.19'
81
+ version: '2.20'
76
82
  - - ">="
77
83
  - !ruby/object:Gem::Version
78
- version: 2.19.2
84
+ version: 2.20.1
79
85
  type: :runtime
80
86
  prerelease: false
81
87
  version_requirements: !ruby/object:Gem::Requirement
82
88
  requirements:
83
89
  - - "~>"
84
90
  - !ruby/object:Gem::Version
85
- version: '2.19'
91
+ version: '2.20'
86
92
  - - ">="
87
93
  - !ruby/object:Gem::Version
88
- version: 2.19.2
94
+ version: 2.20.1
89
95
  - !ruby/object:Gem::Dependency
90
96
  name: haml
91
97
  requirement: !ruby/object:Gem::Requirement