doing 2.1.40 → 2.1.41

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/CHANGELOG.md +22 -0
  4. data/Gemfile.lock +1 -1
  5. data/Rakefile +4 -4
  6. data/bin/commands/changes.rb +1 -1
  7. data/bin/commands/tag_dir.rb +49 -15
  8. data/{Dockerfile → docker/Dockerfile} +3 -1
  9. data/{Dockerfile-2.6 → docker/Dockerfile-2.6} +2 -2
  10. data/{Dockerfile-2.7 → docker/Dockerfile-2.7} +2 -2
  11. data/{Dockerfile-3.0 → docker/Dockerfile-3.0} +2 -2
  12. data/{bash_profile → docker/bash_profile} +0 -0
  13. data/{inputrc → docker/inputrc} +0 -0
  14. data/docs/doc/Array.html +84 -2
  15. data/docs/doc/BooleanTermParser/Clause.html +1 -1
  16. data/docs/doc/BooleanTermParser/Operator.html +1 -1
  17. data/docs/doc/BooleanTermParser/Query.html +1 -1
  18. data/docs/doc/BooleanTermParser/QueryParser.html +1 -1
  19. data/docs/doc/BooleanTermParser/QueryTransformer.html +1 -1
  20. data/docs/doc/BooleanTermParser.html +1 -1
  21. data/docs/doc/Doing/ArrayNestedHash.html +198 -0
  22. data/docs/doc/Doing/ArrayTags.html +424 -0
  23. data/docs/doc/Doing/CSVExport.html +266 -0
  24. data/docs/doc/Doing/CalendarImport.html +232 -0
  25. data/docs/doc/Doing/Change.html +617 -0
  26. data/docs/doc/Doing/Changes.html +468 -0
  27. data/docs/doc/Doing/ChronifyArray.html +347 -0
  28. data/docs/doc/Doing/ChronifyNumeric.html +271 -0
  29. data/docs/doc/Doing/ChronifyString.html +682 -0
  30. data/docs/doc/Doing/Color.html +2 -2
  31. data/docs/doc/Doing/Completion/BashCompletions.html +445 -0
  32. data/docs/doc/Doing/Completion/FishCompletions.html +445 -0
  33. data/docs/doc/Doing/Completion/StringUtils.html +229 -0
  34. data/docs/doc/Doing/Completion/ZshCompletions.html +445 -0
  35. data/docs/doc/Doing/Completion.html +17 -3
  36. data/docs/doc/Doing/Configuration.html +1 -1
  37. data/docs/doc/Doing/DayOneRenderer.html +383 -0
  38. data/docs/doc/Doing/DayoneExport.html +290 -0
  39. data/docs/doc/Doing/DoingImport.html +391 -0
  40. data/docs/doc/Doing/Entry.html +381 -0
  41. data/docs/doc/Doing/Errors/DoingNoTraceError.html +1 -1
  42. data/docs/doc/Doing/Errors/DoingRuntimeError.html +1 -1
  43. data/docs/doc/Doing/Errors/DoingStandardError.html +1 -1
  44. data/docs/doc/Doing/Errors/EmptyInput.html +1 -1
  45. data/docs/doc/Doing/Errors/HistoryLimitError.html +1 -1
  46. data/docs/doc/Doing/Errors/InvalidPlugin.html +1 -1
  47. data/docs/doc/Doing/Errors/MissingBackupFile.html +1 -1
  48. data/docs/doc/Doing/Errors/NoResults.html +1 -1
  49. data/docs/doc/Doing/Errors/PluginException.html +1 -1
  50. data/docs/doc/Doing/Errors/UserCancelled.html +1 -1
  51. data/docs/doc/Doing/Errors/WrongCommand.html +1 -1
  52. data/docs/doc/Doing/Errors.html +1 -1
  53. data/docs/doc/Doing/HTMLExport.html +256 -0
  54. data/docs/doc/Doing/Hooks.html +1 -1
  55. data/docs/doc/Doing/Item.html +47 -3
  56. data/docs/doc/Doing/ItemDates.html +564 -0
  57. data/docs/doc/Doing/ItemQuery.html +614 -0
  58. data/docs/doc/Doing/ItemState.html +387 -0
  59. data/docs/doc/Doing/ItemTags.html +498 -0
  60. data/docs/doc/Doing/Items.html +460 -11
  61. data/docs/doc/Doing/JSONExport.html +222 -0
  62. data/docs/doc/Doing/Logger.html +1 -1
  63. data/docs/doc/Doing/MarkdownExport.html +266 -0
  64. data/docs/doc/Doing/MarkdownRenderer.html +383 -0
  65. data/docs/doc/Doing/Note.html +16 -3
  66. data/docs/doc/Doing/Pager.html +1 -1
  67. data/docs/doc/Doing/Plugins.html +1 -1
  68. data/docs/doc/Doing/Prompt.html +31 -682
  69. data/docs/doc/Doing/PromptChoose.html +484 -0
  70. data/docs/doc/Doing/PromptFZF.html +391 -0
  71. data/docs/doc/Doing/PromptInput.html +572 -0
  72. data/docs/doc/Doing/PromptSTD.html +293 -0
  73. data/docs/doc/Doing/PromptYN.html +237 -0
  74. data/docs/doc/Doing/Section.html +58 -2
  75. data/docs/doc/Doing/StringHighlight.html +533 -0
  76. data/docs/doc/Doing/StringNormalize.html +929 -0
  77. data/docs/doc/Doing/StringQuery.html +725 -0
  78. data/docs/doc/Doing/StringTags.html +884 -0
  79. data/docs/doc/Doing/StringTransform.html +565 -0
  80. data/docs/doc/Doing/StringTruncate.html +448 -0
  81. data/docs/doc/Doing/StringURL.html +409 -0
  82. data/docs/doc/Doing/SymbolNormalize.html +341 -0
  83. data/docs/doc/Doing/TaskPaperExport.html +222 -0
  84. data/docs/doc/Doing/TemplateExport.html +249 -0
  85. data/docs/doc/Doing/TemplateString.html +101 -2
  86. data/docs/doc/Doing/TimingImport.html +285 -0
  87. data/docs/doc/Doing/Types.html +1 -1
  88. data/docs/doc/Doing/Util/Backup.html +9 -7
  89. data/docs/doc/Doing/Util.html +2 -2
  90. data/docs/doc/Doing/Version.html +523 -0
  91. data/docs/doc/Doing/WWID/WWIDUtil.html +510 -0
  92. data/docs/doc/Doing/WWID.html +4377 -217
  93. data/docs/doc/Doing/WWIDDisplay.html +865 -0
  94. data/docs/doc/Doing/WWIDEditor.html +466 -0
  95. data/docs/doc/Doing/WWIDFileTools.html +359 -0
  96. data/docs/doc/Doing/WWIDFilter.html +466 -0
  97. data/docs/doc/Doing/WWIDGuess.html +299 -0
  98. data/docs/doc/Doing/WWIDInteractive.html +752 -0
  99. data/docs/doc/Doing/WWIDModify.html +1078 -0
  100. data/docs/doc/Doing/WWIDTags.html +302 -0
  101. data/docs/doc/Doing/WWIDTimers.html +359 -0
  102. data/docs/doc/Doing/WWIDUtil.html +510 -0
  103. data/docs/doc/Doing.html +9 -6
  104. data/docs/doc/FalseClass.html +1 -1
  105. data/docs/doc/GLI/Commands/Help.html +1 -1
  106. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
  107. data/docs/doc/GLI/Commands.html +1 -1
  108. data/docs/doc/GLI.html +1 -1
  109. data/docs/doc/Hash.html +1 -1
  110. data/docs/doc/Numeric.html +23 -78
  111. data/docs/doc/Object.html +1 -1
  112. data/docs/doc/PhraseParser/Operator.html +1 -1
  113. data/docs/doc/PhraseParser/PhraseClause.html +1 -1
  114. data/docs/doc/PhraseParser/Query.html +1 -1
  115. data/docs/doc/PhraseParser/QueryParser.html +1 -1
  116. data/docs/doc/PhraseParser/QueryTransformer.html +1 -1
  117. data/docs/doc/PhraseParser/TermClause.html +1 -1
  118. data/docs/doc/PhraseParser.html +1 -1
  119. data/docs/doc/Status.html +1 -1
  120. data/docs/doc/String.html +58 -633
  121. data/docs/doc/Symbol.html +9 -224
  122. data/docs/doc/Time.html +119 -13
  123. data/docs/doc/TrueClass.html +1 -1
  124. data/docs/doc/_index.html +324 -8
  125. data/docs/doc/class_list.html +1 -1
  126. data/docs/doc/file.README.html +1 -1
  127. data/docs/doc/index.html +1 -1
  128. data/docs/doc/method_list.html +2326 -542
  129. data/docs/doc/top-level-namespace.html +2 -2
  130. data/doing.rdoc +13 -3
  131. data/lib/completion/_doing.zsh +1 -1
  132. data/lib/completion/doing.bash +2 -2
  133. data/lib/completion/doing.fish +3 -1
  134. data/lib/doing/array/array.rb +16 -12
  135. data/lib/doing/array/nested_hash.rb +1 -1
  136. data/lib/doing/array/tags.rb +6 -5
  137. data/lib/doing/changelog/changelog.rb +6 -0
  138. data/lib/doing/chronify/array.rb +1 -3
  139. data/lib/doing/chronify/chronify.rb +12 -0
  140. data/lib/doing/chronify/numeric.rb +3 -2
  141. data/lib/doing/chronify/string.rb +1 -1
  142. data/lib/doing/completion/completion_string.rb +25 -0
  143. data/lib/doing/completion.rb +1 -1
  144. data/lib/doing/good.rb +8 -0
  145. data/lib/doing/item/dates.rb +1 -1
  146. data/lib/doing/{item.rb → item/item.rb} +10 -5
  147. data/lib/doing/item/query.rb +1 -1
  148. data/lib/doing/item/state.rb +1 -1
  149. data/lib/doing/item/tags.rb +1 -1
  150. data/lib/doing/items/filter.rb +67 -0
  151. data/lib/doing/items/items.rb +57 -0
  152. data/lib/doing/items/modify.rb +36 -0
  153. data/lib/doing/items/sections.rb +83 -0
  154. data/lib/doing/items/util.rb +74 -0
  155. data/lib/doing/normalize.rb +10 -2
  156. data/lib/doing/plugins/export/markdown_export.rb +4 -2
  157. data/lib/doing/plugins/import/doing_import.rb +1 -1
  158. data/lib/doing/prompt/choose.rb +118 -0
  159. data/lib/doing/prompt/fzf.rb +84 -0
  160. data/lib/doing/prompt/input.rb +129 -0
  161. data/lib/doing/prompt/prompt.rb +41 -0
  162. data/lib/doing/prompt/std.rb +32 -0
  163. data/lib/doing/prompt/yn.rb +64 -0
  164. data/lib/doing/section.rb +4 -0
  165. data/lib/doing/string/highlight.rb +1 -1
  166. data/lib/doing/string/query.rb +1 -1
  167. data/lib/doing/string/string.rb +18 -7
  168. data/lib/doing/string/tags.rb +14 -3
  169. data/lib/doing/string/transform.rb +1 -1
  170. data/lib/doing/string/truncate.rb +1 -1
  171. data/lib/doing/string/url.rb +1 -1
  172. data/lib/doing/time.rb +19 -1
  173. data/lib/doing/util_backup.rb +2 -2
  174. data/lib/doing/version.rb +1 -1
  175. data/lib/doing/wwid/display.rb +357 -360
  176. data/lib/doing/wwid/editor.rb +173 -176
  177. data/lib/doing/wwid/filetools.rb +156 -159
  178. data/lib/doing/wwid/filter.rb +191 -183
  179. data/lib/doing/wwid/guess.rb +58 -60
  180. data/lib/doing/wwid/interactive.rb +332 -330
  181. data/lib/doing/wwid/modify.rb +509 -512
  182. data/lib/doing/wwid/tags.rb +38 -41
  183. data/lib/doing/wwid/timers.rb +293 -296
  184. data/lib/doing/{wwid.rb → wwid/wwid.rb} +32 -23
  185. data/lib/doing/wwid/wwidutil.rb +79 -82
  186. data/lib/doing.rb +5 -5
  187. data/lib/helpers/threaded_tests.rb +1 -0
  188. metadata +76 -14
  189. data/lib/doing/changelog.rb +0 -6
  190. data/lib/doing/completion/string.rb +0 -17
  191. data/lib/doing/items.rb +0 -221
  192. data/lib/doing/prompt.rb +0 -330
