doing 2.1.89 → 2.1.91

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 (248) 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 +26 -0
  6. data/Gemfile +2 -0
  7. data/Gemfile.lock +1 -1
  8. data/README.md +1 -1
  9. data/Rakefile +5 -3
  10. data/bin/commands/changes.rb +3 -1
  11. data/bin/commands/choose.rb +2 -0
  12. data/bin/commands/colors.rb +5 -3
  13. data/bin/commands/commands_accepting.rb +3 -3
  14. data/bin/commands/completion.rb +2 -1
  15. data/bin/commands/config.rb +8 -6
  16. data/bin/commands/done.rb +19 -12
  17. data/bin/commands/finish.rb +4 -2
  18. data/bin/commands/grep.rb +9 -5
  19. data/bin/commands/import.rb +14 -11
  20. data/bin/commands/install_fzf.rb +4 -2
  21. data/bin/commands/last.rb +31 -27
  22. data/bin/commands/meanwhile.rb +6 -2
  23. data/bin/commands/note.rb +6 -3
  24. data/bin/commands/now.rb +2 -0
  25. data/bin/commands/open.rb +6 -1
  26. data/bin/commands/plugins.rb +2 -0
  27. data/bin/commands/recent.rb +47 -33
  28. data/bin/commands/reset.rb +7 -3
  29. data/bin/commands/rotate.rb +6 -3
  30. data/bin/commands/sections.rb +3 -3
  31. data/bin/commands/select.rb +2 -0
  32. data/bin/commands/show.rb +24 -20
  33. data/bin/commands/since.rb +10 -3
  34. data/bin/commands/tag.rb +18 -16
  35. data/bin/commands/tag_dir.rb +5 -2
  36. data/bin/commands/tags.rb +17 -17
  37. data/bin/commands/template.rb +8 -2
  38. data/bin/commands/today.rb +10 -2
  39. data/bin/commands/undo.rb +2 -0
  40. data/bin/commands/update.rb +9 -7
  41. data/bin/commands/view.rb +11 -8
  42. data/bin/commands/views.rb +2 -0
  43. data/bin/commands/yesterday.rb +6 -1
  44. data/bin/doing +54 -57
  45. data/docs/doc/Array.html +3 -3
  46. data/docs/doc/BooleanTermParser/Clause.html +3 -3
  47. data/docs/doc/BooleanTermParser/Operator.html +3 -3
  48. data/docs/doc/BooleanTermParser/Query.html +3 -3
  49. data/docs/doc/BooleanTermParser/QueryParser.html +3 -3
  50. data/docs/doc/BooleanTermParser/QueryTransformer.html +3 -3
  51. data/docs/doc/BooleanTermParser.html +3 -3
  52. data/docs/doc/Doing/ArrayCleanup.html +3 -3
  53. data/docs/doc/Doing/ArrayNestedHash.html +3 -3
  54. data/docs/doc/Doing/ArrayTags.html +9 -9
  55. data/docs/doc/Doing/ByDayExport.html +3 -3
  56. data/docs/doc/Doing/CSVExport.html +4 -4
  57. data/docs/doc/Doing/CalendarImport.html +4 -4
  58. data/docs/doc/Doing/Change.html +3 -3
  59. data/docs/doc/Doing/Changes.html +3 -3
  60. data/docs/doc/Doing/ChronifyArray.html +3 -3
  61. data/docs/doc/Doing/ChronifyNumeric.html +3 -3
  62. data/docs/doc/Doing/ChronifyString.html +6 -6
  63. data/docs/doc/Doing/Color.html +88 -47
  64. data/docs/doc/Doing/Completion/BashCompletions.html +3 -3
  65. data/docs/doc/Doing/Completion/FigCompletions.html +3 -3
  66. data/docs/doc/Doing/Completion/FishCompletions.html +3 -3
  67. data/docs/doc/Doing/Completion/StringUtils.html +3 -3
  68. data/docs/doc/Doing/Completion/ZshCompletions.html +3 -3
  69. data/docs/doc/Doing/Completion.html +5 -5
  70. data/docs/doc/Doing/Configuration.html +6 -6
  71. data/docs/doc/Doing/DayOneRenderer.html +3 -3
  72. data/docs/doc/Doing/DayoneExport.html +4 -4
  73. data/docs/doc/Doing/DoingExport.html +5 -5
  74. data/docs/doc/Doing/DoingImport.html +4 -4
  75. data/docs/doc/Doing/Entry.html +3 -3
  76. data/docs/doc/Doing/Errors/DoingNoTraceError.html +3 -3
  77. data/docs/doc/Doing/Errors/DoingRuntimeError.html +3 -3
  78. data/docs/doc/Doing/Errors/DoingStandardError.html +3 -3
  79. data/docs/doc/Doing/Errors/EmptyInput.html +3 -3
  80. data/docs/doc/Doing/Errors/HistoryLimitError.html +3 -3
  81. data/docs/doc/Doing/Errors/InvalidPlugin.html +3 -3
  82. data/docs/doc/Doing/Errors/MissingBackupFile.html +3 -3
  83. data/docs/doc/Doing/Errors/NoResults.html +3 -3
  84. data/docs/doc/Doing/Errors/PluginException.html +3 -3
  85. data/docs/doc/Doing/Errors/UserCancelled.html +3 -3
  86. data/docs/doc/Doing/Errors/WrongCommand.html +3 -3
  87. data/docs/doc/Doing/Errors.html +3 -3
  88. data/docs/doc/Doing/HTMLExport.html +4 -4
  89. data/docs/doc/Doing/Hooks.html +3 -16
  90. data/docs/doc/Doing/Item.html +4 -4
  91. data/docs/doc/Doing/ItemDates.html +3 -3
  92. data/docs/doc/Doing/ItemQuery.html +3 -3
  93. data/docs/doc/Doing/ItemState.html +3 -3
  94. data/docs/doc/Doing/ItemTags.html +3 -3
  95. data/docs/doc/Doing/Items.html +3 -3
  96. data/docs/doc/Doing/JSONExport.html +4 -4
  97. data/docs/doc/Doing/JSONImport.html +4 -4
  98. data/docs/doc/Doing/Logger.html +183 -3
  99. data/docs/doc/Doing/MarkdownExport.html +4 -4
  100. data/docs/doc/Doing/Note.html +3 -3
  101. data/docs/doc/Doing/Pager.html +54 -58
  102. data/docs/doc/Doing/Plugins.html +3 -3
  103. data/docs/doc/Doing/Prompt.html +4 -4
  104. data/docs/doc/Doing/PromptChoose.html +3 -3
  105. data/docs/doc/Doing/PromptFZF.html +3 -3
  106. data/docs/doc/Doing/PromptInput.html +3 -3
  107. data/docs/doc/Doing/PromptSTD.html +3 -3
  108. data/docs/doc/Doing/PromptYN.html +3 -3
  109. data/docs/doc/Doing/Section.html +3 -3
  110. data/docs/doc/Doing/StringHighlight.html +3 -3
  111. data/docs/doc/Doing/StringNormalize.html +3 -3
  112. data/docs/doc/Doing/StringQuery.html +4 -4
  113. data/docs/doc/Doing/StringTags.html +3 -3
  114. data/docs/doc/Doing/StringTransform.html +3 -3
  115. data/docs/doc/Doing/StringTruncate.html +3 -3
  116. data/docs/doc/Doing/StringURL.html +3 -3
  117. data/docs/doc/Doing/SymbolNormalize.html +5 -5
  118. data/docs/doc/Doing/TaskPaperExport.html +4 -4
  119. data/docs/doc/Doing/TemplateExport.html +5 -5
  120. data/docs/doc/Doing/TemplateString.html +7 -7
  121. data/docs/doc/Doing/TimingImport.html +4 -4
  122. data/docs/doc/Doing/Types.html +3 -3
  123. data/docs/doc/Doing/Util/Backup.html +4 -17
  124. data/docs/doc/Doing/Util.html +56 -61
  125. data/docs/doc/Doing/Version.html +3 -3
  126. data/docs/doc/Doing/WWID.html +6 -4
  127. data/docs/doc/Doing.html +4 -4
  128. data/docs/doc/FalseClass.html +3 -3
  129. data/docs/doc/GLI/Commands/Help.html +5 -5
  130. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +3 -3
  131. data/docs/doc/GLI/Commands.html +3 -3
  132. data/docs/doc/GLI.html +3 -3
  133. data/docs/doc/Hash.html +4 -4
  134. data/docs/doc/Numeric.html +3 -3
  135. data/docs/doc/Object.html +3 -3
  136. data/docs/doc/PhraseParser/Operator.html +3 -3
  137. data/docs/doc/PhraseParser/PhraseClause.html +3 -3
  138. data/docs/doc/PhraseParser/Query.html +3 -3
  139. data/docs/doc/PhraseParser/QueryParser.html +3 -3
  140. data/docs/doc/PhraseParser/QueryTransformer.html +3 -3
  141. data/docs/doc/PhraseParser/TermClause.html +3 -3
  142. data/docs/doc/PhraseParser.html +3 -3
  143. data/docs/doc/Status.html +3 -3
  144. data/docs/doc/String.html +51 -5
  145. data/docs/doc/Symbol.html +3 -3
  146. data/docs/doc/Time.html +3 -3
  147. data/docs/doc/TrueClass.html +3 -3
  148. data/docs/doc/_index.html +4 -4
  149. data/docs/doc/class_list.html +6 -3
  150. data/docs/doc/css/full_list.css +3 -3
  151. data/docs/doc/css/style.css +6 -0
  152. data/docs/doc/file.README.html +4 -4
  153. data/docs/doc/file_list.html +5 -2
  154. data/docs/doc/frames.html +1 -1
  155. data/docs/doc/index.html +4 -4
  156. data/docs/doc/js/app.js +294 -264
  157. data/docs/doc/js/full_list.js +30 -4
  158. data/docs/doc/method_list.html +443 -392
  159. data/docs/doc/top-level-namespace.html +3 -3
  160. data/doing.gemspec +2 -0
  161. data/doing.rdoc +1 -30
  162. data/example_plugin.rb +1 -4
  163. data/lib/completion/_doing.zsh +0 -4
  164. data/lib/completion/doing.bash +0 -11
  165. data/lib/completion/doing.fish +0 -5
  166. data/lib/completion/doing.ts +0 -40
  167. data/lib/doing/add_options.rb +2 -2
  168. data/lib/doing/array/cleanup.rb +2 -0
  169. data/lib/doing/array/nested_hash.rb +2 -0
  170. data/lib/doing/boolean_term_parser.rb +3 -3
  171. data/lib/doing/changelog/changes.rb +4 -5
  172. data/lib/doing/changelog/version.rb +8 -11
  173. data/lib/doing/chronify/array.rb +4 -4
  174. data/lib/doing/chronify/string.rb +5 -4
  175. data/lib/doing/cli_status.rb +7 -2
  176. data/lib/doing/colors.rb +93 -51
  177. data/lib/doing/completion/bash_completion.rb +36 -39
  178. data/lib/doing/completion/completion_string.rb +2 -1
  179. data/lib/doing/completion/fig_completion.rb +33 -33
  180. data/lib/doing/completion/fish_completion.rb +22 -23
  181. data/lib/doing/completion/zsh_completion.rb +5 -5
  182. data/lib/doing/completion.rb +7 -4
  183. data/lib/doing/configuration.rb +21 -13
  184. data/lib/doing/errors.rb +1 -4
  185. data/lib/doing/good.rb +1 -1
  186. data/lib/doing/hash.rb +4 -4
  187. data/lib/doing/help_monkey_patch.rb +1 -1
  188. data/lib/doing/hooks.rb +6 -2
  189. data/lib/doing/item/dates.rb +3 -1
  190. data/lib/doing/item/item.rb +1 -1
  191. data/lib/doing/item/query.rb +14 -14
  192. data/lib/doing/item/state.rb +2 -0
  193. data/lib/doing/logger.rb +113 -45
  194. data/lib/doing/markdown_document_listener.rb +25 -25
  195. data/lib/doing/normalize.rb +1 -1
  196. data/lib/doing/pager.rb +73 -29
  197. data/lib/doing/plugin_manager.rb +4 -5
  198. data/lib/doing/plugins/export/byday.rb +1 -1
  199. data/lib/doing/plugins/export/dayone_export.rb +28 -27
  200. data/lib/doing/plugins/export/doing_export.rb +1 -1
  201. data/lib/doing/plugins/export/html_export.rb +3 -3
  202. data/lib/doing/plugins/export/json_export.rb +4 -5
  203. data/lib/doing/plugins/export/markdown_export.rb +10 -2
  204. data/lib/doing/plugins/export/taskpaper_export.rb +1 -0
  205. data/lib/doing/plugins/export/template_export.rb +110 -107
  206. data/lib/doing/plugins/import/calendar_import.rb +1 -1
  207. data/lib/doing/plugins/import/doing_import.rb +2 -2
  208. data/lib/doing/plugins/import/timing_import.rb +3 -3
  209. data/lib/doing/prompt/choose.rb +5 -6
  210. data/lib/doing/prompt/fzf.rb +3 -2
  211. data/lib/doing/prompt/input.rb +10 -9
  212. data/lib/doing/prompt/yn.rb +9 -11
  213. data/lib/doing/string/tags.rb +7 -4
  214. data/lib/doing/string/transform.rb +15 -10
  215. data/lib/doing/string/truncate.rb +1 -0
  216. data/lib/doing/string/url.rb +1 -1
  217. data/lib/doing/template_string.rb +13 -9
  218. data/lib/doing/time.rb +4 -2
  219. data/lib/doing/util.rb +12 -11
  220. data/lib/doing/util_backup.rb +29 -26
  221. data/lib/doing/version.rb +3 -1
  222. data/lib/doing/wwid/display.rb +182 -151
  223. data/lib/doing/wwid/editor.rb +13 -12
  224. data/lib/doing/wwid/filetools.rb +13 -11
  225. data/lib/doing/wwid/filter.rb +41 -40
  226. data/lib/doing/wwid/guess.rb +6 -8
  227. data/lib/doing/wwid/interactive.rb +10 -10
  228. data/lib/doing/wwid/modify.rb +55 -55
  229. data/lib/doing/wwid/timers.rb +4 -5
  230. data/lib/doing/wwid/wwid.rb +0 -0
  231. data/lib/doing/wwid/wwidutil.rb +8 -10
  232. data/lib/examples/commands/wiki.rb +2 -0
  233. data/lib/examples/plugins/capture_thing_import.rb +1 -1
  234. data/lib/examples/plugins/say_export.rb +1 -2
  235. data/lib/examples/plugins/wiki_export/wiki_export.rb +3 -4
  236. data/lib/helpers/fzf/test/test_go.rb +5 -5
  237. data/lib/helpers/threaded_tests.rb +20 -20
  238. data/lib/helpers/threaded_tests_string.rb +2 -0
  239. data/rdoc_to_mmd.rb +5 -4
  240. data/rdocfixer.rb +1 -2
  241. data/scripts/deploy.rb +3 -4
  242. data/scripts/generate_bash_completions.rb +40 -43
  243. data/scripts/generate_fish_completions.rb +17 -15
  244. data/scripts/generate_zsh_completions.rb +9 -7
  245. data/scripts/setting_replace.rb +1 -0
  246. data/scripts/sort_commands.rb +4 -2
  247. data/yard_templates/default/method_details/setup.rb +3 -1
  248. metadata +3 -1
