doing 2.1.41 → 2.1.44

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 (161) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +67 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +1 -1
  5. data/bin/commands/again.rb +1 -3
  6. data/bin/commands/changes.rb +60 -34
  7. data/bin/commands/commands.rb +77 -52
  8. data/bin/commands/commands_accepting.rb +57 -53
  9. data/bin/commands/config.rb +2 -2
  10. data/bin/commands/finish.rb +94 -68
  11. data/bin/commands/flag.rb +5 -1
  12. data/bin/commands/grep.rb +12 -2
  13. data/bin/commands/last.rb +2 -0
  14. data/bin/commands/now.rb +151 -107
  15. data/bin/commands/on.rb +20 -5
  16. data/bin/commands/recent.rb +4 -1
  17. data/bin/commands/show.rb +8 -0
  18. data/bin/commands/since.rb +6 -2
  19. data/bin/commands/template.rb +14 -25
  20. data/bin/commands/today.rb +4 -1
  21. data/bin/commands/undo.rb +4 -6
  22. data/bin/commands/view.rb +36 -73
  23. data/bin/commands/views.rb +102 -5
  24. data/bin/commands/yesterday.rb +3 -1
  25. data/bin/doing +31 -4
  26. data/docs/doc/Array.html +14 -3
  27. data/docs/doc/BooleanTermParser/Clause.html +1 -1
  28. data/docs/doc/BooleanTermParser/Operator.html +1 -1
  29. data/docs/doc/BooleanTermParser/Query.html +1 -1
  30. data/docs/doc/BooleanTermParser/QueryParser.html +1 -1
  31. data/docs/doc/BooleanTermParser/QueryTransformer.html +1 -1
  32. data/docs/doc/BooleanTermParser.html +1 -1
  33. data/docs/doc/Doing/ArrayCleanup.html +316 -0
  34. data/docs/doc/Doing/ArrayNestedHash.html +1 -1
  35. data/docs/doc/Doing/ArrayTags.html +1 -1
  36. data/docs/doc/Doing/CSVExport.html +1 -1
  37. data/docs/doc/Doing/CalendarImport.html +1 -1
  38. data/docs/doc/Doing/Change.html +74 -3
  39. data/docs/doc/Doing/Changes.html +3 -3
  40. data/docs/doc/Doing/ChronifyArray.html +1 -1
  41. data/docs/doc/Doing/ChronifyNumeric.html +1 -1
  42. data/docs/doc/Doing/ChronifyString.html +1 -1
  43. data/docs/doc/Doing/Color.html +1 -1
  44. data/docs/doc/Doing/Completion/BashCompletions.html +1 -1
  45. data/docs/doc/Doing/Completion/FishCompletions.html +1 -1
  46. data/docs/doc/Doing/Completion/StringUtils.html +1 -1
  47. data/docs/doc/Doing/Completion/ZshCompletions.html +1 -1
  48. data/docs/doc/Doing/Completion.html +1 -1
  49. data/docs/doc/Doing/Configuration.html +82 -2
  50. data/docs/doc/Doing/DayOneRenderer.html +1 -1
  51. data/docs/doc/Doing/DayoneExport.html +1 -1
  52. data/docs/doc/Doing/DoingImport.html +1 -1
  53. data/docs/doc/Doing/Entry.html +109 -4
  54. data/docs/doc/Doing/Errors/DoingNoTraceError.html +1 -1
  55. data/docs/doc/Doing/Errors/DoingRuntimeError.html +1 -1
  56. data/docs/doc/Doing/Errors/DoingStandardError.html +1 -1
  57. data/docs/doc/Doing/Errors/EmptyInput.html +1 -1
  58. data/docs/doc/Doing/Errors/HistoryLimitError.html +1 -1
  59. data/docs/doc/Doing/Errors/InvalidPlugin.html +1 -1
  60. data/docs/doc/Doing/Errors/MissingBackupFile.html +1 -1
  61. data/docs/doc/Doing/Errors/NoResults.html +1 -1
  62. data/docs/doc/Doing/Errors/PluginException.html +1 -1
  63. data/docs/doc/Doing/Errors/UserCancelled.html +1 -1
  64. data/docs/doc/Doing/Errors/WrongCommand.html +1 -1
  65. data/docs/doc/Doing/Errors.html +1 -1
  66. data/docs/doc/Doing/HTMLExport.html +1 -1
  67. data/docs/doc/Doing/Hooks.html +1 -1
  68. data/docs/doc/Doing/Item.html +1 -1
  69. data/docs/doc/Doing/ItemDates.html +1 -1
  70. data/docs/doc/Doing/ItemQuery.html +1 -1
  71. data/docs/doc/Doing/ItemState.html +1 -1
  72. data/docs/doc/Doing/ItemTags.html +1 -1
  73. data/docs/doc/Doing/Items.html +2 -1
  74. data/docs/doc/Doing/JSONExport.html +1 -1
  75. data/docs/doc/Doing/Logger.html +1 -1
  76. data/docs/doc/Doing/MarkdownExport.html +1 -1
  77. data/docs/doc/Doing/Note.html +3 -2
  78. data/docs/doc/Doing/Pager.html +1 -1
  79. data/docs/doc/Doing/Plugins.html +181 -76
  80. data/docs/doc/Doing/Prompt.html +1 -1
  81. data/docs/doc/Doing/PromptChoose.html +1 -1
  82. data/docs/doc/Doing/PromptFZF.html +1 -1
  83. data/docs/doc/Doing/PromptInput.html +1 -1
  84. data/docs/doc/Doing/PromptSTD.html +1 -1
  85. data/docs/doc/Doing/PromptYN.html +1 -1
  86. data/docs/doc/Doing/Section.html +1 -1
  87. data/docs/doc/Doing/StringHighlight.html +1 -1
  88. data/docs/doc/Doing/StringNormalize.html +35 -1
  89. data/docs/doc/Doing/StringQuery.html +1 -1
  90. data/docs/doc/Doing/StringTags.html +1 -1
  91. data/docs/doc/Doing/StringTransform.html +35 -1
  92. data/docs/doc/Doing/StringTruncate.html +1 -1
  93. data/docs/doc/Doing/StringURL.html +1 -1
  94. data/docs/doc/Doing/SymbolNormalize.html +1 -1
  95. data/docs/doc/Doing/TaskPaperExport.html +1 -1
  96. data/docs/doc/Doing/TemplateExport.html +1 -1
  97. data/docs/doc/Doing/TemplateString.html +3 -3
  98. data/docs/doc/Doing/TimingImport.html +1 -1
  99. data/docs/doc/Doing/Types.html +23 -18
  100. data/docs/doc/Doing/Util/Backup.html +2 -156
  101. data/docs/doc/Doing/Util.html +66 -9
  102. data/docs/doc/Doing/Version.html +1 -1
  103. data/docs/doc/Doing/WWID.html +84 -3
  104. data/docs/doc/Doing.html +4 -4
  105. data/docs/doc/FalseClass.html +11 -1
  106. data/docs/doc/GLI/Commands/Help.html +1 -1
  107. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
  108. data/docs/doc/GLI/Commands.html +1 -1
  109. data/docs/doc/GLI.html +1 -1
  110. data/docs/doc/Hash.html +461 -6
  111. data/docs/doc/Numeric.html +1 -1
  112. data/docs/doc/Object.html +1 -1
  113. data/docs/doc/PhraseParser/Operator.html +1 -1
  114. data/docs/doc/PhraseParser/PhraseClause.html +1 -1
  115. data/docs/doc/PhraseParser/Query.html +1 -1
  116. data/docs/doc/PhraseParser/QueryParser.html +1 -1
  117. data/docs/doc/PhraseParser/QueryTransformer.html +1 -1
  118. data/docs/doc/PhraseParser/TermClause.html +1 -1
  119. data/docs/doc/PhraseParser.html +1 -1
  120. data/docs/doc/Status.html +1 -1
  121. data/docs/doc/String.html +5 -5
  122. data/docs/doc/Symbol.html +1 -1
  123. data/docs/doc/Time.html +68 -3
  124. data/docs/doc/TrueClass.html +11 -1
  125. data/docs/doc/_index.html +16 -9
  126. data/docs/doc/class_list.html +1 -1
  127. data/docs/doc/file.README.html +2 -2
  128. data/docs/doc/index.html +2 -2
  129. data/docs/doc/method_list.html +529 -417
  130. data/docs/doc/top-level-namespace.html +11 -1
  131. data/doing.rdoc +169 -13
  132. data/lib/completion/_doing.zsh +13 -13
  133. data/lib/completion/doing.bash +22 -22
  134. data/lib/completion/doing.fish +24 -1
  135. data/lib/doing/add_options.rb +48 -1
  136. data/lib/doing/array/array.rb +2 -0
  137. data/lib/doing/array/cleanup.rb +31 -0
  138. data/lib/doing/changelog/change.rb +13 -5
  139. data/lib/doing/changelog/changes.rb +11 -2
  140. data/lib/doing/changelog/entry.rb +9 -2
  141. data/lib/doing/configuration.rb +28 -3
  142. data/lib/doing/good.rb +18 -1
  143. data/lib/doing/hash.rb +126 -22
  144. data/lib/doing/normalize.rb +13 -0
  145. data/lib/doing/note.rb +1 -1
  146. data/lib/doing/pager.rb +9 -3
  147. data/lib/doing/plugin_manager.rb +30 -5
  148. data/lib/doing/prompt/choose.rb +1 -1
  149. data/lib/doing/prompt/input.rb +1 -1
  150. data/lib/doing/string/transform.rb +6 -0
  151. data/lib/doing/types.rb +9 -8
  152. data/lib/doing/util.rb +12 -6
  153. data/lib/doing/util_backup.rb +55 -48
  154. data/lib/doing/version.rb +1 -1
  155. data/lib/doing/wwid/display.rb +4 -1
  156. data/lib/doing/wwid/editor.rb +6 -3
  157. data/lib/doing/wwid/interactive.rb +10 -20
  158. data/lib/doing/wwid/modify.rb +2 -0
  159. data/lib/doing/wwid/wwid.rb +21 -3
  160. data/lib/doing.rb +12 -3
  161. metadata +4 -2
