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,7 +13,9 @@ module Doing
13
13
  # @return [Items] Filtered Items array
14
14
  #
15
15
  def fuzzy_filter_items(items, query, case_type: :smart)
16
- scannable = items.map.with_index { |item, idx| "#{item.title} #{item.note.join(' ')}".gsub(/[|*?!]/, '') + "|#{idx}" }.join("\n")
16
+ scannable = items.map.with_index do |item, idx|
17
+ "#{item.title} #{item.note.join(' ')}".gsub(/[|*?!]/, '') + "|#{idx}"
18
+ end.join("\n")
17
19
 
18
20
  res = `echo #{Shellwords.escape(scannable)}|#{Prompt.fzf} #{fuzzy_filter_args(query, case_type).join(' ')}`
19
21
  selected = Items.new
@@ -59,59 +61,58 @@ module Doing
59
61
  ## @option opt [Array] :val (nil) Array of tag value queries
60
62
  ##
61
63
  def filter_items(items = Items.new, opt: {})
62
- logger.benchmark(:filter_items, :start)
63
- time_rx = /^(\d{1,2}+(:\d{1,2}+)?( *(am|pm))?|midnight|noon)$/i
64
+ logger.measure(:filter_items) do
65
+ time_rx = /^(\d{1,2}+(:\d{1,2}+)?( *(am|pm))?|midnight|noon)$/i
64
66
 
65
- if items.nil? || items.empty?
66
- section = !opt[:section] || opt[:section].empty? ? 'All' : guess_section(opt[:section])
67
- if section.is_a?(Array)
68
- section.each do |s|
69
- s = s[0] if s.is_a?(Array)
70
- items.concat(s =~ /^all$/i ? @content.clone : @content.in_section(s))
67
+ if items.nil? || items.empty?
68
+ section = !opt[:section] || opt[:section].empty? ? 'All' : guess_section(opt[:section])
69
+ if section.is_a?(Array)
70
+ section.each do |s|
71
+ s = s[0] if s.is_a?(Array)
72
+ items.concat(s =~ /^all$/i ? @content.clone : @content.in_section(s))
73
+ end
74
+ else
75
+ items = section =~ /^all$/i ? @content.clone : @content.in_section(section)
71
76
  end
72
- else
73
- items = section =~ /^all$/i ? @content.clone : @content.in_section(section)
74
77
  end
75
- end
76
78
 
77
- unless opt[:time_filter]
78
- opt[:time_filter] = [nil, nil]
79
- if opt[:from] && !opt[:date_filter]
80
- if opt[:from][0].is_a?(String) && opt[:from][0] =~ time_rx
81
- opt[:time_filter] = opt[:from]
82
- elsif opt[:from][0].is_a?(Time)
83
- opt[:date_filter] = opt[:from]
79
+ unless opt[:time_filter]
80
+ opt[:time_filter] = [nil, nil]
81
+ if opt[:from] && !opt[:date_filter]
82
+ if opt[:from][0].is_a?(String) && opt[:from][0] =~ time_rx
83
+ opt[:time_filter] = opt[:from]
84
+ elsif opt[:from][0].is_a?(Time)
85
+ opt[:date_filter] = opt[:from]
86
+ end
84
87
  end
85
88
  end
86
- end
87
89
 
88
- if opt[:before].is_a?(String) && opt[:before] =~ time_rx
89
- opt[:time_filter][1] = opt[:before]
90
- opt[:before] = nil
91
- end
92
-
93
- if opt[:after].is_a?(String) && opt[:after] =~ time_rx
94
- opt[:time_filter][0] = opt[:after]
95
- opt[:after] = nil
96
- end
90
+ if opt[:before].is_a?(String) && opt[:before] =~ time_rx
91
+ opt[:time_filter][1] = opt[:before]
92
+ opt[:before] = nil
93
+ end
97
94
 
98
- items.sort_by! { |item| [item.date, item.title.downcase] }.reverse
95
+ if opt[:after].is_a?(String) && opt[:after] =~ time_rx
96
+ opt[:time_filter][0] = opt[:after]
97
+ opt[:after] = nil
98
+ end
99
99
 
