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
@@ -1,4 +1,21 @@
1
1
  # @@changelog @@changes
2
+
3
+ MARKDOWN_THEME = {
4
+ em: %i[white dark],
5
+ header: %i[cyan bold],
6
+ hr: :yellow,
7
+ link: %i[bright_cyan underline],
8
+ list: :yellow,
9
+ strong: %i[yellow bold],
10
+ table: :yellow,
11
+ quote: :yellow,
12
+ image: :bright_black,
13
+ note: :yellow,
14
+ comment: :bright_black
15
+ }.deep_freeze
16
+
17
+ CHANGE_RX = /^(?:(?:(?:[<>=]+|p(?:rior)|b(?:efore)|o(?:lder)|s(?:ince)|a(?:fter)|n(?:ewer))? *[0-9.*?]+ *)+|(?:[\d.]+ *(?:-|to)+ *[0-9.]+))$/
18
+
2
19
  desc 'List recent changes in Doing'
3
20
  long_desc %(Display a formatted list of changes in recent versions.
4
21
 
@@ -10,14 +27,30 @@ command %i[changes changelog] do |c|
10
27
 
11
28
  c.desc %(Look up a specific version. Specify versions as "MAJ.MIN.PATCH", MIN
12
29
  and PATCH are optional. Use > or < to see all changes since or prior
13
- to a version.)
30
+ to a version. Wildcards (*?) accepted unless using < or >.)
14
31
  c.arg_name 'VERSION'
15
- c.flag %i[l lookup], must_match: /^(?:(?:(?:[<>=]|p(?:rior)|b(?:efore)|o(?:lder)|s(?:ince)|a(?:fter)|n(?:ewer))? *[\d.*?]+ *)+|(?:[\d.]+ *-+ *[\d.]+))$/
32
+ c.flag %i[l lookup], must_match: CHANGE_RX
16
33
 
17
34
  c.desc %(Show changelogs matching search terms (uses pattern-based searching).
18
35
  Add slashes to search with regular expressions, e.g. `--search "/output.*flag/"`)
19
36
  c.flag %i[s search]
20
37
 
38
+ c.desc 'Sort order (asc/desc)'
39
+ c.arg_name 'ORDER'
40
+ c.flag %i[sort], must_match: REGEX_SORT_ORDER, default_value: :desc, type: OrderSymbol
41
+
42
+ c.desc 'Only output changes, no version numbers, headers, or dates'
43
+ c.switch %i[C changes], default_value: false, negatable: false
44
+
45
+ c.desc 'Output raw Markdown'
46
+ c.switch %i[m md markdown], default_value: false, negatable: false
47
+
48
+ c.desc 'Force rendered output'
49
+ c.switch %i[render], default_value: false, negatable: false
50
+
51
+ c.desc 'Open changelog in interactive viewer'
52
+ c.switch %i[i interactive], default_value: false, negatable: false
53
+
21
54
  c.example 'doing changes', desc: 'View changes in the current version'
22
55
  c.example 'doing changes --all', desc: 'See the entire changelog'
23
56
  c.example 'doing changes --lookup 2.0.21', desc: 'See changes from version 2.0.21'
@@ -25,18 +58,26 @@ command %i[changes changelog] do |c|
25
58
  c.example 'doing changes --search "tags +bool"', desc: 'See all changes containing "tags" and "bool"'
26
59
  c.example 'doing changes -l "> 2.1" -s "pattern"', desc: 'Lookup and search can be combined'
27
60
 
61
+ c.action do |_global_options, options, _args|
62
+ cl = Doing::Changes.new(lookup: options[:lookup], search: options[:search], changes: options[:changes], sort: options[:sort])
28
63
 
29
- c.action do |_global_options, options, args|
30
- cl = Doing::Changes.new(lookup: options[:lookup], search: options[:search])
64
+ if options[:interactive]
65
+ cl.interactive
66
+ else
67
+ content = if options[:all] || options[:search] || options[:lookup]
68
+ cl.to_s
69
+ else
70
+ cl.latest
71
+ end
31
72
 
32
- content = if options[:all] || options[:search] || options[:lookup]
33
- cl.to_s
34
- else
35
- cl.latest
36
- end
73
+ parsed = if (options[:markdown] || !$stdout.isatty) && !options[:render]
74
+ content
75
+ else
76
+ TTY::Markdown.parse(content, width: 80, theme: MARKDOWN_THEME, symbols: { override: { bullet: '•' } })
77
+ end
37
78
 
