doing 2.1.39 → 2.1.40

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +1 -1
  5. data/bin/commands/config.rb +43 -34
  6. data/bin/commands/done.rb +1 -18
  7. data/bin/commands/finish.rb +30 -25
  8. data/bin/commands/grep.rb +3 -14
  9. data/bin/commands/last.rb +2 -8
  10. data/bin/commands/meanwhile.rb +13 -6
  11. data/bin/commands/on.rb +3 -16
  12. data/bin/commands/recent.rb +2 -8
  13. data/bin/commands/reset.rb +24 -1
  14. data/bin/commands/select.rb +1 -1
  15. data/bin/commands/show.rb +6 -17
  16. data/bin/commands/since.rb +1 -12
  17. data/bin/commands/today.rb +2 -13
  18. data/bin/commands/view.rb +1 -1
  19. data/bin/commands/yesterday.rb +2 -13
  20. data/bin/doing +15 -8
  21. data/docs/doc/Array.html +1 -1
  22. data/docs/doc/BooleanTermParser/Clause.html +1 -1
  23. data/docs/doc/BooleanTermParser/Operator.html +1 -1
  24. data/docs/doc/BooleanTermParser/Query.html +1 -1
  25. data/docs/doc/BooleanTermParser/QueryParser.html +1 -1
  26. data/docs/doc/BooleanTermParser/QueryTransformer.html +1 -1
  27. data/docs/doc/BooleanTermParser.html +1 -1
  28. data/docs/doc/Doing/Color.html +166 -20
  29. data/docs/doc/Doing/Completion.html +1 -1
  30. data/docs/doc/Doing/Configuration.html +1 -1
  31. data/docs/doc/Doing/Errors/DoingNoTraceError.html +7 -3
  32. data/docs/doc/Doing/Errors/DoingRuntimeError.html +7 -3
  33. data/docs/doc/Doing/Errors/DoingStandardError.html +1 -1
  34. data/docs/doc/Doing/Errors/EmptyInput.html +10 -2
  35. data/docs/doc/Doing/Errors/HistoryLimitError.html +194 -0
  36. data/docs/doc/Doing/Errors/InvalidPlugin.html +194 -0
  37. data/docs/doc/Doing/Errors/MissingBackupFile.html +194 -0
  38. data/docs/doc/Doing/Errors/NoResults.html +10 -2
  39. data/docs/doc/Doing/Errors/PluginException.html +1 -1
  40. data/docs/doc/Doing/Errors/UserCancelled.html +10 -2
  41. data/docs/doc/Doing/Errors/WrongCommand.html +10 -2
  42. data/docs/doc/Doing/Errors.html +9 -9
  43. data/docs/doc/Doing/Hooks.html +1 -1
  44. data/docs/doc/Doing/Item.html +90 -1615
  45. data/docs/doc/Doing/Items.html +121 -5
  46. data/docs/doc/Doing/Logger.html +1 -1
  47. data/docs/doc/Doing/Note.html +1 -1
  48. data/docs/doc/Doing/Pager.html +1 -1
  49. data/docs/doc/Doing/Plugins.html +1 -1
  50. data/docs/doc/Doing/Prompt.html +2 -2
  51. data/docs/doc/Doing/Section.html +1 -1
  52. data/docs/doc/Doing/TemplateString.html +2 -2
  53. data/docs/doc/Doing/Types.html +1 -1
  54. data/docs/doc/Doing/Util/Backup.html +5 -5
  55. data/docs/doc/Doing/Util.html +1 -1
  56. data/docs/doc/Doing/WWID.html +197 -4033
  57. data/docs/doc/Doing.html +2 -2
  58. data/docs/doc/FalseClass.html +1 -1
  59. data/docs/doc/GLI/Commands/Help.html +1 -1
  60. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
  61. data/docs/doc/GLI/Commands.html +1 -1
  62. data/docs/doc/GLI.html +1 -1
  63. data/docs/doc/Hash.html +1 -1
  64. data/docs/doc/Object.html +1 -1
  65. data/docs/doc/PhraseParser/Operator.html +1 -1
  66. data/docs/doc/PhraseParser/PhraseClause.html +1 -1
  67. data/docs/doc/PhraseParser/Query.html +1 -1
  68. data/docs/doc/PhraseParser/QueryParser.html +1 -1
  69. data/docs/doc/PhraseParser/QueryTransformer.html +1 -1
  70. data/docs/doc/PhraseParser/TermClause.html +1 -1
  71. data/docs/doc/PhraseParser.html +1 -1
  72. data/docs/doc/Status.html +1 -1
  73. data/docs/doc/String.html +1 -1
  74. data/docs/doc/Symbol.html +1 -1
  75. data/docs/doc/Time.html +1 -1
  76. data/docs/doc/TrueClass.html +1 -1
  77. data/docs/doc/_index.html +26 -5
  78. data/docs/doc/class_list.html +1 -1
  79. data/docs/doc/file.README.html +2 -2
  80. data/docs/doc/index.html +2 -2
  81. data/docs/doc/method_list.html +293 -773
  82. data/docs/doc/top-level-namespace.html +3 -3
  83. data/docs/index.md +1 -1
  84. data/doing.rdoc +49 -7
  85. data/lib/completion/_doing.zsh +5 -5
  86. data/lib/completion/doing.bash +8 -8
  87. data/lib/completion/doing.fish +7 -2
  88. data/lib/doing/add_options.rb +31 -1
  89. data/lib/doing/chronify/array.rb +64 -22
  90. data/lib/doing/colors.rb +77 -30
  91. data/lib/doing/completion.rb +4 -5
  92. data/lib/doing/errors.rb +51 -35
  93. data/lib/doing/hooks.rb +3 -3
  94. data/lib/doing/item/dates.rb +112 -0
  95. data/lib/doing/item/query.rb +433 -0
  96. data/lib/doing/item/state.rb +59 -0
  97. data/lib/doing/item/tags.rb +87 -0
  98. data/lib/doing/item.rb +6 -667
  99. data/lib/doing/items.rb +38 -13
  100. data/lib/doing/plugin_manager.rb +3 -3
  101. data/lib/doing/plugins/export/template_export.rb +4 -4
  102. data/lib/doing/plugins/import/cal_to_json.scpt +0 -0
  103. data/lib/doing/util_backup.rb +6 -8
  104. data/lib/doing/version.rb +1 -1
  105. data/lib/doing/wwid/display.rb +399 -0
  106. data/lib/doing/wwid/editor.rb +214 -0
  107. data/lib/doing/wwid/filetools.rb +186 -0
  108. data/lib/doing/wwid/filter.rb +218 -0
  109. data/lib/doing/wwid/guess.rb +87 -0
  110. data/lib/doing/wwid/interactive.rb +385 -0
  111. data/lib/doing/wwid/modify.rb +618 -0
  112. data/lib/doing/wwid/tags.rb +54 -0
  113. data/lib/doing/wwid/timers.rb +345 -0
  114. data/lib/doing/wwid/wwidutil.rb +104 -0
  115. data/lib/doing/wwid.rb +31 -2317
  116. metadata +19 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 02eff91d6af3da80b7a9f728c517dbb34c4a308d74f7b722a45c0999e3d9cec8