@@ -15,7 +15,7 @@ command :since do |c|
15
15
  add_options(:time_display, c)
16
16
  add_options(:tag_filter, c)
17
17
  add_options(:search, c)
18
-
18
+ add_options(:save, c)
19
19
  c.action do |_global_options, options, args|
20
20
  raise DoingRuntimeError, %(Invalid output type "#{options[:output]}") if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
21
21
 
@@ -25,7 +25,7 @@ command :since do |c|
25
25
 
26
26
  date_string.sub!(/(day) (\d)/, '\1 at \2')
27
27
  date_string.sub!(/(\d+)d( ago)?/, '\1 days ago')
28
-
28
+ Doing.original_options[:date_begin] = date_string
29
29
  start = date_string.chronify(guess: :begin)
30
30
  finish = Time.now
31
31
 
@@ -37,5 +37,9 @@ command :since do |c|
37
37
  options[:sort_tags] = options[:tag_sort]
38
38
 
39
39
  Doing::Pager.page @wwid.list_date([start, finish], options[:section], options[:times], options[:output], options).chomp
40
+ if options[:save]
41
+ options[:after] = Doing.original_options[:date_begin] if Doing.original_options[:date_begin].good?
42
+ Doing.config.save_view(options.to_view, options[:save].downcase)
43
+ end
40
44
  end