@@ -8,11 +8,12 @@ module Doing
8
8
  attr_reader :original
9
9
 
10
10
  include Color
11
- def initialize(string, placeholders: {}, force_color: false, wrap_width: 0, color: '', tags_color: '', reset: '')
11
+ def initialize(string, placeholders: {}, force_color: false, disable_color: false, wrap_width: 0, color: '', tags_color: '', reset: '')
12
12
  Color.coloring = true if force_color
13
+ Color.coloring = false if disable_color
13
14
  @colors = nil
14
15
  @original = string
15
- super(Color.reset + string)
16
+ super(Doing::Color.coloring? ? Color.reset + string : string)
16
17
 
17
18
  placeholders.each { |k, v| fill(k, v, wrap_width: wrap_width, color: color, tags_color: tags_color) }
18
19
  end
@@ -96,10 +97,13 @@ module Doing
96
97
 
97
98
  def fill(placeholder, value, wrap_width: 0, color: '', tags_color: '', reset: '')
98
99
  reparse
99
- rx = /(?mi)(?<!\\)%(?<width>-?\d+)?(?:\^(?<mchar>.))?(?:(?<ichar>[ _t]|[^a-z0-9])(?<icount>\d+))?(?<prefix>.[ _t]?)?#{placeholder.sub(/^%/, '')}(?<after>.*?)$/
100
+ rx = /(?mi)(?<!\\)%(?<width>-?\d+)?(?:\^(?<mchar>.))?(?:(?<ichar>[ _t]|[^a-z0-9])(?<icount>\d+))?(?<prefix>.[ _t]?)?#{placeholder.sub(
101
+ /^%/, ''
102
+ )}(?<after>.*?)$/
100
103
  ph = raw.match(rx)