4
- data.tar.gz: edb57cbb3c4c3c6a6a598f3e16a6a8d23dcb2a466635b68e0ecd359db207f8f3
3
+ metadata.gz: 8bd8641c5280331189462c44f52c5bc4437c77610072d3c142cf7a56a6e75be6
4
+ data.tar.gz: 40a53127983360a0b7720dd4b27c71d5b783d23d22790bfbcdc8b7f49556ce2d
5
5
  SHA512:
6
- metadata.gz: f1c66ccce28e225692c0e3fbbb46a74ba0c5ebd5f8043c79f2a938948cbb5c8a65dc6a7a80a19901bf5633441e01c083a7d1ab6e589cb1bfd5542f4aa6d48b5d
7
- data.tar.gz: 53560dc1b93d92e67e9bc3a1803da23aaf167041857301126b4ae8b2eff851b75c45b36386cfad34922e22cbc2acc1e689b3c7b635f46dfd0fe5833d7ea24d4e
6
+ metadata.gz: 4d47d3a88086dd579b3b0f1f37a7e17890dd5969487bebd00f92f6194b6281987056b792ece88718c1a4da35803a9748d7cddb7e72f5c908fb0056e299ff9ef3
7
+ data.tar.gz: b2ba0a2c7a3b21e09c1da73c959895fb4dff4f72244cc5c6f855a1d44668d8b5620292881bbb47a7c1896c0fb68430fe33d1e5509a657c5c1fd870c1f5211028
data/CHANGELOG.md CHANGED
@@ -1,3 +1,26 @@
1
+ ### 2.1.40
2
+
3
+ 2022-03-14 19:56
4
+
5
+ #### NEW
6
+
7
+ - `doing finish` accepts `--from` ranges to update both start and finish dates
8
+ - `doing finish` allows `--back` and `--took` to be used together
9
+ - `doing finish` allows `--search` and `--tag` to be used together
10
+ - `doing finish --from 'DATE to DATE'` allows you to set a new start and end time with a single range string
11
+ - `doing reset --from 'DATE to DATE'` allows you to reset an entry's start time and update or add @done time
12
+ - `doing reset` accepts a `--took Xm` flag to change the finish time
13
+ - `--output FORMAT` option for all display commands, including last, recent and today
14
+
15
+ #### IMPROVED
16
+
17
+ - Code refactoring, split up WWID class
18
+ - Better diff method available to hooks to see what changed
19
+
20
+ #### FIXED
21
+
22
+ - Search highlighting was being skipped in all cases
23
+
1
24
  ### 2.1.39