100
- filtered_items = items.select { |item| item.keep_item?(opt) }
100
+ items.sort_by! { |item| [item.date, item.title.downcase] }.reverse
101
101
 
102
- count = opt[:count].to_i&.positive? ? opt[:count].to_i : filtered_items.count
102
+ filtered_items = items.select { |item| item.keep_item?(opt) }
103
103
 
104
- output = Items.new
104
+ count = opt[:count].to_i&.positive? ? opt[:count].to_i : filtered_items.count
105
105
 
106
- if opt[:age] && opt[:age].normalize_age == :oldest
107
- output.concat(filtered_items.slice(0, count).reverse)
108
- else
109
- output.concat(filtered_items.reverse.slice(0, count))
110
- end
106
+ output = Items.new
111
107
 
112
- logger.benchmark(:filter_items, :finish)
108
+ if opt[:age] && opt[:age].normalize_age == :oldest
109
+ output.concat(filtered_items.slice(0, count).reverse)
110
+ else
111
+ output.concat(filtered_items.reverse.slice(0, count))
112
+ end
113
113
 
114
- output
114
+ output
115
+ end
115
116
  end
116
117
  end
117
118
  end
@@ -9,9 +9,7 @@ module Doing
9
9
  ## @param guessed [Boolean] already guessed and failed
10
10
  ##
11
11
  def guess_section(frag, guessed: false, suggest: false)
12
- if frag.is_a?(Array) && frag.count == 1
13
- frag = frag[0]
14
- end
12
+ frag = frag[0] if frag.is_a?(Array) && frag.count == 1
15
13
 
16
14
  frag = frag.split(/ *, */).map(&:strip) if frag.is_a?(String) && frag =~ /,/
17
15
 
@@ -25,7 +23,7 @@ module Doing
25
23
 
26
24
  found = @content.guess_section(frag, distance: 2)
27
25
 
28
- section = found ? found.title : nil
26
+ section = found&.title
29
27
 
30
28
  if section && suggest
31
29
  Doing.logger.debug('Match:', %(Assuming "#{section}" from "#{frag}"))
@@ -38,12 +36,12 @@ module Doing
38
36
  prompt = Color.template("{bw}Did you mean `{xy}doing {by}view {xy}#{alt}`{bw}?{x}")
39
37
  meant_view = Prompt.yn(prompt, default_response: 'n')
40
38
 
41
- msg = format('%<y>srun with `%<w>sdoing view %<alt>s%<y>s`', w: boldwhite, y: yellow, alt: alt)
39
+ msg = format('%<y>srun with `%<w>sdoing view %<alt>s%<y>s`', w: Color.boldwhite, y: Color.yellow, alt: alt)
42
40
  raise Errors::WrongCommand.new(msg, topic: 'Try again:') if meant_view
43
41
 
44
42
  end
45
43
 
46
- res = Prompt.yn("#{boldwhite}Section #{frag.yellow}#{boldwhite} not found, create it", default_response: 'n')
44
+ res = Prompt.yn("#{Color.boldwhite}Section #{Color.yellow(frag)}#{Color.boldwhite} not found, create it", default_response: 'n')
47
45
 
48
46
  if res
49
47
  @content.add_section(frag.cap_first, log: true)
@@ -53,7 +51,7 @@ module Doing
53
51
 
54
52
  raise Errors::InvalidSection.new("unknown section #{frag.bold.white}", topic: 'Missing:')
55
53
  end
56
- section ? section.cap_first : nil
54
+ section&.cap_first
57
55
  end
58
56
 
59
57
  ##
@@ -82,7 +80,7 @@ module Doing
82
80
  meant_view = Prompt.yn(prompt, default_response: 'n')
83
81
 
84
82
  if meant_view
85
- msg = format('%<y>srun with `%<w>sdoing show %<alt>s%<y>s`', w: boldwhite, y: yellow, alt: alt)
83
+ msg = format('%<y>srun with `%<w>sdoing show %<alt>s%<y>s`', w: Color.boldwhite, y: Color.yellow, alt: alt)
86
84
  raise Errors::WrongCommand.new(msg, topic: 'Try again:')
87
85
 
88
86
  end
@@ -25,14 +25,14 @@ module Doing
25
25
  opt[:query] = "!#{opt[:query]}" if opt[:query] && opt[:not]