101
104
 
102
105
  return unless ph
106
+
103
107
  placeholder_offset = ph.begin(0)
104
108
  last_colors = parsed_colors[:colors].select { |v| v[:index] <= placeholder_offset + 4 }
105
109
 
@@ -148,13 +152,11 @@ module Doing
148
152
  after: after,
149
153
  reset: reset,
150
154
  pad_first: false)
151
- out.highlight_tags!(tags_color, last_color: color) if tags_color && !tags_color.empty?
152
- out
153
155
  else
154
156
  out = format("%s%s%#{pad}s%s", prefix, color, value.gsub(/%/, '\%').sub(/\s*$/, ''), after)
155
- out.highlight_tags!(tags_color, last_color: color) if tags_color && !tags_color.empty?
156
- out
157
157
  end
158
+ out.highlight_tags!(tags_color, last_color: color) if tags_color && !tags_color.empty?
159
+ out
158
160
  elsif placeholder =~ /^note/
159
161
  if wrap_width.positive? || pad.positive?
160
162
  width = pad.positive? ? pad : wrap_width
@@ -162,14 +164,16 @@ module Doing
162
164
  if l.empty?
163
165
  ' '
164
166
  else
165
- line = l.gsub(/%/, '\%').strip.wrap(width, pad: pad, indent: indent, offset: 0, prefix: prefix, color: last_color, after: after, reset: reset, pad_first: true)
167
+ line = l.gsub(/%/, '\%').strip.wrap(width, pad: pad, indent: indent, offset: 0, prefix: prefix,
168
+ color: last_color, after: after, reset: reset, pad_first: true)
166
169
  line.highlight_tags!(tags_color, last_color: last_color) unless !tags_color || !tags_color.good?