2
25
 
3
26
  2022-03-13 04:32
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- doing (2.1.39)
4
+ doing (2.1.40)
5
5
  chronic (~> 0.10, >= 0.10.2)
6
6
  deep_merge (~> 1.2, >= 1.2.1)
7
7
  gli (~> 2.20, >= 2.20.1)
data/README.md CHANGED
@@ -8,7 +8,7 @@ _If you're one of the rare people like me who find this useful, feel free to
8
8
 
9
9
  <!--README-->
10
10
 
11
- The current version of `doing` is <!--VER-->2.1.38<!--END VER-->.
11
+ The current version of `doing` is <!--VER-->2.1.39<!--END VER-->.
12
12
 
13
13
  Find all of the documentation in the [doing wiki][wiki].
14
14
 
@@ -29,7 +29,7 @@ command :config do |c|
29
29
  c.long_desc 'Config files are listed in order of precedence (if there are multiple configs detected).
30
30
  Values defined in the top item in the list will override values in configutations below it.'
31
31
  c.command :list do |list|
32
- list.action do |global, options, args|
32
+ list.action do
33
33
  puts Doing.config.additional_configs.join("\n")
34
34
  puts Doing.config.config_file
35
35
  end
@@ -54,7 +54,8 @@ command :config do |c|
54
54
  edit.arg_name 'BUNDLE_ID'
55
55
  edit.flag %i[b bundle_id]
56
56
 
57
- edit.desc "Use the config editor defined in ~/.config/doing/config.yml (#{Doing.setting('editors.config', 'editors.config not set')})"
57
+ default_editor = Doing.setting('editors.config', 'editors.config not set')
58
+ edit.desc "Use the config editor defined in ~/.config/doing/config.yml (#{default_editor})"
58
59
  edit.switch %i[x default], negatable: false
59
60
  end
60
61
 
@@ -68,10 +69,11 @@ command :config do |c|
68
69
  end
69
70
  action = cmd.send(:get_action, nil)
70
71
  action.call(global, options, args)
