doing 2.1.89 → 2.1.90

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 (242) hide show
  1. checksums.yaml +4 -4
  2. data/.irbrc +2 -0
  3. data/.rubocop.yml +1 -0
  4. data/.rubocop_todo.yml +251 -0
  5. data/CHANGELOG.md +22 -0
  6. data/Gemfile +2 -0
  7. data/Gemfile.lock +1 -1
  8. data/Rakefile +5 -3
  9. data/bin/commands/changes.rb +3 -1
  10. data/bin/commands/choose.rb +2 -0
  11. data/bin/commands/colors.rb +5 -3
  12. data/bin/commands/commands_accepting.rb +3 -3
  13. data/bin/commands/completion.rb +2 -1
  14. data/bin/commands/config.rb +8 -6
  15. data/bin/commands/done.rb +19 -12
  16. data/bin/commands/finish.rb +4 -2
  17. data/bin/commands/grep.rb +9 -5
  18. data/bin/commands/import.rb +14 -11
  19. data/bin/commands/install_fzf.rb +4 -2
  20. data/bin/commands/last.rb +31 -27
  21. data/bin/commands/meanwhile.rb +6 -2
  22. data/bin/commands/note.rb +6 -3
  23. data/bin/commands/now.rb +2 -0
  24. data/bin/commands/open.rb +6 -1
  25. data/bin/commands/plugins.rb +2 -0
  26. data/bin/commands/recent.rb +47 -33
  27. data/bin/commands/reset.rb +7 -3
  28. data/bin/commands/rotate.rb +6 -3
  29. data/bin/commands/sections.rb +3 -3
  30. data/bin/commands/select.rb +2 -0
  31. data/bin/commands/show.rb +24 -20
  32. data/bin/commands/since.rb +10 -3
  33. data/bin/commands/tag.rb +18 -16
  34. data/bin/commands/tag_dir.rb +5 -2
  35. data/bin/commands/tags.rb +17 -17
  36. data/bin/commands/template.rb +8 -2
  37. data/bin/commands/today.rb +10 -2
  38. data/bin/commands/undo.rb +2 -0
  39. data/bin/commands/update.rb +9 -7
  40. data/bin/commands/view.rb +11 -8
  41. data/bin/commands/views.rb +2 -0
  42. data/bin/commands/yesterday.rb +6 -1
  43. data/bin/doing +54 -57
  44. data/docs/doc/Array.html +3 -3
  45. data/docs/doc/BooleanTermParser/Clause.html +3 -3
  46. data/docs/doc/BooleanTermParser/Operator.html +3 -3
  47. data/docs/doc/BooleanTermParser/Query.html +3 -3
  48. data/docs/doc/BooleanTermParser/QueryParser.html +3 -3
  49. data/docs/doc/BooleanTermParser/QueryTransformer.html +3 -3
  50. data/docs/doc/BooleanTermParser.html +3 -3
  51. data/docs/doc/Doing/ArrayCleanup.html +3 -3
  52. data/docs/doc/Doing/ArrayNestedHash.html +3 -3
  53. data/docs/doc/Doing/ArrayTags.html +9 -9
  54. data/docs/doc/Doing/ByDayExport.html +3 -3
  55. data/docs/doc/Doing/CSVExport.html +4 -4
  56. data/docs/doc/Doing/CalendarImport.html +4 -4
  57. data/docs/doc/Doing/Change.html +3 -3
  58. data/docs/doc/Doing/Changes.html +3 -3
  59. data/docs/doc/Doing/ChronifyArray.html +3 -3
  60. data/docs/doc/Doing/ChronifyNumeric.html +3 -3
  61. data/docs/doc/Doing/ChronifyString.html +6 -6
  62. data/docs/doc/Doing/Color.html +88 -47
  63. data/docs/doc/Doing/Completion/BashCompletions.html +3 -3
  64. data/docs/doc/Doing/Completion/FigCompletions.html +3 -3
  65. data/docs/doc/Doing/Completion/FishCompletions.html +3 -3
  66. data/docs/doc/Doing/Completion/StringUtils.html +3 -3
  67. data/docs/doc/Doing/Completion/ZshCompletions.html +3 -3
  68. data/docs/doc/Doing/Completion.html +5 -5
  69. data/docs/doc/Doing/Configuration.html +6 -6
  70. data/docs/doc/Doing/DayOneRenderer.html +3 -3
  71. data/docs/doc/Doing/DayoneExport.html +4 -4
  72. data/docs/doc/Doing/DoingExport.html +5 -5
  73. data/docs/doc/Doing/DoingImport.html +4 -4
  74. data/docs/doc/Doing/Entry.html +3 -3
  75. data/docs/doc/Doing/Errors/DoingNoTraceError.html +3 -3
  76. data/docs/doc/Doing/Errors/DoingRuntimeError.html +3 -3
  77. data/docs/doc/Doing/Errors/DoingStandardError.html +3 -3
  78. data/docs/doc/Doing/Errors/EmptyInput.html +3 -3
  79. data/docs/doc/Doing/Errors/HistoryLimitError.html +3 -3
  80. data/docs/doc/Doing/Errors/InvalidPlugin.html +3 -3
  81. data/docs/doc/Doing/Errors/MissingBackupFile.html +3 -3
  82. data/docs/doc/Doing/Errors/NoResults.html +3 -3
  83. data/docs/doc/Doing/Errors/PluginException.html +3 -3
  84. data/docs/doc/Doing/Errors/UserCancelled.html +3 -3
  85. data/docs/doc/Doing/Errors/WrongCommand.html +3 -3
  86. data/docs/doc/Doing/Errors.html +3 -3
  87. data/docs/doc/Doing/HTMLExport.html +4 -4
  88. data/docs/doc/Doing/Hooks.html +3 -16
  89. data/docs/doc/Doing/Item.html +4 -4
  90. data/docs/doc/Doing/ItemDates.html +3 -3
  91. data/docs/doc/Doing/ItemQuery.html +3 -3
  92. data/docs/doc/Doing/ItemState.html +3 -3
  93. data/docs/doc/Doing/ItemTags.html +3 -3
  94. data/docs/doc/Doing/Items.html +3 -3
  95. data/docs/doc/Doing/JSONExport.html +4 -4
  96. data/docs/doc/Doing/JSONImport.html +4 -4
  97. data/docs/doc/Doing/Logger.html +183 -3
  98. data/docs/doc/Doing/MarkdownExport.html +4 -4
  99. data/docs/doc/Doing/Note.html +3 -3
  100. data/docs/doc/Doing/Pager.html +54 -58
  101. data/docs/doc/Doing/Plugins.html +3 -3
  102. data/docs/doc/Doing/Prompt.html +4 -4
  103. data/docs/doc/Doing/PromptChoose.html +3 -3
  104. data/docs/doc/Doing/PromptFZF.html +3 -3
  105. data/docs/doc/Doing/PromptInput.html +3 -3
  106. data/docs/doc/Doing/PromptSTD.html +3 -3
  107. data/docs/doc/Doing/PromptYN.html +3 -3
  108. data/docs/doc/Doing/Section.html +3 -3
  109. data/docs/doc/Doing/StringHighlight.html +3 -3
  110. data/docs/doc/Doing/StringNormalize.html +3 -3
  111. data/docs/doc/Doing/StringQuery.html +4 -4
  112. data/docs/doc/Doing/StringTags.html +3 -3
  113. data/docs/doc/Doing/StringTransform.html +3 -3
  114. data/docs/doc/Doing/StringTruncate.html +3 -3
  115. data/docs/doc/Doing/StringURL.html +3 -3
  116. data/docs/doc/Doing/SymbolNormalize.html +5 -5
  117. data/docs/doc/Doing/TaskPaperExport.html +4 -4
  118. data/docs/doc/Doing/TemplateExport.html +5 -5
  119. data/docs/doc/Doing/TemplateString.html +7 -7
  120. data/docs/doc/Doing/TimingImport.html +4 -4
  121. data/docs/doc/Doing/Types.html +3 -3
  122. data/docs/doc/Doing/Util/Backup.html +4 -17
  123. data/docs/doc/Doing/Util.html +56 -61
  124. data/docs/doc/Doing/Version.html +3 -3
  125. data/docs/doc/Doing/WWID.html +6 -4
  126. data/docs/doc/Doing.html +4 -4
  127. data/docs/doc/FalseClass.html +3 -3
  128. data/docs/doc/GLI/Commands/Help.html +5 -5
  129. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +3 -3
  130. data/docs/doc/GLI/Commands.html +3 -3
  131. data/docs/doc/GLI.html +3 -3
  132. data/docs/doc/Hash.html +4 -4
  133. data/docs/doc/Numeric.html +3 -3
  134. data/docs/doc/Object.html +3 -3
  135. data/docs/doc/PhraseParser/Operator.html +3 -3
  136. data/docs/doc/PhraseParser/PhraseClause.html +3 -3
  137. data/docs/doc/PhraseParser/Query.html +3 -3
  138. data/docs/doc/PhraseParser/QueryParser.html +3 -3
  139. data/docs/doc/PhraseParser/QueryTransformer.html +3 -3
  140. data/docs/doc/PhraseParser/TermClause.html +3 -3
  141. data/docs/doc/PhraseParser.html +3 -3
  142. data/docs/doc/Status.html +3 -3
  143. data/docs/doc/String.html +51 -5
  144. data/docs/doc/Symbol.html +3 -3
  145. data/docs/doc/Time.html +3 -3
  146. data/docs/doc/TrueClass.html +3 -3
  147. data/docs/doc/_index.html +4 -4
  148. data/docs/doc/class_list.html +6 -3
  149. data/docs/doc/css/full_list.css +3 -3
  150. data/docs/doc/css/style.css +6 -0
  151. data/docs/doc/file.README.html +3 -3
  152. data/docs/doc/file_list.html +5 -2
  153. data/docs/doc/frames.html +1 -1
  154. data/docs/doc/index.html +3 -3
  155. data/docs/doc/js/app.js +294 -264
  156. data/docs/doc/js/full_list.js +30 -4
  157. data/docs/doc/method_list.html +443 -392
  158. data/docs/doc/top-level-namespace.html +3 -3
  159. data/doing.gemspec +2 -0
  160. data/doing.rdoc +1 -1
  161. data/example_plugin.rb +1 -4
  162. data/lib/doing/add_options.rb +2 -2
  163. data/lib/doing/array/cleanup.rb +2 -0
  164. data/lib/doing/array/nested_hash.rb +2 -0
  165. data/lib/doing/boolean_term_parser.rb +3 -3
  166. data/lib/doing/changelog/changes.rb +4 -5
  167. data/lib/doing/changelog/version.rb +8 -11
  168. data/lib/doing/chronify/array.rb +4 -4
  169. data/lib/doing/chronify/string.rb +5 -4
  170. data/lib/doing/cli_status.rb +7 -2
  171. data/lib/doing/colors.rb +93 -51
  172. data/lib/doing/completion/bash_completion.rb +36 -39
  173. data/lib/doing/completion/completion_string.rb +2 -1
  174. data/lib/doing/completion/fig_completion.rb +33 -33
  175. data/lib/doing/completion/fish_completion.rb +22 -23
  176. data/lib/doing/completion/zsh_completion.rb +5 -5
  177. data/lib/doing/completion.rb +7 -4
  178. data/lib/doing/configuration.rb +21 -13
  179. data/lib/doing/errors.rb +1 -4
  180. data/lib/doing/good.rb +1 -1
  181. data/lib/doing/hash.rb +4 -4
  182. data/lib/doing/help_monkey_patch.rb +1 -1
  183. data/lib/doing/hooks.rb +6 -2
  184. data/lib/doing/item/dates.rb +3 -1
  185. data/lib/doing/item/query.rb +10 -10
  186. data/lib/doing/item/state.rb +2 -0
  187. data/lib/doing/logger.rb +113 -45
  188. data/lib/doing/markdown_document_listener.rb +25 -25
  189. data/lib/doing/normalize.rb +1 -1
  190. data/lib/doing/pager.rb +73 -29
  191. data/lib/doing/plugin_manager.rb +4 -5
  192. data/lib/doing/plugins/export/byday.rb +1 -1
  193. data/lib/doing/plugins/export/dayone_export.rb +28 -27
  194. data/lib/doing/plugins/export/doing_export.rb +1 -1
  195. data/lib/doing/plugins/export/html_export.rb +3 -3
  196. data/lib/doing/plugins/export/json_export.rb +4 -5
  197. data/lib/doing/plugins/export/markdown_export.rb +10 -2
  198. data/lib/doing/plugins/export/taskpaper_export.rb +1 -0
  199. data/lib/doing/plugins/export/template_export.rb +110 -107
  200. data/lib/doing/plugins/import/calendar_import.rb +1 -1
  201. data/lib/doing/plugins/import/doing_import.rb +2 -2
  202. data/lib/doing/plugins/import/timing_import.rb +3 -3
  203. data/lib/doing/prompt/choose.rb +5 -6
  204. data/lib/doing/prompt/fzf.rb +3 -2
  205. data/lib/doing/prompt/input.rb +7 -6
  206. data/lib/doing/prompt/yn.rb +9 -11
  207. data/lib/doing/string/tags.rb +7 -4
  208. data/lib/doing/string/transform.rb +15 -10
  209. data/lib/doing/string/truncate.rb +1 -0
  210. data/lib/doing/string/url.rb +1 -1
  211. data/lib/doing/template_string.rb +13 -9
  212. data/lib/doing/time.rb +4 -2
  213. data/lib/doing/util.rb +12 -11
  214. data/lib/doing/util_backup.rb +29 -26
  215. data/lib/doing/version.rb +3 -1
  216. data/lib/doing/wwid/display.rb +182 -151
  217. data/lib/doing/wwid/editor.rb +13 -12
  218. data/lib/doing/wwid/filetools.rb +13 -11
  219. data/lib/doing/wwid/filter.rb +41 -40
  220. data/lib/doing/wwid/guess.rb +6 -8
  221. data/lib/doing/wwid/interactive.rb +9 -9
  222. data/lib/doing/wwid/modify.rb +53 -53
  223. data/lib/doing/wwid/timers.rb +4 -5
  224. data/lib/doing/wwid/wwid.rb +0 -0
  225. data/lib/doing/wwid/wwidutil.rb +8 -10
  226. data/lib/examples/commands/wiki.rb +2 -0
  227. data/lib/examples/plugins/capture_thing_import.rb +1 -1
  228. data/lib/examples/plugins/say_export.rb +1 -2
  229. data/lib/examples/plugins/wiki_export/wiki_export.rb +3 -4
  230. data/lib/helpers/fzf/test/test_go.rb +5 -5
  231. data/lib/helpers/threaded_tests.rb +20 -20
  232. data/lib/helpers/threaded_tests_string.rb +2 -0
  233. data/rdoc_to_mmd.rb +5 -4
  234. data/rdocfixer.rb +1 -2
  235. data/scripts/deploy.rb +3 -4
  236. data/scripts/generate_bash_completions.rb +40 -43
  237. data/scripts/generate_fish_completions.rb +17 -15
  238. data/scripts/generate_zsh_completions.rb +9 -7
  239. data/scripts/setting_replace.rb +1 -0
  240. data/scripts/sort_commands.rb +4 -2
  241. data/yard_templates/default/method_details/setup.rb +3 -1
  242. metadata +3 -1