26
26
  opt[:multiple] = true
27
27
  opt[:show_if_single] = true
28
- filter_options = %i[after before case date_filter from fuzzy not search section val].each_with_object({}) {
28
+ filter_options = %i[after before case date_filter from fuzzy not search section val].each_with_object({}) do
29
29
  |k, hsh| hsh[k] = opt[k]
30
- }
30
+ end
31
31
  items = filter_items(Items.new, opt: filter_options)
32
32
 
33
- menu_options = %i[search query exact multiple show_if_single menu sort case].each_with_object({}) {
34
- |k, hsh| hsh[k] = opt[k]
35
- }
33
+ menu_options = %i[search query exact multiple show_if_single menu sort case].each_with_object({}) do |k, hsh|
34
+ hsh[k] = opt[k]
35
+ end
36
36
  include_section = (opt[:section].is_a?(Array) && opt[:section][0] =~ /^all$/i) || (opt[:section].is_a?(String) && opt[:section] =~ /^all$/i)
37
37
 
38
38
  selection = Prompt.choose_from_items(items, include_section: include_section, **menu_options)
@@ -118,7 +118,7 @@ module Doing
118
118
  tags = type == 'add' ? all_tags(@content) : all_tags(items)
119
119
 
120
120
  add_msg = type == 'add' ? ', include values with tag(value)' : ''
121
- puts "#{yellow}Separate multiple tags with spaces, hit tab to complete known tags#{add_msg}"
121
+ puts "#{Color.yellow}Separate multiple tags with spaces, hit tab to complete known tags#{add_msg}"
122
122
  puts "#{boldgreen}Available tags: #{boldwhite}#{tags.sort.map(&:add_at).join(', ')}" if type == 'remove'
123
123
  tag = Prompt.read_line(prompt: "Tags to #{type}", completions: tags)
124
124
 
@@ -255,8 +255,8 @@ module Doing
255
255
 
256
256
  if opt[:editor]
257
257
  sleep 2 # This seems to be necessary between running fzf
258
- # and forking the editor, otherwise vim gets all
259
- # screwy and I can't figure out why
258
+ # and forking the editor, otherwise vim gets all
259
+ # screwy and I can't figure out why
260
260
  edit_items(items) # hooked
261
261
 
262
262
  write(@doing_file)
@@ -367,7 +367,7 @@ module Doing
367
367
  if max_elapsed.positive? && (elapsed > max_elapsed)
368
368
  puts boldwhite(title) if title
369
369
  human = elapsed.time_string(format: :natural)
370
- res = Prompt.yn(yellow("Did this entry actually take #{human}"), default_response: true)
370
+ res = Prompt.yn(Color.yellow("Did this entry actually take #{human}"), default_response: true)
371
371
  unless res
372
372
  new_elapsed = Prompt.enter_text('How long did it take?').chronify_qty
373
373
  raise InvalidTimeExpression, 'Unrecognized time span entry' unless new_elapsed.positive?
@@ -19,7 +19,7 @@ module Doing
19
19
  opt ||= {}
20
20
  section ||= Doing.setting('current_section')
21
21
  @content.add_section(section, log: false)
22
- opt[:back] ||= opt[:date] ? opt[:date] : Time.now
22
+ opt[:back] ||= opt[:date] || Time.now
23
23
  opt[:date] ||= Time.now
24
24
  note = Note.new
25
25
  opt[:timed] ||= false
@@ -78,8 +78,8 @@ module Doing
78
78
  if finish_date
79
79
  item.tag('done', remove: true)
80
80
  item.tag('done', value: finish_date.strftime('%F %R'))
81
- else
82
- item.tag('done', remove: true) if resume
81
+ elsif resume
82
+ item.tag('done', remove: true)
83
83
  end