41
45
  end
@@ -28,34 +28,23 @@ command :template do |c|
28
28
  else
29
29
  $stdout.puts "Available templates: #{Doing::Plugins.plugin_templates.join(', ')}"
30
30
  end
31
- return
32
- end
33
-
34
- if args.empty?
35
- type = Doing::Prompt.choose_from(Doing::Plugins.plugin_templates, sorted: false, prompt: 'Select template type > ')
36
- type.sub!(/ \(.*?\)$/, '').strip!
37
- options[:save] = Doing::Prompt.yn("Save to #{options[:path]}? (No outputs to STDOUT)", default_response: false)
38
31
  else
39
- type = args[0]
40
- end
41
32
 
42
- raise InvalidPluginType, "No type specified, use `doing template [#{Doing::Plugins.plugin_templates.join('|')}]`" unless type
33
+ if args.empty?
34
+ type = Doing::Prompt.choose_from(Doing::Plugins.plugin_templates, sorted: false, prompt: 'Select template type > ')
35
+ type.sub!(/ \(.*?\)$/, '').strip!
36
+ options[:save] = Doing::Prompt.yn("Save to #{options[:path]}? (No outputs to STDOUT)", default_response: false)
37
+ else
38
+ type = args[0]
39
+ end
40
+
41
+ raise InvalidPluginType, "No type specified, use `doing template [#{Doing::Plugins.plugin_templates.join('|')}]`" unless type
43
42
 
44
- if options[:save]
45
- Doing::Plugins.template_for_trigger(type, save_to: options[:path])
46
- else
47
- $stdout.puts Doing::Plugins.template_for_trigger(type, save_to: nil)
43
+ if options[:save]
44
+ Doing::Plugins.template_for_trigger(type, save_to: options[:path])
45
+ else
46
+ $stdout.puts Doing::Plugins.template_for_trigger(type, save_to: nil)
47
+ end
48
48
  end
49
-
50
- # case args[0]
51
- # when /html|haml/i
52
- # $stdout.puts @wwid.haml_template
53
- # when /css/i
54
- # $stdout.puts @wwid.css_template
55
- # when /markdown|md|erb/i
56
- # $stdout.puts @wwid.markdown_template
57
- # else
58
- # exit_now! 'Invalid type specified, must be HAML or CSS'
59
- # end
60
49
  end
61
50
  end