@@ -2,343 +2,340 @@
2
2
 
3
3
  module Doing
4
4
  class WWID
5
- # Timer methods for WWID class
6
- module Timers
7
- ##
8
- ## Get total elapsed time for all tags in
9
- ## selection
10
- ##
11
- ## @param format [String] return format (html,
12
- ## json, or text)
13
- ## @param sort_by [Symbol] Sort by :name or :time
14
- ## @param sort_order [Symbol] The sort order (:asc or :desc)
15
- ##
16
- def tag_times(format: :text, sort_by: :time, sort_order: :asc)
17
- return '' if @timers.empty?
5
+ ##
6
+ ## Get total elapsed time for all tags in
7
+ ## selection
8
+ ##
9
+ ## @param format [String] return format (html,
10
+ ## json, or text)
11
+ ## @param sort_by [Symbol] Sort by :name or :time
12
+ ## @param sort_order [Symbol] The sort order (:asc or :desc)
13
+ ##
14
+ def tag_times(format: :text, sort_by: :time, sort_order: :asc)
15
+ return '' if @timers.empty?
18
16
 
19
- max = @timers.keys.sort_by(&:length).reverse[0].length + 1
17
+ max = @timers.keys.sort_by(&:length).reverse[0].length + 1
20
18
 
21
- total = @timers.delete('All')
19
+ total = @timers.delete('All')
22
20
 
