doing 1.0.66 → 1.0.70

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6e02c8453f718dfa428e578ab1b125528aa07ffee1390bbe8222fb425abd63fa
4
- data.tar.gz: 333707321b7e92312ee8a2874292b45df782c83eff2ddcdb5279b648b14730ff
3
+ metadata.gz: 10dc5d92f3e7079a9525d39c47fe0f69ef22f64ae5400cd9da1925f9b0fc1964
4
+ data.tar.gz: ec08df722ce07bbfcee808bfd4bd9eabe5470ef173f5d11e47fc52356b2c2c95
5
5
  SHA512:
6
- metadata.gz: 187ce7735035b86ae1233d08dd154f502c7b2def0fc1fd11532de5256647c8cce57bd4ea73ca3fa704c2dfb4a307b94f339222a476e3fd30ba991fea77daa190
7
- data.tar.gz: 29f7123aa51cb8a5754bca68854dbbb606f69533d8cdbd90a7a2187ca1cc29dd09131aed0787f72fd680e2d04fe9e47a92555cf90c1327b74cba23cc8a2fab2b
6
+ metadata.gz: c56a9a328d2ed31e70633333be5f7666d9586154fba7cc59f34116f1a972156fb4dd7d087e59452bf860167e618dad815da8a113fe0e4cf9f12faafa98d68d72
7
+ data.tar.gz: 3152021d8017af18e4046736f1f994bd1821f95bece924ca9ad78de997ad3473cbfd411389ede1dfe6313a1c4fde3debdc9907f3f2da899b1bab823a02a932e7
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.65<!--END VER-->.
30
+ The current version of `doing` is <!--VER-->1.0.69<!--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
 
data/bin/doing CHANGED
@@ -368,7 +368,7 @@ command %i[done did] do |c|
368
368
 
369
369
  date = options[:took] ? finish_date - took : finish_date
370
370
  elsif options[:took]
371
- finish_date = options[:back] ? date + took : nil
371
+ finish_date = date + took
372
372
  elsif options[:back]
373
373
  finish_date = date
374
374
  else
@@ -446,6 +446,9 @@ command :cancel do |c|
446
446
  c.arg_name 'BOOLEAN'
447
447
  c.flag [:bool], must_match: /(?:and|all|any|or|not|none)/i, default_value: 'AND'
448
448
 
449
+ c.desc 'Cancel last entry (or entries) not already marked @done'
450
+ c.switch %i[u unfinished], negatable: false, default_value: false
451
+
449
452
  c.action do |_global_options, options, args|
450
453
  section = wwid.guess_section(options[:s]) || options[:s].cap_first
451
454
 
@@ -478,7 +481,8 @@ command :cancel do |c|
478
481
  sequential: false,
479
482
  tag: tags,
480
483
  tag_bool: options[:bool],
481
- tags: ['done']
484
+ tags: ['done'],
485
+ unfinished: options[:unfinished]
482
486
  }
483
487
  wwid.tag_last(opts)
484
488
  end
@@ -512,6 +516,9 @@ command :finish do |c|
512
516
  c.arg_name 'BOOLEAN'
513
517
  c.flag [:bool], must_match: /(?:and|all|any|or|not|none)/i, default_value: 'AND'
514
518
 
519
+ c.desc 'Finish last entry (or entries) not already marked @done'
520
+ c.switch %i[u unfinished], negatable: false, default_value: false
521
+
515
522
  c.desc %(Auto-generate finish dates from next entry's start time.
516
523
  Automatically generate completion dates 1 minute before next start date.
517
524
  --auto overrides the --date and --back parameters.)
@@ -574,7 +581,8 @@ command :finish do |c|
574
581
  sequential: options[:auto],
575
582
  tag: tags,
576
583
  tag_bool: options[:bool],
577
- tags: ['done']
584
+ tags: ['done'],
585
+ unfinished: options[:unfinished]
578
586
  }
579
587
  wwid.tag_last(opts)
580
588
  end
@@ -648,6 +656,9 @@ command :tag do |c|
648
656
  c.desc 'Remove given tag(s)'
