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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'stringio'
2
4
  require 'time'
3
5
  require 'fileutils'
@@ -10,7 +12,7 @@ module GLI
10
12
  @exe = app.exe_name
11
13
  if File.exist?('COMMANDS.md') # Back up existing README
12
14
  FileUtils.mv('COMMANDS.md', 'COMMANDS.bak')
13
- $stderr.puts "Backing up existing COMMANDS.md"
15
+ warn 'Backing up existing COMMANDS.md'
14
16
  end
15
17
  @io = File.new('COMMANDS.md', 'w')
16
18
  @nest = '#'
@@ -18,8 +20,7 @@ module GLI
18
20
  @parent_command = []
19
21
  end
20
22
 
21
- def beginning
22
- end
23
+ def beginning; end
23
24
 
24
25
  # Called when processing has completed
25
26
  def ending
@@ -61,32 +62,32 @@ module GLI
61
62
  @io.puts "*v#{version}*"
62
63
  @io.puts
63
64
  # Hacking in the overview file
64
- if File.exist?('OVERVIEW.md')
65
- @io.puts IO.read('OVERVIEW.md')
66
- @io.puts
67
- end
65
+ return unless File.exist?('OVERVIEW.md')
66
+
67
+ @io.puts IO.read('OVERVIEW.md')
68
+ @io.puts
68
69
  end
69
70
 
70
71
  def options
71
72
  if @nest.size == 1
72
- @io.puts "## Global Options"
73
+ @io.puts '## Global Options'
73
74
  else
74
- @io.puts header("Options", 1)
75
+ @io.puts header('Options', 1)
75
76
  end
76
77
  @io.puts
77
78
  end
78
79
 
79
80
  # Gives you a flag in the current context
80
81
  def flag(name, aliases, desc, long_desc, default_value, arg_name, must_match, _type)
81
- invocations = ([name] + Array(aliases)).map { |_| "`" + add_dashes(_) + "`" }.join(' | ')
82
+ invocations = ([name] + Array(aliases)).map { |_| "`#{add_dashes(_)}`" }.join(' | ')
82
83
  usage = "#{invocations} #{arg_name || 'arg'}"
83
84
  @io.puts header(usage, 2)
84
85
  @io.puts
85
86
  @io.puts String(desc).strip
86
87
  @io.puts "\n*Default Value:* `#{default_value || 'None'}`\n" unless default_value.nil?
87
- @io.puts "\n*Must Match:* `#{must_match.to_s}`\n" unless must_match.nil?
88
+ @io.puts "\n*Must Match:* `#{must_match}`\n" unless must_match.nil?
88
89
  cmd_desc = String(long_desc).strip
89
- @io.puts "> #{cmd_desc}\n" unless cmd_desc.length == 0
90
+ @io.puts "> #{cmd_desc}\n" unless cmd_desc.empty?
90
91
  @io.puts
91
92
  end
92
93
 
@@ -94,22 +95,21 @@ module GLI
94
95
  def switch(name, aliases, desc, long_desc, negatable)
95
96
  if negatable
96
97
  name = "[no-]#{name}" if name.to_s.length > 1
97
- aliases = aliases.map { |_| _.to_s.length > 1 ? "[no-]#{_}" : _ }
98
+ aliases = aliases.map { |_| _.to_s.length > 1 ? "[no-]#{_}" : _ }
98
99
  end
99
- invocations = ([name] + aliases).map { |_| "`" + add_dashes(_).strip + "`" }.join('|')
100
- @io.puts header("#{invocations}", 2)
100
+ invocations = ([name] + aliases).map { |_| "`#{add_dashes(_).strip}`" }.join('|')
101
+ @io.puts header(invocations.to_s, 2)
101
102
  @io.puts
102
103
  @io.puts String(desc).strip
103
104
  cmd_desc = String(long_desc).strip
104
- @io.puts "\n> #{cmd_desc}\n" unless cmd_desc.length == 0
105
+ @io.puts "\n> #{cmd_desc}\n" unless cmd_desc.empty?
105
106
  @io.puts
106
107
  end
107
108
 
108
- def end_options
109
- end
109
+ def end_options; end
110
110
 
111
111
  def commands
112
- @io.puts header("Commands", 1)
112
+ @io.puts header('Commands', 1)
113
113
  @io.puts
114
114
  increment_nest
115
115
  end
@@ -124,7 +124,7 @@ module GLI
124
124
  @io.puts "*#{String(desc).strip}*"
125
125
  @io.puts
126
126
  cmd_desc = String(long_desc).strip.split("\n").map { |_| "> #{_}" }.join("\n")