@@ -15,6 +15,7 @@ command :today do |c|
15
15
  add_options(:output_template, c, default_template: 'today')
16
16
  add_options(:time_filter, c)
17
17
  add_options(:time_display, c)
18
+ add_options(:save, c)
18
19
 
19
20
  c.action do |_global_options, options, _args|
20
21
  raise InvalidPlugin.new('output', options[:output]) if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
@@ -22,7 +23,9 @@ command :today do |c|
22
23
  options[:times] = true if options[:totals]
23
24
  options[:sort_tags] = options[:tag_sort]
24
25
  filter_options = %i[after before times duration from section sort_tags totals tag_order template config_template only_timed].each_with_object({}) { |k, hsh| hsh[k] = options[k] }
25
-
26
+ filter_options[:today] = true
26
27
  Doing::Pager.page @wwid.today(options[:times], options[:output], filter_options).chomp
28
+ filter_options[:title] = options[:title]
29
+ Doing.config.save_view(filter_options.to_view, options[:save].downcase) if options[:save]
27
30
  end
28
31
  end
data/bin/commands/undo.rb CHANGED
@@ -28,7 +28,7 @@ command :undo do |c|
28
28
  c.action do |_global_options, options, args|
29
29
  file = options[:file] || @wwid.doing_file
30
30
  count = args.empty? ? 1 : args[0].to_i
31
- raise InvalidArgument, "Invalid count specified for undo" unless count&.positive?
31
+ raise InvalidArgument, 'Invalid count specified for undo' unless count&.positive?
32
32
 
33
33
  if options[:prune]
34
34
  Doing::Util::Backup.prune_backups(file, options[:prune])
@@ -38,12 +38,10 @@ command :undo do |c|
38
38
  else
39
39
  Doing::Util::Backup.redo_backup(file, count: count)
40
40
  end
41
+ elsif options[:interactive]
42
+ Doing::Util::Backup.select_backup(file)
41
43
  else
42
- if options[:interactive]
43
- Doing::Util::Backup.select_backup(file)
44
- else
45
- Doing::Util::Backup.restore_last_backup(file, count: count)
46
- end
44
+ Doing::Util::Backup.restore_last_backup(file, count: count)
47
45
  end
48
46
  end
49
47
  end
data/bin/commands/view.rb CHANGED
@@ -15,28 +15,24 @@ command :view do |c|
15
15
  c.arg_name 'COUNT'
16
16
  c.flag %i[c count], must_match: /^\d+$/, type: Integer
17
17
 
18
- c.desc "Output to export format (#{Doing::Plugins.plugin_names(type: :export)})"
19
- c.arg_name 'FORMAT'
20
- c.flag %i[o output]
21
-
22
18
  c.desc 'Age (oldest|newest)'
23
19
  c.arg_name 'AGE'
24
- c.flag %i[age], default_value: :newest, type: AgeSymbol
20
+ c.flag %i[age], type: AgeSymbol
25
21
 
26
22
  c.desc 'Show time intervals on @done tasks'
27
23
  c.switch %i[t times], default_value: true, negatable: true
28
24
 
29
25
  c.desc 'Show elapsed time on entries without @done tag'
30
- c.switch [:duration]
26
+ c.switch [:duration], default_value: false, negatable: false
31
27
 
32
28
  c.desc 'Show intervals with totals at the end of output'
33
29
  c.switch [:totals], default_value: false, negatable: false
34
30
 
35
31
  c.desc 'Include colors in output'
36
- c.switch [:color], default_value: true, negatable: true
32
+ c.switch [:color], negatable: true
37
33
 
38
34
  c.desc "Highlight search matches in output. Only affects command line output"
39
- c.switch %i[h hilite], default_value: Doing.settings.dig('search', 'highlight')
35
+ c.switch %i[h hilite], default_value: false, negatable: true
40
36
 
41
37
  c.desc 'Sort tags by (name|time)'
42
38
  c.arg_name 'KEY'
@@ -53,8 +49,9 @@ command :view do |c|
53
49
  c.switch %i[i interactive], negatable: false, default_value: false
54
50
 
55
51
  add_options(:search, c)
56
- add_options(:tag_filter, c)
52
+ add_options(:tag_filter_no_defaults, c)
57
53
  add_options(:date_filter, c)
54
+ add_options(:output_template_no_defaults, c)
58
55
 
59
56
  c.action do |global_options, options, args|
60
57
  options[:fuzzy] = false
@@ -85,83 +82,55 @@ command :view do |c|
85
82
  Doing.setting('current_section')
86
83
  end
87
84
 
88
- view = @wwid.get_view(title)
85
+ view = @wwid.view_to_options(title)
89
86
 
90
87
  if view