649
657
  c.switch %i[r remove], negatable: false, default_value: false
650
658
 
659
+ c.desc 'Tag last entry (or entries) not marked @done'
660
+ c.switch %i[u unfinished], negatable: false, default_value: false
661
+
651
662
  c.desc 'Autotag entries based on autotag configuration in ~/.doingrc'
652
663
  c.switch %i[a autotag], negatable: false, default_value: false
653
664
 
@@ -691,7 +702,8 @@ command :tag do |c|
691
702
  date: options[:date],
692
703
  remove: options[:r],
693
704
  section: section,
694
- tags: tags
705
+ tags: tags,
706
+ unfinished: options[:unfinished]
695
707
  }
696
708
  wwid.tag_last(opts)
697
709
  end
@@ -706,9 +718,17 @@ command [:mark, :flag] do |c|
706
718
  c.desc 'Remove mark'
707
719
  c.switch %i[r remove], negatable: false, default_value: false
708
720
 
721
+ c.desc 'Mark last entry not marked @done'
722
+ c.switch %i[u unfinished], negatable: false, default_value: false
723
+
709
724
  c.action do |_global_options, options, _args|
710
725
  mark = wwid.config['marker_tag'] || 'flagged'
711
- wwid.tag_last({ tags: [mark], section: options[:s], remove: options[:r] })
726
+ wwid.tag_last({
727
+ remove: options[:r],
728
+ section: options[:s],
729
+ tags: [mark],
730
+ unfinished: options[:unfinished]
731
+ })
712
732
  end
713
733
  end
714
734
 
@@ -737,7 +757,7 @@ command :show do |c|
737
757
 
738
758
  c.desc 'Sort order (asc/desc)'
739
759
  c.arg_name 'ORDER'
740
- c.flag %i[s sort], must_match: /^(?:a|d)/i, default_value: 'ASC'
760
+ c.flag %i[s sort], must_match: /^[ad].*/i, default_value: 'ASC'
741
761
 