167
170
  "#{line} "
168
171
  end
169
172
  end.join("\n")
170
173
  "\n#{last_color}#{mark}#{outstring} "
171
174
  else
172
- out = format("\n%s%s%s%#{pad}s%s", indent, prefix, last_color, value.join("\n#{indent}#{prefix}").gsub(/%/, '\%').sub(/\s*$/, ''), after)
175
+ out = format("\n%s%s%s%#{pad}s%s", indent, prefix, last_color,
176
+ value.join("\n#{indent}#{prefix}").gsub(/%/, '\%').sub(/\s*$/, ''), after)
173
177
  out.highlight_tags!(tags_color, last_color: last_color) if tags_color && !tags_color.empty?
174
178
  out
175
179
  end
data/lib/doing/time.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doing
2
4
  ##
3
5
  ## Date helpers
@@ -35,7 +37,7 @@ module Doing
35
37
  h = (m / 60).floor
36
38
  m = (m % 60).floor
37
39
  d = (h / 24).floor
38
- h = h % 24
40
+ h %= 24
39
41
 
40
42
  output = []
41
43
  output.push("#{d} #{'day'.to_p(d)}") if d.positive?
@@ -58,7 +60,7 @@ module Doing
58
60
  "Yesterday at #{strftime('%_I:%M:%S%P')}"
59
61
  elsif self > (Date.today - 6).to_time
60
62
  strftime('%a %I:%M:%S%P')
61
- elsif self.year == Date.today.year
63
+ elsif year == Date.today.year
62
64
  strftime('%m/%d %I:%M:%S%P')
63
65
  else
64
66
  strftime('%m/%d/%Y %I:%M:%S%P')
data/lib/doing/util.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  module Doing
4
4
  # Utilities
5
5
  module Util
6
- extend self
6
+ module_function
7
7
 
8
8
  def user_home
9
9
  if Dir.respond_to?('home')
@@ -119,19 +119,20 @@ module Doing
119
119
  puts content
120
120
  return
121
121
  end
122
- Doing.logger.benchmark(:write_file, :start)
123
- file = File.expand_path(file)
122
+ Doing.logger.measure(:write_file) do
123
+ file = File.expand_path(file)
124
124
 
125
- Backup.write_backup(file) if backup
125
+ Backup.write_backup(file) if backup
126
126
 
127
- File.open(file, 'w+') do |f|
128
- f.puts content
129
- Doing.logger.debug('Write:', "File written: #{file}")
127
+ File.open(file, 'w+') do |f|
128
+ f.puts content
129
+ Doing.logger.debug('Write:', "File written: #{file}")
130
+ end
131
+
132
+ Doing.logger.measure(:_post_write_hook) do
133
+ Hooks.trigger :post_write, file
134
+ end
130
135
  end