91
- page_title = view['title'] || title.cap_first
92
- only_timed = if (view.key?('only_timed') && view['only_timed']) || options[:only_timed]
93
- true
94
- else
95
- false
96
- end
88
+ options = Doing::Util.deep_merge_hashes(view, options)
97
89
 
98
- template = view['template'] || nil
99
- date_format = view['date_format'] || nil
90
+ options[:totals] = view[:totals] unless options[:totals]
91
+ options[:only_timed] = view[:only_timed] unless options[:only_timed]
92
+ options[:times] = view[:times] if options[:times]
93
+ options[:duration] = view[:duration] unless options[:duration]
94
+ options[:hilite] = view[:hilite] unless options[:hilite]
100
95
 
101
- tags_color = view['tags_color'] || nil
96
+ page_title = options[:title] || title.cap_first
102
97
  tag_filter = false
103
- if options[:tag]
98
+ if options[:tag] && options[:tag].good
104
99
  tag_filter = { 'tags' => [], 'bool' => 'OR' }
105
- bool = options[:bool]
100
+ bool = options[:bool].normalize_bool
106
101
  tag_filter['bool'] = bool
107
102
  tag_filter['tags'] = if bool == :pattern
108
103
  options[:tag]
109
104
  else
110
105
  options[:tag].gsub(/[, ]+/, ' ').split(' ').map(&:strip)
111
106
  end
112
- elsif view.key?('tags') && view['tags'].good?
107
+ options[:tags] = nil
108
+ options[:bool] = bool
109
+ elsif options[:tags]
113
110
  tag_filter = { 'tags' => [], 'bool' => 'OR' }
114
- bool = view.key?('tags_bool') && !view['tags_bool'].nil? ? view['tags_bool'].normalize_bool : :pattern
111
+ bool = options[:bool] ? options[:bool].normalize_bool : :pattern
115
112
  tag_filter['bool'] = bool
116
- tag_filter['tags'] = if view['tags'].instance_of?(Array)
117
- bool == :pattern ? view['tags'].join(' ').strip : view['tags'].map(&:strip)
113
+ tag_filter['tags'] = if options[:tags].instance_of?(Array)
114
+ bool == :pattern ? options[:tags].join(' ').strip : options[:tags].map(&:strip)
118
115
  else
119
- bool == :pattern ? view['tags'].strip : view['tags'].gsub(/[, ]+/, ' ').split(' ').map(&:strip)
116
+ bool == :pattern ? options[:tags].strip : options[:tags].gsub(/[, ]+/, ' ').split(' ').map(&:strip)
120
117
  end
118
+ options[:tags] = nil
119
+ options[:bool] = bool
121
120
  end
122
121
 
123
- # If the -o/--output flag was specified, override any default in the view template
124
- options[:output] ||= view.key?('output_format') ? view['output_format'] : 'template'
125
-
126
- count = if options[:count]
127
- options[:count]
128
- elsif view.key?('count')
129
- view['count']
130
- else
131
- 10
132
- end
133
-
134
- section = if options[:section]
135
- section
136
- else
137
- view['section'] || Doing.setting('current_section')
138
- end
139
- order = if view.key?('order')
140
- view['order'].normalize_order
141
- else
142
- :asc
143
- end
144
-
145
- totals = if options[:totals]
146
- true
147
- else
148
- view['totals'] || false
149
- end
150
- tag_order = options[:tag_order] || view['tag_order']&.normalize_order || :asc
151
-
152
- options[:times] = true if totals
122
+ section = options[:section] || Doing.setting('current_section')
123
+ order = options[:order]&.normalize_order || :asc
124
+ totals = options[:totals] || false
125
+ tag_order = options[:tag_order]&.normalize_order || :asc
153
126
  output_format = options[:output]&.downcase || 'template'
154
127
 
155
- options[:sort_tags] = if options[:tag_sort]
156
- options[:tag_sort]
157
- elsif view.key?('tag_sort')
158
- view['tag_sort'].normalize_tag_sort
159
- else
160
- false
161
- end
162
-
163
- %w[before after from duration].each { |k| options[k.to_sym] = view[k] if view.key?(k) && !options[k.to_sym] }
128
+ options[:times] = true if totals
164
129
 
130
+ options.rename_key(:tag_sort, :sort_tags)
131
+ options[:sort_tags] ||= :name
132
+ options.rename_key(:date_format, :format)
133
+ options.rename_key(:color, :highlight)
165
134
  search = nil
166
135
 
167
136
  if options[:search]
@@ -172,12 +141,8 @@ command :view do |c|
172
141
  options[:age] ||= :newest
173
142
 
174
143
  opts = options.clone
