doing 2.1.26 → 2.1.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. checksums.yaml +4 -4
  2. data/.yardoc/checksums +15 -20
  3. data/.yardoc/object_types +0 -0
  4. data/.yardoc/objects/root.dat +0 -0
  5. data/CHANGELOG.md +52 -0
  6. data/Dockerfile +5 -5
  7. data/Dockerfile-2.6 +5 -5
  8. data/Dockerfile-2.7 +5 -4
  9. data/Dockerfile-3.0 +5 -4
  10. data/Gemfile.lock +2 -1
  11. data/README.md +1 -1
  12. data/Rakefile +2 -3
  13. data/bin/commands/add_section.rb +2 -0
  14. data/bin/commands/again.rb +23 -65
  15. data/bin/commands/archive.rb +20 -61
  16. data/bin/commands/cancel.rb +27 -69
  17. data/bin/commands/changes.rb +53 -12
  18. data/bin/commands/colors.rb +4 -2
  19. data/bin/commands/commands.rb +4 -2
  20. data/bin/commands/commands_accepting.rb +62 -11
  21. data/bin/commands/completion.rb +10 -7
  22. data/bin/commands/config.rb +8 -8
  23. data/bin/commands/done.rb +3 -17
  24. data/bin/commands/finish.rb +7 -30
  25. data/bin/commands/flag.rb +15 -51
  26. data/bin/commands/grep.rb +12 -28
  27. data/bin/commands/import.rb +3 -33
  28. data/bin/commands/last.rb +3 -36
  29. data/bin/commands/meanwhile.rb +3 -13
  30. data/bin/commands/note.rb +13 -52
  31. data/bin/commands/now.rb +15 -21
  32. data/bin/commands/on.rb +3 -4
  33. data/bin/commands/open.rb +3 -3
  34. data/bin/commands/recent.rb +3 -4
  35. data/bin/commands/redo.rb +6 -2
  36. data/bin/commands/reset.rb +19 -52
  37. data/bin/commands/rotate.rb +5 -36
  38. data/bin/commands/select.rb +23 -41
  39. data/bin/commands/show.rb +28 -74
  40. data/bin/commands/since.rb +3 -4
  41. data/bin/commands/tag.rb +4 -34
  42. data/bin/commands/tags.rb +5 -32
  43. data/bin/commands/today.rb +3 -4
  44. data/bin/commands/view.rb +36 -73
  45. data/bin/commands/yesterday.rb +4 -5
  46. data/bin/doing +150 -13
  47. data/docs/doc/Array.html +3 -502
  48. data/docs/doc/BooleanTermParser/Clause.html +1 -1
  49. data/docs/doc/BooleanTermParser/Operator.html +1 -1
  50. data/docs/doc/BooleanTermParser/Query.html +1 -1
  51. data/docs/doc/BooleanTermParser/QueryParser.html +1 -1
  52. data/docs/doc/BooleanTermParser/QueryTransformer.html +1 -1
  53. data/docs/doc/BooleanTermParser.html +1 -1
  54. data/docs/doc/Doing/Color.html +62 -56
  55. data/docs/doc/Doing/Completion.html +1 -1
  56. data/docs/doc/Doing/Configuration.html +35 -1
  57. data/docs/doc/Doing/Errors/DoingNoTraceError.html +1 -1
  58. data/docs/doc/Doing/Errors/DoingRuntimeError.html +1 -1
  59. data/docs/doc/Doing/Errors/DoingStandardError.html +1 -1
  60. data/docs/doc/Doing/Errors/EmptyInput.html +1 -1
  61. data/docs/doc/Doing/Errors/NoResults.html +1 -1
  62. data/docs/doc/Doing/Errors/PluginException.html +1 -1
  63. data/docs/doc/Doing/Errors/UserCancelled.html +1 -1
  64. data/docs/doc/Doing/Errors/WrongCommand.html +1 -1
  65. data/docs/doc/Doing/Errors.html +1 -1
  66. data/docs/doc/Doing/Hooks.html +1 -1
  67. data/docs/doc/Doing/Item.html +1 -1
  68. data/docs/doc/Doing/Items.html +2 -2
  69. data/docs/doc/Doing/LogAdapter.html +1 -1
  70. data/docs/doc/Doing/Note.html +2 -2
  71. data/docs/doc/Doing/Pager.html +1 -1
  72. data/docs/doc/Doing/Plugins.html +1 -1
  73. data/docs/doc/Doing/Prompt.html +1 -1
  74. data/docs/doc/Doing/Section.html +1 -1
  75. data/docs/doc/Doing/TemplateString.html +2 -2
  76. data/docs/doc/Doing/Types.html +41 -1
  77. data/docs/doc/Doing/Util/Backup.html +1 -1
  78. data/docs/doc/Doing/Util.html +1 -1
  79. data/docs/doc/Doing/WWID.html +10 -10
  80. data/docs/doc/Doing.html +3 -3
  81. data/docs/doc/FalseClass.html +35 -1
  82. data/docs/doc/GLI/Commands/Help.html +1 -1
  83. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
  84. data/docs/doc/GLI/Commands.html +1 -1
  85. data/docs/doc/GLI.html +1 -1
  86. data/docs/doc/Hash.html +1 -1
  87. data/docs/doc/Object.html +1 -1
  88. data/docs/doc/PhraseParser/Operator.html +1 -1
  89. data/docs/doc/PhraseParser/PhraseClause.html +1 -1
  90. data/docs/doc/PhraseParser/Query.html +1 -1
  91. data/docs/doc/PhraseParser/QueryParser.html +1 -1
  92. data/docs/doc/PhraseParser/QueryTransformer.html +1 -1
  93. data/docs/doc/PhraseParser/TermClause.html +1 -1
  94. data/docs/doc/PhraseParser.html +1 -1
  95. data/docs/doc/Status.html +1 -1
  96. data/docs/doc/String.html +287 -3155
  97. data/docs/doc/Symbol.html +40 -6
  98. data/docs/doc/Time.html +1 -1
  99. data/docs/doc/TrueClass.html +35 -1
  100. data/docs/doc/_index.html +5 -10
  101. data/docs/doc/class_list.html +1 -1
  102. data/docs/doc/file.README.html +2 -2
  103. data/docs/doc/index.html +2 -2
  104. data/docs/doc/method_list.html +278 -678
  105. data/docs/doc/top-level-namespace.html +2 -2
  106. data/doing.gemspec +1 -0
  107. data/doing.rdoc +297 -206
  108. data/lib/completion/_doing.zsh +32 -32
  109. data/lib/completion/doing.bash +30 -30
  110. data/lib/completion/doing.fish +87 -77
  111. data/lib/doing/array/array.rb +4 -0
  112. data/lib/doing/array/nested_hash.rb +17 -0
  113. data/lib/doing/{array.rb → array/tags.rb} +7 -25
  114. data/lib/doing/changelog/change.rb +26 -11
  115. data/lib/doing/changelog/changes.rb +37 -8
  116. data/lib/doing/changelog/version.rb +11 -3
  117. data/lib/doing/{array_chronify.rb → chronify/array.rb} +0 -0
  118. data/lib/doing/chronify/chronify.rb +5 -0
  119. data/lib/doing/{numeric_chronify.rb → chronify/numeric.rb} +0 -0
  120. data/lib/doing/{string_chronify.rb → chronify/string.rb} +0 -0
  121. data/lib/doing/colors.rb +115 -54
  122. data/lib/doing/completion/zsh_completion.rb +5 -0
  123. data/lib/doing/configuration.rb +9 -5
  124. data/lib/doing/good.rb +8 -0
  125. data/lib/doing/help_monkey_patch.rb +6 -5
  126. data/lib/doing/item.rb +5 -5
  127. data/lib/doing/items.rb +2 -2
  128. data/lib/doing/log_adapter.rb +35 -2
  129. data/lib/doing/normalize.rb +188 -0
  130. data/lib/doing/plugins/export/dayone_export.rb +1 -1
  131. data/lib/doing/plugins/export/html_export.rb +1 -1
  132. data/lib/doing/plugins/export/json_export.rb +1 -1
  133. data/lib/doing/plugins/export/markdown_export.rb +1 -1
  134. data/lib/doing/plugins/export/template_export.rb +3 -1
  135. data/lib/doing/prompt.rb +1 -3
  136. data/lib/doing/section.rb +1 -1
  137. data/lib/doing/string/highlight.rb +95 -0
  138. data/lib/doing/string/query.rb +129 -0
  139. data/lib/doing/string/string.rb +12 -0
  140. data/lib/doing/string/tags.rb +164 -0
  141. data/lib/doing/string/transform.rb +168 -0
  142. data/lib/doing/string/truncate.rb +75 -0
  143. data/lib/doing/string/url.rb +82 -0
  144. data/lib/doing/template_string.rb +0 -22
  145. data/lib/doing/types.rb +8 -0
  146. data/lib/doing/util.rb +13 -9
  147. data/lib/doing/version.rb +1 -1
  148. data/lib/doing/wwid.rb +54 -36
  149. data/lib/doing.rb +5 -6
  150. data/lib/examples/plugins/wiki_export/wiki_export.rb +1 -1
  151. data/lib/helpers/threaded_tests.rb +15 -2
  152. data/scripts/deploy.rb +107 -0
  153. data/scripts/runtests.sh +4 -0
  154. metadata +39 -8
  155. data/lib/doing/string.rb +0 -765
  156. data/lib/doing/symbol.rb +0 -28