23
- tags_data = @timers.delete_if { |_k, v| v.zero? }
24
- sorted_tags_data = if sort_by.normalize_tag_sort == :name
25
- tags_data.sort_by { |k, _v| k }
26
- else
27
- tags_data.sort_by { |_k, v| v }
28
- end
21
+ tags_data = @timers.delete_if { |_k, v| v.zero? }
22
+ sorted_tags_data = if sort_by.normalize_tag_sort == :name
23
+ tags_data.sort_by { |k, _v| k }
24
+ else
25
+ tags_data.sort_by { |_k, v| v }
26
+ end
29
27
 
30
- sorted_tags_data.reverse! if sort_order.normalize_order == :asc
31
- case format
32
- when :html
28
+ sorted_tags_data.reverse! if sort_order.normalize_order == :asc
29
+ case format
30
+ when :html
33
31
 
34
- output = <<EOHEAD
35
- <table>
36
- <caption id="tagtotals">Tag Totals</caption>
37
- <colgroup>
38
- <col style="text-align:left;"/>
39
- <col style="text-align:left;"/>
40
- </colgroup>
41
- <thead>
42
- <tr>
43
- <th style="text-align:left;">project</th>
44
- <th style="text-align:left;">time</th>
45
- </tr>
46
- </thead>
47
- <tbody>
48
- EOHEAD
49
- sorted_tags_data.reverse.each do |k, v|
50
- if v.positive?
51
- output += "<tr><td style='text-align:left;'>#{k}</td><td style='text-align:left;'>#{v.time_string(format: :clock)}</td></tr>\n"
52
- end
53
- end
54
- tail = <<EOTAIL
55
- <tr>
56
- <td style="text-align:left;" colspan="2"></td>
57
- </tr>
58
- </tbody>
59
- <tfoot>
32
+ output = <<EOHEAD
33
+ <table>
34
+ <caption id="tagtotals">Tag Totals</caption>
35
+ <colgroup>
36
+ <col style="text-align:left;"/>
37
+ <col style="text-align:left;"/>
38
+ </colgroup>
39
+ <thead>
60
40
  <tr>