742
762
  c.desc %(
743
763
  Date range to show, or a single day to filter date on.
@@ -0,0 +1,121 @@
1
+ ##
2
+ ## @brief Hash helpers
3
+ ##
4
+ class ::Hash
5
+ def has_tags?(tags, bool = :and)
6
+ tags = tags.split(/ *, */) if tags.is_a? String
7
+ bool = bool.normalize_bool if bool.is_a? String
8
+ item = self
9
+ tags.map! {|t| t.strip.sub(/^@/, '')}
10
+ case bool
11
+ when :and
12
+ result = true
13
+ tags.each do |tag|
14
+ unless item['title'] =~ /@#{tag}/
15
+ result = false
16
+ break
17
+ end
18
+ end
19
+ result
20
+ when :not
21
+ result = true
22
+ tags.each do |tag|
23
+ if item['title'] =~ /@#{tag}/
24
+ result = false
25
+ break
26
+ end
27
+ end
28
+ result
29
+ else
30
+ result = false
31
+ tags.each do |tag|
32
+ if item['title'] =~ /@#{tag}/
33
+ result = true
34
+ break
35
+ end
36
+ end
37
+ result
38
+ end
39
+ end
40
+
41
+ def matches_search?(search)
42
+ item = self
43
+ text = item['note'] ? item['title'] + item['note'].join(' ') : item['title']
44
+ pattern = if search.strip =~ %r{^/.*?/$}
45
+ search.sub(%r{/(.*?)/}, '\1')
46
+ else
47
+ search.split('').join('.{0,3}')
48
+ end
49
+ text =~ /#{pattern}/i ? true : false
50
+ end
51
+ end
52
+
53
+ ##
54
+ ## @brief String helpers
55
+ ##
56
+ class ::String
57
+ def cap_first
58
+ sub(/^\w/) do |m|
59
+ m.upcase
60
+ end
61
+ end
62
+
63
+
64
+ ##
65
+ ## @brief Convert a boolean string to a symbol
66
+ ##
67
+ ## @return Symbol :and, :or, or :not
68
+ ##
69
+ def normalize_bool!
70
+ replace normalize_bool
71
+ end
72
+
73
+ def normalize_bool(default = :and)
74
+ case self
75
+ when /(and|all)/i
76
+ :and
77
+ when /(any|or)/i
78
+ :or
79
+ when /(not|none)/i
80
+ :not
81
+ else
82
+ default.is_a?(Symbol) ? default : default.normalize_bool
83
+ end
84
+ end
85
+
86
+
87
+ ##
88
+ ## @brief Turn raw urls into HTML links
89
+ ##
90
+ ## @param opt (Hash) Additional Options
91
+ ##
92
+ def link_urls(opt = {})
93
+ opt[:format] ||= :html
94
+ if opt[:format] == :html
95
+ gsub(%r{(?mi)((http|https)://)?([\w\-_]+(\.[\w\-_]+)+)([\w\-.,@?^=%&amp;:/~+#]*[\w\-@^=%&amp;/~+#])?}) do |_match|
96
+ m = Regexp.last_match
97
+ proto = m[1].nil? ? 'http://' : ''
98
+ %(<a href="#{proto}#{m[0]}" title="Link to #{m[0]}">[#{m[3]}]</a>)
99
+ end.gsub(/<(\w+:.*?)>/) do |match|
100
+ m = Regexp.last_match
101
+ if m[1] =~ /<a href/
102
+ match
103
+ else
104
+ %(<a href="#{m[1]}" title="Link to #{m[1]}">[link]</a>)
105
+ end
106
+ end
107
+ else
108
+ self
109
+ end
110
+ end
111
+ end
112
+
113
+ class ::Symbol
114
+ def normalize_bool!
115
+ replace normalize_bool
116
+ end
117
+
118
+ def normalize_bool
119
+ to_s.normalize_bool
120
+ end
121
+ end
data/lib/doing/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '1.0.66'
2
+ VERSION = '1.0.70'
3
3
  end
data/lib/doing/wwid.rb CHANGED
@@ -781,6 +781,7 @@ class WWID
781
781
  opt[:autotag] ||= false
782
782
  opt[:back] ||= false
783
783
  opt[:took] ||= nil
784
+ opt[:unfinished] ||= false
784
785
 
785
786
  sec_arr = []
786
787
 
@@ -816,10 +817,11 @@ class WWID
816
817
  items.map! do |item|
817
818
  break if idx == count
818
819
 
820
+ finished = opt[:unfinished] && item.has_tags?('done', :and)
819
821
  tag_match = opt[:tag].nil? || opt[:tag].empty? ? true : item.has_tags?(opt[:tag], opt[:tag_bool])
820
822
  search_match = opt[:search].nil? || opt[:search].empty? ? true : item.matches_search?(opt[:search])
821
823
 
822
- if tag_match && search_match
824
+ if tag_match && search_match && !finished
823
825
  if opt[:autotag]
824
826
  new_title = autotag(item['title']) if @auto_tag
825
827
  if new_title == item['title']
@@ -832,12 +834,6 @@ class WWID
832
834
  if opt[:sequential]
833
835
  done_date = next_start - 1
834
836
  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
837
  elsif opt[:took]
842
838
  if item['date'] + opt[:took] > Time.now
843
839
  item['date'] = Time.now - opt[:took]
@@ -845,6 +841,12 @@ class WWID
845
841
  else
846
842
  done_date = item['date'] + opt[:took]
847
843
  end
844
+ elsif opt[:back]
845
+ if opt[:back].is_a? Integer
846
+ done_date = item['date'] + opt[:back]
847
+ else
848
+ done_date = item['date'] + (opt[:back] - item['date'])
849
+ end
848
850
  else
849
851
  done_date = Time.now
850
852
  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.66
4
+ version: 1.0.70
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-26 00:00:00.000000000 Z
11
+ date: 2021-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -165,6 +165,7 @@ files:
165
165
  - README.md
166
166
  - bin/doing
167
167
  - lib/doing.rb
168
+ - lib/doing/helpers.rb
168
169
  - lib/doing/version.rb
169
170
  - lib/doing/wwid.rb
170
171
  - lib/templates/doing.css