175
- opts[:age] = options[:age]
176
- opts[:count] = count
177
- opts[:format] = date_format
178
- opts[:highlight] = options[:color]
179
- opts[:hilite] = options[:hilite]
180
- opts[:only_timed] = only_timed
144
+
145
+ opts[:count] ||= 10
181
146
  opts[:order] = order
182
147
  opts[:output] = options[:interactive] ? nil : options[:output]
183
148
  opts[:output] = output_format
@@ -186,8 +151,6 @@ command :view do |c|
186
151
  opts[:section] = section
187
152
  opts[:tag_filter] = tag_filter
188
153
  opts[:tag_order] = tag_order
189
- opts[:tags_color] = tags_color
190
- opts[:template] = template
191
154
  opts[:totals] = totals
192
155
  opts[:view_template] = title
193
156
 
@@ -1,11 +1,108 @@
1
1
  # @@views
2
- desc 'List available custom views'
2
+ desc 'List available custom views. Specify view names to see YAML configurations.'
3
+ arg_name 'NAME(S)', optional: true
3
4
  command :views do |c|
5
+ c.example 'doing views', desc: 'list all views'
6
+ c.example 'doing views -c', desc: 'list views in column, ideal for shell completion'
7
+ c.example 'doing views color', desc: 'dump the YAML for a single view'
8
+ c.example 'doing views -e color', desc: 'edit the YAML configuration for a single view'
9
+ c.example 'doing views -e -o json color finished', desc: 'edit multiple view configs as JSON'
10
+
4
11
  c.desc 'List in single column'
5
- c.switch %i[c column], default_value: false
12
+ c.switch %i[c column], default_value: false, negatable: false
13
+
14
+ c.desc 'Open YAML for view in editor (requires argument)'
15
+ c.switch %i[e editor], negatable: false
16
+
17
+ c.desc 'Output/edit view in alternative format (json, yaml)'
18
+ c.arg_name 'FORMAT'
19
+ c.flag %i[o output], must_match: /^[jy]/i, default_value: 'yaml'
20
+
21
+ c.desc 'Delete view config'
22
+ c.switch %i[r remove], negatable: false
23
+
24
+ c.action do |_global_options, options, args|
25
+ cmd = Doing::ViewsCommand.new(options, args, @wwid)
26
+
27
+ if args.count.positive?
28
+ if options[:remove]
29
+ cmd.remove_views
30
+ elsif options[:editor]
31
+ cmd.edit_views
32
+ else
33
+ cmd.output_views
34
+ end
35
+ else
36
+ cmd.list_views
37
+ end
38
+ end
39
+ end
40
+
41
+ module Doing
42
+ # views Command
43
+ class ViewsCommand
44
+ def initialize(options, args, wwid)
45
+ @options = options
46
+ @args = args
47
+ @wwid = wwid
48
+
49
+ @views = {}
50
+ args.each do |v|
51
+ view = @wwid.get_view(v)
52
+ raise InvalidArgument, 'Unrecognized view' unless view
53
+
54
+ @views[v] = view if view
55
+ end
56
+ end
57
+
58
+ def list_views
59
+ joiner = @options[:column] ? "\n" : "\t"
60
+ print @wwid.views.join(joiner)
61
+ end
62
+
63
+ def save_view(view, res)
64
+ val = if res.nil? || !res.key?(view) || res[view]&.empty?
65
+ nil
66
+ else
67
+ res[view]
68
+ end
69
+
70
+ Doing.set("views.#{view}", val)
71
+ end
72
+
73
+ def remove_views
74
+ @args.each do |v|
75
+ Doing.set("views.#{v}", nil)
76
+ end
77
+
78
+ save_config
79
+ end
80
+
81
+ def edit_views
82
+ res = if @options[:output] =~ /^j/i
83
+ JSON.parse(@wwid.fork_editor(JSON.pretty_generate(@views), message: nil))
84
+ else
85
+ YAML.safe_load(@wwid.fork_editor(YAML.dump(@views), message: nil))
86
+ end
87
+ @args.each do |v|
88
+ save_view(v, res)
89
+ end
90
+ save_config
91
+ end
92
+
93
+ def output_views
94
+ out = if @options[:output] =~ /^j/i
95
+ JSON.pretty_generate(@views)
96
+ else
97
+ YAML.dump(@views)
98
+ end
99
+
100
+ Doing::Pager.page out
101
+ end
6
102
 
7
- c.action do |_global_options, options, _args|
8
- joiner = options[:column] ? "\n" : "\t"
9
- print @wwid.views.join(joiner)
103
+ def save_config
104
+ Doing::Util.write_to_file(Doing.config.config_file, YAML.dump(Doing.settings), backup: true)
105
+ Doing.logger.warn('Config:', "#{Doing.config.config_file} updated")
106
+ end
10
107
  end