61
- <td style="text-align:left;"><strong>Total</strong></td>
62
- <td style="text-align:left;">#{total.time_string(format: :clock)}</td>
41
+ <th style="text-align:left;">project</th>
42
+ <th style="text-align:left;">time</th>
63
43
  </tr>
64
- </tfoot>
65
- </table>
66
- EOTAIL
67
- output + tail
68
- when :markdown
69
- pad = sorted_tags_data.map { |k, _| k }.group_by(&:size).max.last[0].length
70
- pad = 7 if pad < 7
71
- output = <<~EOHEADER
72
- | #{' ' * (pad - 7)}project | time |
73
- | #{'-' * (pad - 1)}: | :------- |
74
- EOHEADER
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
44
+ </thead>
45
+ <tbody>
46
+ EOHEAD
47
+ sorted_tags_data.reverse.each do |k, v|
48
+ if v.positive?
49
+ output += "<tr><td style='text-align:left;'>#{k}</td><td style='text-align:left;'>#{v.time_string(format: :clock)}</td></tr>\n"
79
50
  end
80
- tail = '[Tag Totals]'
81
- output + tail
82
- when :json
83
- output = []
84
- sorted_tags_data.reverse.each do |k, v|
85
- output << {
86
- 'tag' => k,
87
- 'seconds' => v,
88
- 'formatted' => v.time_string(format: :clock)
89
- }
51
+ end
52
+ tail = <<EOTAIL
53
+ <tr>
54
+ <td style="text-align:left;" colspan="2"></td>
55
+ </tr>
56
+ </tbody>
57
+ <tfoot>
58
+ <tr>
59
+ <td style="text-align:left;"><strong>Total</strong></td>
60
+ <td style="text-align:left;">#{total.time_string(format: :clock)}</td>
61
+ </tr>
62
+ </tfoot>
63
+ </table>
64
+ EOTAIL
65
+ output + tail
66
+ when :markdown
67
+ pad = sorted_tags_data.map { |k, _| k }.group_by(&:size).max.last[0].length
68
+ pad = 7 if pad < 7
69
+ output = <<~EOHEADER
70
+ | #{' ' * (pad - 7)}project | time |
71
+ | #{'-' * (pad - 1)}: | :------- |
72
+ EOHEADER
73
+ sorted_tags_data.reverse.each do |k, v|
74
+ if v.positive?
75
+ output += "| #{' ' * (pad - k.length)}#{k} | #{v.time_string(format: :clock)} |\n"
90
76
  end