@@ -13,15 +13,15 @@ module Doing
13
13
  attr_accessor :commands, :global_options
14
14
 
15
15
  def generate_helpers
16
- out=<<~EOFUNCTIONS
17
- const completionSpec: Fig.Spec = {
18
- name: "doing",
19
- description: "A CLI for a What Was I Doing system",
20
- subcommands: [
21
- #{generate_subcommand_completions.join("\n ")}
22
- ],
23
- };
24
- export default completionSpec;
16
+ out = <<~EOFUNCTIONS
17
+ const completionSpec: Fig.Spec = {
18
+ name: "doing",
19
+ description: "A CLI for a What Was I Doing system",
20
+ subcommands: [
21
+ #{generate_subcommand_completions.join("\n ")}
22
+ ],
23
+ };
24
+ export default completionSpec;
25
25
  EOFUNCTIONS
26
26
  @bar.advance(status: '✅')
27
27
  @bar.finish
@@ -62,34 +62,33 @@ module Doing
62
62
  arg = ''
63
63
 
64
64
  if option[:arg]
65
- arg =<<~EOARG
66
- args: {
67
- #{indent} name: "#{option[:arg]}",
68
- #{indent} description: "#{option[:arg]}",
69
- #{indent} },
65
+ arg = <<~EOARG
66
+ args: {
67
+ #{indent} name: "#{option[:arg]}",
68
+ #{indent} description: "#{option[:arg]}",
69
+ #{indent} },
70
70
  EOARG
71
71
  end
72
72
 
73
- if option[:short]
74
- opt_data =<<~EOOPT
75
- {
76
- #{indent} name: ["-#{option[:short]}", "--#{option[:long]}"],
77
- #{indent} description: "#{option[:description].sanitize}",
78
- #{indent} #{arg}
79
- #{indent}},
80
- EOOPT
81
- else
82
- opt_data = <<~EOOPT
83
- {
84
- #{indent} name: ["--#{option[:long]}"],
85
- #{indent} description: "#{option[:description].sanitize}",
86
- #{indent} #{arg}
87
- #{indent}},
88
- EOOPT
89
- end
73
+ opt_data = if option[:short]
74
+ <<~EOOPT
75
+ {
76
+ #{indent} name: ["-#{option[:short]}", "--#{option[:long]}"],
77
+ #{indent} description: "#{option[:description].sanitize}",
78
+ #{indent} #{arg}
79
+ #{indent}},
80
+ EOOPT
81
+ else
82
+ <<~EOOPT
83
+ {
84
+ #{indent} name: ["--#{option[:long]}"],
85
+ #{indent} description: "#{option[:description].sanitize}",
86
+ #{indent} #{arg}
87
+ #{indent}},
88
+ EOOPT
89
+ end
90
90
 
91
91
  option_arr << opt_data
92
-
93
92
  end
94
93
 
95
94
  cmd_opts = <<~EOCMD
@@ -107,7 +106,8 @@ module Doing
107
106
  data = Completion.get_help_sections
108
107
  @global_options = Completion.parse_options(data[:global_options])
109
108
  @commands = Completion.parse_commands(data[:commands])
110
- @bar = TTY::ProgressBar.new(" \033[0;0;33mGenerating Fig completions: \033[0;35;40m[:bar] :status\033[0m", total: @commands.count + 1, bar_format: :square, hide_cursor: true, status: 'processing subcommands')
109
+ @bar = TTY::ProgressBar.new(" \033[0;0;33mGenerating Fig completions: \033[0;35;40m[:bar] :status\033[0m",
110
+ total: @commands.count + 1, bar_format: :square, hide_cursor: true, status: 'processing subcommands')
111
111
  width = TTY::Screen.columns - 45
112
112
  @bar.resize(width)
113
113
  end
@@ -4,7 +4,6 @@ module Doing
4
4
  module Completion
5
5
  # Generate completions for Fish
6
6
  class FishCompletions
7
-
8
7
  attr_accessor :commands, :global_options
9
8
 
10
9
  def generate_helpers
@@ -152,7 +151,6 @@ module Doing
152
151
  end
153
152
 
154
153
  def generate_subcommand_option_completions
155
-
156
154
  out = []
157
155
  need_export = []
158
156
  need_bool = []
@@ -163,32 +161,32 @@ module Doing
163
161
  need_age = []
164
162
  need_section = []
165
163
 
166
- @commands.each_with_index do |cmd, i|
164
+ @commands.each_with_index do |cmd, _i|
167
165
  @bar.advance(status: cmd[:commands].first)
168
166
  data = Completion.get_help_sections(cmd[:commands].first)
169
167
 
170
168
  if data[:synopsis].join(' ').strip.split(/ /).last =~ /(path|file)/i
171
- out << "complete -c doing -F -n '__fish_doing_using_command #{cmd[:commands].join(" ")}'"
169
+ out << "complete -c doing -F -n '__fish_doing_using_command #{cmd[:commands].join(' ')}'"
172
170
  end
173
171
 
174
- if data[:command_options]
175
- Completion.parse_options(data[:command_options]).each do |option|
176
- next if option.nil?
177
-
178
- arg = option[:arg] ? '-r' : ''
179
- short = option[:short] ? "-s #{option[:short]}" : ''
180
- long = option[:long] ? "-l #{option[:long]}" : ''
181
- out << "complete -c doing #{long} #{short} -f #{arg} -n '__fish_doing_using_command #{cmd[:commands].join(' ')}' -d #{Shellwords.escape(option[:description])}"
182
-
183
- need_export.concat(cmd[:commands]) if option[:long] == 'output'
184
- need_bool.concat(cmd[:commands]) if option[:long] == 'bool'
185
- need_case.concat(cmd[:commands]) if option[:long] == 'case'
186
- need_sort.concat(cmd[:commands]) if option[:long] == 'sort'
187
- need_tag_sort.concat(cmd[:commands]) if option[:long] == 'tag_sort'
188
- need_tag_order.concat(cmd[:commands]) if option[:long] == 'tag_order'
189
- need_age.concat(cmd[:commands]) if option[:long] == 'age'
190
- need_section.concat(cmd[:commands]) if option[:long] == 'section'
191
- end
172
+ next unless data[:command_options]
173
+
174
+ Completion.parse_options(data[:command_options]).each do |option|
175
+ next if option.nil?
176
+
177
+ arg = option[:arg] ? '-r' : ''
178
+ short = option[:short] ? "-s #{option[:short]}" : ''
179
+ long = option[:long] ? "-l #{option[:long]}" : ''
180
+ out << "complete -c doing #{long} #{short} -f #{arg} -n '__fish_doing_using_command #{cmd[:commands].join(' ')}' -d #{Shellwords.escape(option[:description])}"
181
+
182
+ need_export.concat(cmd[:commands]) if option[:long] == 'output'
183
+ need_bool.concat(cmd[:commands]) if option[:long] == 'bool'
184
+ need_case.concat(cmd[:commands]) if option[:long] == 'case'
185
+ need_sort.concat(cmd[:commands]) if option[:long] == 'sort'
186
+ need_tag_sort.concat(cmd[:commands]) if option[:long] == 'tag_sort'
187
+ need_tag_order.concat(cmd[:commands]) if option[:long] == 'tag_order'
188
+ need_age.concat(cmd[:commands]) if option[:long] == 'age'
189
+ need_section.concat(cmd[:commands]) if option[:long] == 'section'
192
190
  end
193
191
  end
194
192
 
@@ -232,7 +230,8 @@ module Doing
232
230
  data = Completion.get_help_sections
233
231
  @global_options = Completion.parse_options(data[:global_options])
234
232
  @commands = Completion.parse_commands(data[:commands])
235
- @bar = TTY::ProgressBar.new("\033[0;0;33mGenerating Fish completions: \033[0;35;40m[:bar] :status\033[0m", total: @commands.count + 1, bar_format: :square, hide_cursor: true, status: 'processing subcommands')
233
+ @bar = TTY::ProgressBar.new("\033[0;0;33mGenerating Fish completions: \033[0;35;40m[:bar] :status\033[0m",
234
+ total: @commands.count + 1, bar_format: :square, hide_cursor: true, status: 'processing subcommands')
236
235
  width = TTY::Screen.columns - 45
237
236
  @bar.resize(width)
238
237
  end
@@ -13,7 +13,7 @@ module Doing
13
13
  attr_accessor :commands, :global_options
14
14
 
15
15
  def generate_helpers
16
- out=<<~EOFUNCTIONS
16
+ out = <<~EOFUNCTIONS
17
17
  compdef _doing doing
18
18
 
19
19
  function _doing() {
@@ -49,7 +49,7 @@ module Doing
49
49
 
50
50
  def generate_subcommand_completions
51
51
  out = []
52
- @commands.each_with_index do |cmd, i|
52
+ @commands.each_with_index do |cmd, _i|
53
53
  cmd[:commands].each do |c|
54
54
  out << "'#{c}:#{cmd[:description].gsub(/'/, '\\\'')}'"
55
55
  end
@@ -58,10 +58,9 @@ module Doing
58
58
  end
59
59
 
60
60
  def generate_subcommand_option_completions(indent: ' ')
61
-
62
61
  out = []
63
62
 
64
- @commands.each_with_index do |cmd, i|
63
+ @commands.each_with_index do |cmd, _i|
65
64
  @bar.advance(status: cmd[:commands].first)
66
65
 
67
66
  data = Completion.get_help_sections(cmd[:commands].first)
@@ -93,7 +92,8 @@ module Doing
93
92
  data = Completion.get_help_sections
94
93
  @global_options = Completion.parse_options(data[:global_options])
95
94
  @commands = Completion.parse_commands(data[:commands])
96
- @bar = TTY::ProgressBar.new(" \033[0;0;33mGenerating Zsh completions: \033[0;35;40m[:bar] :status\033[0m", total: @commands.count + 1, bar_format: :square, hide_cursor: true, status: 'processing subcommands')
95
+ @bar = TTY::ProgressBar.new(" \033[0;0;33mGenerating Zsh completions: \033[0;35;40m[:bar] :status\033[0m",
96
+ total: @commands.count + 1, bar_format: :square, hide_cursor: true, status: 'processing subcommands')
97
97
  width = TTY::Screen.columns - 45
98
98
  @bar.resize(width)
99
99
  end
@@ -16,7 +16,7 @@ module Doing
16
16
  COMMAND_RX = /^(?<cmd>[^, \t]+)(?<alias>(?:, [^, \t]+)*)?\s+- (?<desc>.*?)$/.freeze
17
17
 
18
18
  class << self
19
- def get_help_sections(command = "")
19
+ def get_help_sections(command = '')
20
20
  res = `doing help #{command}|command cat`.strip
21
21
  scanned = res.scan(SECTIONS_RX)
22
22
  sections = {}
@@ -97,8 +97,10 @@ module Doing
97
97
  FileUtils.mkdir_p(default_dir)
98
98
  src = File.expand_path(File.join(File.dirname(__FILE__), '..', 'completion', default_filenames[type]))
99
99
 
100
- if File.exist?(File.join(default_dir, default_filenames[type]))
101
- return unless Doing::Prompt.yn("Update #{type} completion script", default_response: 'n')
100
+ if File.exist?(File.join(default_dir,
101
+ default_filenames[type])) && !Doing::Prompt.yn("Update #{type} completion script",
102
+ default_response: 'n')
103
+ return
102
104
 
103
105
  end
104
106
 
@@ -203,7 +205,8 @@ module Doing
203
205
  case type.to_s
204
206
  when /^b/i
205
207
  unless dir =~ %r{(\.bash_it/completion|bash_completion/completions)}
206
- link_completion(file, ['~/.bash_it/completion/enabled', '/usr/share/bash-completion/completions', '/usr/share/bash_completion/completions'], 'doing.bash')
208
+ link_completion(file,
209
+ ['~/.bash_it/completion/enabled', '/usr/share/bash-completion/completions', '/usr/share/bash_completion/completions'], 'doing.bash')
207
210
  end
208
211
  when /^fig/i
209
212
  when /^f/i
@@ -116,7 +116,7 @@ module Doing
116
116
  'interaction' => {
117
117
  'confirm_longer_than' => '5h'
118
118
  }
119
- }
119
+ }.freeze
120
120
 
121
121
  def initialize(file = nil, options: {})
122
122
  @config_file = file.nil? ? default_config_file : File.expand_path(file)
@@ -237,11 +237,9 @@ module Doing
237
237
  if new_cfg.nil?
238
238
  return real_path if real_path[-1] == path && real_path.count == element_count
239
239
 
240
- if distance < 5 && !create
241
- return resolve_key_path(keypath, create: false, distance: distance + 1)
242
- else
243
- return nil unless create
244
- end
240
+ return resolve_key_path(keypath, create: false, distance: distance + 1) if distance < 5 && !create
241
+
242
+ return nil unless create
245
243
 
246
244
  resolved = real_path.count.positive? ? "Resolved #{real_path.join('.')}, but " : ''
247
245
  Doing.logger.log_now(:warn, "#{resolved}#{path} is unknown")
@@ -251,13 +249,19 @@ module Doing
251
249
  raise InvalidArgument, 'Invalid key path' unless res
252
250
 
253
251
  real_path.push(path).concat(paths).compact!
254
- Doing.logger.debug('Config:', "translated key path #{keypath} to #{real_path.join('.')}") unless keypath == real_path.join('.')
252
+ unless keypath == real_path.join('.')
253
+ Doing.logger.debug('Config:',
254
+ "translated key path #{keypath} to #{real_path.join('.')}")
255
+ end
255
256
  return real_path
256
257
  end
257
258
  cfg = new_cfg
258
259
  end
259
260
  end
260
- Doing.logger.debug('Config:', "translated key path #{keypath} to #{real_path.join('.')}") unless keypath == real_path.join('.')
261
+ unless keypath == real_path.join('.')
262
+ Doing.logger.debug('Config:',
263
+ "translated key path #{keypath} to #{real_path.join('.')}")
264
+ end
261
265
  real_path
262
266
  end
263
267
 
@@ -295,7 +299,8 @@ module Doing
295
299
  #
296
300
  def from(user_config)
297
301
  # Util.deep_merge_hashes(DEFAULTS, Configuration[user_config].stringify_keys)
298
- Configuration[user_config].stringify_keys.deep_merge(DEFAULTS, { extend_existing_arrays: true, sort_merged_arrays: true })
302
+ Configuration[user_config].stringify_keys.deep_merge(DEFAULTS,
303
+ { extend_existing_arrays: true, sort_merged_arrays: true })
299
304
  end
300
305
 
301
306
  ##
@@ -346,7 +351,7 @@ module Doing
346
351
 
347
352
  load_plugins(plugin_config['plugin_path'])
348
353
 
349
- Plugins.plugins.each do |_type, plugins|
354
+ Plugins.plugins.each_value do |plugins|
350
355
  plugins.each do |title, plugin|
351
356
  plugin_config[title] = plugin[:config] if plugin[:config].good?
352
357
  config['export_templates'][title] ||= nil if plugin[:templates] && !plugin[:templates].empty?
@@ -366,7 +371,10 @@ module Doing
366
371
 
367
372
  Hooks.trigger :post_config, self
368
373
 
369
- config = local_config.deep_merge(config, { extend_existing_arrays: true, sort_merged_arrays: true }) unless @ignore_local
374
+ unless @ignore_local
375
+ config = local_config.deep_merge(config,
376
+ { extend_existing_arrays: true, sort_merged_arrays: true })
377
+ end
370
378
  # config = Util.deep_merge_hashes(config, local_config) unless @ignore_local
371
379
 
372
380
  Hooks.trigger :post_local_config, self
@@ -483,13 +491,13 @@ module Doing
483
491
  end
484
492
 
485
493
  begin
486
-
487
494
  user_config = Util.safe_load_file(config_file)
488
495
  raise StandardError, 'Invalid config file format' unless user_config.is_a?(Hash)
489
496
 
490
497
  if user_config.key?('html_template')
491
498
  user_config['export_templates'] ||= {}
492
- user_config['export_templates'].deep_merge(user_config.delete('html_template'), { extend_existing_arrays: true, sort_merged_arrays: true })
499
+ user_config['export_templates'].deep_merge(user_config.delete('html_template'),
500
+ { extend_existing_arrays: true, sort_merged_arrays: true })
493
501
  end
494
502
 
495
503
  user_config['include_notes'] = user_config.delete(':include_notes') if user_config.key?(':include_notes')
data/lib/doing/errors.rb CHANGED
@@ -6,9 +6,7 @@ module Doing
6
6
  def initialize(msg = nil, level: nil, topic: 'Error:', exit_code: 1)
7
7
  level ||= :error
8
8
  Doing.logger.output_results
9
- if msg
10
- Doing.logger.log_now(level, topic, msg)
11
- end
9
+ Doing.logger.log_now(level, topic, msg) if msg
12
10
 
13
11
  Process.exit exit_code
14
12
  end
@@ -52,7 +50,6 @@ module Doing
52
50
  class NoResults < DoingNoTraceError
53
51
  def initialize(msg = 'No results', topic = 'Exited:')
54
52
  super(msg, level: :warn, topic: topic, exit_code: 0)
55
-
56
53
  end
57
54
  end
58
55
 
data/lib/doing/good.rb CHANGED
@@ -18,7 +18,7 @@ module Doing
18
18
  ## has content
19
19
  ##
20
20
  def good?
21
- !nil? && !self&.empty? || false
21
+ !nil? && !empty? || false
22
22
  end
23
23
  end
24
24
 
data/lib/doing/hash.rb CHANGED
@@ -153,7 +153,7 @@ module Doing
153
153
  ## Remove keys with empty values
154
154
  ##
155
155
  def remove_empty
156
- delete_if { |k, v| !v.is_a?(FalseClass) && !v.good? }
156
+ delete_if { |_k, v| !v.is_a?(FalseClass) && !v.good? }
157
157
  end
158
158
 
159
159
  def tag_filter_to_options
@@ -193,9 +193,9 @@ module Doing
193
193
  ## @param to_delete [Array] the keys to delete if key doesn't exist
194
194
  ##
195
195
  def delete_unless_key(key, to_delete)
196
- unless key?(key)
197
- to_delete.each { |k| delete(k) }
198
- end
196
+ return if key?(key)
197
+
198
+ to_delete.each { |k| delete(k) }
199
199
  end
200
200
  end
201
201
  end
@@ -4,7 +4,7 @@ module GLI
4
4
  module Commands
5
5
  # Help Command Monkeypatch for paginated output
6
6
  class Help < Command
7
- def show_help(global_options, options, arguments, out, error)
7
+ def show_help(_global_options, options, arguments, out, error)
8
8
  Doing::Pager.paginate = true
9
9
 
10
10
  command_finder = HelpModules::CommandFinder.new(@app, arguments, error)
data/lib/doing/hooks.rb CHANGED
@@ -40,10 +40,14 @@ module Doing
40
40
  # register a single hook to be called later, internal API
41
41
  def self.register_one(event, priority, &block)
42
42
  unless @registry[event]
43
- raise Doing::Errors::HookUnavailable.new("Invalid hook. Doing only supports #{@registry.keys.inspect}", 'hook', event)
43
+ raise Doing::Errors::HookUnavailable.new("Invalid hook. Doing only supports #{@registry.keys.inspect}", 'hook',
44
+ event)
44
45
  end
45
46
 
46
- raise Doing::Errors::PluginUncallable.new('Hooks must respond to :call', 'hook', event) unless block.respond_to? :call
47
+ unless block.respond_to? :call
48
+ raise Doing::Errors::PluginUncallable.new('Hooks must respond to :call', 'hook',
49
+ event)
50
+ end
47
51
 
48
52
  Doing.logger.debug('Hook Manager:', "Registered #{event} hook") if ENV['DOING_PLUGIN_DEBUG']
49
53
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doing
2
4
  module ItemDates
3
5
  # def date=(new_date)
@@ -10,7 +12,7 @@ module Doing
10
12
 
11
13
  return nil if @title =~ /(?<=^| )@done\b/
12
14
 
13
- return Time.now - @date
15
+ Time.now - @date
14
16
  end
15
17
 
16
18
  ##
@@ -448,16 +448,16 @@ module Doing
448
448
  end
449
449
 
450
450
  def value_string_matches?(tag_val, comp, value)
451
- case comp
452
- when /\^=/
453
- tag_val =~ /^#{value.wildcard_to_rx}/i
454
- when /\$=/
455
- tag_val =~ /#{value.wildcard_to_rx}$/i
456
- when %r{==}
457
- tag_val =~ /^#{value.wildcard_to_rx}$/i
458
- else
459
- tag_val =~ /#{value.wildcard_to_rx}/i
460
- end
451
+ tag_val =~ case comp
452
+ when /\^=/
453
+ /^#{value.wildcard_to_rx}/i
454
+ when /\$=/
455
+ /#{value.wildcard_to_rx}$/i
456
+ when /==/
457
+ /^#{value.wildcard_to_rx}$/i
458
+ else
459
+ /#{value.wildcard_to_rx}/i
460
+ end
461
461
  end
462
462
 
463
463
  def value_number_matches?(tag_val, comp, value)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doing
2
4
  # State queries for a Doing entry
3
5
  module ItemState
data/lib/doing/logger.rb CHANGED
@@ -270,58 +270,126 @@ module Doing
270
270
  def benchmark(key, state)
271
271
  return unless ENV['DOING_BENCHMARK']
272
272
 
273
+ # Pre-allocate benchmarks hash to avoid repeated allocation
273
274
  @benchmarks ||= {}
274
- @benchmarks[key] ||= { start: nil, finish: nil }
275
+
276
+ # Use direct assignment instead of ||= for better performance
277
+ @benchmarks[key] = { start: nil, finish: nil } if @benchmarks[key].nil?
275
278
  @benchmarks[key][state] = Process.clock_gettime(Process::CLOCK_MONOTONIC)
276
279
  end
277
280
 
281
+ # Measure execution time of a block with automatic start/finish
282
+ def measure(key, &_block)
283
+ return yield unless ENV['DOING_BENCHMARK']
284
+
285
+ benchmark(key, :start)
286
+ result = yield
287
+ benchmark(key, :finish)
288
+ result
289
+ end
290
+
291
+ # Get benchmark statistics for a specific key
292
+ def benchmark_stats(key)
293
+ return nil unless @benchmarks.dig(key, :start) && @benchmarks.dig(key, :finish)
294
+
295
+ {
296
+ key: key,
297
+ duration: (@benchmarks[key][:finish] - @benchmarks[key][:start]).round(4),
298
+ start_time: @benchmarks[key][:start].round(4),
299
+ end_time: @benchmarks[key][:finish].round(4)
300
+ }
301
+ end
302
+
303
+ # Get all benchmark statistics sorted by duration
304
+ def all_benchmark_stats
305
+ return [] unless @benchmarks
306
+
307
+ @benchmarks.map do |key, timers|
308
+ next unless timers[:start] && timers[:finish]
309
+
310
+ {
311
+ key: key,
312
+ duration: (timers[:finish] - timers[:start]).round(4),
313
+ start_time: timers[:start].round(4),
314
+ end_time: timers[:finish].round(4)
315
+ }
316
+ end.compact.sort_by { |stats| -stats[:duration] }
317
+ end
318
+
319
+ # Generate a compact benchmark summary
320
+ def benchmark_summary
321
+ return unless ENV['DOING_BENCHMARK'] && @benchmarks
322
+
323
+ stats = all_benchmark_stats
324
+ return if stats.empty?
325
+
326
+ total_duration = stats.find { |s| s[:key] == :total }&.dig(:duration) || 0
327
+ return if total_duration <= 0
328
+
329
+ output = []
330
+ output << "Benchmark Summary (Total: #{total_duration.round(4)}s):"
331
+ stats.reject { |s| s[:key] == :total }.each do |stat|
332
+ percentage = (stat[:duration] / total_duration * 100).round(1)
333
+ output << " #{stat[:key]}: #{stat[:duration]}s (#{percentage}%)"
334
+ end
335
+
336
+ output.join("\n")
337
+ end
338
+
278
339
  def log_benchmarks
279
- if ENV['DOING_BENCHMARK']
280
-
281
- output = []
282
- beginning = @benchmarks[:total][:start]
283
- ending = @benchmarks[:total][:finish]
284
- total = ending - beginning
285
- factor = TTY::Screen.columns / total
286
-
287
- cols = Array.new(TTY::Screen.columns)
288
-
289
- colors = %w[bgred bggreen bgyellow bgblue bgmagenta bgcyan bgwhite boldbgred boldbggreen boldbgyellow boldbgblue boldbgwhite]
290
- idx = 0
291
- # @benchmarks.delete(:total)
292
-
293
- @benchmarks.sort_by { |_, timers| [timers[:start], timers[:finish]] }.each do |k, timers|
294
- if timers[:finish] && timers[:start]
295
- color = colors[idx % colors.count]
296
- fg = if idx < 7
297
- Color.boldblack
298
- else
299
- Color.boldwhite
300
- end
301
- color = Color.send(color) + fg
302
-
303
- start = ((timers[:start] - beginning) * factor).floor
304
- finish = ((timers[:finish] - beginning) * factor).ceil
305
-
306
- cols.fill("#{color}-", start..finish)
307
- cols[start] = "#{color}|"
308
- cols[finish] = "#{color}|"
309
- output << "#{color}#{k}#{Color.default}: #{timers[:finish] - timers[:start]}"
310
- else
311
- output << "#{k}: error"
312
- end
313
-
314
- idx += 1
315
- end
340
+ return unless ENV['DOING_BENCHMARK'] && @benchmarks
316
341
 
317
- output.each do |msg|
318
- $stdout.puts color_message(:debug, 'Benchmark:', msg)
319
- end
342
+ # Cache screen width to avoid repeated calls
343
+ screen_width = TTY::Screen.columns
344
+ return if screen_width <= 0
345
+
346
+ beginning = @benchmarks[:total]&.dig(:start)
347
+ ending = @benchmarks[:total]&.dig(:finish)
348
+ return unless beginning && ending
349
+
350
+ total = ending - beginning
351
+ return if total <= 0
352
+
353
+ factor = screen_width.to_f / total
354
+ cols = Array.new(screen_width, ' ')
355
+ output = []
320
356
 
321
- $stdout.puts color_message(:debug, 'Benchmark:', "Total: #{total}")
357
+ # Pre-allocate colors array to avoid repeated allocation
358
+ colors = %w[bgred bggreen bgyellow bgblue bgmagenta bgcyan bgwhite
359
+ boldbgred boldbggreen boldbgyellow boldbgblue boldbgwhite]
360
+ color_count = colors.size
322
361
 
323
- $stdout.puts cols[0..TTY::Screen.columns-1].join + Color.reset
362
+ # Sort benchmarks once and cache the result
363
+ sorted_benchmarks = @benchmarks.reject { |k, _| k == :total }
364
+ .select { |_, timers| timers[:finish] && timers[:start] }
365
+ .sort_by { |_, timers| timers[:start] }
366
+
367
+ sorted_benchmarks.each_with_index do |(key, timers), idx|
368
+ color_name = colors[idx % color_count]
369
+ fg_color = idx < 7 ? Color.boldblack : Color.boldwhite
370
+ color = Color.send(color_name) + fg_color
371
+
372
+ start_pos = ((timers[:start] - beginning) * factor).floor
373
+ finish_pos = ((timers[:finish] - beginning) * factor).ceil
374
+
375
+ # Ensure positions are within bounds
376
+ start_pos = [start_pos, 0].max
377
+ finish_pos = [finish_pos, screen_width - 1].min
378
+
379
+ if start_pos < finish_pos
380
+ cols.fill("#{color}-", start_pos..finish_pos)
381
+ cols[start_pos] = "#{color}|"
382
+ cols[finish_pos] = "#{color}|"
383
+ end
384
+
385
+ duration = (timers[:finish] - timers[:start]).round(4)
386
+ output << "#{color}#{key}#{Color.default}: #{duration}"
324
387
  end
388
+
389
+ # Output all messages at once to reduce I/O overhead
390
+ output.each { |msg| $stdout.puts color_message(:debug, 'Benchmark:', msg) }
391
+ $stdout.puts color_message(:debug, 'Benchmark:', "Total: #{total.round(4)}")
392
+ $stdout.puts cols.join + Color.reset
325
393
  end
326
394
 
327
395
  def log_change(tags_added: [], tags_removed: [], count: 1, item: nil, single: false)
@@ -467,9 +535,9 @@ module Doing
467
535
 
468
536
  message.sub!(/^(\s*\S.*?): (.*?)$/) do
469
537
  m = Regexp.last_match
470
- msg = m[2] =~ /(\e\[[\d;]+m)/ ? msg : "#{message_fg}#{m[2]}"
538
+ msg_content = m[2] =~ /(\e\[[\d;]+m)/ ? m[2] : "#{message_fg}#{m[2]}"
471
539
 
472
- "#{topic_fg}#{m[1]}#{colors.reset}: #{message_fg}#{m[2]}"
540
+ "#{topic_fg}#{m[1]}#{colors.reset}: #{msg_content}"
473
541
  end
474
542
 
475
543
  "#{prefix} #{message.highlight_tags}#{colors.reset}"