38
- parsed = TTY::Markdown.parse(content, width: 80, symbols: {override: {bullet: "•"}})
39
- Doing::Pager.paginate = true
40
- Doing::Pager.page parsed
79
+ Doing::Pager.paginate = true
80
+ Doing::Pager.page parsed
81
+ end
41
82
  end
42
83
  end
@@ -5,10 +5,12 @@ command :colors do |c|
5
5
  bgs = []
6
6
  fgs = []
7
7
  @colors::attributes.each do |color|
8
+ colname = color.to_s
9
+ colname << " (#{color.to_s.sub(/bold/, 'bright')})" if colname =~ /bold/
8
10
  if color.to_s =~ /bg/
9
- bgs.push("#{@colors.send(color, " ")}#{@colors.default} <-- #{color.to_s}")
11
+ bgs.push("#{@colors.send(color, " ")}#{@colors.default} <-- #{colname}")
10
12
  else
11
- fgs.push("#{@colors.send(color, "XXXX")}#{@colors.default} <-- #{color.to_s}")
13
+ fgs.push("#{@colors.send(color, "XXXX")}#{@colors.default} <-- #{colname}")
12
14
  end
13
15
  end
14
16
  out = []
@@ -27,9 +27,11 @@ command :commands do |c|
27
27
  Doing::Prompt.choose_from(available,
28
28
  prompt: 'Select commands to enable',
29
29
  multiple: true,
30
- sorted: true).strip.split("\n")
30
+ sorted: true)
31
31
  end
32
- to_enable.each do |cmd|
32
+ raise UserCancelled unless to_enable
33
+
34
+ to_enable.strip.split("\n").each do |cmd|
33
35
  default_command = File.join(File.dirname(__FILE__), "#{cmd}.rb")
34
36
  custom_command = File.join(File.expand_path(custom_dir), "#{cmd}.rb")
35
37
  unless File.exist?(default_command) || File.exist?(custom_command)
@@ -1,25 +1,76 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # @@commands_accepting
2
4
  arg_name 'OPTION'
3
5
  command :commands_accepting do |c|
4
6
  c.desc 'Output in single column for completion'
5
7
  c.switch %i[c column]
6
8
 
9
+ c.desc 'Join multiple arguments using boolean (AND|OR|NOT)'
10
+ c.flag [:bool], must_match: REGEX_BOOL,
11
+ default_value: :and,
12
+ type: BooleanSymbol
13
+
7
14
  c.action do |g, o, a|
8
- a.each do |option|
9
- cmds = []
10
- commands.each do |cmd, v|
11
- v.flags.merge(v.switches).each do |n, flag|
12
- if flag.name == option.to_sym || flag.aliases&.include?(option.to_sym)
13
- cmds.push(cmd)
14
- end
15
+ cmds = []
16
+ commands.each { |cmd, v| cmds.push(cmd) if has_flags?(v, a, o[:bool]) }
17
+
18
+ if o[:column]
19
+ puts cmds.sort
20
+ else
21
+ description = "Commands "
22
+ description += "not " if o[:bool] == :not
23
+ description += "accepting "
24
+ description += a.map { |arg| "--#{arg}" }.join(o[:bool] == :and ? ' and ' : ' or ')
25
+ puts "#{description}: #{cmds.sort.join(', ')}"
26
+ end
27
+ end
28
+
29
+ def has_flags?(options, args, bool)
30
+ case bool
31
+ when :and
32
+ all_flags?(options, args)
33
+ when :not
34
+ no_flags?(options, args)
35
+ else
36
+ any_flags?(options, args)
37
+ end
38
+ end
39
+
40
+ def all_flags?(options, args)
41
+ args.each do |arg|
42
+ has_flag = false
43
+ options.flags.merge(options.switches).each do |_, flag|
44
+ if flag.name == arg.to_sym || flag.aliases&.include?(arg.to_sym)
45
+ has_flag = true
46
+ break
15
47
  end
16
48
  end
49
+ return false unless has_flag
50
+ end
51
+
52
+ true
53
+ end
54
+
55
+ def any_flags?(options, args)
56
+ args.each do |option|
57
+ options.flags.merge(options.switches).each do |_, flag|
58
+ return true if flag.name == option.to_sym || flag.aliases&.include?(option.to_sym)
59
+ end
60
+ end
17
61
 