91
- output
92
- when :human
93
- output = []
94
- sorted_tags_data.reverse.each do |k, v|
95
- spacer = ''
96
- (max - k.length).times do
97
- spacer += ' '
98
- end
99
- output.push("┃ #{spacer}#{k}:#{v.time_string(format: :hm)} ┃")
77
+ end
78
+ tail = '[Tag Totals]'
79
+ output + tail
80
+ when :json
81
+ output = []
82
+ sorted_tags_data.reverse.each do |k, v|
83
+ output << {
84
+ 'tag' => k,
85
+ 'seconds' => v,
86
+ 'formatted' => v.time_string(format: :clock)
87
+ }
88
+ end
89
+ output
90
+ when :human
91
+ output = []
92
+ sorted_tags_data.reverse.each do |k, v|
93
+ spacer = ''
94
+ (max - k.length).times do
95
+ spacer += ' '
100
96
  end
97
+ output.push("┃ #{spacer}#{k}:#{v.time_string(format: :hm)} ┃")
98
+ end
101
99
 
102
- header = '┏━━ Tag Totals '
103
- (max - 2).times { header += '━' }
104
- header += '┓'
105
- footer = '┗'
106
- (max + 12).times { footer += '━' }
107
- footer += '┛'
108
- divider = '┣'
109
- (max + 12).times { divider += '━' }
110
- divider += '┫'
111
- output = output.empty? ? '' : "\n#{header}\n#{output.join("\n")}"
112
- output += "\n#{divider}"
100
+ header = '┏━━ Tag Totals '
101
+ (max - 2).times { header += '━' }
102
+ header += '┓'
103
+ footer = '┗'
104
+ (max + 12).times { footer += '━' }
105
+ footer += '┛'
106
+ divider = '┣'
107
+ (max + 12).times { divider += '━' }
108
+ divider += '┫'
109
+ output = output.empty? ? '' : "\n#{header}\n#{output.join("\n")}"
110
+ output += "\n#{divider}"
111
+ spacer = ''
112
+ (max - 6).times do
113
+ spacer += ' '
114
+ end
115
+ total_time = total.time_string(format: :hm)
116
+ total = "┃ #{spacer}total: "
117
+ total += total_time
118
+ total += ' ┃'
119
+ output += "\n#{total}"
120
+ output += "\n#{footer}"
121
+ output
122
+ else
123
+ output = []
124
+ sorted_tags_data.reverse.each do |k, v|
113
125
  spacer = ''
114
- (max - 6).times do
126
+ (max - k.length).times do
115
127
  spacer += ' '
116
128
  end
117
- total_time = total.time_string(format: :hm)
118
- total = "┃ #{spacer}total: "
119
- total += total_time
120
- total += ' ┃'
121
- output += "\n#{total}"
122
- output += "\n#{footer}"
123
- output
124
- else
125
- output = []
126
- sorted_tags_data.reverse.each do |k, v|
127
- spacer = ''
128
- (max - k.length).times do
129
- spacer += ' '
130
- end
131
- output.push("#{k}:#{spacer}#{v.time_string(format: :clock)}")
132
- end
133
-
134
- output = output.empty? ? '' : "\n--- Tag Totals ---\n#{output.join("\n")}"
135
- output += "\n\nTotal tracked: #{total.time_string(format: :clock)}\n"
136
- output
129
+ output.push("#{k}:#{spacer}#{v.time_string(format: :clock)}")
137
130
  end
131
+
132
+ output = output.empty? ? '' : "\n--- Tag Totals ---\n#{output.join("\n")}"
133
+ output += "\n\nTotal tracked: #{total.time_string(format: :clock)}\n"
134
+ output
138
135
  end
136
+ end
139
137
 