data/bin/commands/show.rb CHANGED
@@ -18,69 +18,20 @@ command :show do |c|
18
18
  c.example 'doing show Ideas @doing --from "mon to fri"', desc: 'Show entries tagged @doing from the Ideas section added between monday and friday of the current week.'
19
19
  c.example 'doing show --interactive Later @doing', desc: 'Create a menu from entries from the Later section tagged @doing to perform batch actions'
20
20
 
21
- c.desc 'Tag filter, combine multiple tags with a comma. Use `--tag pick` for a menu of available tags. Wildcards allowed (*, ?). Added for compatibility with other commands'
22
- c.arg_name 'TAG'
23
- c.flag [:tag], type: TagArray
24
-
25
- c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
26
- c.arg_name 'QUERY'
27
- c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
28
-
29
- c.desc 'Tag boolean (AND,OR,NOT). Use PATTERN to parse + and - as booleans'
30
- c.arg_name 'BOOLEAN'
31
- c.flag %i[b bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
32
-
33
21
  c.desc 'Max count to show'
34
22
  c.arg_name 'MAX'
35
23
  c.flag %i[c count], default_value: 0, must_match: /^\d+$/, type: Integer
36
24
 
37
25
  c.desc 'Age (oldest|newest)'
38
26
  c.arg_name 'AGE'
39
- c.flag %i[a age], default_value: 'newest'
40
-
41
- c.desc 'Show entries older than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day'
42
- c.arg_name 'DATE_STRING'
43
- c.flag [:before], type: DateBeginString
44
-
45
- c.desc 'Show entries newer than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day'
46
- c.arg_name 'DATE_STRING'
47
- c.flag [:after], type: DateEndString
48
-
49
- c.desc %(
50
- Date range to show, or a single day to filter date on.
51
- Date range argument should be quoted. Date specifications can be natural language.
52
- To specify a range, use "to" or "through": `doing show --from "monday 8am to friday 5pm"`.
53
-
54
- If values are only time(s) (6am to noon) all dates will be included, but entries will be filtered
55
- by time of day.
56
- )
57
-
58
- c.arg_name 'DATE_OR_RANGE'
59
- c.flag [:from], type: DateRangeString
60
-
61
- c.desc 'Search filter, surround with slashes for regex (/query/), start with single quote for exact match ("\'query")'
62
- c.arg_name 'QUERY'
63
- c.flag [:search]
27
+ c.flag %i[a age], default_value: :newest, type: AgeSymbol
64
28
 
65
29
  c.desc "Highlight search matches in output. Only affects command line output"
66
30
  c.switch %i[h hilite], default_value: @settings.dig('search', 'highlight')
67
31
 
68
- # c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
69
- # c.switch [:fuzzy], default_value: false, negatable: false
70
-
71
- c.desc 'Force exact search string matching (case sensitive)'
72
- c.switch %i[x exact], default_value: @config.exact_match?, negatable: @config.exact_match?
73
-
74
- c.desc 'Show items that *don\'t* match search/tag/date filters'
75
- c.switch [:not], default_value: false, negatable: false
76
-
77
- c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
78
- c.arg_name 'TYPE'
79
- c.flag [:case], must_match: /^[csi]/, default_value: @settings.dig('search', 'case')
80
-
81
32
  c.desc 'Sort order (asc/desc)'
82
33
  c.arg_name 'ORDER'
83
- c.flag %i[s sort], must_match: REGEX_SORT_ORDER, default_value: 'asc'
34
+ c.flag %i[s sort], must_match: REGEX_SORT_ORDER, default_value: :asc, type: OrderSymbol
84
35
 
85
36
  c.desc 'Show time intervals on @done tasks'
86
37
  c.switch %i[t times], default_value: true, negatable: true
@@ -92,14 +43,13 @@ command :show do |c|
92
43
  c.switch [:totals], default_value: false, negatable: false
93
44
 
94
45
  c.desc 'Sort tags by (name|time)'
95
- default = 'time'
96
- default = @settings['tag_sort'] || 'name'
46
+ default = @settings['tag_sort'].normalize_tag_sort || :name
97
47
  c.arg_name 'KEY'
98
- c.flag [:tag_sort], must_match: /^(?:name|time)/i, default_value: default
48
+ c.flag [:tag_sort], must_match: REGEX_TAG_SORT, default_value: default, type: TagSortSymbol
99
49
 
100
50
  c.desc 'Tag sort direction (asc|desc)'
101
51
  c.arg_name 'DIRECTION'
102
- c.flag [:tag_order], must_match: REGEX_SORT_ORDER, default_value: 'asc'
52
+ c.flag [:tag_order], must_match: REGEX_SORT_ORDER, default_value: :asc, type: OrderSymbol
103
53
 
104
54
  c.desc 'Only show items with recorded time intervals'
105
55
  c.switch [:only_timed], default_value: false, negatable: false
@@ -121,9 +71,17 @@ command :show do |c|
121
71
  c.desc "Output to export format (#{Doing::Plugins.plugin_names(type: :export)})"
122
72
  c.arg_name 'FORMAT'
123
73
  c.flag %i[o output]
74
+
75
+ add_options(:search, c)
76
+ add_options(:tag_filter, c)
77
+ add_options(:date_filter, c)
78
+
124
79
  c.action do |global_options, options, args|
125
80
  options[:fuzzy] = false
126
- raise DoingRuntimeError, %(Invalid output type "#{options[:output]}") if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
81
+ if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
82
+ raise DoingRuntimeError, %(Invalid output type "#{options[:output]}")
83
+
84
+ end
127
85
 
128
86
  tag_filter = false
129
87
  tags = []
@@ -142,7 +100,7 @@ command :show do |c|
142
100
  else
143
101
  begin
144
102
  section = @wwid.guess_section(args[0])
145
- rescue WrongCommand => exception
103
+ rescue WrongCommand
146
104
  cmd = commands[:view]
147
105
  action = cmd.send(:get_action, nil)
148
106
  return action.call(global_options, options, args)
@@ -155,8 +113,8 @@ command :show do |c|
155
113
  if args.length.positive?
156
114
  args.each do |arg|
157
115
  arg.split(/,/).each do |tag|
158
- tags.push(tag.strip.sub(/^@/, ''))
159
- end
116
+ tags.push(tag.strip.sub(/^@/, ''))
117
+ end
160
118
  end
161
119
  end
162
120
  else
@@ -169,13 +127,11 @@ command :show do |c|
169
127
  options[:times] = true if options[:totals]
170
128
 
171
129
  template = @settings['templates'][options[:config_template]].deep_merge({
172
- 'wrap_width' => @settings['wrap_width'] || 0,
173
- 'date_format' => @settings['default_date_format'],
174
- 'order' => @settings['order'] || 'asc',
175
- 'tags_color' => @settings['tags_color']
176
- })
177
-
178
- options[:case] = options[:case].normalize_case
130
+ 'wrap_width' => @settings['wrap_width'] || 0,
131
+ 'date_format' => @settings['default_date_format'],
132
+ 'order' => @settings['order']&.normalize_order || :asc,
133
+ 'tags_color' => @settings['tags_color']
134
+ })
179
135
 