18
- if o[:column]
19
- puts cmds.sort
20
- else
21
- puts "Commands accepting --#{option}: #{cmds.sort.join(', ')}"
62
+ false
63
+ end
64
+
65
+ def no_flags?(options, args)
66
+ args.each do |option|
67
+ options.flags.merge(options.switches).each do |_, flag|
68
+ return false if flag.name == option.to_sym || flag.aliases&.include?(option.to_sym)
22
69
  end
23
70
  end
71
+
72
+ true
24
73
  end
25
74
  end
75
+
76
+
@@ -1,12 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # @@completion
2
4
  desc 'Generate shell completion scripts'
3
- long_desc 'Generates the necessary scripts to add command line completion to various shells, so typing \'doing\' and hitting
4
- tab will offer completions of subcommands and their options.'
5
+ long_desc 'Generates the necessary scripts to add command line completion to various shells,
6
+ so typing \'doing\' and hitting tab will offer completions of subcommands and their options.'
5
7
  command :completion do |c|
6
8
  c.example 'doing completion', desc: 'Output zsh (default) to STDOUT'
7
- c.example 'doing completion --type zsh --file ~/.zsh-completions/_doing.zsh', desc: 'Output zsh completions to file'
8
- c.example 'doing completion --type fish --file ~/.config/fish/completions/doing.fish', desc: 'Output fish completions to file'
9
- c.example 'doing completion --type bash --file ~/.bash_it/completion/enabled/doing.bash', desc: 'Output bash completions to file'
9
+ c.example 'doing completion --type zsh --file ~/.zsh-completions/_doing.zsh',
10
+ desc: 'Output zsh completions to file'
11
+ c.example 'doing completion --type fish --file ~/.config/fish/completions/doing.fish',
12
+ desc: 'Output fish completions to file'
13
+ c.example 'doing completion --type bash --file ~/.bash_it/completion/enabled/doing.bash',
14
+ desc: 'Output bash completions to file'
10
15
 
11
16
  c.desc 'Shell to generate for (bash, zsh, fish)'
12
17
  c.arg_name 'SHELL'
@@ -17,8 +22,6 @@ command :completion do |c|
17
22
  c.flag %i[f file], default_value: 'STDOUT'
18
23
 
19
24
  c.action do |_global_options, options, _args|
20
- script_dir = File.join(File.dirname(__FILE__), '..', 'scripts')
21
-
22
25
  Doing::Completion.generate_completion(type: options[:type], file: options[:file])
23
26
  end
24
27
  end
@@ -45,7 +45,7 @@ command :config do |c|
45
45
  edit.arg_name 'EDITOR'
46
46
  edit.flag %i[e editor], default_value: nil
47
47
 
48
- if `uname` =~ /Darwin/
48
+ if Sys::Platform.mac?
49
49
  edit.desc 'Application to use'
50
50
  edit.arg_name 'APP_NAME'
51
51
  edit.flag %i[a app]
@@ -76,7 +76,7 @@ command :config do |c|
76
76
 
77
77
  config_file = @config.choose_config
78
78
 
79
- if `uname` =~ /Darwin/
79
+ if Sys::Platform.mac?
80
80
  if options[:default]
81
81
  editor = Doing::Util.find_default_editor('config')
82
82
  if editor
@@ -139,7 +139,7 @@ command :config do |c|
139
139
  dump.example 'doing config get', desc: 'Output the entire configuration'
140
140
  dump.example 'doing config get timer_format --output raw', desc: 'Output the value of timer_format as a plain string'
141
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'
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
143
 
144
144
  dump.desc 'Format for output (json|yaml|raw)'
145
145
  dump.arg_name 'FORMAT'
@@ -188,7 +188,7 @@ command :config do |c|
188
188
  c.arg 'KEY VALUE'
189
189
  c.command :set do |set|
190
190
  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'
191
+ set.example 'doing config set plug.plugpath ~/my_plugins', desc: 'Key path is fuzzy matched: set the value of plugins.plugin_path'
192
192
 
193
193
  set.desc 'Delete specified key'
194
194
  set.switch %i[r remove], default_value: false, negatable: false
@@ -206,7 +206,7 @@ command :config do |c|
206
206
  old_type = old_value&.class.to_s || nil