140
- ##
141
- ## Gets the interval between entry's start
142
- ## date and @done date
143
- ##
144
- ## @param item [Item] The entry
145
- ## @param formatted [Boolean] Return human readable
146
- ## time (default seconds)
147
- ## @param record [Boolean] Add the interval to the
148
- ## total for each tag
149
- ##
150
- ## @return Interval in seconds, or [d, h, m] array if
151
- ## formatted is true. False if no end date or
152
- ## interval is 0
153
- ##
154
- def get_interval(item, formatted: true, record: true)
155
- if item.interval
156
- seconds = item.interval
157
- record_tag_times(item, seconds) if record
158
- return seconds.positive? ? seconds : false unless formatted
138
+ ##
139
+ ## Gets the interval between entry's start
140
+ ## date and @done date
141
+ ##
142
+ ## @param item [Item] The entry
143
+ ## @param formatted [Boolean] Return human readable
144
+ ## time (default seconds)
145
+ ## @param record [Boolean] Add the interval to the
146
+ ## total for each tag
147
+ ##
148
+ ## @return Interval in seconds, or [d, h, m] array if
149
+ ## formatted is true. False if no end date or
150
+ ## interval is 0
151
+ ##
152
+ def get_interval(item, formatted: true, record: true)
153
+ if item.interval
154
+ seconds = item.interval
155
+ record_tag_times(item, seconds) if record
156
+ return seconds.positive? ? seconds : false unless formatted
159
157
 
160
- return seconds.positive? ? seconds.time_string(format: :clock) : false
161
- end
158
+ return seconds.positive? ? seconds.time_string(format: :clock) : false
159
+ end
162
160
 
163
- false
164
- end##
165
- ## Get total elapsed time for all tags in
166
- ## selection
167
- ##
168
- ## @param format [String] return format (html,
169
- ## json, or text)
170
- ## @param sort_by [Symbol] Sort by :name or :time
171
- ## @param sort_order [Symbol] The sort order (:asc or :desc)
172
- ##
173
- def tag_times(format: :text, sort_by: :time, sort_order: :asc)
174
- return '' if @timers.empty?
161
+ false
162
+ end##
163
+ ## Get total elapsed time for all tags in
164
+ ## selection
165
+ ##
166
+ ## @param format [String] return format (html,
167
+ ## json, or text)
168
+ ## @param sort_by [Symbol] Sort by :name or :time
169
+ ## @param sort_order [Symbol] The sort order (:asc or :desc)
170
+ ##
171
+ def tag_times(format: :text, sort_by: :time, sort_order: :asc)
172
+ return '' if @timers.empty?
175
173
 
176
- max = @timers.keys.sort_by(&:length).reverse[0].length + 1
174
+ max = @timers.keys.sort_by(&:length).reverse[0].length + 1
177
175
 
178
- total = @timers.delete('All')
176
+ total = @timers.delete('All')
179
177
 
180
- tags_data = @timers.delete_if { |_k, v| v.zero? }
181
- sorted_tags_data = if sort_by.normalize_tag_sort == :name
182
- tags_data.sort_by { |k, _v| k }
183
- else
184
- tags_data.sort_by { |_k, v| v }
185
- end
178
+ tags_data = @timers.delete_if { |_k, v| v.zero? }
179
+ sorted_tags_data = if sort_by.normalize_tag_sort == :name
180
+ tags_data.sort_by { |k, _v| k }
181
+ else
182
+ tags_data.sort_by { |_k, v| v }
183
+ end
186
184
 
187
- sorted_tags_data.reverse! if sort_order.normalize_order == :asc
188
- case format
189
- when :html
185
+ sorted_tags_data.reverse! if sort_order.normalize_order == :asc
186
+ case format
187
+ when :html
190
188
 
191
- output = <<EOHEAD
192
- <table>
193
- <caption id="tagtotals">Tag Totals</caption>
194
- <colgroup>
195
- <col style="text-align:left;"/>
196
- <col style="text-align:left;"/>
197
- </colgroup>
198
- <thead>
199
- <tr>
200
- <th style="text-align:left;">project</th>
201
- <th style="text-align:left;">time</th>
202
- </tr>
203
- </thead>
204
- <tbody>
205
- EOHEAD
206
- sorted_tags_data.reverse.each do |k, v|
207
- if v.positive?
208
- output += "<tr><td style='text-align:left;'>#{k}</td><td style='text-align:left;'>#{v.time_string(format: :clock)}</td></tr>\n"
209
- end
210
- end
211
- tail = <<EOTAIL
189
+ output = <<EOHEAD
190
+ <table>
191
+ <caption id="tagtotals">Tag Totals</caption>
192
+ <colgroup>
193
+ <col style="text-align:left;"/>
194
+ <col style="text-align:left;"/>
195
+ </colgroup>
196
+ <thead>
212
197
  <tr>
213
- <td style="text-align:left;" colspan="2"></td>
198
+ <th style="text-align:left;">project</th>
199
+ <th style="text-align:left;">time</th>
214
200
  </tr>
