doing 2.1.42 → 2.1.45

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 (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +53 -0
  3. data/Gemfile.lock +4 -4
  4. data/README.md +1 -1
  5. data/bin/commands/changes.rb +11 -1
  6. data/bin/commands/flag.rb +1 -1
  7. data/bin/commands/grep.rb +12 -2
  8. data/bin/commands/last.rb +2 -0
  9. data/bin/commands/on.rb +13 -1
  10. data/bin/commands/recent.rb +4 -1
  11. data/bin/commands/show.rb +8 -0
  12. data/bin/commands/since.rb +6 -2
  13. data/bin/commands/template.rb +14 -25
  14. data/bin/commands/today.rb +4 -1
  15. data/bin/commands/view.rb +36 -73
  16. data/bin/commands/views.rb +102 -5
  17. data/bin/commands/yesterday.rb +3 -1
  18. data/bin/doing +31 -4
  19. data/docs/doc/Array.html +12 -2
  20. data/docs/doc/BooleanTermParser/Clause.html +1 -1
  21. data/docs/doc/BooleanTermParser/Operator.html +1 -1
  22. data/docs/doc/BooleanTermParser/Query.html +1 -1
  23. data/docs/doc/BooleanTermParser/QueryParser.html +1 -1
  24. data/docs/doc/BooleanTermParser/QueryTransformer.html +1 -1
  25. data/docs/doc/BooleanTermParser.html +1 -1
  26. data/docs/doc/Doing/ArrayCleanup.html +316 -0
  27. data/docs/doc/Doing/ArrayNestedHash.html +1 -1
  28. data/docs/doc/Doing/ArrayTags.html +1 -1
  29. data/docs/doc/Doing/CSVExport.html +1 -1
  30. data/docs/doc/Doing/CalendarImport.html +1 -1
  31. data/docs/doc/Doing/Change.html +74 -3
  32. data/docs/doc/Doing/Changes.html +3 -3
  33. data/docs/doc/Doing/ChronifyArray.html +1 -1
  34. data/docs/doc/Doing/ChronifyNumeric.html +1 -1
  35. data/docs/doc/Doing/ChronifyString.html +1 -1
  36. data/docs/doc/Doing/Color.html +1 -1
  37. data/docs/doc/Doing/Completion/BashCompletions.html +1 -1
  38. data/docs/doc/Doing/Completion/FishCompletions.html +1 -1
  39. data/docs/doc/Doing/Completion/StringUtils.html +1 -1
  40. data/docs/doc/Doing/Completion/ZshCompletions.html +1 -1
  41. data/docs/doc/Doing/Completion.html +1 -1
  42. data/docs/doc/Doing/Configuration.html +80 -1
  43. data/docs/doc/Doing/DayOneRenderer.html +1 -1
  44. data/docs/doc/Doing/DayoneExport.html +1 -1
  45. data/docs/doc/Doing/DoingImport.html +1 -1
  46. data/docs/doc/Doing/Entry.html +109 -4
  47. data/docs/doc/Doing/Errors/DoingNoTraceError.html +1 -1
  48. data/docs/doc/Doing/Errors/DoingRuntimeError.html +1 -1
  49. data/docs/doc/Doing/Errors/DoingStandardError.html +1 -1
  50. data/docs/doc/Doing/Errors/EmptyInput.html +1 -1
  51. data/docs/doc/Doing/Errors/HistoryLimitError.html +1 -1
  52. data/docs/doc/Doing/Errors/InvalidPlugin.html +1 -1
  53. data/docs/doc/Doing/Errors/MissingBackupFile.html +1 -1
  54. data/docs/doc/Doing/Errors/NoResults.html +1 -1
  55. data/docs/doc/Doing/Errors/PluginException.html +1 -1
  56. data/docs/doc/Doing/Errors/UserCancelled.html +1 -1
  57. data/docs/doc/Doing/Errors/WrongCommand.html +1 -1
  58. data/docs/doc/Doing/Errors.html +1 -1
  59. data/docs/doc/Doing/HTMLExport.html +1 -1
  60. data/docs/doc/Doing/Hooks.html +1 -1
  61. data/docs/doc/Doing/Item.html +1 -1
  62. data/docs/doc/Doing/ItemDates.html +1 -1
  63. data/docs/doc/Doing/ItemQuery.html +1 -1
  64. data/docs/doc/Doing/ItemState.html +1 -1
  65. data/docs/doc/Doing/ItemTags.html +1 -1
  66. data/docs/doc/Doing/Items.html +1 -1
  67. data/docs/doc/Doing/JSONExport.html +1 -1
  68. data/docs/doc/Doing/Logger.html +1 -1
  69. data/docs/doc/Doing/MarkdownExport.html +1 -1
  70. data/docs/doc/Doing/Note.html +1 -1
  71. data/docs/doc/Doing/Pager.html +1 -1
  72. data/docs/doc/Doing/Plugins.html +1 -1
  73. data/docs/doc/Doing/Prompt.html +1 -1
  74. data/docs/doc/Doing/PromptChoose.html +1 -1
  75. data/docs/doc/Doing/PromptFZF.html +1 -1
  76. data/docs/doc/Doing/PromptInput.html +1 -1
  77. data/docs/doc/Doing/PromptSTD.html +1 -1
  78. data/docs/doc/Doing/PromptYN.html +1 -1
  79. data/docs/doc/Doing/Section.html +1 -1
  80. data/docs/doc/Doing/StringHighlight.html +1 -1
  81. data/docs/doc/Doing/StringNormalize.html +35 -1
  82. data/docs/doc/Doing/StringQuery.html +1 -1
  83. data/docs/doc/Doing/StringTags.html +1 -1
  84. data/docs/doc/Doing/StringTransform.html +1 -1
  85. data/docs/doc/Doing/StringTruncate.html +1 -1
  86. data/docs/doc/Doing/StringURL.html +1 -1
  87. data/docs/doc/Doing/SymbolNormalize.html +1 -1
  88. data/docs/doc/Doing/TaskPaperExport.html +1 -1
  89. data/docs/doc/Doing/TemplateExport.html +1 -1
  90. data/docs/doc/Doing/TemplateString.html +2 -2
  91. data/docs/doc/Doing/TimingImport.html +1 -1
  92. data/docs/doc/Doing/Types.html +23 -18
  93. data/docs/doc/Doing/Util/Backup.html +1 -1
  94. data/docs/doc/Doing/Util.html +1 -1
  95. data/docs/doc/Doing/Version.html +1 -1
  96. data/docs/doc/Doing/WWID.html +71 -3
  97. data/docs/doc/Doing.html +2 -2
  98. data/docs/doc/FalseClass.html +11 -1
  99. data/docs/doc/GLI/Commands/Help.html +1 -1
  100. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
  101. data/docs/doc/GLI/Commands.html +1 -1
  102. data/docs/doc/GLI.html +1 -1
  103. data/docs/doc/Hash.html +461 -6
  104. data/docs/doc/Numeric.html +1 -1
  105. data/docs/doc/Object.html +1 -1
  106. data/docs/doc/PhraseParser/Operator.html +1 -1
  107. data/docs/doc/PhraseParser/PhraseClause.html +1 -1
  108. data/docs/doc/PhraseParser/Query.html +1 -1
  109. data/docs/doc/PhraseParser/QueryParser.html +1 -1
  110. data/docs/doc/PhraseParser/QueryTransformer.html +1 -1
  111. data/docs/doc/PhraseParser/TermClause.html +1 -1
  112. data/docs/doc/PhraseParser.html +1 -1
  113. data/docs/doc/Status.html +1 -1
  114. data/docs/doc/String.html +4 -4
  115. data/docs/doc/Symbol.html +1 -1
  116. data/docs/doc/Time.html +68 -3
  117. data/docs/doc/TrueClass.html +11 -1
  118. data/docs/doc/_index.html +1 -1
  119. data/docs/doc/file.README.html +2 -2
  120. data/docs/doc/index.html +2 -2
  121. data/docs/doc/method_list.html +511 -407
  122. data/docs/doc/top-level-namespace.html +3 -1
  123. data/doing.rdoc +163 -7
  124. data/lib/completion/_doing.zsh +13 -13
  125. data/lib/completion/doing.bash +22 -22
  126. data/lib/completion/doing.fish +24 -1
  127. data/lib/doing/add_options.rb +40 -1
  128. data/lib/doing/changelog/change.rb +13 -5
  129. data/lib/doing/changelog/changes.rb +11 -2
  130. data/lib/doing/changelog/entry.rb +9 -2
  131. data/lib/doing/configuration.rb +21 -0
  132. data/lib/doing/good.rb +18 -1
  133. data/lib/doing/hash.rb +126 -22
  134. data/lib/doing/normalize.rb +13 -0
  135. data/lib/doing/pager.rb +1 -1
  136. data/lib/doing/types.rb +9 -8
  137. data/lib/doing/version.rb +1 -1
  138. data/lib/doing/wwid/display.rb +4 -1
  139. data/lib/doing/wwid/filter.rb +6 -3
  140. data/lib/doing/wwid/wwid.rb +21 -3
  141. data/lib/doing.rb +9 -0
  142. metadata +3 -2
data/lib/doing/hash.rb CHANGED
@@ -40,14 +40,46 @@ module Doing
40
40
 
41
41
  # Turn all keys into string
42
42
  #
43
- # Return a copy of the hash where all its keys are strings
43
+ # If the hash has both a string and a symbol for key,
44
+ # keep the string value, discarding the symnbol value
45
+ #
46
+ # @return [Hash] a copy of the hash where all its
47
+ # keys are strings
48
+ #
44
49
  def stringify_keys
45
- each_with_object({}) { |(k, v), hsh| hsh[k.to_s] = v.is_a?(Hash) ? v.stringify_keys : v }
50
+ each_with_object({}) do |(k, v), hsh|
51
+ next if k.is_a?(Symbol) && key?(k.to_s)
52
+
53
+ hsh[k.to_s] = v.is_a?(Hash) ? v.stringify_keys : v
54
+ end
46
55
  end
47
56
 
48
57
  # Turn all keys into symbols
58
+ #
59
+ # If the hash has both a string and a symbol for a key,
60
+ # keep the symbol value and discard the string value
61
+ #
62
+ # @return [Hash] a copy of the hash where all its
63
+ # keys are symbols
64
+ #
49
65
  def symbolize_keys
50
- each_with_object({}) { |(k, v), hsh| hsh[k.to_sym] = v.is_a?(Hash) ? v.symbolize_keys : v }
66
+ each_with_object({}) do |(k, v), hsh|
67
+ next if k.is_a?(String) && key?(k.to_sym)
68
+
69
+ hsh[k.to_sym] = v.is_a?(Hash) ? v.symbolize_keys : v
70
+ end
71
+ end
72
+
73
+ def stringify_values
74
+ transform_values do |v|
75
+ if v.is_a?(Hash)
76
+ v.stringify_values
77
+ elsif v.is_a?(Symbol)
78
+ v.to_s
79
+ else
80
+ v
81
+ end
82
+ end
51
83
  end
52
84
 
53
85
  # Set a nested hash value using an array
@@ -61,30 +93,102 @@ module Doing
61
93
  #
62
94
  def deep_set(path, value)
63
95
  if path.count == 1
64
- unless value.nil? || value =~ /^ *$/
65
- self[path[0]] = value
66
- else
96
+ if value.nil? || value =~ /^ *$/
67
97
  delete(path[0])
98
+ else
99
+ self[path[0]] = value
68
100
  end
101
+ elsif value
102
+ self.default_proc = ->(h, k) { h[k] = Hash.new(&h.default_proc) }
103
+ dig(*path[0..-2])[path.fetch(-1)] = value
69
104
  else
70
- if value
71
- self.default_proc = ->(h, k) { h[k] = Hash.new(&h.default_proc) }
72
- dig(*path[0..-2])[path.fetch(-1)] = value
73
- else
74
- return self unless dig(*path)
75
-
76
- dig(*path[0..-2]).delete(path.fetch(-1))
77
- path.pop
78
- cleaned = self
79
- path.each do |key|
80
- if cleaned[key].empty?
81
- cleaned.delete(key)
82
- break
83
- end
84
- cleaned = cleaned[key]
105
+ return self unless dig(*path)
106
+
107
+ dig(*path[0..-2]).delete(path.fetch(-1))
108
+ path.pop
109
+ cleaned = self
110
+ path.each do |key|
111
+ if cleaned[key].empty?
112
+ cleaned.delete(key)
113
+ break
85
114
  end
86
- empty? ? nil : self
115
+ cleaned = cleaned[key]
87
116
  end
117
+ empty? ? nil : self
118
+ end
119
+ end
120
+
121
+ ##
122
+ ## Rename a key, deleting old key
123
+ ##
124
+ ## @param old_key The original key
125
+ ## @param new_key The new key
126
+ ## @param keep [Boolean] if true, keep old key
127
+ ## in addition to new key
128
+ ##
129
+ def rename_key(old_key, new_key, keep: false)
130
+ return unless key?(old_key)
131
+
132
+ self[new_key] = self[old_key]
133
+ self[new_key.to_s] = self[old_key] if key?(new_key.to_s)
134
+ delete(old_key) unless keep
135
+ end
136
+
137
+ ##
138
+ ## Rename keys in batch
139
+ ##
140
+ ## @param pairs [Array] pairs of old and new keys
141
+ ##
142
+ def rename_keys(*pairs)
143
+ pairs.each { |p| rename_key(p[0], p[1]) }
144
+ end
145
+
146
+ ##
147
+ ## Remove keys with empty values
148
+ ##
149
+ def remove_empty
150
+ delete_if { |k, v| !v.is_a?(FalseClass) && !v.good? }
151
+ end
152
+
153
+ def tag_filter_to_options
154
+ hsh = dup
155
+ if hsh.key?(:tag_filter)
156
+ hsh[:tags] = hsh[:tag_filter][:tags]
157
+ hsh[:bool] = hsh[:tag_filter][:bool]
158
+ hsh.delete(:tag_filter)
159
+ end
160
+ replace hsh
161
+ end
162
+
163
+ ##
164
+ ## Convert an options hash to a view config
165
+ ##
166
+ ## @return [Hash] View representation of the object.
167
+ ##
168
+ def to_view
169
+ hsh = symbolize_keys
170
+ %w[x save c a s o h e editor m menu i interactive d delete t fuzzy time_filter sort_tags].each do |key|
171
+ hsh.delete(key.to_sym) if hsh.key?(key.to_sym)
172
+ end
173
+
174
+ hsh.delete_unless_key(:tag, %i[bool])
175
+ hsh.delete_unless_key(:search, %i[exact case])
176
+ hsh.rename_keys(%i[not negate], %i[tag tags])
177
+ hsh.tag_filter_to_options
178
+
179
+ hsh = hsh.remove_empty.stringify_keys.stringify_values
180
+ hsh.keys.sort.each_with_object({}) { |k, out| out[k] = hsh[k] }
181
+ end
182
+
183
+ ##
184
+ ## Delete array of keys unless key exists
185
+ ##
186
+ ## @param key The key to verify
187
+ ## @param to_delete [Array] the keys to delete if key doesn't exist
188
+ ##
189
+ def delete_unless_key(key, to_delete)
190
+ unless key?(key)
191
+ to_delete.each { |k| delete(k) }
88
192
  end
89
193
  end
90
194
  end
@@ -155,6 +155,19 @@ module Doing
155
155
  def normalize_trigger!
156
156
  replace normalize_trigger
157
157
  end
158
+
159
+ def normalize_change_type
160
+ case self
161
+ when /^c/i
162
+ :changed
163
+ when /^i/i
164
+ :improved
165
+ when /^f/i
166
+ :fixed
167
+ when /^n/i
168
+ :new
169
+ end
170
+ end
158
171
  end
159
172
 
160
173
  ##
data/lib/doing/pager.rb CHANGED
@@ -73,7 +73,7 @@ module Doing
73
73
  [
74
74
  Doing.setting('editors.pager'),
75
75
  ENV['PAGER'],
76
- 'less -Xr',
76
+ 'less -FXr',
77
77
  ENV['GIT_PAGER'],
78
78
  git_pager,
79
79
  'more -r'
data/lib/doing/types.rb CHANGED
@@ -17,18 +17,19 @@ module Doing
17
17
  InvalidExportType = Class.new(RuntimeError)
18
18
  MissingConfigFile = Class.new(RuntimeError)
19
19
 
20
- TagArray = Class.new(Array)
21
- TemplateName = Class.new(String)
20
+ AgeSymbol = Class.new(String)
21
+ BooleanSymbol = Class.new(Symbol)
22
+ CaseSymbol = Class.new(Symbol)
22
23
  DateBeginString = Class.new(DateTime)
23
24
  DateEndString = Class.new(DateTime)
24
- DateRangeString = Class.new(Array)
25
- DateRangeOptionalString = Class.new(Array)
26
25
  DateIntervalString = Class.new(DateTime)
27
- BooleanSymbol = Class.new(Symbol)
28
- CaseSymbol = Class.new(Symbol)
29
- AgeSymbol = Class.new(String)
26
+ DateRangeOptionalString = Class.new(Array)
27
+ DateRangeString = Class.new(Array)
28
+ ExportTemplate = Class.new(String)
29
+ MatchingSymbol = Class.new(Symbol)
30
30
  OrderSymbol = Class.new(Symbol)
31
+ TagArray = Class.new(Array)
31
32
  TagSortSymbol = Class.new(Symbol)
32
- MatchingSymbol = Class.new(Symbol)
33
+ TemplateName = Class.new(String)
33
34
  end
34
35
  end
data/lib/doing/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '2.1.42'
2
+ VERSION = '2.1.45'
3
3
  end
@@ -357,7 +357,10 @@ module Doing
357
357
  opt ||= {}
358
358
  out = nil
359
359
 
360
- raise InvalidArgument, 'Unknown output format' unless opt[:output] =~ Plugins.plugin_regex(type: :export)
360
+ unless opt[:output] =~ Plugins.plugin_regex(type: :export)
361
+ raise InvalidPlugin.new('Unknown output format', opt[:output])
362
+
363
+ end
361
364
 
362
365
  export_options = { page_title: title, is_single: is_single, options: opt }
363
366
 
@@ -146,21 +146,24 @@ module Doing
146
146
  end
147
147
 
148
148
  if keep && opt[:time_filter][0] || opt[:time_filter][1]
149
+ opt[:time_filter][0] = '00:00' if opt[:time_filter][0] =~ /12 *am/i
150
+ opt[:time_filter][1] = '00:00' if opt[:time_filter][1] =~ /12 *am/i
149
151
  start_string = if opt[:time_filter][0].nil?
150
- "#{item.date.strftime('%Y-%m-%d')} 12am"
152
+ "#{item.date.strftime('%Y-%m-%d')} 00:00"
151
153
  else
152
154
  "#{item.date.strftime('%Y-%m-%d')} #{opt[:time_filter][0]}"
153
155
  end
154
156
  start_time = start_string.chronify(guess: :begin)
155
157
 
156
158
  end_string = if opt[:time_filter][1].nil?
157
- "#{item.date.to_datetime.next_day.strftime('%Y-%m-%d')} 12am"
159
+ "#{item.date.to_datetime.next_day.strftime('%Y-%m-%d')} 00:00"
158
160
  else
159
161
  "#{item.date.strftime('%Y-%m-%d')} #{opt[:time_filter][1]}"
160
162
  end
161
- end_time = end_string.chronify(guess: :end)
163
+ end_time = end_string.chronify(guess: :end) || Time.now
162
164
 
163
165
  in_time_range = item.date >= start_time && item.date <= end_time
166
+
164
167
  keep = false unless in_time_range
165
168
  keep = opt[:not] ? !keep : keep
166
169
  end
@@ -100,10 +100,28 @@ module Doing
100
100
  ##
101
101
  ## @param title [String] The title of the view to retrieve
102
102
  ##
103
- def get_view(title)
104
- return Doing.setting(['views', title], nil)
103
+ def get_view(title, fallback: nil)
104
+ Doing.setting(['views', title], fallback)
105
+ end
106
+
107
+ def rename_view_keys(view)
108
+ options = view.symbolize_keys
109
+ # options.rename_key(:tags, :tag, keep: true)
110
+ options.rename_key(:output_format, :output)
111
+ options.rename_key(:tags_bool, :bool)
112
+ options.rename_key(:tag_sort, :sort_tags)
113
+ options.rename_key(:negate, :not)
114
+ options.rename_key(:order, :sort)
115
+
116
+ options
117
+ end
105
118
 
106
- false
119
+ def view_to_options(title)
120
+ view = rename_view_keys(get_view(guess_view(title)))
121
+ view.deep_merge(rename_view_keys(get_view(guess_view(view[:parent]), fallback: {}))) if view.key?(:parent)
122
+ view.deep_merge(rename_view_keys(get_view(view[:config_template], fallback: {}))) if view.key?(:config_template)
123
+ view.deep_merge(Doing.setting('templates.default').symbolize_keys)
124
+ view
107
125
  end
108
126
 
109
127
  private
data/lib/doing.rb CHANGED
@@ -85,6 +85,15 @@ module Doing
85
85
  config.settings
86
86
  end
87
87
 
88
+ def original_options
89
+ @original_options ||= {
90
+ date_begin: nil,
91
+ date_end: nil,
92
+ date_range: nil,
93
+ date_interval: nil
94
+ }
95
+ end
96
+
88
97
  ##
89
98
  ## Fetch a config setting using a dot-separated keypath
90
99
  ## or array of keys
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: doing
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.42
4
+ version: 2.1.45
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-18 00:00:00.000000000 Z
11
+ date: 2022-03-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: github-markup
@@ -489,6 +489,7 @@ files:
489
489
  - docs/doc/BooleanTermParser/QueryParser.html
490
490
  - docs/doc/BooleanTermParser/QueryTransformer.html
491
491
  - docs/doc/Doing.html
492
+ - docs/doc/Doing/ArrayCleanup.html
492
493
  - docs/doc/Doing/ArrayNestedHash.html
493
494
  - docs/doc/Doing/ArrayTags.html
494
495
  - docs/doc/Doing/CLIFormat.html