207
207
 
208
208
  if old_value.is_a?(Hash) && !options[:remove]
209
- Doing.logger.log_now(:warn, 'Config:', "Config key must point to a single value, #{real_path.join('->').boldwhite} is a mapping")
209
+ Doing.logger.log_now(:warn, 'Config:', "Config key must point to a single value, #{real_path.join('.').boldwhite} is a mapping")
210
210
  didyou = 'Did you mean:'
211
211
  old_value.keys.each do |k|
212
212
  Doing.logger.log_now(:warn, "#{didyou}", "#{keypath}.#{k}?")
@@ -218,17 +218,17 @@ command :config do |c|
218
218
 
219
219
  config_file = @config.choose_config(create: true)
220
220
 
221
- cfg = YAML.safe_load_file(config_file) || {}
221
+ cfg = Doing::Util.safe_load_file(config_file) || {}
222
222
 
223
223
  $stderr.puts "Updating #{config_file}".yellow
224
224
 
225
225
  if options[:remove]
226
226
  cfg.deep_set(real_path, nil)
227
- $stderr.puts "#{'Deleting key:'.yellow} #{real_path.join('->').boldwhite}"
227
+ $stderr.puts "#{'Deleting key:'.yellow} #{real_path.join('.').boldwhite}"
228
228
  else
229
229
  current_value = cfg.dig(*real_path)
230
230
  cfg.deep_set(real_path, value.set_type(old_type))
231
- $stderr.puts "#{' Key path:'.yellow} #{real_path.join('->').boldwhite}"
231
+ $stderr.puts "#{' Key path:'.yellow} #{real_path.join('.').boldwhite}"
232
232
  $stderr.puts "#{'Inherited:'.yellow} #{(old_value ? old_value.to_s : 'empty').boldwhite}"
233
233
  $stderr.puts "#{' Current:'.yellow} #{ (current_value ? current_value.to_s : 'empty').boldwhite }"
234
234
  $stderr.puts "#{' New:'.yellow} #{value.set_type(old_type).to_s.boldwhite}"
data/bin/commands/done.rb CHANGED
@@ -24,10 +24,6 @@ command %i[done did] do |c|
24
24
  c.arg_name 'DATE_STRING'
25
25
  c.flag %i[at finished], type: DateEndString
26
26
 