131
- Doing.logger.benchmark(:_post_write_hook, :start)
132
- Hooks.trigger :post_write, file
133
- Doing.logger.benchmark(:_post_write_hook, :finish)
134
- Doing.logger.benchmark(:write_file, :finish)
135
136
  end
136
137
 
137
138
  def safe_load_file(filename)
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'zlib'
3
4
 
4
5
  module Doing
@@ -17,7 +18,7 @@ module Doing
17
18
  backups = get_backups(filename)
18
19
  return unless backups.count > limit
19
20
 
20
- backups[limit..-1].each do |file|
21
+ backups[limit..].each do |file|
21
22
  FileUtils.rm(File.join(backup_dir, file))
22
23
  end
23
24
 
@@ -45,18 +46,18 @@ module Doing
45
46
  ## different from default
46
47
  ##
47
48
  def restore_last_backup(filename = nil, count: 1)
48
- Doing.logger.benchmark(:restore_backup, :start)
49
- filename ||= Doing.setting('doing_file')
49
+ Doing.logger.measure(:restore_backup) do
50
+ filename ||= Doing.setting('doing_file')
50
51
 
51
- backup_file = last_backup(filename, count: count)
52
- raise HistoryLimitError, 'End of undo history' if backup_file.nil?
52
+ backup_file = last_backup(filename, count: count)
53
+ raise HistoryLimitError, 'End of undo history' if backup_file.nil?
53
54
 
54
- save_undone(filename)
55
- move_backup(backup_file, filename)
55
+ save_undone(filename)
56
+ move_backup(backup_file, filename)
56
57
 
57
- prune_backups_after(File.basename(backup_file))
58
- Doing.logger.warn('File update:', "restored from #{backup_file}")
59
- Doing.logger.benchmark(:restore_backup, :finish)
58
+ prune_backups_after(File.basename(backup_file))
59
+ Doing.logger.warn('File update:', "restored from #{backup_file}")
60
+ end
60
61
  end
61
62
 
62
63
  ##
@@ -138,13 +139,15 @@ module Doing
138
139
  options = get_backups(filename).each_with_object([]) do |file, arr|
139
140
  d, _base = date_of_backup(file)
140
141
  next if d.nil?
142
+
141
143
  arr.push("#{d.time_ago}\t#{File.join(backup_dir, file)}")
142
144
  end
143
145
 
144
146
  raise MissingBackupFile, 'No backup files to load' if options.empty?
145
147
 
146
148
  backup_file = show_menu(options, filename)
147
- Util.write_to_file(File.join(backup_dir, "undone___#{File.basename(filename)}"), IO.read(filename), backup: false)
149
+ Util.write_to_file(File.join(backup_dir, "undone___#{File.basename(filename)}"), IO.read(filename),
150
+ backup: false)
148
151
  move_backup(backup_file, filename)
149
152
  prune_backups_after(File.basename(backup_file))
150
153
  Doing.logger.warn('File update:', "restored from #{backup_file}")
@@ -157,25 +160,25 @@ module Doing
157
160
  ## @param filename [String] The filename
158
161
  ##
159
162
  def write_backup(filename = nil)
160
- Doing.logger.benchmark(:_write_backup, :start)
161
- filename ||= Doing.setting('doing_file')
163
+ Doing.logger.measure(:_write_backup) do
164
+ filename ||= Doing.setting('doing_file')
162
165
 
163
- unless File.exist?(filename)
164
- Doing.logger.debug('Backup:', "original file doesn't exist (#{filename})")
165
- return
166
- end
166
+ unless File.exist?(filename)
167
+ Doing.logger.debug('Backup:', "original file doesn't exist (#{filename})")
168
+ return
169
+ end
167
170
 
168
- backup_file = File.join(backup_dir, "#{timestamp_filename}___#{File.basename(filename)}")
169
- # compressed = Zlib::Deflate.deflate(content)
170
- # Zlib::GzipWriter.open(backup_file + '.gz') do |gz|
171
- # gz.write(IO.read(filename))
172
- # end
171
+ backup_file = File.join(backup_dir, "#{timestamp_filename}___#{File.basename(filename)}")
172
+ # compressed = Zlib::Deflate.deflate(content)
173
+ # Zlib::GzipWriter.open(backup_file + '.gz') do |gz|
174
+ # gz.write(IO.read(filename))
175
+ # end
173
176
 
174
- FileUtils.cp(filename, backup_file)
177
+ FileUtils.cp(filename, backup_file)
175
178
 
176
- prune_backups(filename, Doing.setting('history_size').to_i)
177
- clear_undone(filename)
178
- Doing.logger.benchmark(:_write_backup, :finish)
179
+ prune_backups(filename, Doing.setting('history_size').to_i)
180
+ clear_undone(filename)
181
+ end
179
182
  end
180
183
 
181
184
  private
data/lib/doing/version.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Doing
2
- VERSION = '2.1.89'
4
+ VERSION = '2.1.91'
3
5
  end
@@ -8,91 +8,108 @@ module Doing
8
8
  ## @param opt [Hash] Additional Options
9
9
  ##
10
10
  def list_section(opt, items: Items.new)