11
108
  end
@@ -14,6 +14,7 @@ command :yesterday do |c|
14
14
  add_options(:output_template, c, default_template: 'today')
15
15
  add_options(:time_filter, c)
16
16
  add_options(:time_display, c)
17
+ add_options(:save, c)
17
18
 
18
19
  c.action do |_global_options, options, _args|
19
20
  raise InvalidPlugin.new('output', options[:output]) if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
@@ -22,7 +23,8 @@ command :yesterday do |c|
22
23
 
23
24
  opt = options.clone
24
25
  opt[:order] = Doing.setting(['templates', options[:config_template], 'order'])
25
-
26
+ opt[:yesterday] = true
26
27
  Doing::Pager.page @wwid.yesterday(options[:section], options[:times], options[:output], opt).chomp
28
+ Doing.config.save_view(opt.to_view, options[:save].downcase) if options[:save]
27
29
  end
28
30
  end
data/bin/doing CHANGED
@@ -26,7 +26,7 @@ include Doing::Errors
26
26
 
27
27
  version Doing::VERSION
28
28
  hide_commands_without_desc true
29
- autocomplete_commands true
29
+ autocomplete_commands false
30
30
  wrap_help_text :one_line unless $stdout.isatty
31
31
 
32
32
  include Doing::Types
@@ -88,14 +88,33 @@ accept TagSortSymbol do |value|
88
88
  value.normalize_tag_sort(Doing.config.fetch('tag_sort', :name))
89
89
  end
90
90
 