27
- c.desc 'Backdate start date by interval or set to time [4pm|20m|2h|"yesterday noon"]'
28
- c.arg_name 'DATE_STRING'
29
- c.flag %i[b back started], type: DateBeginString
30
-
31
27
  c.desc %(
32
28
  Start and end times as a date/time range `doing done --from "1am to 8am"`.
33
29
  Overrides other date flags.
@@ -45,24 +41,14 @@ command %i[done did] do |c|
45
41
  c.arg_name 'NAME'
46
42
  c.flag %i[s section]
47
43
 
48
- c.desc "Edit entry with #{Doing::Util.default_editor} (with no arguments, edits the last entry)"
49
- c.switch %i[e editor], negatable: false, default_value: false
50
-
51
- c.desc 'Include a note'
52
- c.arg_name 'TEXT'
53
- c.flag %i[n note]
54
-
55
- c.desc 'Prompt for note via multi-line input'
56
- c.switch %i[ask], negatable: false, default_value: false
57
-
58
44
  c.desc 'Finish last entry not already marked @done'
59
45
  c.switch %i[u unfinished], negatable: false, default_value: false
60
46
 
61
- # c.desc "Edit entry with specified app"
62
- # c.arg_name 'editor_app'
63
- # # c.flag [:a, :app]
47
+ add_options(:add_entry, c)
64
48
 
65
49
  c.action do |_global_options, options, args|
50
+ @wwid.auto_tag = !options[:noauto]
51
+
66
52
  took = 0
67
53
  donedate = nil
68
54
 
@@ -22,37 +22,10 @@ command :finish do |c|
22
22
  c.arg_name 'DATE_STRING'
23
23
  c.flag %i[at finished], type: DateEndString
24
24
 
25
- c.desc 'Finish the last X entries containing TAG.
26
- Separate multiple tags with comma (--tag=tag1,tag2), combine with --bool. Wildcards allowed (*, ?).'
27
- c.arg_name 'TAG'
28
- c.flag [:tag], type: TagArray
25
+ c.desc 'Overwrite existing @done tag with new date'
26
+ c.switch %i[update], negatable: false, default_value: false
29
27
 
30
- c.desc 'Finish the last X entries matching search filter, surround with slashes for regex (e.g. "/query.*/"), start with single quote for exact match ("\'query")'
31
- c.arg_name 'QUERY'
32
- c.flag [:search]
33
-
34
- c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
35
- c.arg_name 'QUERY'
36
- c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
37
-
38
- # c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
39
- # c.switch [:fuzzy], default_value: false, negatable: false
40
-
41
- c.desc 'Force exact search string matching (case sensitive)'
42
- c.switch %i[x exact], default_value: @config.exact_match?, negatable: @config.exact_match?
43
-
44
- c.desc 'Finish items that *don\'t* match search/tag filters'
45
- c.switch [:not], default_value: false, negatable: false
46
-
47
- c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
48
- c.arg_name 'TYPE'
49
- c.flag [:case], must_match: /^[csi]/, default_value: @settings.dig('search', 'case')
50
-
51
- c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans'
52
- c.arg_name 'BOOLEAN'
53
- c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
54
-
55
- c.desc 'Remove done tag'
28
+ c.desc 'Remove @done tag'
56
29
  c.switch %i[r remove], negatable: false, default_value: false
57
30
 
58
31
  c.desc 'Finish last entry (or entries) not already marked @done'
@@ -73,6 +46,9 @@ command :finish do |c|
73
46
  c.desc 'Select item(s) to finish from a menu of matching entries'
74
47
  c.switch %i[i interactive], negatable: false, default_value: false
75
48
 
49
+ add_options(:search, c)
50
+ add_options(:tag_filter, c)
51
+
76
52
  c.action do |_global_options, options, args|
77
53
  options[:fuzzy] = false
78
54
  unless options[:auto]
@@ -141,6 +117,7 @@ command :finish do |c|
141
117
  tags: ['done'],
142
118
  took: options[:took],
143
119
  unfinished: options[:unfinished],
120
+ update: options[:update],
144
121
  val: options[:val]
145
122
  }
146
123
 
data/bin/commands/flag.rb CHANGED
@@ -26,39 +26,12 @@ command %i[mark flag] do |c|
26
26
  c.desc 'Flag last entry (or entries) not marked @done'
27
27
  c.switch %i[u unfinished], negatable: false, default_value: false
28
28
 
29
- c.desc 'Flag the last entry containing TAG.
30
- Separate multiple tags with comma (--tag=tag1,tag2), combine with --bool. Wildcards allowed (*, ?).'
31
- c.arg_name 'TAG'
32
- c.flag [:tag], type: TagArray
33
-
34
- c.desc 'Flag the last entry matching search filter, surround with slashes for regex (e.g. "/query.*/"), start with single quote for exact match ("\'query")'
35
- c.arg_name 'QUERY'
36
- c.flag [:search]
37
-
38
- c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
39
- c.arg_name 'QUERY'
40
- c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
41
-
42
- # c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
43
- # c.switch [:fuzzy], default_value: false, negatable: false
44
-
45
- c.desc 'Force exact search string matching (case sensitive)'
46
- c.switch %i[x exact], default_value: @config.exact_match?, negatable: @config.exact_match?
47
-
48
- c.desc 'Flag items that *don\'t* match search/tag/date filters'
49
- c.switch [:not], default_value: false, negatable: false
50
-
51
- c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
52
- c.arg_name 'TYPE'
53
- c.flag [:case], must_match: /^[csi]/, default_value: @settings.dig('search', 'case')
54
-
55
- c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans'
56
- c.arg_name 'BOOLEAN'
57
- c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
58
-
59
29
  c.desc 'Select item(s) to flag from a menu of matching entries'
60
30
  c.switch %i[i interactive], negatable: false, default_value: false
61
31
 
32
+ add_options(:search, c)
33
+ add_options(:tag_filter, c)
34
+
62
35
  c.action do |_global_options, options, _args|
63
36
  options[:fuzzy] = false
64
37
  mark = @settings['marker_tag'] || 'flagged'
@@ -67,15 +40,9 @@ command %i[mark flag] do |c|
67
40
 
68
41
  section = 'All'
69
42
 