215
- </tbody>
216
- <tfoot>
217
- <tr>
218
- <td style="text-align:left;"><strong>Total</strong></td>
219
- <td style="text-align:left;">#{total.time_string(format: :clock)}</td>
220
- </tr>
221
- </tfoot>
222
- </table>
223
- EOTAIL
224
- output + tail
225
- when :markdown
226
- pad = sorted_tags_data.map { |k, _| k }.group_by(&:size).max.last[0].length
227
- pad = 7 if pad < 7
228
- output = <<~EOHEADER
229
- | #{' ' * (pad - 7)}project | time |
230
- | #{'-' * (pad - 1)}: | :------- |
231
- EOHEADER
232
- sorted_tags_data.reverse.each do |k, v|
233
- if v.positive?
234
- output += "| #{' ' * (pad - k.length)}#{k} | #{v.time_string(format: :clock)} |\n"
235
- end
201
+ </thead>
202
+ <tbody>
203
+ EOHEAD
204
+ sorted_tags_data.reverse.each do |k, v|
205
+ if v.positive?
206
+ output += "<tr><td style='text-align:left;'>#{k}</td><td style='text-align:left;'>#{v.time_string(format: :clock)}</td></tr>\n"
236
207
  end
237
- tail = '[Tag Totals]'
238
- output + tail
239
- when :json
240
- output = []
241
- sorted_tags_data.reverse.each do |k, v|
242
- output << {
243
- 'tag' => k,
244
- 'seconds' => v,
245
- 'formatted' => v.time_string(format: :clock)
246
- }
208
+ end
209
+ tail = <<EOTAIL
210
+ <tr>
211
+ <td style="text-align:left;" colspan="2"></td>
212
+ </tr>
213
+ </tbody>
214
+ <tfoot>
215
+ <tr>
216
+ <td style="text-align:left;"><strong>Total</strong></td>
217
+ <td style="text-align:left;">#{total.time_string(format: :clock)}</td>
218
+ </tr>
219
+ </tfoot>
220
+ </table>
221
+ EOTAIL
222
+ output + tail
223
+ when :markdown
224
+ pad = sorted_tags_data.map { |k, _| k }.group_by(&:size).max.last[0].length
225
+ pad = 7 if pad < 7
226
+ output = <<~EOHEADER
227
+ | #{' ' * (pad - 7)}project | time |
228
+ | #{'-' * (pad - 1)}: | :------- |
229
+ EOHEADER
230
+ sorted_tags_data.reverse.each do |k, v|
231
+ if v.positive?
232
+ output += "| #{' ' * (pad - k.length)}#{k} | #{v.time_string(format: :clock)} |\n"
247
233
  end
248
- output
249
- when :human
250
- output = []
251
- sorted_tags_data.reverse.each do |k, v|
252
- spacer = ''
253
- (max - k.length).times do
254
- spacer += ' '
255
- end
256
- output.push("┃ #{spacer}#{k}:#{v.time_string(format: :hm)} ┃")
234
+ end
235
+ tail = '[Tag Totals]'
236
+ output + tail
237
+ when :json
238
+ output = []
239
+ sorted_tags_data.reverse.each do |k, v|
240
+ output << {
241
+ 'tag' => k,
242
+ 'seconds' => v,
243
+ 'formatted' => v.time_string(format: :clock)
244
+ }
245
+ end
246
+ output
247
+ when :human
248
+ output = []
249
+ sorted_tags_data.reverse.each do |k, v|
250
+ spacer = ''
251
+ (max - k.length).times do
252
+ spacer += ' '
257
253
  end
254
+ output.push("┃ #{spacer}#{k}:#{v.time_string(format: :hm)} ┃")
255
+ end
258
256
 
259
- header = '┏━━ Tag Totals '
260
- (max - 2).times { header += '━' }
261
- header += '┓'
262
- footer = '┗'
263
- (max + 12).times { footer += '━' }
264
- footer += '┛'
265
- divider = '┣'
266
- (max + 12).times { divider += '━' }
267
- divider += '┫'
268
- output = output.empty? ? '' : "\n#{header}\n#{output.join("\n")}"
269
- output += "\n#{divider}"
257
+ header = '┏━━ Tag Totals '
258
+ (max - 2).times { header += '━' }
259
+ header += '┓'
260
+ footer = '┗'
261
+ (max + 12).times { footer += '━' }
262
+ footer += '┛'
263
+ divider = '┣'
264
+ (max + 12).times { divider += '━' }
265
+ divider += '┫'
266
+ output = output.empty? ? '' : "\n#{header}\n#{output.join("\n")}"
267
+ output += "\n#{divider}"
268
+ spacer = ''
269
+ (max - 6).times do
270
+ spacer += ' '
271
+ end
272
+ total_time = total.time_string(format: :hm)
273
+ total = "┃ #{spacer}total: "
274
+ total += total_time
275
+ total += ' ┃'
276
+ output += "\n#{total}"
277
+ output += "\n#{footer}"
278
+ output
279
+ else
280
+ output = []
281
+ sorted_tags_data.reverse.each do |k, v|
270
282
  spacer = ''