91
+ accept ExportTemplate do |value|
92
+ if value !~ Doing::Plugins.plugin_regex(type: :export)
93
+ raise Doing::Errors::InvalidPlugin.new('output', value)
94
+
95
+ end
96
+
97
+ tpl = nil
98
+
99
+ Doing::Plugins.plugins[:export].each do |k, options|
100
+ next unless value =~ /^(#{options[:trigger].normalize_trigger})$/i
101
+
102
+ tpl = k
103
+ break
104
+ end
105
+
106
+ tpl.nil? ? 'template' : value
107
+ end
108
+
91
109
  accept TemplateName do |value|
92
110
  res = Doing.setting('templates').keys.select { |k| k =~ value.to_rx(distance: 2) }
93
- raise InvalidArgument, "Unknown template: #{value}" unless res.good?
111
+ raise Doing::Errors::InvalidArgument, "Unknown template: #{value}" unless res.good?
94
112
 
95
113
  res.group_by(&:length).min.last[0]
96
114
  end
97
115
 
98
116
  accept DateBeginString do |value|
117
+ Doing.original_options[:date_begin] = value
99
118
  res = if value =~ REGEX_TIME
100
119
  value
101
120
  else
@@ -107,6 +126,7 @@ accept DateBeginString do |value|
107
126
  end
108
127
 
109
128
  accept DateEndString do |value|
129
+ Doing.original_options[:date_end] = value
110
130
  res = if value =~ REGEX_TIME
111
131
  value
112
132
  else
@@ -118,6 +138,7 @@ accept DateEndString do |value|
118
138
  end
119
139
 
120
140
  accept DateRangeString do |value|
141
+ Doing.original_options[:date_range] = value
121
142
  start, finish = value.split_date_range
122
143
  raise InvalidTimeExpression, 'Invalid range' unless start
123
144
 
@@ -126,6 +147,7 @@ accept DateRangeString do |value|
126
147
  end
127
148
 
128
149
  accept DateRangeOptionalString do |value|
150
+ Doing.original_options[:date_range] = value
129
151
  start, finish = value.split_date_range
130
152
  raise InvalidTimeExpression, 'Invalid range' unless start
131
153
 
@@ -133,6 +155,7 @@ accept DateRangeOptionalString do |value|
133
155
  end
134
156
 
135
157
  accept DateIntervalString do |value|
158
+ Doing.original_options[:date_interval] = value
136
159
  res = value.chronify_qty
137
160
  raise InvalidTimeExpression, 'Invalid time quantity' unless res
138
161
 
@@ -233,16 +256,20 @@ pre do |global, _command, _options, _args|
233
256
  end
234
257
 
235
258
  on_error do |exception|
236
- if exception.is_a?(GLI::UnknownCommand)
259
+ case exception
260
+ when GLI::UnknownCommand
237
261
  if ARGV.count > 1
262
+ exit run(['view'].concat(ARGV.unshift(@command))) if @wwid.get_view(@command, fallback: false)
238
263
  exit run(['now'].concat(ARGV.unshift(@command)))
239
264
  else
265
+ exit run(['view'].concat(ARGV.unshift(@command))) if @wwid.get_view(@command, fallback: false)
266
+
240
267
  Doing::Color.coloring = $stdout.isatty
241
268
  Doing.logger.error('Unknown Command:', @command)
242
269
  Doing.logger.output_results
243
270
  false
244
271
  end
245
- elsif exception.is_a?(SystemExit)
272
+ when SystemExit
246
273
  false
247
274
  else
248
275
  # Doing.logger.error('Fatal:', exception)
data/docs/doc/Array.html CHANGED
@@ -89,7 +89,7 @@
89
89
 
90
90
  <dl>
91
91
  <dt>Includes:</dt>
92
- <dd>ArrayNestedHash, ArrayTags, <span class='object_link'><a href="Doing/ChronifyArray.html" title="Doing::ChronifyArray (module)">Doing::ChronifyArray</a></span></dd>
92
+ <dd>ArrayCleanup, ArrayNestedHash, ArrayTags, <span class='object_link'><a href="Doing/ChronifyArray.html" title="Doing::ChronifyArray (module)">Doing::ChronifyArray</a></span></dd>
93
93
  </dl>
94
94
 
95
95
 
@@ -106,7 +106,17 @@
106
106
 
107
107
  </div>
108
108
 
109
- <div id="subclasses">
109
+ <h2>Overview</h2><div class="docstring">
110
+ <div class="discussion">
111
+ <p>Array helpers</p>
112
+
113
+
114
+ </div>
115
+ </div>
116
+ <div class="tags">
117
+
118
+
119
+ </div><div id="subclasses">
110
120
  <h2>Direct Known Subclasses</h2>
111
121
  <p class="children"><span class='object_link'><a href="Doing/Items.html" title="Doing::Items (class)">Doing::Items</a></span>, <span class='object_link'><a href="Doing/Note.html" title="Doing::Note (class)">Doing::Note</a></span></p>
112
122
  </div>
@@ -188,6 +198,7 @@
188
198
 
189
199
 
190
200
 
201
+
191
202
 
192
203
  <div id="instance_method_details" class="method_details_list">
193
204
  <h2>Instance Method Details</h2>
@@ -277,7 +288,7 @@ has content</p>
277
288
  </div>
278
289
 
279
290
  <div id="footer">
280
- Generated on Wed Mar 16 09:42:15 2022 by
291
+ Generated on Mon Mar 21 07:53:15 2022 by
281
292
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
282
293
  0.9.27 (ruby-3.0.1).
283
294
  </div>
@@ -283,7 +283,7 @@
283
283
  </div>
284
284
 
285
285
  <div id="footer">
286
- Generated on Wed Mar 16 09:42:15 2022 by
286
+ Generated on Mon Mar 21 07:53:16 2022 by
287
287
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
288
288
  0.9.27 (ruby-3.0.1).
289
289
  </div>
@@ -162,7 +162,7 @@
162
162
  </div>
163
163
 
164
164
  <div id="footer">
165
- Generated on Wed Mar 16 09:42:15 2022 by
165
+ Generated on Mon Mar 21 07:53:16 2022 by
166
166
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
167
167
  0.9.27 (ruby-3.0.1).
168
168
  </div>
@@ -407,7 +407,7 @@
407
407
  </div>
408
408
 
409
409
  <div id="footer">
410
- Generated on Wed Mar 16 09:42:15 2022 by
410
+ Generated on Mon Mar 21 07:53:16 2022 by
411
411
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
412
412
  0.9.27 (ruby-3.0.1).
413
413
  </div>
@@ -125,7 +125,7 @@ parser. In order to do that, a new &quot;clause&quot; node is added to the parse
125
125
  </div>
126
126
 
127
127
  <div id="footer">
128
- Generated on Wed Mar 16 09:42:15 2022 by
128
+ Generated on Mon Mar 21 07:53:16 2022 by
129
129
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
130
130
  0.9.27 (ruby-3.0.1).
131
131
  </div>
@@ -114,7 +114,7 @@
114
114
  </div>
115
115
 
116
116
  <div id="footer">
117
- Generated on Wed Mar 16 09:42:15 2022 by
117
+ Generated on Mon Mar 21 07:53:16 2022 by
118
118
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
119
119
  0.9.27 (ruby-3.0.1).
120
120
  </div>
@@ -105,7 +105,7 @@
105
105
  </div>
106
106
 
107
107
  <div id="footer">
108
- Generated on Wed Mar 16 09:42:15 2022 by
108
+ Generated on Mon Mar 21 07:53:15 2022 by
109
109
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
110
110
  0.9.27 (ruby-3.0.1).
111
111
  </div>