70
- if options[:section]
71
- section = @wwid.guess_section(options[:section]) || options[:section].cap_first
72
- end
43
+ section = @wwid.guess_section(options[:section]) || options[:section].cap_first if options[:section]
73
44
 
74
- if options[:tag].nil?
75
- search_tags = []
76
- else
77
- search_tags = options[:tag]
78
- end
45
+ search_tags = options[:tag].nil? ? [] : options[:tag]
79
46
 
80
47
  if options[:interactive]
81
48
  count = 0
@@ -84,8 +51,6 @@ command %i[mark flag] do |c|
84
51
  count = options[:count].to_i
85
52
  end
86
53
 
87
- options[:case] = options[:case].normalize_case
88
-
89
54
  if options[:search]
90
55
  search = options[:search]
91
56
  search.sub!(/^'?/, "'") if options[:exact]
@@ -93,16 +58,15 @@ command %i[mark flag] do |c|
93
58
  end
94
59
 
95
60
  if count.zero? && !options[:force]
96
- if options[:search]
97
- section_q = ' matching your search terms'
98
- elsif options[:tag]
99
- section_q = ' matching your tag search'
100
- elsif section == 'All'
101
- section_q = ''
102
- else
103
- section_q = " in section #{section}"
104
- end
105
-
61
+ section_q = if options[:search]
62
+ ' matching your search terms'
63
+ elsif options[:tag]
64
+ ' matching your tag search'
65
+ elsif section == 'All'
66
+ ''
67
+ else
68
+ " in section #{section}"
69
+ end
106
70
 
107
71
  question = if options[:remove]
108
72
  "Are you sure you want to unflag all entries#{section_q}"
@@ -119,7 +83,7 @@ command %i[mark flag] do |c|
119
83
  options[:section] = section
120
84
  options[:tag] = search_tags
121
85
  options[:tags] = [mark]
122
- options[:tag_bool] = options[:bool].normalize_bool
86
+ options[:tag_bool] = options[:bool]
123
87
 
124
88
  @wwid.tag_last(options)
125
89
  end
data/bin/commands/grep.rb CHANGED
@@ -16,25 +16,6 @@ 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 'Search 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'
20
- c.arg_name 'DATE_STRING'
21
- c.flag [:before], type: DateBeginString
22
-
23
- c.desc 'Search 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'
24
- c.arg_name 'DATE_STRING'
25
- c.flag [:after], type: DateEndString
26
-
27
- c.desc %(
28
- Date range to show, or a single day to filter date on.
29
- Date range argument should be quoted. Date specifications can be natural language.
30
- To specify a range, use "to" or "through": `doing search --from "monday 8am to friday 5pm"`.
31
-
32
- If values are only time(s) (6am to noon) all dates will be included, but entries will be filtered
33
- by time of day.
34
- )
35
- c.arg_name 'DATE_OR_RANGE'
36
- c.flag [:from], type: DateRangeString
37
-
38
19
  c.desc "Output to export format (#{Doing::Plugins.plugin_names(type: :export)})"
39
20
  c.arg_name 'FORMAT'
40
21
  c.flag %i[o output]
@@ -57,10 +38,9 @@ command %i[grep search] do |c|
57
38
  c.switch [:totals], default_value: false, negatable: false
58
39
 
59
40
  c.desc 'Sort tags by (name|time)'
60
- default = 'time'
61
- default = @settings['tag_sort'] || 'name'
41
+ default = @settings['tag_sort'].normalize_tag_sort || :name
62
42
  c.arg_name 'KEY'
63
- c.flag [:tag_sort], must_match: /^(?:name|time)$/i, default_value: default
43
+ c.flag [:tag_sort], must_match: REGEX_TAG_SORT, default_value: default, type: TagSortSymbol
64
44
 
65
45
  c.desc 'Only show items with recorded time intervals'
66
46
  c.switch [:only_timed], default_value: false, negatable: false
@@ -76,7 +56,9 @@ command %i[grep search] do |c|
76
56
 
77
57
  c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
78
58
  c.arg_name 'TYPE'
79
- c.flag [:case], must_match: /^[csi]/, default_value: @settings.dig('search', 'case')
59
+ c.flag [:case], must_match: REGEX_CASE,
60
+ default_value: @settings.dig('search', 'case').normalize_case,
61
+ type: CaseSymbol
80
62
 
81
63
  c.desc "Highlight search matches in output. Only affects command line output"
82
64
  c.switch %i[h hilite], default_value: @settings.dig('search', 'highlight')
@@ -95,7 +77,12 @@ command %i[grep search] do |c|
95
77
  c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
96
78
 
97
79
  c.desc 'Combine multiple tags or value queries using AND, OR, or NOT'
98
- c.flag [:bool], must_match: REGEX_BOOL, default_value: 'AND'
80
+ c.arg_name 'BOOLEAN'
81
+ c.flag [:bool], must_match: REGEX_BOOL,
82
+ default_value: :pattern,
83
+ type: BooleanSymbol
84
+
85
+ add_options(:date_filter, c)
99
86
 
100
87
  c.action do |_global_options, options, args|
101
88
  options[:fuzzy] = false
@@ -106,14 +93,11 @@ command %i[grep search] do |c|
106
93
 
107
94
  section = @wwid.guess_section(options[:section]) if options[:section]
108
95
 
109
- options[:case] = options[:case].normalize_case
110
- options[:bool] = options[:bool].normalize_bool
111
-
112
96
  search = args.join(' ')
113
97
  search.sub!(/^'?/, "'") if options[:exact]
114
98
 
115
99
  options[:times] = true if options[:totals]
116
- options[:sort_tags] = options[:tag_sort] =~ /^n/i
100
+ options[:sort_tags] = options[:tag_sort]
117
101
  options[:highlight] = true
118
102
  options[:search] = search
119
103
  options[:section] = section
@@ -11,23 +11,9 @@ command :import do |c|
11
11
  c.arg_name 'TYPE'
12
12
  c.flag :type, default_value: 'doing'
13
13
 
14
- c.desc 'Only import items matching search. Surround with slashes for regex (/query/), start with single quote for exact match ("\'query")'
15
- c.arg_name 'QUERY'
16
- c.flag [:search]
17
-
18
- # c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
19
- # c.switch [:fuzzy], default_value: false, negatable: false
20
-
21
- c.desc 'Force exact search string matching (case sensitive)'
22
- c.switch %i[x exact], default_value: @config.exact_match?, negatable: @config.exact_match?
23
-
24
14
  c.desc 'Import items that *don\'t* match search/tag/date filters'
25
15
  c.switch [:not], default_value: false, negatable: false
26
16
 
27
- c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
28
- c.arg_name 'TYPE'
29
- c.flag [:case], must_match: /^[csi]/, default_value: @settings.dig('search', 'case')
30
-
31
17
  c.desc 'Only import items with recorded time intervals'
32
18
  c.switch [:only_timed], default_value: false, negatable: false
33
19
 
@@ -46,26 +32,12 @@ command :import do |c|
46
32
  c.arg_name 'PREFIX'
47
33
  c.flag :prefix
48
34
 
49
- # TODO: Allow time range filtering
50
- c.desc 'Import entries older than date'
51
- c.arg_name 'DATE_STRING'
52
- c.flag [:before], type: DateBeginString
53
-
54
- c.desc 'Import entries newer than date'
55
- c.arg_name 'DATE_STRING'
56
- c.flag [:after], type: DateEndString
57
-
58
- c.desc %(
59
- Date range to import. Date range argument should be quoted. Date specifications can be natural language.
60
- To specify a range, use "to" or "through": `--from "monday to friday"` or `--from 10/1 to 10/31`.
61
- Has no effect unless the import plugin has implemented date range filtering.
62
- )
63
- c.arg_name 'DATE_OR_RANGE'
64
- c.flag %i[f from], type: DateRangeString
65
-
66
35
  c.desc 'Allow entries that overlap existing times'
67
36
  c.switch [:overlap], negatable: true
68
37
 
38
+ add_options(:search, c)
39
+ add_options(:date_filter, c)
40
+
69
41
  c.action do |_global_options, options, args|
70
42
  options[:fuzzy] = false
71
43
  if options[:section]
@@ -88,8 +60,6 @@ command :import do |c|
88
60
  options[:date_filter][0] = options[:after] || Time.now - (1 << 64)
89
61
  end
90
62
 
91
- options[:case] = options[:case].normalize_case
92
-
93
63
  if options[:type] =~ Doing::Plugins.plugin_regex(type: :import)
94
64
  options[:no_overlap] = !options[:overlap]
95
65
  @wwid.import(args, options)