271
- (max - 6).times do
283
+ (max - k.length).times do
272
284
  spacer += ' '
273
285
  end
274
- total_time = total.time_string(format: :hm)
275
- total = "┃ #{spacer}total: "
276
- total += total_time
277
- total += ' ┃'
278
- output += "\n#{total}"
279
- output += "\n#{footer}"
280
- output
281
- else
282
- output = []
283
- sorted_tags_data.reverse.each do |k, v|
284
- spacer = ''
285
- (max - k.length).times do
286
- spacer += ' '
287
- end
288
- output.push("#{k}:#{spacer}#{v.time_string(format: :clock)}")
289
- end
290
-
291
- output = output.empty? ? '' : "\n--- Tag Totals ---\n#{output.join("\n")}"
292
- output += "\n\nTotal tracked: #{total.time_string(format: :clock)}\n"
293
- output
286
+ output.push("#{k}:#{spacer}#{v.time_string(format: :clock)}")
294
287
  end
288
+
289
+ output = output.empty? ? '' : "\n--- Tag Totals ---\n#{output.join("\n")}"
290
+ output += "\n\nTotal tracked: #{total.time_string(format: :clock)}\n"
291
+ output
295
292
  end
293
+ end
296
294
 
297
- ##
298
- ## Gets the interval between entry's start
299
- ## date and @done date
300
- ##
301
- ## @param item [Item] The entry
302
- ## @param formatted [Boolean] Return human readable
303
- ## time (default seconds)
304
- ## @param record [Boolean] Add the interval to the
305
- ## total for each tag
306
- ##
307
- ## @return Interval in seconds, or [d, h, m] array if
308
- ## formatted is true. False if no end date or
309
- ## interval is 0
310
- ##
311
- def get_interval(item, formatted: true, record: true)
312
- if item.interval
313
- seconds = item.interval
314
- record_tag_times(item, seconds) if record
315
- return seconds.positive? ? seconds : false unless formatted
295
+ ##
296
+ ## Gets the interval between entry's start
297
+ ## date and @done date
298
+ ##
299
+ ## @param item [Item] The entry
300
+ ## @param formatted [Boolean] Return human readable
301
+ ## time (default seconds)
302
+ ## @param record [Boolean] Add the interval to the
303
+ ## total for each tag
304
+ ##
305
+ ## @return Interval in seconds, or [d, h, m] array if
306
+ ## formatted is true. False if no end date or
307
+ ## interval is 0
308
+ ##
309
+ def get_interval(item, formatted: true, record: true)
310
+ if item.interval
311
+ seconds = item.interval
312
+ record_tag_times(item, seconds) if record
313
+ return seconds.positive? ? seconds : false unless formatted
316
314
 
317
- return seconds.positive? ? seconds.time_string(format: :clock) : false
318
- end
319
-
320
- false
315
+ return seconds.positive? ? seconds.time_string(format: :clock) : false
321
316
  end
322
317
 
323
- private
318
+ false
319
+ end
324
320
 
325
- ##
326
- ## Record times for item tags
327
- ##
328
- ## @param item [Item] The item to record
329
- ##
330
- def record_tag_times(item, seconds)
331
- item_hash = "#{item.date.strftime('%s')}#{item.title}#{item.section}"
332
- return if @recorded_items.include?(item_hash)
333
- item.title.scan(/(?mi)@(\S+?)(\(.*\))?(?=\s|$)/).each do |m|
334
- k = m[0] == 'done' ? 'All' : m[0].downcase
335
- if @timers.key?(k)
336
- @timers[k] += seconds
337
- else
338
- @timers[k] = seconds
339
- end
340
- @recorded_items.push(item_hash)
321
+ private
322
+
323
+ ##
324
+ ## Record times for item tags
325
+ ##
326
+ ## @param item [Item] The item to record
327
+ ##
328
+ def record_tag_times(item, seconds)
329
+ item_hash = "#{item.date.strftime('%s')}#{item.title}#{item.section}"
330
+ return if @recorded_items.include?(item_hash)
331
+ item.title.scan(/(?mi)@(\S+?)(\(.*\))?(?=\s|$)/).each do |m|
332
+ k = m[0] == 'done' ? 'All' : m[0].downcase
333
+ if @timers.key?(k)
334
+ @timers[k] += seconds
335
+ else
336
+ @timers[k] = seconds
341
337
  end
338
+ @recorded_items.push(item_hash)
342
339
  end
343
340
  end
344
341
  end