doing 2.1.4pre → 2.1.5pre

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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/.yardoc/checksums +14 -13
  3. data/.yardoc/object_types +0 -0
  4. data/.yardoc/objects/root.dat +0 -0
  5. data/CHANGELOG.md +21 -0
  6. data/Gemfile.lock +3 -1
  7. data/README.md +1 -1
  8. data/bin/doing +149 -91
  9. data/doc/Array.html +63 -1
  10. data/doc/BooleanTermParser/Clause.html +293 -0
  11. data/doc/BooleanTermParser/Operator.html +172 -0
  12. data/doc/BooleanTermParser/Query.html +417 -0
  13. data/doc/BooleanTermParser/QueryParser.html +135 -0
  14. data/doc/BooleanTermParser/QueryTransformer.html +124 -0
  15. data/doc/BooleanTermParser.html +115 -0
  16. data/doc/Doing/CLIFormat.html +131 -0
  17. data/doc/Doing/Color.html +2 -2
  18. data/doc/Doing/Completion.html +1 -1
  19. data/doc/Doing/Configuration.html +116 -12
  20. data/doc/Doing/Errors/DoingNoTraceError.html +1 -1
  21. data/doc/Doing/Errors/DoingRuntimeError.html +1 -1
  22. data/doc/Doing/Errors/DoingStandardError.html +1 -1
  23. data/doc/Doing/Errors/EmptyInput.html +1 -1
  24. data/doc/Doing/Errors/NoResults.html +1 -1
  25. data/doc/Doing/Errors/PluginException.html +1 -1
  26. data/doc/Doing/Errors/UserCancelled.html +1 -1
  27. data/doc/Doing/Errors/WrongCommand.html +1 -1
  28. data/doc/Doing/Errors.html +1 -1
  29. data/doc/Doing/Hooks.html +1 -1
  30. data/doc/Doing/Item.html +100 -73
  31. data/doc/Doing/Items.html +2 -2
  32. data/doc/Doing/LogAdapter.html +70 -1
  33. data/doc/Doing/Note.html +5 -134
  34. data/doc/Doing/Pager.html +1 -1
  35. data/doc/Doing/Plugins.html +380 -40
  36. data/doc/Doing/Prompt.html +1 -1
  37. data/doc/Doing/Section.html +1 -1
  38. data/doc/Doing/TemplateString.html +713 -0
  39. data/doc/Doing/Util/Backup.html +686 -0
  40. data/doc/Doing/Util.html +1 -1
  41. data/doc/Doing/WWID.html +5 -5
  42. data/doc/Doing.html +4 -4
  43. data/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
  44. data/doc/GLI/Commands.html +1 -1
  45. data/doc/GLI.html +1 -1
  46. data/doc/Hash.html +1 -1
  47. data/doc/PhraseParser/Operator.html +172 -0
  48. data/doc/PhraseParser/PhraseClause.html +303 -0
  49. data/doc/PhraseParser/Query.html +495 -0
  50. data/doc/PhraseParser/QueryParser.html +136 -0
  51. data/doc/PhraseParser/QueryTransformer.html +124 -0
  52. data/doc/PhraseParser/TermClause.html +293 -0
  53. data/doc/PhraseParser.html +115 -0
  54. data/doc/Status.html +1 -1
  55. data/doc/String.html +182 -12
  56. data/doc/Symbol.html +35 -1
  57. data/doc/Time.html +1 -1
  58. data/doc/_index.html +21 -14
  59. data/doc/class_list.html +1 -1
  60. data/doc/file.README.html +2 -2
  61. data/doc/index.html +2 -2
  62. data/doc/method_list.html +319 -175
  63. data/doc/top-level-namespace.html +1 -1
  64. data/doing.gemspec +1 -0
  65. data/doing.rdoc +56 -9
  66. data/lib/doing/array.rb +9 -0
  67. data/lib/doing/configuration.rb +30 -8
  68. data/lib/doing/item.rb +12 -3
  69. data/lib/doing/log_adapter.rb +28 -0
  70. data/lib/doing/note.rb +31 -30
  71. data/lib/doing/plugin_manager.rb +57 -13
  72. data/lib/doing/plugins/export/dayone_export.rb +209 -0
  73. data/lib/doing/plugins/export/template_export.rb +90 -85
  74. data/lib/doing/prompt.rb +9 -6
  75. data/lib/doing/string.rb +68 -27
  76. data/lib/doing/symbol.rb +4 -0
  77. data/lib/doing/template_string.rb +197 -0
  78. data/lib/doing/util.rb +4 -2
  79. data/lib/doing/util_backup.rb +55 -3
  80. data/lib/doing/version.rb +1 -1
  81. data/lib/doing/wwid.rb +27 -18
  82. data/lib/doing.rb +3 -0
  83. data/lib/templates/doing-dayone-entry.erb +6 -0
  84. data/lib/templates/doing-dayone.erb +5 -0
  85. metadata +42 -2