11
- logger.benchmark(:list_section, :start)
12
- opt[:config_template] ||= 'default'
13
-
14
- tpl_cfg = Doing.setting(['templates', opt[:config_template]])
15
-
16
- cfg = if opt[:view_template]
17
- Doing.setting(['views', opt[:view_template]]).deep_merge(tpl_cfg, { extend_existing_arrays: true, sort_merged_arrays: true })
18
- else
19
- tpl_cfg
20
- end
21
-
22
- cfg.deep_merge({
23
- 'wrap_width' => Doing.setting('wrap_width') || 0,
24
- 'date_format' => Doing.setting('default_date_format'),
25
- 'order' => Doing.setting('order') || :asc,
26
- 'tags_color' => Doing.setting('tags_color'),
27
- 'duration' => Doing.setting('duration'),
28
- 'interval_format' => Doing.setting('interval_format')
29
- }, { extend_existing_arrays: true, sort_merged_arrays: true })
11
+ logger.measure(:list_section) do
12
+ cfg = nil
13
+ logger.measure(:list_section_config) do
14
+ opt[:config_template] ||= 'default'
30
15
 
31
- opt[:duration] ||= cfg['duration'] || false
32
- opt[:interval_format] ||= cfg['interval_format'] || 'text'
33
- opt[:count] ||= 0
34
- opt[:age] ||= :newest
35
- opt[:age] = opt[:age].normalize_age
36
- opt[:format] ||= cfg['date_format']
37
- opt[:order] ||= cfg['order'] || :asc
38
- opt[:tag_order] ||= :asc
39
- opt[:tags_color] = cfg['tags_color'] || false if opt[:tags_color].nil?
40
- opt[:template] ||= cfg['template']
41
- opt[:sort_tags] ||= opt[:tag_sort]
42
-
43
- # opt[:highlight] ||= true
44
- title = ''
45
- is_single = true
46
- if opt[:section].nil?
47
- opt[:section] = choose_section
48
- title = opt[:section]
49
- elsif opt[:section].is_a?(Array)
50
- title = opt[:section].join(', ')
51
- elsif opt[:section].is_a?(String)
52
- title = if opt[:section] =~ /^all$/i
53
- if opt[:page_title]
54
- opt[:page_title]
55
- elsif opt[:tag_filter] && opt[:tag_filter]['bool'].normalize_bool != :not
56
- opt[:tag_filter]['tags'].map { |tag| "@#{tag}" }.join(' + ')
57
- else
58
- 'doing'
59
- end
16
+ tpl_cfg = Doing.setting(['templates', opt[:config_template]])
17
+
18
+ cfg = if opt[:view_template]
19
+ Doing.setting(['views', opt[:view_template]]).deep_merge(tpl_cfg,
20
+ { extend_existing_arrays: true,
21
+ sort_merged_arrays: true })
60
22
  else
61
- guess_section(opt[:section])
23
+ tpl_cfg
62
24
  end
63
- end
64
-
65
- items = filter_items(items, opt: opt)
66
-
67
- items.reverse! unless opt[:order].normalize_order == :desc
68
-
69
- if opt[:delete]
70
- delete_items(items, force: opt[:force])
71
-
72
- write(@doing_file)
73
- return
74
- elsif opt[:editor]
75
- edit_items(items)
76
-
77
- write(@doing_file)
78
- return
79
- elsif opt[:interactive]
80
- opt[:menu] = !opt[:force]
81
- opt[:query] = '' # opt[:search]
82
- opt[:multiple] = true
83
- selected = Prompt.choose_from_items(items.reverse, include_section: opt[:section] =~ /^all$/i, **opt)
84
-
85
- raise NoResults, 'no items selected' if selected.nil? || selected.empty?
86
25
 
87
- act_on(selected, opt)
88
- return
26
+ cfg.deep_merge({
27
+ 'wrap_width' => Doing.setting('wrap_width') || 0,
28
+ 'date_format' => Doing.setting('default_date_format'),
29
+ 'order' => Doing.setting('order') || :asc,
30
+ 'tags_color' => Doing.setting('tags_color'),
31
+ 'duration' => Doing.setting('duration'),
32
+ 'interval_format' => Doing.setting('interval_format')
33
+ }, { extend_existing_arrays: true, sort_merged_arrays: true })
34
+ end
35
+
36
+ logger.measure(:list_section_options) do
37
+ opt[:duration] ||= cfg['duration'] || false
38
+ opt[:interval_format] ||= cfg['interval_format'] || 'text'
39
+ opt[:count] ||= 0
40
+ opt[:age] ||= :newest
41
+ opt[:age] = opt[:age].normalize_age
42
+ opt[:format] ||= cfg['date_format']
43
+ opt[:order] ||= cfg['order'] || :asc
44
+ opt[:tag_order] ||= :asc
45
+ opt[:tags_color] = cfg['tags_color'] || false if opt[:tags_color].nil?
46
+ opt[:template] ||= cfg['template']
47
+ opt[:sort_tags] ||= opt[:tag_sort]
48
+ end
49
+
50
+ title = ''
51
+ is_single = true
52
+ logger.measure(:list_section_title) do
53
+ # opt[:highlight] ||= true
54
+ if opt[:section].nil?
55
+ opt[:section] = choose_section
56
+ title = opt[:section]
57
+ elsif opt[:section].is_a?(Array)
58
+ title = opt[:section].join(', ')
59
+ elsif opt[:section].is_a?(String)
60
+ title = if opt[:section] =~ /^all$/i
61
+ if opt[:page_title]
62
+ opt[:page_title]
63
+ elsif opt[:tag_filter] && opt[:tag_filter]['bool'].normalize_bool != :not
64
+ opt[:tag_filter]['tags'].map { |tag| "@#{tag}" }.join(' + ')
65
+ else
66
+ 'doing'
67
+ end
68
+ else
69
+ guess_section(opt[:section])
70
+ end
71
+ end
72
+ end
73
+
74
+ logger.measure(:list_section_filter) do
75
+ items = filter_items(items, opt: opt)
76
+ end
77
+
78
+ logger.measure(:list_section_sort) do
79
+ items.reverse! unless opt[:order].normalize_order == :desc
80
+ end
81
+
82
+ logger.measure(:list_section_actions) do
83
+ if opt[:delete]
84
+ delete_items(items, force: opt[:force])
85
+
86
+ write(@doing_file)
87
+ return
88
+ elsif opt[:editor]
89
+ edit_items(items)
90
+
91
+ write(@doing_file)
92
+ return
93
+ elsif opt[:interactive]
94
+ opt[:menu] = !opt[:force]
95
+ opt[:query] = '' # opt[:search]
96
+ opt[:multiple] = true
97
+ selected = Prompt.choose_from_items(items.reverse, include_section: opt[:section] =~ /^all$/i, **opt)
98
+
99
+ raise NoResults, 'no items selected' if selected.nil? || selected.empty?
100
+
101
+ act_on(selected, opt)
102
+ return
103
+ end
104
+ end
105
+
106
+ logger.measure(:list_section_output) do
107
+ opt[:output] ||= 'template'
108
+ opt[:wrap_width] ||= Doing.setting('templates.default.wrap_width', 0)
109
+
110
+ output(items, title, is_single, opt)
111
+ end
89
112
  end