180
136
  if options[:search]
181
137
  search = options[:search]
@@ -188,7 +144,7 @@ command :show do |c|
188
144
  if tags.good?
189
145
  tag_filter = {
190
146
  'tags' => tags,
191
- 'bool' => options[:bool].normalize_bool
147
+ 'bool' => options[:bool]
192
148
  }
193
149
  end
194
150
 
@@ -198,32 +154,30 @@ command :show do |c|
198
154
  items = @wwid.filter_items([], opt: options)
199
155
 
200
156
  if options[:menu]
157
+ Doing.logger.benchmark(:menu, :start)
201
158
  tag = @wwid.choose_tag(section, items: items, include_all: true)
202
159
  raise UserCancelled unless tag
203
160
 
204
- # options[:bool] = :and unless tags.empty?
205
-
206
161
  tags = tag.split(/ +/).map { |t| t.strip.sub(/^@?/, '') } if tag =~ /^@/
207
162
  if tags.good?
208
163
  tag_filter = {
209
164
  'tags' => tags,
210
- 'bool' => options[:bool].normalize_bool
165
+ 'bool' => options[:bool]
211
166
  }
212
167
  options[:tag_filter] = tag_filter
213
168
  end
169
+ Doing.logger.benchmark(:menu, :finish)
214
170
  end