127
- @io.puts "#{cmd_desc}\n\n" unless cmd_desc.length == 0
127
+ @io.puts "#{cmd_desc}\n\n" unless cmd_desc.empty?
128
128
  increment_nest
129
129
  end
130
130
 
@@ -156,16 +156,16 @@ module GLI
156
156
  if @nest.size + increment > 6
157
157
  "**#{content}**"
158
158
  else
159
- "#{@nest}#{'#'*increment} #{content}"
159
+ "#{@nest}#{'#' * increment} #{content}"
160
160
  end
161
161
  end
162
162
 
163
- def increment_nest(increment=1)
164
- @nest = "#{@nest}#{'#'*increment}"
163
+ def increment_nest(increment = 1)
164
+ @nest = "#{@nest}#{'#' * increment}"
165
165
  end
166
166
 
167
- def decrement_nest(increment=1)
168
- @nest.gsub!(/#{'#'*increment}$/, '')
167
+ def decrement_nest(increment = 1)
168
+ @nest.gsub!(/#{'#' * increment}$/, '')
169
169
  end
170
170
  end
171
171
  end
@@ -194,7 +194,7 @@ module Doing
194
194
  ## Symbol helpers
195
195
  ##
196
196
  module SymbolNormalize
197
- def normalize_tag_sort(default = :name)
197
+ def normalize_tag_sort(_default = :name)
198
198
  to_s.normalize_tag_sort
199
199
  end
200
200
 
data/lib/doing/pager.rb CHANGED
@@ -14,9 +14,7 @@ module Doing
14
14
  # Enable/disable pagination
15
15
  #
16
16
  # @param should_paginate [Boolean] true to paginate
17
- def paginate=(should_paginate)
18
- @paginate = should_paginate
19
- end
17
+ attr_writer :paginate
20
18
 
21
19
  # Page output. If @paginate is false, just dump to
22
20
  # STDOUT
@@ -29,48 +27,94 @@ module Doing
29
27
  return
30
28
  end
31
29
 
30
+ # Smart pagination: skip pager for small outputs
31
+ if should_skip_pager?(text)
32
+ puts text
33
+ return
34
+ end
35
+
36
+ # Use external pager (IO.popen for best performance and UX)
37
+ external_pager(text)
38
+ end
39
+
40
+ # External pager using IO.popen for optimal performance and UX
41
+ def external_pager(text)
32
42
  pager = which_pager
33
- Doing.logger.debug('Pager:', "Using #{pager}")
43
+ Doing.logger.debug('Pager:', "Using external pager: #{pager}")
34
44
 
35
- read_io, write_io = IO.pipe
45
+ begin
46
+ IO.popen(pager, 'w') do |io|
47
+ io.write(text)
48
+ io.close_write
49
+ end
50
+ rescue SystemCallError => e
51
+ # Fallback to direct output if pager fails
52
+ puts text
53
+ Doing.logger.debug('Pager:', "Pager failed, using direct output: #{e}")
54
+ end
55
+ end
36
56
 
37
- input = $stdin
57
+ private
38
58
 
39
- pid = Kernel.fork do
40
- write_io.close
41
- input.reopen(read_io)
42
- read_io.close
59
+ # Smart pagination: skip pager for small outputs
60
+ def should_skip_pager?(text)
61
+ return true if text.nil? || text.empty?
43
62
 
44
- # Wait until we have input before we start the pager
45
- IO.select [input]
63
+ line_count = text.lines.count
46
64
 
47
- begin
48
- exec(pager)
49
- rescue SystemCallError => e
50
- raise Errors::DoingStandardError, "Pager error, #{e}"
51
- end
52
- end
65
+ # Always paginate if output is very large (more than 200 lines)
66
+ return false if line_count > 200
53
67
 
54
- begin
55
- read_io.close
56
- write_io.write(text)
57
- write_io.close
58
- rescue SystemCallError # => e
59
- # raise Errors::DoingStandardError, "Pager error, #{e}"
68
+ # Check if output fits within 150% of terminal height
69
+ term_height = terminal_height
70
+ if term_height > 0
71
+ # Only paginate if output is 150% of terminal height or more
72
+ # This allows scrolling up half a page for reasonable outputs
73
+ threshold = (term_height * 1.5).to_i
74
+ return true if line_count < threshold
60
75
  end
61
76
 
62
- _, status = Process.waitpid2(pid)
63
- status.success?
77
+ # Fallback: skip pager for small outputs (less than 50 lines)
78
+ # This covers most typical doing commands while avoiding pager overhead
79
+ line_count < 50
64
80
  end
65
81
 
66
- private
82
+ # Get terminal height, with caching and fallback
83
+ def terminal_height
84
+ @terminal_height ||= begin
85
+ # Try TTY::Screen first (most reliable)
86
+ if defined?(TTY::Screen) && TTY::Screen.respond_to?(:height)
87
+ TTY::Screen.height
88
+ # Fallback to stty
89
+ elsif system('stty size >/dev/null 2>&1')
90
+ `stty size`.split.first.to_i
91
+ # Fallback to tput
92
+ elsif system('tput lines >/dev/null 2>&1')
93
+ `tput lines`.to_i
94
+ # Last resort: assume 24 lines
95
+ else
96
+ 24
97
+ end
98
+ rescue StandardError
99
+ 24
100
+ end
101
+ end
67
102
 
68
103
  def git_pager
69
- TTY::Which.exist?('git') ? `#{TTY::Which.which('git')} config --get-all core.pager` : nil
104
+ @git_pager ||= begin
105
+ if TTY::Which.exist?('git')
106
+ result = `#{TTY::Which.which('git')} config --get-all core.pager 2>/dev/null`.strip
107
+ result.empty? ? nil : result
108
+ else
109
+ nil
110
+ end
111
+ rescue StandardError
112
+ nil
113
+ end
70
114
  end
71
115
 
72
116
  def pagers
73
- [
117
+ @pagers ||= [
74
118
  Doing.setting('editors.pager'),
75
119
  ENV['PAGER'],
76
120
  'less -FXr',
@@ -59,7 +59,6 @@ module Doing
59
59
  paths.map { |d| File.expand_path(d) }
60
60
  end
61
61
 
62
-
63
62
  # Register a plugin
64
63
  #
65
64
  # @param title [String|Array] The name of the
@@ -209,7 +208,7 @@ module Doing
209
208
  def plugin_regex(type: :export)
210
209
  type = valid_type(type)
211
210
  pattern = []
212
- plugins[type].each do |_, options|
211
+ plugins[type].each_value do |options|
213
212
  pattern << options[:trigger].normalize_trigger
214
213
  end
215
214
  Regexp.new("^(?:#{pattern.sort.uniq.join('|')})$", true)
@@ -227,7 +226,7 @@ module Doing
227
226
  type = valid_type(type)
228
227
  templates = []
229
228
  plugs = plugins[type].clone
230
- plugs.delete_if { |_t, o| o[:templates].nil? }.each do |_, options|
229
+ plugs.delete_if { |_t, o| o[:templates].nil? }.each_value do |options|
231
230
  options[:templates].each do |t|
232
231
  out = t[:name]
233
232
  out += " (#{t[:format]})" if t.key?(:format)
@@ -251,7 +250,7 @@ module Doing
251
250
  type = valid_type(type)
252
251
  pattern = []
253
252
  plugs = plugins[type].clone
254
- plugs.delete_if { |_, o| o[:templates].nil? }.each do |_, options|
253
+ plugs.delete_if { |_, o| o[:templates].nil? }.each_value do |options|
255
254
  options[:templates].each do |t|
256
255
  pattern << t[:trigger].normalize_trigger
257
256
  end
@@ -274,7 +273,7 @@ module Doing
274
273
  ## @return [String] string content of template for trigger
275
274
  ##
276
275
  def template_for_trigger(trigger, type: :export, save_to: nil)
277
- plugins[valid_type(type)].clone.delete_if { |_t, o| o[:templates].nil? }.each do |_, options|
276
+ plugins[valid_type(type)].clone.delete_if { |_t, o| o[:templates].nil? }.each_value do |options|
278
277
  options[:templates].each do |t|
279
278
  next unless trigger =~ /^(?:#{t[:trigger].normalize_trigger})$/
280
279
 
@@ -38,7 +38,7 @@ module Doing
38
38
  end
39
39
  end
40
40
  width = wwid.config['plugins']['byday']['item_width'].to_i || 60
41
- divider = "{wd}+{xk}#{'-' *10}{wd}+{xk}#{'-' * width}{wd}+{xk}#{'-' * 8}{wd}+{x}"
41
+ divider = "{wd}+{xk}#{'-' * 10}{wd}+{xk}#{'-' * width}{wd}+{xk}#{'-' * 8}{wd}+{x}"
42
42
  out = []
43
43
  out << divider
44
44
  out << "{wd}|{xm}date {wd}|{xbw}item#{' ' * (width - 4)}{wd}|{xy}duration{wd}|{x}"
@@ -17,7 +17,7 @@ module Doing
17
17
  end
18
18
 
19
19
  def get_binding
20
- binding()
20
+ binding
21
21
  end
22
22
  end
23
23
 
@@ -44,7 +44,6 @@ module Doing
44
44
  end
45
45
 
46
46
  def self.render(wwid, items, variables: {})
47
-
48
47
  return unless items.good?
49
48
 
50
49
  config = Doing.settings
@@ -82,15 +81,18 @@ module Doing
82
81
  tags.concat(i.tag_array).sort!.uniq!
83
82
  flagged = day_flagged = true if i.tags?(config['marker_tag'])
84
83
 
85
- interval = wwid.get_interval(i, record: true) if i.title =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
84
+ if i.title =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
85
+ interval = wwid.get_interval(i,
86
+ record: true)
87
+ end
86
88
  interval ||= false
87
89
  human_time = false
88
90
  if interval
89
91
  d, h, m = wwid.get_interval(i, formatted: false).format_time
90
92
  human_times = []
91
- human_times << format('%<d>d day%<p>s', d: d, p: d == 1 ? '' : 's') if d > 0
92
- human_times << format('%<h>d hour%<p>s', h: h, p: h == 1 ? '' : 's') if h > 0
93
- human_times << format('%<m>d minute%<p>s', m: m, p: m == 1 ? '' : 's') if m > 0
93
+ human_times << format('%<d>d day%<p>s', d: d, p: d == 1 ? '' : 's') if d.positive?
94
+ human_times << format('%<h>d hour%<p>s', h: h, p: h == 1 ? '' : 's') if h.positive?
95
+ human_times << format('%<m>d minute%<p>s', m: m, p: m == 1 ? '' : 's') if m.positive?
94
96
  human_time = human_times.join(', ')
95
97
  end
96
98
 
@@ -111,27 +113,24 @@ module Doing
111
113
  }
112
114
  all_items << item
113
115
 
114
-
115
- if days.key?(date_key)
116
- days[date_key][:starred] = true if day_flagged
117
- days[date_key][:tags] = days[date_key][:tags].concat(i.tag_array).sort.uniq
118
- days[date_key][:entries].push(item)
119
- else
120
- days[date_key] ||= { tags: [], entries: [], starred: false }
121
- days[date_key][:starred] = true if day_flagged
122
- days[date_key][:tags] = days[date_key][:tags].concat(i.tag_array).sort.uniq
123
- days[date_key][:entries].push(item)
124
- end
116
+ days[date_key] ||= { tags: [], entries: [], starred: false } unless days.key?(date_key)
117
+ days[date_key][:starred] = true if day_flagged
118
+ days[date_key][:tags] = days[date_key][:tags].concat(i.tag_array).sort.uniq
119
+ days[date_key][:entries].push(item)
125
120
  end
126
121
 
127
-
128
122
  template = if config['export_templates']['dayone'] && File.exist?(File.expand_path(config['export_templates']['dayone']))
129
123
  IO.read(File.expand_path(config['export_templates']['dayone']))
130
124
  else
131
125
  self.template('dayone')
132
126
  end
133
127
 
134
- totals = opt[:totals] ? wwid.tag_times(format: :markdown, sort_by: opt[:sort_tags], sort_order: opt[:tag_order]) : ''
128
+ totals = if opt[:totals]
129
+ wwid.tag_times(format: :markdown, sort_by: opt[:sort_tags],
130
+ sort_order: opt[:tag_order])
131
+ else
132
+ ''
133
+ end
135
134
 
136
135
  case digest
137
136
  when :day
@@ -162,18 +161,19 @@ module Doing
162
161
  end
163
162
  else
164
163
  to_dayone(template: template,
165
- title: variables[:page_title],
166
- items: all_items,
167
- totals: totals,
168
- date: Time.now,
169
- tags: tags,
170
- starred: flagged)
164
+ title: variables[:page_title],
165
+ items: all_items,
166
+ totals: totals,
167
+ date: Time.now,
168
+ tags: tags,
169
+ starred: flagged)
171
170
  end
172
171
 
173
172
  @out = ''
174
173
  end
175
174
 
176
- def self.to_dayone(template: self.template(nil), title: 'doing', items: [], totals: '', date: Time.now, tags: [], starred: false)
175
+ def self.to_dayone(template: self.template(nil), title: 'doing', items: [], totals: '', date: Time.now, tags: [],
176
+ starred: false)
177
177
  mdx = DayOneRenderer.new(title, items, totals)
178
178
 
179
179
  engine = ERB.new(template)
@@ -201,7 +201,8 @@ module Doing
201
201
  f.puts plist.to_plist
202
202
  end
203
203
 
204
- Doing.logger.count(:exported, level: :info, count: items.count, message: '%count %items exported to Day One import folder')
204
+ Doing.logger.count(:exported, level: :info, count: items.count,
205
+ message: '%count %items exported to Day One import folder')
205
206
  end
206
207
 
207
208
  Doing::Plugins.register 'dayone', :export, self
@@ -12,7 +12,7 @@ module Doing
12
12
  }
13
13
  end
14
14
 
15
- def self.render(wwid, items, variables: {})
15
+ def self.render(_wwid, items, variables: {})
16
16
  return if items.nil?
17
17
 
18
18
  content = Doing::Items.new
@@ -51,7 +51,7 @@ module Doing
51
51
 
52
52
  items_out << {
53
53
  date: i.date.strftime('%a %-I:%M%p'),
54
- title: title.gsub(/(@[^ (]+(\(.*?\))?)/im, '<span class="tag">\1</span>').strip, #+ " #{note}"
54
+ title: title.gsub(/(@[^ (]+(\(.*?\))?)/im, '<span class="tag">\1</span>').strip, # + " #{note}"
55
55
  note: note,
56
56
  time: interval,
57
57
  section: i.section
@@ -74,10 +74,10 @@ module Doing
74
74
  engine = Haml::Engine.new(template)
75
75
  Doing.logger.debug('HTML Export:', "#{items_out.count} items output to HTML")
76
76
  @out = engine.render(Object.new,
77
- { :@items => items_out, :@page_title => variables[:page_title], :@style => style, :@totals => totals })
77
+ { :@items => items_out, :@page_title => variables[:page_title], :@style => style,
78
+ :@totals => totals })
78
79
  end
79
80
 
80
81
  Doing::Plugins.register 'html', :export, self
81
82
  end
82
83
  end
83
-
@@ -21,10 +21,10 @@ module Doing
21
21
  {
22
22
  'section' => '',
23
23
  'items' => [],
24
- 'timers' => ""
24
+ 'timers' => ''
25
25
  }.to_json
26
26
  when 'timeline'
27
- "<html></html>"
27
+ '<html></html>'
28
28
  end
29
29
  end
30
30
 
@@ -62,7 +62,7 @@ module Doing
62
62
  i = {
63
63
  date: i.date,
64
64
  end_date: end_date,
65
- title: title.strip, #+ " #{note}"
65
+ title: title.strip, # + " #{note}"
66
66
  section: i.section,
67
67
  note: note.to_s(prefix: ''),
68
68
  time: interval.time_string(format: :clock),
@@ -78,7 +78,7 @@ module Doing
78
78
  when 'timeline'
79
79
  new_item = {
80
80
  'id' => index + 1,
81
- 'content' => title.strip, #+ " #{note}"
81
+ 'content' => title.strip, # + " #{note}"
82
82
  'title' => title.strip + " (#{interval.time_string(format: :clock)})",
83
83
  'start' => i.date.strftime('%F %T'),
84
84
  'type' => 'box',
@@ -151,4 +151,3 @@ module Doing
151
151
  Doing::Plugins.register 'timeline', :export, self
152
152
  end
153
153
  end
154
-
@@ -52,7 +52,10 @@ module Doing
52
52
 
53
53
  title = "#{title} @section(#{i.section})" unless variables[:is_single]
54
54
 
55
- interval = wwid.get_interval(i, record: true) if i.title =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
55
+ if i.title =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
56
+ interval = wwid.get_interval(i,
57
+ record: true)
58
+ end
56
59
  interval ||= false
57
60
 
58
61
  finished = i.title =~ /(?<= |^)@done/ ? true : false
@@ -77,7 +80,12 @@ module Doing
77
80
  self.template(nil)
78
81
  end
79
82
 
80
- totals = opt[:totals] ? wwid.tag_times(format: :markdown, sort_by: opt[:sort_tags], sort_order: opt[:tag_order]) : ''
83
+ totals = if opt[:totals]
84
+ wwid.tag_times(format: :markdown, sort_by: opt[:sort_tags],
85
+ sort_order: opt[:tag_order])
86
+ else
87
+ ''
88
+ end
81
89
 
82
90
  mdx = MarkdownRenderer.new(variables[:page_title], all_items, totals)
83
91
  Doing.logger.debug('Markdown Export:', "#{all_items.count} items output to Markdown")
@@ -24,6 +24,7 @@ module Doing
24
24
  options[:tags_color] = false
25
25
  options[:output] = 'template'
26
26
  options[:template] = '- %title @date(%date)%note'
27
+ options[:disable_color] = true
27
28
 
28
29
  Doing.logger.debug('TaskPaper Export:', "#{items.count} items output to TaskPaper format")
29
30
  @out = wwid.list_section(options)