90
-
91
- opt[:output] ||= 'template'
92
- opt[:wrap_width] ||= Doing.setting('templates.default.wrap_width', 0)
93
-
94
- logger.benchmark(:list_section, :finish)
95
- output(items, title, is_single, opt)
96
113
  end
97
114
 
98
115
  ##
@@ -120,9 +137,7 @@ module Doing
120
137
  opt[:output] = output
121
138
 
122
139
  time_rx = /^(\d{1,2}+(:\d{1,2}+)?( *(am|pm))?|midnight|noon)$/
123
- if opt[:from] && opt[:from][0].is_a?(String) && opt[:from][0] =~ time_rx
124
- opt[:time_filter] = opt[:from]
125
- end
140
+ opt[:time_filter] = opt[:from] if opt[:from] && opt[:from][0].is_a?(String) && opt[:from][0] =~ time_rx
126
141
 
127
142
  list_section(opt)
128
143
  end
@@ -220,33 +235,40 @@ module Doing
220
235
  ## @param opt [Hash] Additional Options
221
236
  ##
222
237
  def recent(count = 10, section = nil, opt)
223
- opt ||= {}
224
- opt[:times] ||= false
225
- opt[:totals] ||= false
226
- opt[:sort_tags] ||= false
227
-
228
- cfg = Doing.setting('templates.recent').deep_merge(Doing.setting('templates.default'), { extend_existing_arrays: true, sort_merged_arrays: true }).deep_merge({
229
- 'wrap_width' => Doing.setting('wrap_width') || 0,
230
- 'date_format' => Doing.setting('default_date_format'),
231
- 'order' => Doing.setting('order') || :asc,
232
- 'tags_color' => Doing.setting('tags_color'),
233
- 'duration' => Doing.setting('duration'),
234
- 'interval_format' => Doing.setting('interval_format')
235
- }, { extend_existing_arrays: true, sort_merged_arrays: true })
236
- opt[:duration] ||= cfg['duration'] || false
237
- opt[:interval_format] ||= cfg['interval_format'] || 'text'
238
-
239
- section ||= Doing.setting('current_section')
240
- section = guess_section(section)
241
-
242
- opt[:section] = section
243
- opt[:wrap_width] = cfg['wrap_width']
244
- opt[:count] = count
245
- opt[:format] = cfg['date_format']
246
- opt[:template] = opt[:template] || cfg['template']
247
- opt[:order] = :asc
248
-
249
- list_section(opt)
238
+ logger.measure(:recent_method) do
239
+ opt ||= {}
240
+ opt[:times] ||= false
241
+ opt[:totals] ||= false
242
+ opt[:sort_tags] ||= false
243
+
244
+ cfg = nil
245
+ logger.measure(:recent_config_merge) do
246
+ cfg = Doing.setting('templates.recent').deep_merge(Doing.setting('templates.default'), { extend_existing_arrays: true, sort_merged_arrays: true }).deep_merge({
247
+ 'wrap_width' => Doing.setting('wrap_width') || 0,
248
+ 'date_format' => Doing.setting('default_date_format'),
249
+ 'order' => Doing.setting('order') || :asc,
250
+ 'tags_color' => Doing.setting('tags_color'),
251
+ 'duration' => Doing.setting('duration'),
252
+ 'interval_format' => Doing.setting('interval_format')
253
+ }, { extend_existing_arrays: true, sort_merged_arrays: true })
254
+ opt[:duration] ||= cfg['duration'] || false
255
+ opt[:interval_format] ||= cfg['interval_format'] || 'text'
256
+ end
257
+
258
+ logger.measure(:recent_section_setup) do
259
+ section ||= Doing.setting('current_section')
260
+ section = guess_section(section)
261
+
262
+ opt[:section] = section
263
+ opt[:wrap_width] = cfg['wrap_width']
264
+ opt[:count] = count
265
+ opt[:format] = cfg['date_format']
266
+ opt[:template] = opt[:template] || cfg['template']
267
+ opt[:order] = :asc
268
+ end
269
+
270
+ list_section(opt)
271
+ end
250
272
  end