215
171
 
216
172
  options[:age] ||= :newest
217
173
 
218
174
  opt = options.clone
219
- opt[:age] = options[:age].normalize_age(:newest) if options[:age]
220
- opt[:sort_tags] = options[:tag_sort] =~ /^n/i
175
+ opt[:sort_tags] = options[:tag_sort]
221
176
  opt[:count] = options[:count].to_i
222
177
  opt[:highlight] = true
223
178
  opt[:hilite] = options[:hilite]
224
- opt[:order] = options[:sort].normalize_order
179
+ opt[:order] = options[:sort]
225
180
  opt[:tag] = nil
226
- opt[:tag_order] = options[:tag_order].normalize_order
227
181
  opt[:tags_color] = template['tags_color']
228
182
 
229
183
  Doing::Pager.page @wwid.list_section(opt, items: items)
@@ -21,10 +21,9 @@ command :since do |c|
21
21
  c.switch [:totals], default_value: false, negatable: false
22
22
 
23
23
  c.desc 'Sort tags by (name|time)'
24
- default = 'time'
25
- default = @settings['tag_sort'] || 'name'
24
+ default = @settings['tag_sort'].normalize_tag_sort || :name
26
25
  c.arg_name 'KEY'
27
- c.flag [:tag_sort], must_match: /^(?:name|time)$/i, default_value: default
26
+ c.flag [:tag_sort], must_match: REGEX_TAG_SORT, default_value: default, type: TagSortSymbol
28
27
 