71
- Doing.logger.warn('Deprecated:', '--dump and --update are deprecated,
72
- use `doing config get` and `doing config update`')
73
- Doing.logger.output_results
74
- return
72
+
73
+ raise DoingNoTraceError.new('--dump and --update are deprecated,
74
+ use `doing config get` and `doing config update`',
75
+ level: :warn,
76
+ topic: 'Deprecated:')
75
77
  end
76
78
 
77
79
  config_file = Doing.config.choose_config
@@ -79,14 +81,12 @@ command :config do |c|
79
81
  if `uname` =~ /Darwin/
80
82
  if options[:default]
81
83
  editor = Doing::Util.find_default_editor('config')
82
- if editor
83
- if Doing::Util.exec_available(editor.split(/ /).first)
84
- system %(#{editor} "#{config_file}")
85
- else
86
- `open -a "#{editor}" "#{config_file}"`
87
- end
84
+ raise InvalidArgument, 'No viable editor found in config or environment.' unless editor
85
+
86
+ if Doing::Util.exec_available(editor.split(/ /).first)
87
+ system %(#{editor} "#{config_file}")
88
88
  else
89
- raise InvalidArgument, 'No viable editor found in config or environment.'
89
+ `open -a "#{editor}" "#{config_file}"`
90
90
  end
91
91
  elsif options[:app] || options[:bundle_id]
92
92
  if options[:app]
@@ -107,7 +107,10 @@ command :config do |c|
107
107
  end
108
108
  else
109
109
  editor = options[:editor] || Doing::Util.default_editor
110
- raise MissingEditor, 'No EDITOR variable defined in environment' unless editor && Doing::Util.exec_available(editor.split(/ /).first)
110
+ unless editor && Doing::Util.exec_available(editor.split(/ /).first)
111
+ raise MissingEditor, 'No EDITOR variable defined in environment'
112
+
113
+ end
111
114
 
112
115
  system %(#{editor} "#{config_file}")
113
116
  end
@@ -117,8 +120,8 @@ command :config do |c|
117
120
  # @@config.update @@config.refresh
118
121
  c.desc 'Update default config file, adding any missing keys'
119
122
  c.command %i[update refresh] do |update|
120
- update.action do |_global, options, args|
121
- Doing.config.configure({rewrite: true, ignore_local: true})
123
+ update.action do
124
+ Doing.config.configure({ rewrite: true, ignore_local: true })
122
125
  Doing.logger.warn('Config:', 'config refreshed')
123
126
  end
124
127
  end
@@ -126,7 +129,7 @@ command :config do |c|
126
129
  # @@config.undo
127
130
  c.desc 'Undo the last change to a config file'
128
131
  c.command :undo do |undo|
129
- undo.action do |_global, options, args|
132
+ undo.action do
130
133
  config_file = Doing.config.choose_config
131
134
  Doing::Util::Backup.restore_last_backup(config_file, count: 1)
132
135
  end
@@ -137,22 +140,24 @@ command :config do |c|
137
140
  c.arg 'KEY_PATH'
138
141
  c.command %i[get dump] do |dump|
139
142
  dump.example 'doing config get', desc: 'Output the entire configuration'
140
- dump.example 'doing config get timer_format --output raw', desc: 'Output the value of timer_format as a plain string'
141
- dump.example 'doing config get doing_file', desc: 'Output the value of the doing_file setting, respecting local configurations'
142
- dump.example 'doing config get -o json plug.plugpath', desc: 'Key path is fuzzy matched: output the value of plugins.plugin_path as JSON'
143
+ dump.example 'doing config get timer_format --output raw',
144
+ desc: 'Output the value of timer_format as a plain string'
145
+ dump.example 'doing config get doing_file',
146
+ desc: 'Output the value of the doing_file setting, respecting local configurations'
147
+ dump.example 'doing config get -o json plug.plugpath',
148
+ desc: 'Key path is fuzzy matched: output the value of plugins.plugin_path as JSON'
143
149
 
144
150
  dump.desc 'Format for output (json|yaml|raw)'
145
151
  dump.arg_name 'FORMAT'
146
152
  dump.flag %i[o output], default_value: 'yaml', must_match: /^(?:y(?:aml)?|j(?:son)?|r(?:aw)?)$/
147
153
 
148
154
  dump.action do |_global, options, args|
149
-
150
155
  keypath = args.join('.')
151
156
  cfg = Doing.config.value_for_key(keypath)
152
157
  real_path = Doing.config.resolve_key_path(keypath)
153
158
 
154
159
  if cfg
155
- val = cfg.map {|k, v| v }[0]
160
+ val = cfg.map { |_, v| v }[0]
156
161
  if real_path.count.positive?
157
162
  nested_cfg = {}
158
163
  nested_cfg.deep_set(real_path, val)
@@ -161,13 +166,15 @@ command :config do |c|
161
166
  end
162
167
 
163
168
  if options[:output] =~ /^r/
164
- if val.is_a?(Hash)
165
- $stdout.puts YAML.dump(val)
166
- elsif val.is_a?(Array)
167
- $stdout.puts val.join(', ')
168
- else
169
- $stdout.puts val.to_s
170
- end
169
+
170
+ $stdout.puts case val
171
+ when Hash
172
+ YAML.dump(val)
173
+ when Array
174
+ val.join(', ')
175
+ else
176
+ val.to_s
177
+ end
171
178
  else
172
179
  $stdout.puts case options[:output]
173
180
  when /^j/
@@ -188,13 +195,14 @@ command :config do |c|
188
195
  c.arg 'KEY VALUE'
189
196
  c.command :set do |set|
190
197
  set.example 'doing config set timer_format human', desc: 'Set the value of timer_format to "human"'
191
- set.example 'doing config set plug.plugpath ~/my_plugins', desc: 'Key path is fuzzy matched: set the value of plugins.plugin_path'
198
+ set.example 'doing config set plug.plugpath ~/my_plugins',
199
+ desc: 'Key path is fuzzy matched: set the value of plugins.plugin_path'
192
200
 
193
201
  set.desc 'Delete specified key'
194
202
  set.switch %i[r remove], negatable: false
195
203
 
196
204
  set.desc 'Force update to .doingrc in the current directory'
197
- set.switch %[local], negatable: false
205
+ set.switch %i[local], negatable: false
198
206
 
199
207
  set.action do |_global, options, args|
200
208
  if args.count < 2 && !options[:remove]
@@ -209,10 +217,11 @@ command :config do |c|
209
217
  old_type = old_value&.class.to_s || nil
210
218
 
211
219
  if old_value.is_a?(Hash) && !options[:remove]
212
- Doing.logger.log_now(:warn, 'Config:', "Config key must point to a single value, #{real_path.join('.').boldwhite} is a mapping")
220
+ Doing.logger.log_now(:warn, 'Config:', ['Config key must point to a single value, ',
221
+ "#{real_path.join('.').boldwhite} is a mapping"].join(' '))
213
222
  didyou = 'Did you mean:'
214
- old_value.keys.each do |k|
215
- Doing.logger.log_now(:warn, "#{didyou}", "#{keypath}.#{k}?")
223
+ old_value.each_key do |k|
224
+ Doing.logger.log_now(:warn, didyou, "#{keypath}.#{k}?")
216
225
  didyou = '..........or:'
217
226
  end
218
227
  raise InvalidArgument, 'Config value is a mapping, can not be set to a single value'
data/bin/commands/done.rb CHANGED
@@ -19,24 +19,6 @@ command %i[done did] do |c|
19
19
  c.desc 'Immediately archive the entry'
20
20
  c.switch %i[a archive], negatable: false, default_value: false
21
21
 
22
- c.desc %(Set finish date to specific date/time (natural langauge parsed, e.g. --at=1:30pm).
23
- Used with --took, backdates start date)
24
- c.arg_name 'DATE_STRING'
25
- c.flag %i[at finished], type: DateEndString
26
-
27
- c.desc %(
28
- Start and end times as a date/time range `doing done --from "1am to 8am"`.
29
- Overrides other date flags.
30
- )
31
- c.arg_name 'TIME_RANGE'
32
- c.flag [:from], must_match: REGEX_RANGE
33
-
34
- c.desc %(Set completion date to start date plus interval (XX[mhd] or HH:MM).
35
- If used without the --back option, the start date will be moved back to allow
36
- the completion date to be the current time.)
37
- c.arg_name 'INTERVAL'
38
- c.flag %i[t took for], type: DateIntervalString
39
-
40
22
  c.desc 'Section'
41
23
  c.arg_name 'NAME'
42
24
  c.flag %i[s section]
@@ -45,6 +27,7 @@ command %i[done did] do |c|
45
27
  c.switch %i[u unfinished], negatable: false, default_value: false
46
28
 
47
29
  add_options(:add_entry, c)
30
+ add_options(:finish_entry, c)
48
31
 
49
32
  c.action do |global_options, options, args|
50
33
  Doing.auto_tag = !options[:noauto]
@@ -14,14 +14,6 @@ command :finish do |c|
14
14
  c.arg_name 'DATE_STRING'
15
15
  c.flag %i[b back started], type: DateBeginString
16
16
 
17
- c.desc 'Set the completed date to the start date plus XX[hmd]'
18
- c.arg_name 'INTERVAL'
19
- c.flag %i[t took for], type: DateIntervalString
20
-
21
- c.desc %(Set finish date to specific date/time (natural langauge parsed, e.g. --at=1:30pm). If used, ignores --back.)
22
- c.arg_name 'DATE_STRING'
23
- c.flag %i[at finished], type: DateEndString
24
-
25
17
  c.desc 'Overwrite existing @done tag with new date'
26
18
  c.switch %i[update], negatable: false, default_value: false
27
19
 
@@ -48,32 +40,43 @@ command :finish do |c|
48
40
 
49
41
  add_options(:search, c)
50
42
  add_options(:tag_filter, c)
43
+ add_options(:finish_entry, c)
51
44
 
52
45
  c.action do |_global_options, options, args|
53
46
  options[:fuzzy] = false
54
47
  unless options[:auto]
55
- if options[:took]
56
- took = options[:took]
57
- raise InvalidTimeExpression, 'Unable to parse date string for --took' if took.nil?
58
- end
48
+ if options[:from]
49
+ options[:from] = options[:from].split(/#{REGEX_RANGE_INDICATOR}/).map do |time|
50
+ time =~ REGEX_TIME ? "today #{time.sub(/(?mi)(^.*?(?=\d+)|(?<=[ap]m).*?$)/, '')}" : time
51
+ end.join(' to ').split_date_range
52
+ start_date, finish_date = options[:from]
53
+ finish_date ||= Time.now
54
+ else
55
+ if options[:took]
56
+ took = options[:took]
57
+ raise InvalidTimeExpression, 'Unable to parse date string for --took' if took.nil?
59
58
 
60
- raise InvalidArgument, '--back and --took can not be used together' if options[:back] && options[:took]
59
+ end
61
60
 
62
- raise InvalidArgument, '--search and --tag can not be used together' if options[:search] && options[:tag]
61
+ if options[:at]
62
+ finish_date = options[:at]
63
+ finish_date = finish_date.chronify(guess: :begin) if finish_date.is_a? String
64
+ raise InvalidTimeExpression, 'Unable to parse date string for --at' if finish_date.nil?
63
65
 
64
- if options[:at]
65
- finish_date = options[:at]
66
- finish_date = finish_date.chronify(guess: :begin) if finish_date.is_a? String
67
- raise InvalidTimeExpression, 'Unable to parse date string for --at' if finish_date.nil?
66
+ start_date = options[:took] ? finish_date - took : nil
67
+ elsif options[:back]
68
+ start_date = options[:back]
69
+ finish_date = options[:took] ? start_date + took : Time.now
68
70
 
69
- date = options[:took] ? finish_date - took : finish_date
70
- elsif options[:back]
71
- date = options[:back]
71
+ raise InvalidTimeExpression, 'Unable to parse date string' if start_date.nil?
72
72
 
73
- raise InvalidTimeExpression, 'Unable to parse date string' if date.nil?
74
- else
75
- date = Time.now
73
+ else
74
+ start_date = options[:took] ? Time.now - took : nil
75
+ finish_date = Time.now
76
+ end
76
77
  end
78
+
79
+
77
80
  end
78
81
 
79
82
  if options[:tag].nil?
@@ -101,10 +104,11 @@ command :finish do |c|
101
104
 
102
105
  opts = {
103
106
  archive: options[:archive],
104
- back: date,
107
+ back: start_date,
105
108
  case: options[:case].normalize_case,
106
109
  count: count,
107
110
  date: options[:date],
111
+ done_date: finish_date,
108
112
  fuzzy: options[:fuzzy],
109
113
  interactive: options[:interactive],
110
114
  not: options[:not],
@@ -112,6 +116,7 @@ command :finish do |c|
112
116
  search: search,
113
117
  section: options[:section],
114
118
  sequential: options[:auto],
119
+ start_date: start_date,
115
120
  tag: tags,
116
121
  tag_bool: options[:bool].normalize_bool,
117
122
  tags: ['done'],
data/bin/commands/grep.rb CHANGED
@@ -16,25 +16,12 @@ command %i[grep search] do |c|
16
16
  c.arg_name 'NAME'
17
17
  c.flag %i[s section], default_value: 'All'
18
18
 
19
- c.desc "Output to export format (#{Doing::Plugins.plugin_names(type: :export)})"
20
- c.arg_name 'FORMAT'
21
- c.flag %i[o output]
22
-
23
- c.desc "Output using a template from configuration"
24
- c.arg_name 'TEMPLATE_KEY'
25
- c.flag [:config_template], type: TemplateName, default_value: 'default'
26
-
27
- c.desc 'Override output format with a template string containing %placeholders'
28
- c.arg_name 'TEMPLATE_STRING'
29
- c.flag [:template]
30
-
31
19
  # c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
32
20
  # c.switch [:fuzzy], default_value: false, negatable: false
33
21
 
34
22
  c.desc 'Force exact string matching (case sensitive)'
35
23
  c.switch %i[x exact], default_value: Doing.config.exact_match?, negatable: Doing.config.exact_match?
36
24
 
37
-
38
25
  c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
39
26
  c.arg_name 'TYPE'
40
27
  c.flag [:case], must_match: REGEX_CASE,
@@ -53,13 +40,15 @@ command %i[grep search] do |c|
53
40
  c.desc 'Display an interactive menu of results to perform further operations'
54
41
  c.switch %i[i interactive], default_value: false, negatable: false
55
42
 
43
+ add_options(:output_template, c)
56
44
  add_options(:tag_filter, c)
57
45
  add_options(:date_filter, c)
58
46
  add_options(:time_display, c)
59
47
 
60
48
  c.action do |_global_options, options, args|
61
49
  options[:fuzzy] = false
62
- raise DoingRuntimeError, %(Invalid output type "#{options[:output]}") if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
50
+
51
+ raise InvalidPlugin.new('output', options[:output]) if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
63
52
 
64
53
  template = Doing.setting(['templates', options[:config_template]]).deep_merge(Doing.settings)
65
54
  tags_color = template.key?('tags_color') ? template['tags_color'] : nil
data/bin/commands/last.rb CHANGED
@@ -21,20 +21,13 @@ command :last do |c|
21
21
  c.desc "Delete the last entry"
22
22
  c.switch %i[d delete], negatable: false, default_value: false
23
23
 
24
- c.desc "Output using a template from configuration"
25
- c.arg_name 'TEMPLATE_KEY'
26
- c.flag [:config_template], type: TemplateName, default_value: 'last'
27
-
28
- c.desc 'Override output format with a template string containing %placeholders'
29
- c.arg_name 'TEMPLATE_STRING'
30
- c.flag [:template]
31
-
32
24
  c.desc "Highlight search matches in output. Only affects command line output"
33
25
  c.switch %i[h hilite], default_value: Doing.settings.dig('search', 'highlight')
34
26
 
35
27
  c.desc 'Show elapsed time if entry is not tagged @done'
36
28
  c.switch [:duration]
37
29
 
30
+ add_options(:output_template, c, default_template: 'last')
38
31
  add_options(:search, c)
39
32
  add_options(:tag_filter, c)
40
33
 
@@ -69,6 +62,7 @@ command :last do |c|
69
62
  case: options[:case],
70
63
  hilite: options[:hilite],
71
64
  negate: options[:not],
65
+ output: options[:output],
72
66
  tag: options[:tag],
73
67
  tag_bool: options[:bool],
74
68
  delete: options[:delete],
@@ -19,6 +19,8 @@ command :meanwhile do |c|
19
19
  c.switch %i[a archive], negatable: false, default_value: false
20
20
 
21
21
  add_options(:add_entry, c)
22
+ # TODO: Add took and from handling for post-dating meanwhile entries
23
+ # add_options(:add_dated, c)
22
24
 
23
25
  c.action do |global_options, options, args|
24
26
  Doing.auto_tag = !options[:noauto]
@@ -31,17 +33,18 @@ command :meanwhile do |c|
31
33
  date = Time.now
32
34
  end
33
35
 
34
- if options[:section]
35
- section = @wwid.guess_section(options[:section]) || options[:section].cap_first
36
- else
37
- section = Doing.setting('current_section')
38
- end
36
+ section = if options[:section]
37
+ @wwid.guess_section(options[:section]) || options[:section].cap_first
38
+ else
39
+ Doing.setting('current_section')
40
+ end
39
41
  input = ''
40
42
 
41
43
  ask_note = options[:ask] ? Doing::Prompt.read_lines(prompt: 'Add a note') : []
42
44
 
43
45
  if options[:editor]
44
46
  raise MissingEditor, 'No EDITOR variable defined in environment' if Doing::Util.default_editor.nil?
47
+
45
48
  input += date.strftime('%F %R | ')
46
49
  input += args.join(' ') unless args.empty?
47
50
  input += "\n#{options[:note]}" if options[:note]
@@ -70,7 +73,11 @@ command :meanwhile do |c|
70
73
  note.add(ask_note) if ask_note.good?
71
74
  end
72
75
 
73
- @wwid.stop_start('meanwhile', { new_item: input, back: date, section: section, archive: options[:archive], note: note })
76
+ @wwid.stop_start('meanwhile', { new_item: input,
77
+ back: date,
78
+ section: section,
79
+ archive: options[:archive],
80
+ note: note })
74
81
  @wwid.write(@wwid.doing_file)
75
82
  end
76
83
  end
data/bin/commands/on.rb CHANGED
@@ -13,35 +13,22 @@ command :on do |c|
13
13
  c.arg_name 'NAME'
14
14
  c.flag %i[s section], default_value: 'All'
15
15
 
16
- c.desc "Output to export format (#{Doing::Plugins.plugin_names(type: :export)})"
17
- c.arg_name 'FORMAT'
18
- c.flag %i[o output]
19
-
20
- c.desc "Output using a template from configuration"
21
- c.arg_name 'TEMPLATE_KEY'
22
- c.flag [:config_template], type: TemplateName, default_value: 'default'
23
-
24
- c.desc 'Override output format with a template string containing %placeholders'
25
- c.arg_name 'TEMPLATE_STRING'
26
- c.flag [:template]
27
-
16
+ add_options(:output_template, c)
28
17
  add_options(:time_display, c)
29
18
  add_options(:search, c)
30
19
  add_options(:tag_filter, c)
31
20
  add_options(:time_filter, c)
32
21
 
33
22
  c.action do |_global_options, options, args|
34
- raise DoingRuntimeError, %(Invalid output type "#{options[:output]}") if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
23
+ raise InvalidPlugin.new('output', options[:output]) if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
35
24
 
36
25
  raise MissingArgument, 'Missing date argument' if args.empty?
37
26
 
38
27
  date_string = args.join(' ').strip
39
28
  if date_string =~ /^tod(?:ay)?/i
40
- date_string = 'today 01:00 to today 23:59'
29
+ date_string = 'midnight to today 23:59'
41
30
  end
42
31
 
43
- puts date_string
44
-
45
32
  start, finish = date_string.split_date_range
46
33
 
47
34
  raise InvalidTimeExpression, "Unrecognized date string (#{date_string})" unless start
@@ -12,17 +12,10 @@ command :recent do |c|
12
12
  c.arg_name 'NAME'
13
13
  c.flag %i[s section], default_value: 'All'
14
14
 
15
- c.desc "Output using a template from configuration"
16
- c.arg_name 'TEMPLATE_KEY'
17
- c.flag [:config_template], type: TemplateName, default_value: 'recent'
18
-
19
- c.desc 'Override output format with a template string containing %placeholders'
20
- c.arg_name 'TEMPLATE_STRING'
21
- c.flag [:template]
22
-
23
15
  c.desc 'Select from a menu of matching entries to perform additional operations'
24
16
  c.switch %i[i interactive], negatable: false, default_value: false
25
17
 
18
+ add_options(:output_template, c, default_template: 'recent')
26
19
  add_options(:time_display, c)
27
20
 
28
21
  c.action do |global_options, options, args|
@@ -53,6 +46,7 @@ command :recent do |c|
53
46
  times: options[:times],
54
47
  totals: options[:totals],
55
48
  interactive: options[:interactive],
49
+ output: options[:output],
56
50
  duration: options[:duration],
57
51
  config_template: options[:config_template],
58
52
  template: options[:template]
@@ -17,6 +17,17 @@ command %i[reset begin] do |c|
17
17
  c.desc 'Resume entry (remove @done)'
18
18
  c.switch %i[r resume], default_value: true
19
19
 
20
+ c.desc %(
21
+ Start and end times as a date/time range `doing done --from "1am to 8am"`.
22
+ Overrides any date argument and disables --resume.
23
+ )
24
+ c.arg_name 'TIME_RANGE'
25
+ c.flag [:from], must_match: REGEX_RANGE
26
+
27
+ c.desc %(Set completion date to start date plus interval (XX[mhd] or HH:MM). Disables --resume)
28
+ c.arg_name 'INTERVAL'
29
+ c.flag %i[t took for], type: DateIntervalString
30
+
20
31
  c.desc 'Change start date but do not remove @done (shortcut for --no-resume)'
21
32
  c.switch [:n]
22
33
 
@@ -62,9 +73,21 @@ command %i[reset begin] do |c|
62
73
 
63
74
  raise NoResults, 'No entry matching parameters was found.' unless last_entry
64
75
 
76
+ finish_date = nil
77
+
78
+ if options[:from]
79
+ options[:from] = options[:from].split(/#{REGEX_RANGE_INDICATOR}/).map do |time|
80
+ time =~ REGEX_TIME ? "today #{time.sub(/(?mi)(^.*?(?=\d+)|(?<=[ap]m).*?$)/, '')}" : time
81
+ end.join(' to ').split_date_range
82
+ reset_date, finish_date = options[:from]
83
+ options[:resume] = false if finish_date
84
+ end
85
+
86
+ finish_date = reset_date + options[:took] if options[:took]
87
+
65
88
  old_item = last_entry.clone
66
89
 
67
- @wwid.reset_item(last_entry, date: reset_date, resume: options[:resume])
90
+ @wwid.reset_item(last_entry, date: reset_date, finish_date: finish_date, resume: options[:resume])
68
91
  Doing::Hooks.trigger :post_entry_updated, @wwid, last_entry, old_item
69
92
  # new_entry = Doing::Item.new(last_entry.date, last_entry.title, last_entry.section, new_note)
70
93
 
@@ -94,7 +94,7 @@ command :select do |c|
94
94
 
95
95
  c.action do |_global_options, options, _args|
96
96
  if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
97
- raise DoingRuntimeError, %(Invalid output type "#{options[:output]}")
97
+ raise InvalidPlugin.new('output', options[:output])
98
98
 
99
99
  end
100
100
 
data/bin/commands/show.rb CHANGED
@@ -22,38 +22,27 @@ command :show do |c|
22
22
  c.arg_name 'MAX'
23
23
  c.flag %i[c count], default_value: 0, must_match: /^\d+$/, type: Integer
24
24
 
25
- c.desc 'Age (oldest|newest)'
26
- c.arg_name 'AGE'
27
- c.flag %i[a age], default_value: :newest, type: AgeSymbol
28
-
29
25
  c.desc "Highlight search matches in output. Only affects command line output"
30
26
  c.switch %i[h hilite], default_value: Doing.settings.dig('search', 'highlight')
31
27
 
32
28
  c.desc "Edit matching entries with #{Doing::Util.default_editor}"
33
29
  c.switch %i[e editor], negatable: false, default_value: false
34
30
 
31
+ c.desc 'Age (oldest|newest)'
32
+ c.arg_name 'AGE'
33
+ c.flag %i[a age], default_value: :newest, type: AgeSymbol
34
+
35
35
  c.desc 'Sort order (asc/desc)'
36
36
  c.arg_name 'ORDER'
37
37
  c.flag %i[s sort], must_match: REGEX_SORT_ORDER, default_value: :asc, type: OrderSymbol
38
38
 
39
- c.desc "Output using a template from configuration"
40
- c.arg_name 'TEMPLATE_KEY'
41
- c.flag [:config_template], type: TemplateName, default_value: 'default'
42
-
43
- c.desc 'Override output format with a template string containing %placeholders'
44
- c.arg_name 'TEMPLATE_STRING'
45
- c.flag [:template]
46
-
47
39
  c.desc 'Select section or tag to display from a menu'
48
40
  c.switch %i[m menu], negatable: false, default_value: false
49
41
 
50
42
  c.desc 'Select from a menu of matching entries to perform additional operations'
51
43
  c.switch %i[i interactive], negatable: false, default_value: false
52
44
 
53
- c.desc "Output to export format (#{Doing::Plugins.plugin_names(type: :export)})"
54
- c.arg_name 'FORMAT'
55
- c.flag %i[o output]
56
-
45
+ add_options(:output_template, c)
57
46
  add_options(:time_display, c)
58
47
  add_options(:search, c)
59
48
  add_options(:tag_filter, c)
@@ -62,7 +51,7 @@ command :show do |c|
62
51
  c.action do |global_options, options, args|
63
52
  options[:fuzzy] = false
64
53
  if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
65
- raise DoingRuntimeError, %(Invalid output type "#{options[:output]}")
54
+ raise InvalidPlugin.new('output', options[:output])
66
55
 
67
56
  end
68
57