84
84
  logger.info('Reset:', %(Reset #{resume ? 'and resumed ' : ''} "#{item.title}" in #{item.section}))
85
85
  item
@@ -118,7 +118,7 @@ module Doing
118
118
  note = opt[:note] || Note.new
119
119
 
120
120
  if opt[:editor]
121
- start = opt[:date] ? opt[:date] : Time.now
121
+ start = opt[:date] || Time.now
122
122
  to_edit = "#{start.strftime('%F %R')} | #{title}"
123
123
  to_edit += "\n#{note.strip_lines.join("\n")}" unless note.empty?
124
124
  new_item = fork_editor(to_edit)
@@ -168,7 +168,8 @@ module Doing
168
168
  ##
169
169
  ## @see #filter_items
170
170
  ##
171
- def tag_last(opt) # hooked
171
+ # hooked
172
+ def tag_last(opt)
172
173
  opt ||= {}
173
174
  opt[:count] ||= 1
174
175
  opt[:archive] ||= false
@@ -186,11 +187,11 @@ module Doing
186
187
 
187
188
  if opt[:interactive]
188
189
  items = Prompt.choose_from_items(items, include_section: opt[:section] =~ /^all$/i, menu: true,
189
- header: '',
190
- prompt: 'Select entries to tag > ',
191
- multiple: true,
192
- sort: true,
193
- show_if_single: true)
190
+ header: '',
191
+ prompt: 'Select entries to tag > ',
192
+ multiple: true,
193
+ sort: true,
194
+ show_if_single: true)
194
195
 
195
196
  raise NoResults, 'no items selected' if items.empty?
196
197
 
@@ -201,9 +202,9 @@ module Doing
201
202
  if opt[:tags].empty? && !opt[:autotag]
202
203
  completions = opt[:remove] ? all_tags(items) : all_tags(@content)
203
204
  if opt[:remove]
204
- puts "#{yellow}Available tags: #{boldwhite}#{completions.map(&:add_at).join(', ')}"
205
+ puts "#{Color.yellow}Available tags: #{Color.boldwhite}#{completions.map(&:add_at).join(', ')}"
205
206
  else
206
- puts "#{yellow}Use tab to complete known tags"
207
+ puts "#{Color.yellow}Use tab to complete known tags"
207
208
  end
208
209
  opt[:tags] = Doing::Prompt.read_line(prompt: "Enter tag(s) to #{opt[:remove] ? 'remove' : 'add'}",
209
210
  completions: completions,
@@ -267,10 +268,10 @@ module Doing
267
268
  if max_elapsed.positive? && (elapsed > max_elapsed) && !opt[:took]
268
269
  puts boldwhite(item.title)
269
270
  human = elapsed.time_string(format: :natural)
270
- res = Prompt.yn(yellow("Did this actually take #{human}"), default_response: true)
271
+ res = Prompt.yn(Color.yellow("Did this actually take #{human}"), default_response: true)
271
272
  unless res
272
273
  new_elapsed = Prompt.enter_text('How long did it take?').chronify_qty
273
- raise InvalidTimeExpression, 'Unrecognized time span entry' unless new_elapsed > 0
274
+ raise InvalidTimeExpression, 'Unrecognized time span entry' unless new_elapsed.positive?
274
275
 
275
276
  opt[:took] = new_elapsed
276
277
  done_date = item.calculate_end_date(opt) if opt[:took]
@@ -289,7 +290,8 @@ module Doing
289
290
  end
290
291
  old_title = item.title.dup
291
292
  force = opt[:value].nil? ? false : true
292
- item.title.tag!(tag, remove: opt[:remove], rename_to: rename_to, regex: opt[:regex], value: opt[:value], force: force)
293
+ item.title.tag!(tag, remove: opt[:remove], rename_to: rename_to, regex: opt[:regex], value: opt[:value],
294
+ force: force)
293
295
  if old_title != item.title
294
296
  removed << tag
295
297
  added << rename_to if rename_to
@@ -310,7 +312,7 @@ module Doing
310
312
 
311
313
  item.note.add(opt[:note]) if opt[:note]
312
314
 
313
- if opt[:archive] && opt[:section] != 'Archive' && (opt[:count]).positive?
315
+ if opt[:archive] && opt[:section] != 'Archive' && opt[:count].positive?
314
316
  item.move_to('Archive', label: true)
315
317
  elsif opt[:archive] && opt[:count].zero?
316
318
  logger.warn('Skipped:', 'Archiving is skipped when operating on all entries')
@@ -376,7 +378,6 @@ module Doing
376
378
  Hooks.trigger :post_entry_updated, self, item, old_item
377
379
  end
378
380
 
379
-
380
381
  logger.debug('Skipped:', "No active @#{tag} tasks found.") if found_items.zero?
381
382
 
382
383
  if opt[:new_item]
@@ -431,12 +432,13 @@ module Doing
431
432
 
432
433
  destination = guess_section(destination)
433
434
 
434
- if @content.section?(destination) && (@content.section?(section) || archive_all)
435
- do_archive(section, destination, { count: count, tags: tags, bool: bool, search: options[:search], label: options[:label], before: options[:before], after: options[:after], from: options[:from] })
436
- write(doing_file)
437
- else
435
+ unless @content.section?(destination) && (@content.section?(section) || archive_all)
438
436
  raise InvalidArgument, 'Either source or destination does not exist'
439
437
  end
438
+
439
+ do_archive(section, destination,
440
+ { count: count, tags: tags, bool: bool, search: options[:search], label: options[:label], before: options[:before], after: options[:after], from: options[:from] })
441
+ write(doing_file)
440
442
  end
441
443
 
442
444
  ##
@@ -483,43 +485,41 @@ module Doing
483
485
  end
484
486
  end
485
487
 
486
- if Doing.setting('autotag.transform')
487
- Doing.setting('autotag.transform').each do |tag|
488
- next unless tag =~ /\S+:\S+/
488
+ Doing.setting('autotag.transform')&.each do |tag|
489
+ next unless tag =~ /\S+:\S+/
489
490
 
490
- if tag =~ /::/
491
- rx, r = tag.split(/::/)
492
- else
493
- rx, r = tag.split(/:/)
494
- end
491
+ if tag =~ /::/
492
+ rx, r = tag.split(/::/)
493
+ else
494
+ rx, r = tag.split(/:/)
495
+ end
495
496
 
496
- flag_rx = %r{/([r]+)$}
497
- if r =~ flag_rx
498
- flags = r.match(flag_rx)[1].split(//)
499
- r.sub!(flag_rx, '')
500
- end
501
- r.gsub!(/\$/, '\\')
502
- rx.sub!(/^@?/, '@')
503
- regex = Regexp.new("(?<= |\\A)#{rx}(?= |\\Z)")
497
+ flag_rx = %r{/(r+)$}
498
+ if r =~ flag_rx
499
+ flags = r.match(flag_rx)[1].split(//)
500
+ r.sub!(flag_rx, '')
501
+ end
502
+ r.gsub!(/\$/, '\\')
503
+ rx.sub!(/^@?/, '@')
504
+ regex = Regexp.new("(?<= |\\A)#{rx}(?= |\\Z)")
504
505
 
505
- text.sub!(regex) do
506
- m = Regexp.last_match
507
- new_tag = r
506
+ text.sub!(regex) do
507
+ m = Regexp.last_match
508
+ new_tag = r
508
509
 
509
- m.to_a.slice(1, m.length - 1).each_with_index do |v, idx|
510
- next if v.nil?
510
+ m.to_a.slice(1, m.length - 1).each_with_index do |v, idx|
511
+ next if v.nil?
511
512
 
512
- new_tag.gsub!("\\#{idx + 1}", v)
513
- end
514
- # Replace original tag if /r
515
- if flags&.include?('r')
516
- tagged[:replaced].concat(new_tag.split(/ /).map { |t| t.sub(/^@/, '') })
517
- new_tag.split(/ /).map { |t| t.sub(/^@?/, '@') }.join(' ')
518
- else
519
- tagged[:transformed].concat(new_tag.split(/ /).map { |t| t.sub(/^@/, '') })
520
- tagged[:transformed] = tagged[:transformed].uniq
521
- m[0]
522
- end
513
+ new_tag.gsub!("\\#{idx + 1}", v)
514
+ end
515
+ # Replace original tag if /r
516
+ if flags&.include?('r')
517
+ tagged[:replaced].concat(new_tag.split(/ /).map { |t| t.sub(/^@/, '') })
518
+ new_tag.split(/ /).map { |t| t.sub(/^@?/, '@') }.join(' ')
519
+ else
520
+ tagged[:transformed].concat(new_tag.split(/ /).map { |t| t.sub(/^@/, '') })
521
+ tagged[:transformed] = tagged[:transformed].uniq
522
+ m[0]
523
523
  end
524
524
  end
525
525
  end
@@ -69,13 +69,11 @@ EOTAIL
69
69
  pad = sorted_tags_data.map { |k, _| k }.group_by(&:size).max.last[0].length
70
70
  pad = 7 if pad < 7
71
71
  output = <<~EOHEADER
72
- | #{' ' * (pad - 7)}project | time |
73
- | #{'-' * (pad - 1)}: | :------- |
72
+ | #{' ' * (pad - 7)}project | time |
73
+ | #{'-' * (pad - 1)}: | :------- |
74
74
  EOHEADER
75
75
  sorted_tags_data.reverse.each do |k, v|
76
- if v.positive?
77
- output += "| #{' ' * (pad - k.length)}#{k} | #{v.time_string(format: :clock)} |\n"
78
- end
76
+ output += "| #{' ' * (pad - k.length)}#{k} | #{v.time_string(format: :clock)} |\n" if v.positive?
79
77
  end
80
78
  tail = '[Tag Totals]'
81
79
  output + tail
@@ -173,6 +171,7 @@ EOTAIL
173
171
  def record_tag_times(item, seconds)
174
172
  item_hash = "#{item.date.strftime('%s')}#{item.title}#{item.section}"
175
173
  return if @recorded_items.include?(item_hash)
174
+
176
175
  item.title.scan(/(?mi)@(\S+?)(\(.*\))?(?=\s|$)/).each do |m|
177
176
  k = m[0] == 'done' ? 'All' : m[0].downcase
178
177
  if @timers.key?(k)
File without changes
@@ -32,7 +32,7 @@ module Doing
32
32
  ##
33
33
  def import(paths, opt)
34
34
  opt ||= {}
35
- Plugins.plugins[:import].each do |_, options|
35
+ Plugins.plugins[:import].each_value do |options|
36
36
  next unless opt[:type] =~ /^(#{options[:trigger].normalize_trigger})$/i
37
37
 
38
38
  if paths.count.positive?
@@ -54,17 +54,15 @@ module Doing
54
54
  ## alternative config file
55
55
  ##
56
56
  def configure(filename = nil)
57
- logger.benchmark(:configure, :start)
57
+ logger.measure(:configure) do
58
+ if filename
59
+ Doing.config_with(filename, { ignore_local: true })
60
+ elsif ENV['DOING_CONFIG']
61
+ Doing.config_with(ENV['DOING_CONFIG'], { ignore_local: true })
62
+ end
58
63
 
59
- if filename
60
- Doing.config_with(filename, { ignore_local: true })
61
- elsif ENV['DOING_CONFIG']
62
- Doing.config_with(ENV['DOING_CONFIG'], { ignore_local: true })
64
+ Doing.set('backup_dir', ENV['DOING_BACKUP_DIR']) if ENV['DOING_BACKUP_DIR']
63
65
  end
64
-
65
- logger.benchmark(:configure, :finish)
66
-
67
- Doing.set('backup_dir', ENV['DOING_BACKUP_DIR']) if ENV['DOING_BACKUP_DIR']
68
66
  end
69
67
 
70
68
  ##
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  desc 'Output a tag wiki'
2
4
  command :wiki do |c|
3
5
  c.desc 'Section to rotate'
@@ -50,7 +50,7 @@ module Doing
50
50
  new_items = wwid.filter_items(new_items, opt: options)
51
51
 
52
52
  skipped = total - new_items.count
53
- Doing.logger.debug('Skipped:' , %(#{skipped} items that didn't match filter criteria)) if skipped.positive?
53
+ Doing.logger.debug('Skipped:', %(#{skipped} items that didn't match filter criteria)) if skipped.positive?
54
54
 
55
55
  imported = []
56
56
 
@@ -81,7 +81,6 @@ module Doing
81
81
  }
82
82
  end
83
83
 
84
-
85
84
  #-------------------------------------------------------
86
85
  ## Output a template. Only required if template(s) are
87
86
  ## included in settings. The method should return a
@@ -100,10 +99,10 @@ module Doing
100
99
  ##
101
100
  def self.template(trigger)
102
101
  return unless trigger =~ /^say(it)?$/
102
+
103
103
  'On %date, you were %title, recorded in section %section%took'
104
104
  end
105
105
 
106
-
107
106
  ##
108
107
  ## Render data received from an output
109
108
  ## command
@@ -6,7 +6,6 @@
6
6
  # url: https://brettterpstra.com
7
7
  module Doing
8
8
  class WikiExport
9
-
10
9
  def self.settings
11
10
  {
12
11
  trigger: 'wiki',
@@ -55,7 +54,7 @@ module Doing
55
54
 
56
55
  items_out << {
57
56
  date: i.date.strftime('%a %-I:%M%p'),
58
- title: title, #+ " #{note}"
57
+ title: title, # + " #{note}"
59
58
  note: note,
60
59
  time: interval,
61
60
  section: i.section
@@ -78,10 +77,10 @@ module Doing
78
77
  engine = Haml::Engine.new(template)
79
78
  Doing.logger.debug('Wiki Export:', "#{items_out.count} items output to #{variables[:page_title]} wiki page")
80
79
  @out = engine.render(Object.new,
81
- { :@items => items_out, :@page_title => variables[:page_title], :@style => style, :@totals => totals })
80
+ { :@items => items_out, :@page_title => variables[:page_title], :@style => style,
81
+ :@totals => totals })
82
82
  end
83
83
 
84
84
  Doing::Plugins.register 'wiki', :export, self
85
85
  end
86
86
  end
87
-
@@ -890,7 +890,7 @@ class TestGoFZF < TestBase
890
890
  end
891
891
  wait do
892
892
  assert_path_exists history_file
893
- assert_equal input[1..-1], File.readlines(history_file, chomp: true)
893
+ assert_equal input[1..], File.readlines(history_file, chomp: true)
894
894
  end
895
895
 
896
896
  # Update history entries (not changed on disk)
@@ -2212,7 +2212,7 @@ module TestShell
2212
2212
  tmux.prepare
2213
2213
  tmux.send_keys :Escape, :c
2214
2214
  lines = tmux.until { |lines| assert_operator lines.match_count, :>, 0 }
2215
- expected = lines.reverse.find { |l| l.start_with?('> ') }[2..-1]
2215
+ expected = lines.reverse.find { |l| l.start_with?('> ') }[2..]
2216
2216
  tmux.send_keys :Enter
2217
2217
  tmux.prepare
2218
2218
  tmux.send_keys :pwd, :Enter
@@ -2265,7 +2265,7 @@ module TestShell
2265
2265
 
2266
2266
  def test_ctrl_r_multiline
2267
2267
  tmux.send_keys 'echo "foo', :Enter, 'bar"', :Enter
2268
- tmux.until { |lines| assert_equal %w[foo bar], lines[-2..-1] }
2268
+ tmux.until { |lines| assert_equal %w[foo bar], lines[-2..] }
2269
2269
  tmux.prepare
2270
2270
  tmux.send_keys 'C-r'
2271
2271
  tmux.until { |lines| assert_equal '>', lines[-1] }
@@ -2274,7 +2274,7 @@ module TestShell
2274
2274
  tmux.send_keys :Enter
2275
2275
  tmux.until { |lines| assert lines[-1]&.end_with?('bar"') }
2276
2276
  tmux.send_keys :Enter
2277
- tmux.until { |lines| assert_equal %w[foo bar], lines[-2..-1] }
2277
+ tmux.until { |lines| assert_equal %w[foo bar], lines[-2..] }
2278
2278
  end
2279
2279
 
2280
2280
  def test_ctrl_r_abort
@@ -2465,7 +2465,7 @@ module CompletionTest
2465
2465
  tmux.send_keys :Enter
2466
2466
  tmux.until(true) { |lines| assert_match(/cat .*fzf-unicode.*1.* .*fzf-unicode.*2/, lines[-1]) }
2467
2467
  tmux.send_keys :Enter
2468
- tmux.until { |lines| assert_equal %w[test3 test4], lines[-2..-1] }
2468
+ tmux.until { |lines| assert_equal %w[test3 test4], lines[-2..] }
2469
2469
  end
2470
2470
 
2471
2471
  def test_custom_completion_api