29
28
  c.desc "Output to export format (#{Doing::Plugins.plugin_names(type: :export)})"
30
29
  c.arg_name 'FORMAT'
@@ -56,7 +55,7 @@ command :since do |c|
56
55
  Doing.logger.debug('Interpreter:', "date interpreted as #{start} through the current time")
57
56
 
58
57
  options[:times] = true if options[:totals]
59
- options[:sort_tags] = options[:tag_sort] =~ /^n/i
58
+ options[:sort_tags] = options[:tag_sort]
60
59
 
61
60
  Doing::Pager.page @wwid.list_date([start, finish], options[:section], options[:times], options[:output],
62
61
  { template: options[:template], config_template: options[:config_template], duration: options[:duration], totals: options[:totals], sort_tags: options[:sort_tags] }).chomp
data/bin/commands/tag.rb CHANGED
@@ -55,39 +55,12 @@ command :tag do |c|
55
55
  c.desc 'Autotag entries based on autotag configuration in ~/.config/doing/config.yml'
56
56
  c.switch %i[a autotag], negatable: false, default_value: false
57
57
 
58
- c.desc 'Tag the last X entries containing TAG.
59
- Separate multiple tags with comma (--tag=tag1,tag2), combine with --bool. Wildcards allowed (*, ?).'
60
- c.arg_name 'TAG'
61
- c.flag [:tag], type: TagArray
62
-
63
- c.desc 'Tag entries matching search filter, surround with slashes for regex (e.g. "/query.*/"), start with single quote for exact match ("\'query")'
64
- c.arg_name 'QUERY'
65
- c.flag [:search]
66
-
67
- c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
68
- c.arg_name 'QUERY'
69
- c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
70
-
71
- # c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
72
- # c.switch [:fuzzy], default_value: false, negatable: false
73
-
74
- c.desc 'Force exact search string matching (case sensitive)'
75
- c.switch %i[x exact], default_value: @config.exact_match?, negatable: @config.exact_match?
76
-
77
- c.desc 'Tag items that *don\'t* match search/tag filters'
78
- c.switch [:not], default_value: false, negatable: false
79
-
80
- c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
81
- c.arg_name 'TYPE'
82
- c.flag [:case], must_match: /^[csi]/, default_value: @settings.dig('search', 'case')
83
-
84
- c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans'
85
- c.arg_name 'BOOLEAN'
86
- c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
87
-
88
58
  c.desc 'Select item(s) to tag from a menu of matching entries'
89
59
  c.switch %i[i interactive], negatable: false, default_value: false
90
60
 
61
+ add_options(:search, c)
62
+ add_options(:tag_filter, c)
63
+
91
64
  c.action do |_global_options, options, args|
92
65
  options[:fuzzy] = false
93
66
  # raise MissingArgument, 'You must specify at least one tag' if args.empty? && !options[:autotag]
@@ -130,9 +103,6 @@ command :tag do |c|
130
103
  count = options[:count].to_i
131
104
  end
132
105
 
133
- options[:case] ||= :smart
134
- options[:case] = options[:case].normalize_case
135
-
136
106
  if options[:search]
137
107
  search = options[:search]