251
273
 
252
274
  ##
@@ -259,13 +281,17 @@ module Doing
259
281
  section = section[0] if section.is_a?(Array) && section.count == 1
260
282
  section = section.nil? ? 'All' : guess_section(section)
261
283
  cfg = Doing.setting(['templates', options[:config_template]]).deep_merge(Doing.setting('templates.default'), { extend_existing_arrays: true, sort_merged_arrays: true }).deep_merge({
262
- 'wrap_width' => Doing.setting('wrap_width', 0),
263
- 'date_format' => Doing.setting('default_date_format'),
264
- 'order' => Doing.setting('order', :asc),
265
- 'tags_color' => Doing.setting('tags_color'),
266
- 'duration' => Doing.setting('duration'),
267
- 'interval_format' => Doing.setting('interval_format')
268
- }, { extend_existing_arrays: true, sort_merged_arrays: true })
284
+ 'wrap_width' => Doing.setting(
285
+ 'wrap_width', 0
286
+ ),
287
+ 'date_format' => Doing.setting('default_date_format'),
288
+ 'order' => Doing.setting(
289
+ 'order', :asc
290
+ ),
291
+ 'tags_color' => Doing.setting('tags_color'),
292
+ 'duration' => Doing.setting('duration'),
293
+ 'interval_format' => Doing.setting('interval_format')
294
+ }, { extend_existing_arrays: true, sort_merged_arrays: true })
269
295
  options[:duration] ||= cfg['duration'] || false
270
296
  options[:interval_format] ||= cfg['interval_format'] || 'text'
271
297
 
@@ -313,7 +339,7 @@ module Doing
313
339
 
314
340
  logger.log_now(:info, 'Edit note:', last_item.title)
315
341
 
316
- note = last_item.note&.to_s || ''
342
+ note = last_item.note.to_s
317
343
  "#{last_item.title}\n# EDIT BELOW THIS LINE ------------\n#{note}"
318
344
  end
319
345
 
@@ -332,19 +358,16 @@ module Doing
332
358
  logger.debug('Filtered:', "Parameters matched #{items.count} entries")
333
359
 
334
360
  if opt[:interactive]
335
- last_entry = Prompt.choose_from_items(items, include_section: opt[:section] =~ /^all$/i,
336
- menu: true,
337
- header: '',
338
- prompt: 'Select an entry > ',
339
- multiple: false,
340
- sort: false,
341
- show_if_single: true
342
- )
361
+ Prompt.choose_from_items(items, include_section: opt[:section] =~ /^all$/i,
362
+ menu: true,
363
+ header: '',
364
+ prompt: 'Select an entry > ',
365
+ multiple: false,
366
+ sort: false,
367
+ show_if_single: true)
343
368
  else
344
- last_entry = items.max_by { |item| item.date }
369
+ items.max_by(&:date)
345
370
  end
346
-
347
- last_entry
348
371
  end
349
372
 
350
373
  private
@@ -362,29 +385,37 @@ module Doing
362
385
  ## template trigger
363
386
  ## @api private
364
387
  def output(items, title, is_single, opt)
365
- logger.benchmark(:output, :start)
366
- opt ||= {}
367
- out = nil
368
-
369
- unless opt[:output] =~ Plugins.plugin_regex(type: :export)
370
- raise InvalidPlugin.new('Unknown output format', opt[:output])
371
-
388
+ logger.measure(:output) do
389
+ opt ||= {}
390
+ out = nil
391
+
392
+ logger.measure(:output_validation) do
393
+ unless opt[:output] =~ Plugins.plugin_regex(type: :export)
394
+ raise InvalidPlugin.new('Unknown output format', opt[:output])
395
+ end
396
+ end
397
+
398
+ export_options = nil
399
+ logger.measure(:output_setup) do
400
+ export_options = { page_title: title, is_single: is_single, options: opt }
401
+ end
402
+
403
+ logger.measure(:output_hooks) do
404
+ Hooks.trigger :pre_export, self, opt[:output], items
405
+ end
406
+
407
+ logger.measure(:output_render) do
408
+ Plugins.plugins[:export].each_value do |options|
409
+ next unless opt[:output] =~ /^(#{options[:trigger].normalize_trigger})$/i
410
+
411
+ out = options[:class].render(self, items, variables: export_options)
412
+ break
413
+ end
414
+ end
415
+
416
+ logger.debug('Output:', "#{items.count} #{items.count == 1 ? 'item' : 'items'} shown")
417
+ out
372
418
  end
373
-
374
- export_options = { page_title: title, is_single: is_single, options: opt }
375
-
376
- Hooks.trigger :pre_export, self, opt[:output], items
377
-
378
- Plugins.plugins[:export].each do |_, options|
379
- next unless opt[:output] =~ /^(#{options[:trigger].normalize_trigger})$/i
380
-
381
- out = options[:class].render(self, items, variables: export_options)
382
- break
383
- end
384
-
385
- logger.debug('Output:', "#{items.count} #{items.count == 1 ? 'item' : 'items'} shown")
386
- logger.benchmark(:output, :finish)
387
- out
388
419
  end
389
420
 
390
421
  ##