@@ -0,0 +1,197 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doing
4
+ ##
5
+ ## Template string formatting
6
+ ##
7
+ class TemplateString < String
8
+ class ::String
9
+ ##
10
+ ## Extract the longest valid color from a string.
11
+ ##
12
+ ## Allows %colors to bleed into other text and still
13
+ ## be recognized, e.g. %greensomething still finds
14
+ ## %green.
15
+ ##
16
+ ## @return [String] a valid color name
17
+ ## @api private
18
+ def validate_color
19
+ valid_color = nil
20
+ compiled = ''
21
+ split('').each do |char|
22
+ compiled += char
23
+ valid_color = compiled if Color.attributes.include?(compiled.to_sym)
24
+ end
25
+
26
+ valid_color
27
+ end
28
+ end
29
+
30
+ attr_reader :original
31
+
32
+ include Color
33
+ def initialize(string, placeholders: {}, force_color: false, wrap_width: 0, color: '', tags_color: '', reset: '')
34
+ Color.coloring = true if force_color
35
+ @colors = nil
36
+ @original = string
37
+ super(Color.reset + string)
38
+
39
+ placeholders.each { |k, v| fill(k, v, wrap_width: wrap_width, color: color, tags_color: tags_color) }
40
+ end
41
+
42
+ ##
43
+ ## Test if string contains any valid %colors
44
+ ##
45
+ ## @return [Boolean] True if colors, False otherwise.
46
+ ##
47
+ def colors?
48
+ scan(/%([a-z]+)/).each do
49
+ return true if Regexp.last_match(1).validate_color
50
+ end
51
+ false
52
+ end
53
+
54
+ def reparse
55
+ @parsed_colors = nil
56
+ end
57
+
58
+ ##
59
+ ## Return string with %colors replaced with escape codes
60
+ ##
61
+ ## @return [String] colorized string
62
+ ##
63
+ def colored
64
+ reparse
65
+ parsed_colors[:string].apply_colors(parsed_colors[:colors])
66
+ end
67
+
68
+ ##
69
+ ## Remove all valid %colors from string
70
+ ##
71
+ ## @return [String] cleaned string
72
+ ##
73
+ def raw
74
+ parsed_colors[:string].uncolor
75
+ end
76
+
77
+ def parsed_colors
78
+ @parsed_colors ||= parse_colors
79
+ end
80
+
81
+ ##
82
+ ## Parse a template string for %colors and return a hash
83
+ ## of colors and string locations
84
+ ##
85
+ ## @return [Hash] Uncolored string and array of colors and locations
86
+ def parse_colors
87
+ working = dup
88
+ color_array = []
89
+
90
+ scan(/(?<!\\)(%([a-z]+))/).each do |color|
91
+ valid_color = color[1].validate_color
92
+ next unless valid_color
93
+
94
+ idx = working.match(/(?<!\\)%#{valid_color}/).begin(0)
95
+ color_array.push({ name: valid_color, color: Color.send(valid_color), index: idx })
96
+ working.sub!(/(?<!\\)%#{valid_color}/, '')
97
+ end
98
+
99
+ { string: working, colors: color_array }
100
+ end
101
+
102
+ ##
103
+ ## Apply a color array to a string
104
+ ##
105
+ ## @param color_array [Array] Array of hashes
106
+ ## containing :name, :color,
107
+ ## :index
108
+ ##
109
+ def apply_colors(color_array)
110
+ str = dup
111
+ color_array.reverse.each do |color|
112
+ c = color[:color].empty? ? Color.send(color[:name]) : color[:color]
113
+ str.insert(color[:index], c)
114
+ end
115
+ str
116
+ end
117
+
118
+ def fill(placeholder, value, wrap_width: 0, color: '', tags_color: '', reset: '')
119
+ reparse
120
+ rx = /(?mi)(?<!\\)%(?<width>-?\d+)?(?:\^(?<mchar>.))?(?:(?<ichar>[ _t]|[^a-z0-9])(?<icount>\d+))?(?<prefix>.[ _t]?)?#{placeholder.sub(/^%/, '')}(?<after>.*?)$/
121
+ ph = raw.match(rx)
122
+
123
+ return unless ph
124
+ placeholder_offset = ph.begin(0)
125
+ last_colors = parsed_colors[:colors].select { |v| v[:index] <= placeholder_offset + 4 }
126
+
127
+ last_color = last_colors.map { |v| v[:color] }.pop(3).join('')
128
+
129
+ sub!(rx) do
130
+ m = Regexp.last_match
131
+
132
+ after = m['after']
133
+
134
+ if value.nil? || value.empty?
135
+ after
136
+ else
137
+ pad = m['width'].to_i
138
+ mark = m['mchar'] || ''
139
+ if placeholder == 'shortdate' && m['width'].nil?
140
+ pad = 13
141
+ end
142
+ indent = nil
143
+ if m['ichar']
144
+ char = m['ichar'] =~ /t/ ? "\t" : ' '
145
+ indent = char * m['icount'].to_i
146
+ end
147
+ indent ||= placeholder =~ /^title/ ? '' : "\t"
148
+ prefix = m['prefix']
149
+ if placeholder =~ /^title/
150
+ color = last_color + color
151
+
152
+ if wrap_width.positive? || pad.positive?
153
+ width = pad.positive? ? pad : wrap_width
154
+
155
+ out = value.gsub(/%/, '\%').strip.wrap(width,
156
+ pad: pad,
157
+ indent: indent,
158
+ offset: placeholder_offset,
159
+ prefix: prefix,
160
+ color: color,
161
+ after: after,
162
+ reset: reset,
163
+ pad_first: false)
164
+ out.highlight_tags!(tags_color, last_color: color) if tags_color && !tags_color.empty?
165
+ out
166
+ else
167
+ out = format("%s%s%#{pad}s%s", prefix, color, value.gsub(/%/, '\%').sub(/\s*$/, ''), after)
168
+ out.highlight_tags!(tags_color, last_color: color) if tags_color && !tags_color.empty?
169
+ out
170
+ end
171
+ elsif placeholder =~ /^note/
172
+ if wrap_width.positive? || pad.positive?
173
+ width = pad.positive? ? pad : wrap_width
174
+ outstring = value.map do |l|
175
+ if l.empty?
176
+ ' '
177
+ else
178
+ line = l.gsub(/%/, '\%').strip.wrap(width, pad: pad, indent: indent, offset: 0, prefix: prefix, color: last_color, after: after, reset: reset, pad_first: true)
179
+ line.highlight_tags!(tags_color, last_color: last_color) unless tags_color.nil? || tags_color.empty?
180
+ "#{line} "
181
+ end
182
+ end.join("\n")
183
+ "\n#{last_color}#{mark}#{outstring} "
184
+ else
185
+ out = format("\n%s%s%s%#{pad}s%s", indent, prefix, last_color, value.join("\n#{indent}#{prefix}").gsub(/%/, '\%').sub(/\s*$/, ''), after)
186
+ out.highlight_tags!(tags_color, last_color: last_color) if tags_color && !tags_color.empty?
187
+ out
188
+ end
189
+ else
190
+ format("%s%#{pad}s%s", prefix, value.gsub(/%/, '\%').sub(/\s*$/, ''), after)
191
+ end
192
+ end
193
+ end
194
+ @parsed_colors = parse_colors
195
+ end
196
+ end
197
+ end
data/lib/doing/util.rb CHANGED
@@ -112,7 +112,7 @@ module Doing
112
112
  puts content
113
113
  return
114
114
  end
115
-
115
+ Doing.logger.benchmark(:write_file, :start)
116
116
  file = File.expand_path(file)
117
117
 
118
118
  Backup.write_backup(file) if backup
@@ -121,8 +121,10 @@ module Doing
121
121
  f.puts content
122
122
  Doing.logger.debug('Write:', "File written: #{file}")
123
123
  end
124
-
124
+ Doing.logger.benchmark(:_post_write_hook, :start)
125
125
  Hooks.trigger :post_write, file
126
+ Doing.logger.benchmark(:_post_write_hook, :finish)
127
+ Doing.logger.benchmark(:write_file, :finish)
126
128
  end
127
129
 
128
130
  def safe_load_file(filename)
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require 'zlib'
2
3
 
3
4
  module Doing
4
5
  module Util
@@ -29,6 +30,7 @@ module Doing
29
30
  ## different from default
30
31
  ##
31
32
  def restore_last_backup(filename = nil, count: 1)
33
+ Doing.logger.benchmark(:restore_backup, :start)
32
34
  filename ||= Doing.config.settings['doing_file']
33
35
 
34
36
  result = get_backups(filename).slice(count - 1)
@@ -40,6 +42,7 @@ module Doing
40
42
  FileUtils.mv(backup_file, filename)
41
43
  prune_backups_after(File.basename(backup_file))
42
44
  Doing.logger.warn('File update:', "restored from #{result}")
45
+ Doing.logger.benchmark(:restore_backup, :finish)
43
46
  end
44
47
 
45
48
  ##
@@ -79,6 +82,44 @@ module Doing
79
82
  end
80
83
  end
81
84
 
85
+ ##
86
+ ## Select from recent undos. If a filename is
87
+ ## provided, only backups of that filename will be used.
88
+ ##
89
+ ## @param filename The filename to restore
90
+ ##
91
+ def select_redo(filename = nil)
92
+ filename ||= Doing.config.settings['doing_file']
93
+
94
+ undones = Dir.glob("undone*#{File.basename(filename)}", base: backup_dir).sort
95
+
96
+ raise DoingRuntimeError, 'End of redo history' if undones.empty?
97
+
98
+ total = undones.count
99
+ options = undones.each_with_object([]) do |file, arr|
100
+ d, _base = date_of_backup(file)
101
+ next if d.nil?
102
+
103
+ arr.push("#{d.time_ago}\t#{File.join(backup_dir, file)}")
104
+ end
105
+
106
+ backup_file = show_menu(options, filename)
107
+ idx = undones.index(File.basename(backup_file))
108
+ skipped = undones.slice!(idx, undones.count - idx)
109
+ undone = skipped.shift
110
+
111
+ redo_file = File.join(backup_dir, undone)
112
+
113
+ FileUtils.move(redo_file, filename)
114
+
115
+ skipped.each do |f|
116
+ FileUtils.mv(File.join(backup_dir, f), File.join(backup_dir, f.sub(/^undone/, '')))
117
+ end
118
+
119
+ Doing.logger.warn('File update:', "restored undo step #{idx}/#{total}")
120
+ Doing.logger.debug('Backup:', "#{total - skipped.count - 1} redos remaining")
121
+ end
122
+
82
123
  ##
83
124
  ## Select from recent backups. If a filename is
84
125
  ## provided, only backups of that filename will be used.
@@ -90,6 +131,7 @@ module Doing
90
131
 
91
132
  options = get_backups(filename).each_with_object([]) do |file, arr|
92
133
  d, _base = date_of_backup(file)
134
+ next if d.nil?
93
135
  arr.push("#{d.time_ago}\t#{File.join(backup_dir, file)}")
94
136
  end
95
137
 
@@ -123,13 +165,16 @@ module Doing
123
165
  end
124
166
 
125
167
  result = Doing::Prompt.choose_from(options,
168
+ prompt: 'Select a backup to restore',
126
169
  sorted: false,
127
170
  fzf_args: [
128
171
  '--delimiter="\t"',
129
172
  '--with-nth=1',
130
173
  %(--preview='#{preview} "#{filename}" {2} #{pipe}'),
131
174
  '--disabled',
132
- '--preview-window="right,70%,nowrap,follow"'
175
+ '--height=10',
176
+ '--preview-window="right,70%,nowrap,follow"',
177
+ '--header="Select a revision to restore"'
133
178
  ])
134
179
  raise UserCancelled unless result
135
180
 
@@ -143,6 +188,7 @@ module Doing
143
188
  ## @param content The data to back up
144
189
  ##
145
190
  def write_backup(filename = nil)
191
+ Doing.logger.benchmark(:_write_backup, :start)
146
192
  filename ||= Doing.config.settings['doing_file']
147
193
 
148
194
  unless File.exist?(filename)
@@ -152,11 +198,15 @@ module Doing
152
198
 
153
199
  backup_file = File.join(backup_dir, "#{timestamp_filename}___#{File.basename(filename)}")
154
200
  # compressed = Zlib::Deflate.deflate(content)
201
+ # Zlib::GzipWriter.open(backup_file + '.gz') do |gz|
202
+ # gz.write(IO.read(filename))
203
+ # end
155
204
 
156
205
  FileUtils.cp(filename, backup_file)
157
206
 
158
- prune_backups(filename, 100)
207
+ prune_backups(filename, 15)
159
208
  clear_undone(filename)
209
+ Doing.logger.benchmark(:_write_backup, :finish)
160
210
  end
161
211
 
162
212
  private
@@ -183,7 +233,7 @@ module Doing
183
233
  ## @param filename The filename
184
234
  ##
185
235
  def date_of_backup(filename)
186
- m = filename.match(/^(?<date>\d{4}-\d{2}-\d{2})_(?<time>\d{2}\.\d{2}\.\d{2})___(?<file>.*?)$/)
236
+ m = filename.match(/^(?:undone)?(?<date>\d{4}-\d{2}-\d{2})_(?<time>\d{2}\.\d{2}\.\d{2})___(?<file>.*?)$/)
187
237
  return nil if m.nil?
188
238
 
189
239
  [Time.parse("#{m['date']} #{m['time'].gsub(/\./, ':')}"), m['file']]
@@ -220,6 +270,8 @@ module Doing
220
270
  ##
221
271
  def prune_backups_after(filename)
222
272
  target_date, base = date_of_backup(filename)
273
+ return if target_date.nil?
274
+
223
275
  counter = 0
224
276
  get_backups(base).each do |file|
225
277
  date, _base = date_of_backup(file)
data/lib/doing/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '2.1.4pre'
2
+ VERSION = '2.1.5pre'
3
3
  end
data/lib/doing/wwid.rb CHANGED
@@ -262,7 +262,7 @@ module Doing
262
262
  return frag.cap_first if @content.section?(frag)
263
263
 
264
264
  section = nil
265
- re = frag.split('').join('.*?')
265
+ re = frag.to_rx(distance: 2, case_type: :ignore)
266
266
  sections.each do |sect|
267
267
  next unless sect =~ /#{re}/i
268
268
 
@@ -304,7 +304,7 @@ module Doing
304
304
  def guess_view(frag, guessed: false, suggest: false)
305
305
  views.each { |view| return view if frag.downcase == view.downcase }
306
306
  view = false
307
- re = frag.split('').join('.*?')
307
+ re = frag.to_rx(distance: 2, case_type: :ignore)
308
308
  views.each do |v|
309
309
  next unless v =~ /#{re}/i
310
310
 
@@ -780,7 +780,7 @@ module Doing
780
780
 
781
781
  keep
782
782
  end
783
- count = opt[:count]&.positive? ? opt[:count] : filtered_items.length
783
+ count = opt[:count].to_i&.positive? ? opt[:count].to_i : filtered_items.count
784
784
 
785
785
  output = Items.new
786
786
 
@@ -1427,11 +1427,11 @@ module Doing
1427
1427
  ##
1428
1428
  ## @return [String] The selected tag name
1429
1429
  ##
1430
- def choose_tag(section = 'All', include_all: false)
1431
- items = @content.in_section(section)
1430
+ def choose_tag(section = 'All', items: nil, include_all: false)
1431
+ items ||= @content.in_section(section)
1432
1432
  tags = all_tags(items, counts: true).map { |t, c| "@#{t} (#{c})" }
1433
1433
  tags.unshift('No tag filter') if include_all
1434
- choice = Prompt.choose_from(tags, sorted: false, multiple: true, prompt: 'Choose a tag > ', fzf_args: ['--height=60%'])
1434
+ choice = Prompt.choose_from(tags, sorted: false, multiple: true, prompt: 'Choose tag(s) > ', fzf_args: ['--height=60%'])
1435
1435
  choice ? choice.split(/\n/).map { |t| t.strip.sub(/ \(.*?\)$/, '')}.join(' ') : choice
1436
1436
  end
1437
1437
 
@@ -1482,17 +1482,25 @@ module Doing
1482
1482
  ##
1483
1483
  ## @param opt [Hash] Additional Options
1484
1484
  ##
1485
- def list_section(opt = {})
1485
+ def list_section(opt = {}, items: Items.new)
1486
1486
  opt[:config_template] ||= 'default'
1487
- cfg = @config.dig('templates',
1488
- opt[:config_template]).deep_merge({
1489
- 'wrap_width' => @config['wrap_width'] || 0,
1490
- 'date_format' => @config['default_date_format'],
1491
- 'order' => @config['order'] || 'asc',
1492
- 'tags_color' => @config['tags_color'],
1493
- 'duration' => @config['duration'],
1494
- 'interval_format' => @config['interval_format']
1495
- })
1487
+
1488
+ tpl_cfg = @config.dig('templates', opt[:config_template])
1489
+
1490
+ cfg = if opt[:view_template]
1491
+ @config.dig('views', opt[:view_template]).deep_merge(tpl_cfg)
1492
+ else
1493
+ tpl_cfg
1494
+ end
1495
+
1496
+ cfg.deep_merge({
1497
+ 'wrap_width' => @config['wrap_width'] || 0,
1498
+ 'date_format' => @config['default_date_format'],
1499
+ 'order' => @config['order'] || 'asc',
1500
+ 'tags_color' => @config['tags_color'],
1501
+ 'duration' => @config['duration'],
1502
+ 'interval_format' => @config['interval_format']
1503
+ })
1496
1504
  opt[:duration] ||= cfg['duration'] || false
1497
1505
  opt[:interval_format] ||= cfg['interval_format'] || 'text'
1498
1506
  opt[:count] ||= 0
@@ -1523,9 +1531,9 @@ module Doing
1523
1531
  end
1524
1532
  end
1525
1533
 
1526
- items = filter_items(Items.new, opt: opt).reverse
1534
+ items = filter_items(items, opt: opt)
1527
1535
 
1528
- items.reverse! if opt[:order] =~ /^d/i
1536
+ items.reverse! unless opt[:order] =~ /^d/i
1529
1537
 
1530
1538
  if opt[:interactive]
1531
1539
  opt[:menu] = !opt[:force]
@@ -1924,6 +1932,7 @@ EOS
1924
1932
  output + tail
1925
1933
  when :markdown
1926
1934
  pad = sorted_tags_data.map {|k, v| k }.group_by(&:size).max.last[0].length
1935
+ pad = 7 if pad < 7
1927
1936
  output = <<~EOS
1928
1937
  | #{' ' * (pad - 7) }project | time |
1929
1938
  | #{'-' * (pad - 1)}: | :------- |
data/lib/doing.rb CHANGED
@@ -8,10 +8,12 @@ require 'csv'
8
8
  require 'tempfile'
9
9
  require 'zlib'
10
10
  require 'base64'
11
+
11
12
  require 'chronic'
12
13
  require 'tty-link'
13
14
  require 'tty-which'
14
15
  require 'tty-markdown'
16
+ require 'plist'
15
17
  # require 'amatch'
16
18
  require 'haml'
17
19
  require 'json'
@@ -19,6 +21,7 @@ require 'logger'
19
21
  require 'safe_yaml/load'
20
22
  require 'doing/hash'
21
23
  require 'doing/colors'
24
+ require 'doing/template_string'
22
25
  require 'doing/string'
23
26
  require 'doing/string_chronify'
24
27
  require 'doing/time'
@@ -0,0 +1,6 @@
1
+ <% @items.each do |i| %>Doing on <%= i[:date_object].strftime('%A %m/%d/%y') %>
2
+
3
+ <%= i[:title] %><% if i[:note].length.positive? %><%= "\n\n" + i[:note].map{|n| n.strip }.join("\n ") %><% end %>
4
+
5
+ <% if i[:human_time] && i[:time] != "00:00:00" %>_Took <%= i[:human_time] %>._<% end %>
6
+ <% end %>
@@ -0,0 +1,5 @@
1
+ # <%= @page_title %>
2
+ <% @items.each do |i| %>
3
+ - [<%= i[:done] %>] <%= i[:date] %> <%= i[:title] %> <% if i[:time] && i[:time] != "00:00:00" %>[**<%= i[:time] %>**]<% end %><% if i[:note].length.positive? %><%= "\n\n " + i[:note].map{|n| n.strip }.join("\n ") %><% end %><% end %>
4
+
5
+ <%= @totals %>
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.4pre
4
+ version: 2.1.5pre
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-17 00:00:00.000000000 Z
11
+ date: 2021-12-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: safe_yaml
@@ -366,6 +366,26 @@ dependencies:
366
366
  - - ">="
367
367
  - !ruby/object:Gem::Version
368
368
  version: 2.0.0
369
+ - !ruby/object:Gem::Dependency
370
+ name: plist
371
+ requirement: !ruby/object:Gem::Requirement
372
+ requirements:
373
+ - - "~>"
374
+ - !ruby/object:Gem::Version
375
+ version: '3.6'
376
+ - - ">="
377
+ - !ruby/object:Gem::Version
378
+ version: 3.6.0
379
+ type: :runtime
380
+ prerelease: false
381
+ version_requirements: !ruby/object:Gem::Requirement
382
+ requirements:
383
+ - - "~>"
384
+ - !ruby/object:Gem::Version
385
+ version: '3.6'
386
+ - - ">="
387
+ - !ruby/object:Gem::Version
388
+ version: 3.6.0
369
389
  description: A tool for managing a TaskPaper-like file of recent activites. Perfect
370
390
  for the late-night hacker on too much caffeine to remember what they accomplished
371
391
  at 2 in the morning.
@@ -393,7 +413,14 @@ files:
393
413
  - _config.yml
394
414
  - bin/doing
395
415
  - doc/Array.html
416
+ - doc/BooleanTermParser.html
417
+ - doc/BooleanTermParser/Clause.html
418
+ - doc/BooleanTermParser/Operator.html
419
+ - doc/BooleanTermParser/Query.html
420
+ - doc/BooleanTermParser/QueryParser.html
421
+ - doc/BooleanTermParser/QueryTransformer.html
396
422
  - doc/Doing.html
423
+ - doc/Doing/CLIFormat.html
397
424
  - doc/Doing/Color.html
398
425
  - doc/Doing/Completion.html
399
426
  - doc/Doing/Configuration.html
@@ -416,13 +443,22 @@ files:
416
443
  - doc/Doing/Plugins.html
417
444
  - doc/Doing/Prompt.html
418
445
  - doc/Doing/Section.html
446
+ - doc/Doing/TemplateString.html
419
447
  - doc/Doing/Util.html
448
+ - doc/Doing/Util/Backup.html
420
449
  - doc/Doing/WWID.html
421
450
  - doc/Doing/WWIDFile.html
422
451
  - doc/GLI.html
423
452
  - doc/GLI/Commands.html
424
453
  - doc/GLI/Commands/MarkdownDocumentListener.html
425
454
  - doc/Hash.html
455
+ - doc/PhraseParser.html
456
+ - doc/PhraseParser/Operator.html
457
+ - doc/PhraseParser/PhraseClause.html
458
+ - doc/PhraseParser/Query.html
459
+ - doc/PhraseParser/QueryParser.html
460
+ - doc/PhraseParser/QueryTransformer.html
461
+ - doc/PhraseParser/TermClause.html
426
462
  - doc/Status.html
427
463
  - doc/String.html
428
464
  - doc/Symbol.html
@@ -474,6 +510,7 @@ files:
474
510
  - lib/doing/phrase_parser.rb
475
511
  - lib/doing/plugin_manager.rb
476
512
  - lib/doing/plugins/export/csv_export.rb
513
+ - lib/doing/plugins/export/dayone_export.rb
477
514
  - lib/doing/plugins/export/html_export.rb
478
515
  - lib/doing/plugins/export/json_export.rb
479
516
  - lib/doing/plugins/export/markdown_export.rb
@@ -488,6 +525,7 @@ files:
488
525
  - lib/doing/string.rb
489
526
  - lib/doing/string_chronify.rb
490
527
  - lib/doing/symbol.rb
528
+ - lib/doing/template_string.rb
491
529
  - lib/doing/time.rb
492
530
  - lib/doing/util.rb
493
531
  - lib/doing/util_backup.rb
@@ -589,6 +627,8 @@ files:
589
627
  - lib/helpers/fzf/test/fzf.vader
590
628
  - lib/helpers/fzf/test/test_go.rb
591
629
  - lib/helpers/fzf/uninstall
630
+ - lib/templates/doing-dayone-entry.erb
631
+ - lib/templates/doing-dayone.erb
592
632
  - lib/templates/doing-markdown.erb
593
633
  - lib/templates/doing.css
594
634
  - lib/templates/doing.haml