138
108
  search.sub!(/^'?/, "'") if options[:exact]
@@ -143,7 +113,7 @@ command :tag do |c|
143
113
  options[:section] = section
144
114
  options[:tag] = search_tags
145
115
  options[:tags] = tags
146
- options[:tag_bool] = options[:bool].normalize_bool
116
+ options[:tag_bool] = options[:bool]
147
117
 
148
118
  if count.zero? && !options[:force]
149
119
  matches = @wwid.filter_items([], opt: options).count
data/bin/commands/tags.rb CHANGED
@@ -18,41 +18,14 @@ command :tags do |c|
18
18
 
19
19
  c.desc 'Sort order (asc/desc)'
20
20
  c.arg_name 'ORDER'
21
- c.flag %i[o order], must_match: REGEX_SORT_ORDER, default_value: 'asc'
22
-
23
- c.desc 'Get tags for entries matching tags. Combine multiple tags with a comma. Wildcards allowed (*, ?)'
24
- c.arg_name 'TAG'
25
- c.flag [:tag]
26
-
27
- c.desc 'Get tags for items matching search. Surround with
28
- slashes for regex (e.g. "/query/"), start with a single quote for exact match ("\'query").'
29
- c.arg_name 'QUERY'
30
- c.flag [:search]
31
-
32
- c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
33
- c.arg_name 'QUERY'
34
- c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
35
-
36
- # c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
37
- # c.switch [:fuzzy], default_value: false, negatable: false
38
-
39
- c.desc 'Force exact search string matching (case sensitive)'
40
- c.switch %i[x exact], default_value: @config.exact_match?, negatable: @config.exact_match?
41
-
42
- c.desc 'Get tags from items that *don\'t* match search/tag filters'
43
- c.switch [:not], default_value: false, negatable: false
44
-
45
- c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
46
- c.arg_name 'TYPE'
47
- c.flag [:case], must_match: /^[csi]/, default_value: @settings.dig('search', 'case')
48
-
49
- c.desc 'Boolean used to combine multiple tags. Use PATTERN to parse + and - as booleans'
50
- c.arg_name 'BOOLEAN'
51
- c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
21
+ c.flag %i[o order], must_match: REGEX_SORT_ORDER, default_value: :asc, type: OrderSymbol
52
22
 
53
23
  c.desc 'Select items to scan from a menu of matching entries'
54
24
  c.switch %i[i interactive], negatable: false, default_value: false
55
25
 
26
+ add_options(:search, c)
27
+ add_options(:tag_filter, c)
28
+
56
29
  c.action do |_global, options, args|
57
30
  section = @wwid.guess_section(options[:section]) || options[:section].cap_first
58
31
  options[:count] = args.count.positive? ? args[0].to_i : 0
@@ -78,7 +51,7 @@ command :tags do |c|
78
51
  tags = tags.sort_by { |tag, count| count }
79
52
  end
80
53
 
81
- tags.reverse! if options[:order].normalize_order == 'desc'
54
+ tags.reverse! if options[:order] == :desc
82
55
 
83
56
  if options[:counts]
84
57
  tags.each { |t, c| puts "#{t} (#{c})" }
@@ -22,10 +22,9 @@ command :today do |c|
22
22
  c.switch [:totals], default_value: false, negatable: false
23
23
 
24
24
  c.desc 'Sort tags by (name|time)'
25
- default = 'time'
26
- default = @settings['tag_sort'] || 'name'
25
+ default = @settings['tag_sort'].normalize_tag_sort || :name
27
26
  c.arg_name 'KEY'
28
- c.flag [:tag_sort], must_match: /^(?:name|time)$/i, default_value: default
27
+ c.flag [:tag_sort], must_match: REGEX_TAG_SORT, default_value: default, type: TagSortSymbol
29
28
 
30
29
  c.desc "Output to export format (#{Doing::Plugins.plugin_names(type: :export)})"
31
30
  c.arg_name 'FORMAT'
@@ -57,7 +56,7 @@ command :today do |c|
57
56
  raise DoingRuntimeError, %(Invalid output type "#{options[:output]}") if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
58
57
 
59
58
  options[:times] = true if options[:totals]
60
- options[:sort_tags] = options[:tag_sort] =~ /^n/i
59
+ options[:sort_tags] = options[:tag_sort]
61
60
  filter_options = %i[after before duration from section sort_tags totals template config_template].each_with_object({}) { |k, hsh| hsh[k] = options[k] }
62
61
 
63
62
  Doing::Pager.page @wwid.today(options[:times], options[:output], filter_options).chomp
data/bin/commands/view.rb CHANGED
@@ -21,7 +21,7 @@ command :view do |c|
21
21
 
22
22
  c.desc 'Age (oldest|newest)'
23
23
  c.arg_name 'AGE'
24
- c.flag %i[age], default_value: 'newest'
24
+ c.flag %i[age], default_value: :newest, type: AgeSymbol
25
25
 
26
26
  c.desc 'Show time intervals on @done tasks'
27
27
  c.switch %i[t times], default_value: true, negatable: true
@@ -35,64 +35,16 @@ command :view do |c|
35
35
  c.desc 'Include colors in output'
36
36
  c.switch [:color], default_value: true, negatable: true
37
37
 
38
- c.desc 'Tag filter, combine multiple tags with a comma. Wildcards allowed (*, ?)'
39
- c.arg_name 'TAG'
40
- c.flag [:tag]
41
-
42
- c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
43
- c.arg_name 'QUERY'
44
- c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
45
-
46
- c.desc 'Tag boolean (AND,OR,NOT). Use PATTERN to parse + and - as booleans'
47
- c.arg_name 'BOOLEAN'
48
- c.flag %i[b bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
49
-
50
- c.desc 'Search filter, surround with slashes for regex (/query/), start with single quote for exact match ("\'query")'
51
- c.arg_name 'QUERY'
52
- c.flag [:search]
53
-
54
38
  c.desc "Highlight search matches in output. Only affects command line output"
55
39
  c.switch %i[h hilite], default_value: @settings.dig('search', 'highlight')
56
40
 
57
- # c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
58
- # c.switch [:fuzzy], default_value: false, negatable: false
59
-
60
- c.desc 'Force exact search string matching (case sensitive)'
61
- c.switch %i[x exact], default_value: @config.exact_match?, negatable: @config.exact_match?
62
-
63
- c.desc 'Show items that *don\'t* match search string'
64
- c.switch [:not], default_value: false, negatable: false
65
-
66
- c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
67
- c.arg_name 'TYPE'
68
- c.flag [:case], must_match: /^[csi]/, default_value: @settings.dig('search', 'case')
69
-
70
41
  c.desc 'Sort tags by (name|time)'
71
42
  c.arg_name 'KEY'
72
- c.flag [:tag_sort], must_match: /^(?:name|time)$/i
43
+ c.flag [:tag_sort], must_match: REGEX_TAG_SORT, type: TagSortSymbol
73
44
 
74
45
  c.desc 'Tag sort direction (asc|desc)'
75
46
  c.arg_name 'DIRECTION'
76
- c.flag [:tag_order], must_match: REGEX_SORT_ORDER
77
-
78
- c.desc 'View entries older than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day'
79
- c.arg_name 'DATE_STRING'
80
- c.flag [:before], type: DateBeginString
81
-
82
- c.desc 'View entries newer than date. If this is only a time (8am, 1:30pm, 15:00), all dates will be included, but entries will be filtered by time of day'
83
- c.arg_name 'DATE_STRING'
84
- c.flag [:after], type: DateEndString
85
-
86
- c.desc %(
87
- Date range to show, or a single day to filter date on.
88
- Date range argument should be quoted. Date specifications can be natural language.
89
- To specify a range, use "to" or "through": `doing view --from "monday 8am to friday 5pm" view_name`.
90
-
91
- If values are only time(s) (6am to noon) all dates will be included, but entries will be filtered
92
- by time of day.
93
- )
94
- c.arg_name 'DATE_OR_RANGE'
95
- c.flag [:from], type: DateRangeString
47
+ c.flag [:tag_order], must_match: REGEX_SORT_ORDER, type: OrderSymbol
96
48
 
97
49
  c.desc 'Only show items with recorded time intervals (override view settings)'
98
50
  c.switch [:only_timed], default_value: false, negatable: false
@@ -100,9 +52,16 @@ command :view do |c|
100
52
  c.desc 'Select from a menu of matching entries to perform additional operations'
101
53
  c.switch %i[i interactive], negatable: false, default_value: false
102
54
 
55
+ add_options(:search, c)
56
+ add_options(:tag_filter, c)
57
+ add_options(:date_filter, c)
58
+
103
59
  c.action do |global_options, options, args|
104
60
  options[:fuzzy] = false
105
- raise DoingRuntimeError, %(Invalid output type "#{options[:output]}") if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
61
+ if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
62
+ raise DoingRuntimeError, %(Invalid output type "#{options[:output]}")
63
+
64
+ end
106
65
 
107
66
  raise InvalidArgument, '--tag and --search can not be used together' if options[:tag] && options[:search]
108
67
 
@@ -111,20 +70,20 @@ command :view do |c|
111
70
  else
112
71
  begin
113
72
  @wwid.guess_view(args[0])
114
- rescue WrongCommand => exception
73
+ rescue WrongCommand
115
74
  cmd = commands[:show]
116
- options[:sort] = 'asc'
117
- options[:tag_order] = 'asc'
75
+ options[:sort] = :asc
76
+ options[:tag_order] = :asc
118
77
  action = cmd.send(:get_action, nil)
119
78
  return action.call(global_options, options, args)
120
79
  end
121
80
  end
122
81
 
123
- if options[:section]
124
- section = @wwid.guess_section(options[:section]) || options[:section].cap_first
125
- else
126
- section = @settings['current_section']
127
- end
82
+ section = if options[:section]
83
+ @wwid.guess_section(options[:section]) || options[:section].cap_first
84
+ else
85
+ @settings['current_section']
86
+ end
128
87
 
129
88
  view = @wwid.get_view(title)
130
89
 
@@ -143,7 +102,7 @@ command :view do |c|
143
102
  tag_filter = false
144
103
  if options[:tag]
145
104
  tag_filter = { 'tags' => [], 'bool' => 'OR' }
146
- bool = options[:bool].normalize_bool
105
+ bool = options[:bool]
147
106
  tag_filter['bool'] = bool
148
107
  tag_filter['tags'] = if bool == :pattern
149
108
  options[:tag]
@@ -164,41 +123,45 @@ command :view do |c|
164
123
  # If the -o/--output flag was specified, override any default in the view template
165
124
  options[:output] ||= view.key?('output_format') ? view['output_format'] : 'template'
166
125
 
167
- count = options[:count] ? options[:count] : view.key?('count') ? view['count'] : 10
126
+ count = if options[:count]
127
+ options[:count]
128
+ elsif view.key?('count')
129
+ view['count']
130
+ else
131
+ 10
132
+ end
168
133
 
169
134
  section = if options[:section]
170
135
  section
171
136
  else
172
137
  view['section'] || @settings['current_section']
173
138
  end
174
- order = view['order']&.normalize_order || 'asc'
139
+ order = if view.key?('order')
140
+ view['order'].normalize_order
141
+ else
142
+ :asc
143
+ end
175
144
 
176
145
  totals = if options[:totals]
177
146
  true
178
147
  else
179
148
  view['totals'] || false
180
149
  end
181
- tag_order = if options[:tag_order]
182
- options[:tag_order].normalize_order
183
- else
184
- view['tag_order']&.normalize_order || 'asc'
185
- end
150
+ tag_order = options[:tag_order] || view['tag_order']&.normalize_order || :asc
186
151
 
187
152
  options[:times] = true if totals
188
153
  output_format = options[:output]&.downcase || 'template'
189
154
 
190
155
  options[:sort_tags] = if options[:tag_sort]
191
- options[:tag_sort] =~ /^n/i ? true : false
156
+ options[:tag_sort]
192
157
  elsif view.key?('tag_sort')
193
- view['tag_sort'] =~ /^n/i ? true : false
158
+ view['tag_sort'].normalize_tag_sort
194
159
  else
195
160
  false
196
161
  end
197
162
 
198
163
  %w[before after from duration].each { |k| options[k.to_sym] = view[k] if view.key?(k) && !options[k.to_sym] }
199
164
 
200
- options[:case] = options[:case].normalize_case
201
-
202
165
  search = nil
203
166
 
204
167
  if options[:search]
@@ -209,7 +172,7 @@ command :view do |c|
209
172
  options[:age] ||= :newest
210
173
 
211
174
  opts = options.clone
212
- opts[:age] = options[:age].normalize_age(:newest)
175
+ opts[:age] = options[:age]
213
176
  opts[:count] = count
214
177
  opts[:format] = date_format
215
178
  opts[:highlight] = options[:color]
@@ -33,9 +33,9 @@ command :yesterday do |c|
33
33
  c.switch [:totals], default_value: false, negatable: false
34
34
 
35
35
  c.desc 'Sort tags by (name|time)'
36
- default = @settings['tag_sort'] || 'name'
36
+ default = @settings['tag_sort'].normalize_tag_sort || :name
37
37
  c.arg_name 'KEY'
38
- c.flag [:tag_sort], must_match: /^(?:name|time)$/i, default_value: default
38
+ c.flag [:tag_sort], must_match: REGEX_TAG_SORT, default_value: default, type: TagSortSymbol
39
39
 
40
40
  c.desc 'View entries before specified time (e.g. 8am, 12:30pm, 15:00)'
41
41
  c.arg_name 'TIME_STRING'
@@ -51,12 +51,12 @@ command :yesterday do |c|
51
51
 
52
52
  c.desc 'Tag sort direction (asc|desc)'
53
53
  c.arg_name 'DIRECTION'
54
- c.flag [:tag_order], must_match: REGEX_SORT_ORDER, default_value: 'asc'
54
+ c.flag [:tag_order], must_match: REGEX_SORT_ORDER, default_value: :asc, type: OrderSymbol
55
55
 
56
56
  c.action do |_global_options, options, _args|
57
57
  raise DoingRuntimeError, %(Invalid output type "#{options[:output]}") if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
58
58
 
59
- options[:sort_tags] = options[:tag_sort] =~ /^n/i
59
+ options[:sort_tags] = options[:tag_sort]
60
60
 
61
61
  if options[:from]
62
62
  options[:from] = options[:from].split(/#{REGEX_RANGE_INDICATOR}/).map do |time|
@@ -65,7 +65,6 @@ command :yesterday do |c|
65
65
  end
66
66
 
67
67
  opt = options.clone
68
- opt[:tag_order] = options[:tag_order].normalize_order
69
68
  opt[:order] = @settings.dig('templates', options[:config_template], 'order')
70
69
 
71
70
  Doing::Pager.page @wwid.yesterday(options[:section], options[:times], options[:output], opt).chomp