doing 2.1.27 → 2.1.31pre

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 (126) hide show
  1. checksums.yaml +4 -4
  2. data/.irbrc +1 -0
  3. data/.yardoc/checksums +11 -10
  4. data/.yardoc/object_types +0 -0
  5. data/.yardoc/objects/root.dat +0 -0
  6. data/CHANGELOG.md +4952 -0
  7. data/Gemfile.lock +2 -1
  8. data/README.md +1 -1
  9. data/bin/commands/again.rb +1 -1
  10. data/bin/commands/archive.rb +3 -3
  11. data/bin/commands/cancel.rb +1 -1
  12. data/bin/commands/changes.rb +32 -18
  13. data/bin/commands/commands.rb +8 -8
  14. data/bin/commands/completion.rb +61 -19
  15. data/bin/commands/config.rb +16 -16
  16. data/bin/commands/done.rb +1 -1
  17. data/bin/commands/flag.rb +1 -1
  18. data/bin/commands/grep.rb +5 -5
  19. data/bin/commands/last.rb +1 -1
  20. data/bin/commands/meanwhile.rb +1 -1
  21. data/bin/commands/now.rb +1 -1
  22. data/bin/commands/on.rb +1 -1
  23. data/bin/commands/open.rb +4 -4
  24. data/bin/commands/recent.rb +4 -4
  25. data/bin/commands/show.rb +8 -8
  26. data/bin/commands/since.rb +1 -1
  27. data/bin/commands/today.rb +1 -1
  28. data/bin/commands/view.rb +3 -3
  29. data/bin/commands/yesterday.rb +2 -2
  30. data/bin/doing +22 -133
  31. data/docs/doc/Array.html +1 -1
  32. data/docs/doc/BooleanTermParser/Clause.html +1 -1
  33. data/docs/doc/BooleanTermParser/Operator.html +1 -1
  34. data/docs/doc/BooleanTermParser/Query.html +1 -1
  35. data/docs/doc/BooleanTermParser/QueryParser.html +1 -1
  36. data/docs/doc/BooleanTermParser/QueryTransformer.html +1 -1
  37. data/docs/doc/BooleanTermParser.html +1 -1
  38. data/docs/doc/Doing/Color.html +1 -1
  39. data/docs/doc/Doing/Completion.html +324 -4
  40. data/docs/doc/Doing/Configuration.html +1 -1
  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/NoResults.html +1 -1
  46. data/docs/doc/Doing/Errors/PluginException.html +1 -1
  47. data/docs/doc/Doing/Errors/UserCancelled.html +1 -1
  48. data/docs/doc/Doing/Errors/WrongCommand.html +1 -1
  49. data/docs/doc/Doing/Errors.html +1 -1
  50. data/docs/doc/Doing/Hooks.html +1 -1
  51. data/docs/doc/Doing/Item.html +125 -1
  52. data/docs/doc/Doing/Items.html +1 -1
  53. data/docs/doc/Doing/LogAdapter.html +1 -1
  54. data/docs/doc/Doing/Note.html +109 -3
  55. data/docs/doc/Doing/Pager.html +1 -1
  56. data/docs/doc/Doing/Plugins.html +1 -1
  57. data/docs/doc/Doing/Prompt.html +1 -1
  58. data/docs/doc/Doing/Section.html +1 -1
  59. data/docs/doc/Doing/TemplateString.html +1 -1
  60. data/docs/doc/Doing/Types.html +1 -1
  61. data/docs/doc/Doing/Util/Backup.html +1 -1
  62. data/docs/doc/Doing/Util.html +1 -1
  63. data/docs/doc/Doing/WWID.html +6 -6
  64. data/docs/doc/Doing.html +2 -2
  65. data/docs/doc/FalseClass.html +1 -1
  66. data/docs/doc/GLI/Commands/Help.html +1 -1
  67. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
  68. data/docs/doc/GLI/Commands.html +1 -1
  69. data/docs/doc/GLI.html +1 -1
  70. data/docs/doc/Hash.html +1 -1
  71. data/docs/doc/Object.html +1 -1
  72. data/docs/doc/PhraseParser/Operator.html +1 -1
  73. data/docs/doc/PhraseParser/PhraseClause.html +1 -1
  74. data/docs/doc/PhraseParser/Query.html +1 -1
  75. data/docs/doc/PhraseParser/QueryParser.html +1 -1
  76. data/docs/doc/PhraseParser/QueryTransformer.html +1 -1
  77. data/docs/doc/PhraseParser/TermClause.html +1 -1
  78. data/docs/doc/PhraseParser.html +1 -1
  79. data/docs/doc/Status.html +1 -1
  80. data/docs/doc/String.html +1 -1
  81. data/docs/doc/Symbol.html +1 -1
  82. data/docs/doc/Time.html +1 -1
  83. data/docs/doc/TrueClass.html +1 -1
  84. data/docs/doc/_index.html +3 -1
  85. data/docs/doc/file.README.html +2 -2
  86. data/docs/doc/index.html +2 -2
  87. data/docs/doc/method_list.html +337 -241
  88. data/docs/doc/top-level-namespace.html +105 -1
  89. data/doing.gemspec +1 -0
  90. data/doing.rdoc +46 -41
  91. data/example_plugin.rb +7 -5
  92. data/lib/completion/_doing.zsh +4 -8
  93. data/lib/completion/doing.bash +4 -15
  94. data/lib/completion/doing.fish +6 -9
  95. data/lib/doing/add_options.rb +117 -0
  96. data/lib/doing/array/array.rb +16 -0
  97. data/lib/doing/changelog/change.rb +1 -1
  98. data/lib/doing/changelog/changes.rb +26 -7
  99. data/lib/doing/changelog/version.rb +11 -3
  100. data/lib/doing/completion/bash_completion.rb +12 -51
  101. data/lib/doing/completion/fish_completion.rb +16 -52
  102. data/lib/doing/completion/zsh_completion.rb +12 -51
  103. data/lib/doing/completion.rb +203 -17
  104. data/lib/doing/configuration.rb +5 -5
  105. data/lib/doing/item.rb +21 -3
  106. data/lib/doing/items.rb +5 -5
  107. data/lib/doing/note.rb +24 -8
  108. data/lib/doing/plugins/export/dayone_export.rb +8 -6
  109. data/lib/doing/plugins/export/html_export.rb +4 -4
  110. data/lib/doing/plugins/export/json_export.rb +19 -20
  111. data/lib/doing/plugins/export/markdown_export.rb +2 -2
  112. data/lib/doing/plugins/export/template_export.rb +4 -4
  113. data/lib/doing/plugins/import/calendar_import.rb +1 -1
  114. data/lib/doing/plugins/import/doing_import.rb +1 -1
  115. data/lib/doing/plugins/import/timing_import.rb +1 -1
  116. data/lib/doing/section.rb +1 -1
  117. data/lib/doing/string/highlight.rb +3 -4
  118. data/lib/doing/string/string.rb +8 -0
  119. data/lib/doing/util.rb +1 -1
  120. data/lib/doing/util_backup.rb +12 -12
  121. data/lib/doing/version.rb +1 -1
  122. data/lib/doing/wwid.rb +75 -76
  123. data/lib/doing.rb +58 -0
  124. data/lib/examples/commands/wiki.rb +27 -19
  125. data/scripts/setting_replace.rb +11 -0
  126. metadata +26 -4
@@ -220,9 +220,9 @@ module Doing
220
220
  return nil unless create
221
221
  end
222
222
 
223
- resolved = real_path.count.positive? ? "Resolved #{real_path.join('->')}, but " : ''
223
+ resolved = real_path.count.positive? ? "Resolved #{real_path.join('.')}, but " : ''
224
224
  Doing.logger.log_now(:warn, "#{resolved}#{path} is unknown")
225
- new_path = [*real_path, path, *paths].join('->')
225
+ new_path = [*real_path, path, *paths].join('.')
226
226
  Doing.logger.log_now(:warn, "Continuing will create the path #{new_path}")
227
227
  res = Prompt.yn('Key path not found, create it?', default_response: true)
228
228
  raise InvalidArgument, 'Invalid key path' unless res
@@ -374,7 +374,7 @@ module Doing
374
374
  deprecated = true
375
375
  config['editors']['default'] ||= config['editor']
376
376
  config.delete('editor')
377
- Doing.logger.debug('Deprecated:', "config key 'editor' is now 'editors->default', please update your config.")
377
+ Doing.logger.debug('Deprecated:', "config key 'editor' is now 'editors.default', please update your config.")
378
378
  end
379
379
 
380
380
  if config.key?('config_editor_app') && !config['editors']['config']
@@ -382,7 +382,7 @@ module Doing
382
382
  config['editors']['config'] = config['config_editor_app']
383
383
  config.delete('config_editor_app')
384
384
  Doing.logger.debug('Deprecated:',
385
- "config key 'config_editor_app' is now 'editors->config', please update your config.")
385
+ "config key 'config_editor_app' is now 'editors.config', please update your config.")
386
386
  end
387
387
 
388
388
  if config.key?('editor_app') && !config['editors']['doing_file']
@@ -390,7 +390,7 @@ module Doing
390
390
  config['editors']['doing_file'] = config['editor_app']
391
391
  config.delete('editor_app')
392
392
  Doing.logger.debug('Deprecated:',
393
- "config key 'editor_app' is now 'editors->doing_file', please update your config.")
393
+ "config key 'editor_app' is now 'editors.doing_file', please update your config.")
394
394
  end
395
395
 
396
396
  Doing.logger.warn('Deprecated:', 'outdated keys found, please run `doing config --update`.') if deprecated
data/lib/doing/item.rb CHANGED
@@ -272,7 +272,7 @@ module Doing
272
272
  end
273
273
 
274
274
  def highlight_search(search, distance: nil, negate: false, case_type: nil)
275
- prefs = Doing.config.settings['search'] || {}
275
+ prefs = Doing.setting('search', {})
276
276
  matching = prefs.fetch('matching', 'pattern').normalize_matching
277
277
  distance ||= prefs.fetch('distance', 3).to_i
278
278
  case_type ||= prefs.fetch('case', 'smart').normalize_case
@@ -311,7 +311,7 @@ module Doing
311
311
  ## @return [Boolean] matches search criteria
312
312
  ##
313
313
  def search(search, distance: nil, negate: false, case_type: nil)
314
- prefs = Doing.config.settings['search'] || {}
314
+ prefs = Doing.setting('search', {})
315
315
  matching = prefs.fetch('matching', 'pattern').normalize_matching
316
316
  distance ||= prefs.fetch('distance', 3).to_i
317
317
  case_type ||= prefs.fetch('case', 'smart').normalize_case
@@ -354,6 +354,24 @@ module Doing
354
354
  negate ? !matches : matches
355
355
  end
356
356
 
357
+ ##
358
+ ## Test if item has a @done tag
359
+ ##
360
+ ## @return [Boolean] true item has @done tag
361
+ ##
362
+ def finished?
363
+ tags?('done')
364
+ end
365
+
366
+ ##
367
+ ## Test if item does not contain @done tag
368
+ ##
369
+ ## @return [Boolean] true if item is missing @done tag
370
+ ##
371
+ def unfinished?
372
+ tags?('done', negate: true)
373
+ end
374
+
357
375
  ##
358
376
  ## Test if item is included in never_finish config and
359
377
  ## thus should not receive a @done tag
@@ -436,7 +454,7 @@ module Doing
436
454
  private
437
455
 
438
456
  def should?(key)
439
- config = Doing.config.settings
457
+ config = Doing.settings
440
458
  return true unless config[key].is_a?(Array)
441
459
 
442
460
  config[key].each do |tag|
data/lib/doing/items.rb CHANGED
@@ -131,9 +131,9 @@ module Doing
131
131
  out = []
132
132
  @sections.each do |section|
133
133
  out.push(section.original)
134
- items = in_section(section.title).sort_by { |i| i.date }
135
- items.reverse! if Doing.config.settings['doing_file_sort'].normalize_order == :desc
136
- items.each { |item| out.push(item.to_s)}
134
+ items = in_section(section.title).sort_by(&:date)
135
+ items.reverse! if Doing.setting('doing_file_sort').normalize_order == :desc
136
+ items.each { |item| out.push(item.to_s) }
137
137
  end
138
138
 
139
139
  out.join("\n")
@@ -141,8 +141,8 @@ module Doing
141
141
 
142
142
  # @private
143
143
  def inspect
144
- "#<Doing::Items #{count} items, #{@sections.count} sections: #{@sections.map { |s| "<Section:#{s.title} #{in_section(s.title).count} items>" }.join(', ')}>"
144
+ sections = @sections.map { |s| "<Section:#{s.title} #{in_section(s.title).count} items>" }.join(', ')
145
+ "#<Doing::Items #{count} items, #{@sections.count} sections: #{sections}>"
145
146
  end
146
-
147
147
  end
148
148
  end
data/lib/doing/note.rb CHANGED
@@ -5,7 +5,6 @@ module Doing
5
5
  ## This class describes an item note.
6
6
  ##
7
7
  class Note < Array
8
-
9
8
  ##
10
9
  ## Initializes a new note
11
10
  ##
@@ -28,9 +27,10 @@ module Doing
28
27
  ##
29
28
  def add(note, replace: false)
30
29
  clear if replace
31
- if note.is_a?(String)
30
+ case note
31
+ when String
32
32
  append_string(note)
33
- elsif note.is_a?(Array)
33
+ when Array
34
34
  append(note)
35
35
  end
36
36
  end
@@ -55,7 +55,7 @@ module Doing
55
55
  ## @return [Array] Stripped note
56
56
  ##
57
57
  def strip_lines
58
- map(&:strip)
58
+ Note.new(map(&:strip))
59
59
  end
60
60
 
61
61
  def strip_lines!
@@ -64,8 +64,24 @@ module Doing
64
64
 
65
65
  ##
66
66
  ## Note as multi-line string
67
- def to_s
68
- compress.strip_lines.map { |l| "\t\t#{l}" }.join("\n")
67
+ ##
68
+ ## @param prefix [String] prefix for each line (default two tabs, TaskPaper format)
69
+ ##
70
+ def to_s(prefix: "\t\t")
71
+ compress.strip_lines.map { |l| "#{prefix}#{l}" }.join("\n")
72
+ end
73
+
74
+ ##
75
+ ## Returns note as a single line, newlines separated by
76
+ ## space
77
+ ##
78
+ ## @return [String] Line representation of the Note.
79
+ ##
80
+ ## @param separator The separator with which to
81
+ ## join multiple lines
82
+ ##
83
+ def to_line(separator: ' ')
84
+ compress.strip_lines.join(separator)
69
85
  end
70
86
 
71
87
  # @private
@@ -94,7 +110,7 @@ module Doing
94
110
  ## @param lines [Array] Array of strings
95
111
  ##
96
112
  def append(lines)
97
- concat(lines)
113
+ concat(lines.utf8)
98
114
  replace compress
99
115
  end
100
116
 
@@ -105,7 +121,7 @@ module Doing
105
121
  ## newlines will be split
106
122
  ##
107
123
  def append_string(input)
108
- concat(input.split(/\n/).map(&:strip))
124
+ concat(input.utf8.split(/\n/).map(&:strip))
109
125
  replace compress
110
126
  end
111
127
  end
@@ -45,7 +45,9 @@ module Doing
45
45
 
46
46
  def self.render(wwid, items, variables: {})
47
47
 
48
- return if items.nil?
48
+ return unless items.good?
49
+
50
+ config = Doing.settings
49
51
 
50
52
  opt = variables[:options]
51
53
  trigger = opt[:output]
@@ -78,7 +80,7 @@ module Doing
78
80
  title = "#{title} @section(#{i.section})" unless variables[:is_single]
79
81
 
80
82
  tags.concat(i.tag_array).sort!.uniq!
81
- flagged = day_flagged = true if i.tags?(wwid.config['marker_tag'])
83
+ flagged = day_flagged = true if i.tags?(config['marker_tag'])
82
84
 
83
85
  interval = wwid.get_interval(i, record: true) if i.title =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
84
86
  interval ||= false
@@ -123,8 +125,8 @@ module Doing
123
125
  end
124
126
 
125
127
 
126
- template = if wwid.config['export_templates']['dayone'] && File.exist?(File.expand_path(wwid.config['export_templates']['dayone']))
127
- IO.read(File.expand_path(wwid.config['export_templates']['dayone']))
128
+ template = if config['export_templates']['dayone'] && File.exist?(File.expand_path(config['export_templates']['dayone']))
129
+ IO.read(File.expand_path(config['export_templates']['dayone']))
128
130
  else
129
131
  self.template('dayone')
130
132
  end
@@ -144,8 +146,8 @@ module Doing
144
146
  starred: hsh[:starred])
145
147
  end
146
148
  when :entries
147
- entry_template = if wwid.config['export_templates']['dayone_entry'] && File.exist?(File.expand_path(wwid.config['export_templates']['dayone_entry']))
148
- IO.read(File.expand_path(wwid.config['export_templates']['dayone_entry']))
149
+ entry_template = if config['export_templates']['dayone_entry'] && File.exist?(File.expand_path(config['export_templates']['dayone_entry']))
150
+ IO.read(File.expand_path(config['export_templates']['dayone_entry']))
149
151
  else
150
152
  self.template('dayone-entry')
151
153
  end
@@ -58,14 +58,14 @@ module Doing
58
58
  }
59
59
  end
60
60
 
61
- template = if wwid.config['export_templates']['haml'] && File.exist?(File.expand_path(wwid.config['export_templates']['haml']))
62
- IO.read(File.expand_path(wwid.config['export_templates']['haml']))
61
+ template = if Doing.setting('export_templates.haml') && File.exist?(File.expand_path(Doing.setting('export_templates.haml')))
62
+ IO.read(File.expand_path(Doing.setting('export_templates.haml')))
63
63
  else
64
64
  self.template('html')
65
65
  end
66
66
 
67
- style = if wwid.config['export_templates']['css'] && File.exist?(File.expand_path(wwid.config['export_templates']['css']))
68
- IO.read(File.expand_path(wwid.config['export_templates']['css']))
67
+ style = if Doing.setting('export_templates.css') && File.exist?(File.expand_path(Doing.setting('export_templates.css')))
68
+ IO.read(File.expand_path(Doing.setting('export_templates.css')))
69
69
  else
70
70
  self.template('css')
71
71
  end
@@ -29,16 +29,12 @@ module Doing
29
29
  max = last_date.strftime('%F')
30
30
  min = items[0].date.strftime('%F')
31
31
  items.each_with_index do |i, index|
32
- if String.method_defined? :force_encoding
33
- title = i.title.force_encoding('utf-8')
34
- note = i.note.map { |line| line.force_encoding('utf-8').strip } if i.note
35
- else
36
- title = i.title
37
- note = i.note.map { |line| line.strip } if i.note
38
- end
32
+ title = i.title.utf8
33
+ note = i.note.utf8
39
34
 
40
35
  end_date = i.end_date || ''
41
36
  interval = wwid.get_interval(i, formatted: false) || 0
37
+ duration = i.duration || 0
42
38
  note ||= ''
43
39
 
44
40
  tags = []
@@ -49,14 +45,15 @@ module Doing
49
45
  attributes[tag[0]] = tag[1] if tag[1]
50
46
  end
51
47
 
52
- if opt[:output] == 'json'
53
-
48
+ case opt[:output]
49
+ when 'json'
54
50
  i = {
55
51
  date: i.date,
56
52
  end_date: end_date,
57
53
  title: title.strip, #+ " #{note}"
58
- note: note.instance_of?(Array) ? note.to_s : note,
54
+ note: note.to_s(prefix: ''),
59
55
  time: interval.time_string(format: :clock),
56
+ duration: duration.time_string(format: :clock),
60
57
  tags: tags
61
58
  }
62
59
 
@@ -64,7 +61,7 @@ module Doing
64
61
 
65
62
  items_out << i
66
63
 
67
- elsif opt[:output] == 'timeline'
64
+ when 'timeline'
68
65
  new_item = {
69
66
  'id' => index + 1,
70
67
  'content' => title.strip, #+ " #{note}"
@@ -74,26 +71,28 @@ module Doing
74
71
  'style' => 'color:#4c566b;background-color:#d8dee9;'
75
72
  }
76
73
 
77
-
78
- if interval && interval.to_i > 0
74
+ if interval.to_i&.positive?
79
75
  new_item['end'] = end_date.strftime('%F %T')
80
76
  if interval.to_i > 3600
81
77
  new_item['type'] = 'range'
82
78
  new_item['style'] = 'color:white;background-color:#a2bf8a;'
83
79
  end
84
80
  end
85
- new_item['style'] = 'color:white;background-color:#f7921e;' if i.tags?(wwid.config['marker_tag'])
81
+ new_item['style'] = 'color:white;background-color:#f7921e;' if i.tags?(Doing.setting('marker_tag'))
86
82
  items_out.push(new_item)
87
83
  end
88
84
  end
89
- if opt[:output] == 'json'
85
+ case opt[:output]
86
+ when 'json'
90
87
  Doing.logger.debug('JSON Export:', "#{items_out.count} items output to JSON")
91
88
  JSON.pretty_generate({
92
- 'section' => variables[:page_title],
93
- 'items' => items_out,
94
- 'timers' => wwid.tag_times(format: :json, sort_by: opt[:sort_tags], sort_order: opt[:tag_order])
95
- })
96
- elsif opt[:output] == 'timeline'
89
+ 'section' => variables[:page_title],
90
+ 'items' => items_out,
91
+ 'timers' => wwid.tag_times(format: :json,
92
+ sort_by: opt[:sort_tags],
93
+ sort_order: opt[:tag_order])
94
+ })
95
+ when 'timeline'
97
96
  template = <<~EOTEMPLATE
98
97
  <!doctype html>
99
98
  <html>
@@ -66,8 +66,8 @@ module Doing
66
66
  }
67
67
  end
68
68
 
69
- template = if wwid.config['export_templates']['markdown'] && File.exist?(File.expand_path(wwid.config['export_templates']['markdown']))
70
- IO.read(File.expand_path(wwid.config['export_templates']['markdown']))
69
+ template = if Doing.setting('export_templates.markdown') && File.exist?(File.expand_path(Doing.setting('export_templates.markdown')))
70
+ IO.read(File.expand_path(Doing.setting('export_templates.markdown')))
71
71
  else
72
72
  self.template(nil)
73
73
  end
@@ -24,8 +24,8 @@ module Doing
24
24
 
25
25
  out = ''
26
26
  items.each do |item|
27
- if opt[:highlight] && item.title =~ /@#{wwid.config['marker_tag']}\b/i
28
- flag = Doing::Color.send(wwid.config['marker_color'])
27
+ if opt[:highlight] && item.title =~ /@#{Doing.setting('marker_tag')}\b/i
28
+ flag = Doing::Color.send(Doing.setting('marker_color'))
29
29
  reset = Doing::Color.reset + Doing::Color.default
30
30
  else
31
31
  flag = ''
@@ -34,7 +34,7 @@ module Doing
34
34
 
35
35
  placeholders = {}
36
36
 
37
- if !item.note.empty? && wwid.config['include_notes']
37
+ if !item.note.empty? && Doing.setting('include_notes')
38
38
  note = item.note.map(&:strip).delete_if(&:empty?)
39
39
  note.map! { |line| "#{line.sub(/^\t*/, '')} " }
40
40
 
@@ -133,7 +133,7 @@ module Doing
133
133
 
134
134
  # Doing.logger.debug('Template Export:', "#{items.count} items output to template #{opt[:template]}")
135
135
  if opt[:totals]
136
- out += wwid.tag_times(format: wwid.config['timer_format'].to_sym,
136
+ out += wwid.tag_times(format: Doing.setting('timer_format').to_sym,
137
137
  sort_by: opt[:sort_tags],
138
138
  sort_order: opt[:tag_order])
139
139
  end
@@ -23,7 +23,7 @@ module Doing
23
23
  limit_start = options[:start].to_i
24
24
  limit_end = options[:end].to_i
25
25
 
26
- section = options[:section] || wwid.config['current_section']
26
+ section = options[:section] || Doing.setting('current_section')
27
27
  options[:no_overlap] ||= false
28
28
  options[:autotag] ||= wwid.auto_tag
29
29
 
@@ -63,7 +63,7 @@ module Doing
63
63
  title.gsub!(/ +/, ' ')
64
64
  title.strip!
65
65
  section = options[:section] || item.section
66
- section ||= wwid.config['current_section']
66
+ section ||= Doing.setting('current_section')
67
67
 
68
68
  new_item = Item.new(item.date, title, section)
69
69
  new_item.note = item.note
@@ -24,7 +24,7 @@ module Doing
24
24
  ##
25
25
  def self.import(wwid, path, options: {})
26
26
  exit_now! 'Path to JSON report required' if path.nil?
27
- section = options[:section] || wwid.config['current_section']
27
+ section = options[:section] || Doing.setting('current_section')
28
28
  options[:no_overlap] ||= false
29
29
  options[:autotag] ||= wwid.auto_tag
30
30
  wwid.content.add_section(section) unless wwid.content.section?(section)
data/lib/doing/section.rb CHANGED
@@ -13,7 +13,7 @@ module Doing
13
13
  @original = if original.nil?
14
14
  "#{title}:"
15
15
  else
16
- original =~ /:(\s+@\S+(\(.*?\))?)*$/ ? original : "#{original}:"
16
+ original =~ /:(\s+@[^ (]+(\([^)]*\))?)*?$/ ? original : "#{original}:"
17
17
  end
18
18
  end
19
19
 
@@ -35,10 +35,9 @@ module Doing
35
35
 
36
36
  def highlight_search(search, distance: nil, negate: false, case_type: nil)
37
37
  out = dup
38
- prefs = Doing.config.settings['search'] || {}
39
- matching = prefs.fetch('matching', 'pattern').normalize_matching
40
- distance ||= prefs.fetch('distance', 3).to_i
41
- case_type ||= prefs.fetch('case', 'smart').normalize_case
38
+ matching = Doing.setting('search.matching', 'pattern').normalize_matching
39
+ distance ||= Doing.setting('search.distance', 3).to_i
40
+ case_type ||= Doing.setting('search.case', 'smart').normalize_case
42
41
 
43
42
  if search.rx? || matching == :fuzzy
44
43
  rx = search.to_rx(distance: distance, case_type: case_type)
@@ -2,6 +2,14 @@
2
2
 
3
3
  class ::String
4
4
  include Doing::Color
5
+
6
+ def utf8
7
+ if String.method_defined? :force_encoding
8
+ dup.force_encoding('utf-8')
9
+ else
10
+ self
11
+ end
12
+ end
5
13
  end
6
14
 
7
15
  require_relative 'highlight'
data/lib/doing/util.rb CHANGED
@@ -159,7 +159,7 @@ module Doing
159
159
 
160
160
  return ENV['EDITOR'] if ENV['DOING_EDITOR_TEST']
161
161
 
162
- editor_config = Doing.config.settings['editors']
162
+ editor_config = Doing.setting('editors')
163
163
 
164
164
  if editor_config.is_a?(String)
165
165
  msg = "Please update your configuration, 'editors' should be a mapping."
@@ -30,7 +30,7 @@ module Doing
30
30
  ## @param limit Maximum number of backups to retain
31
31
  ##
32
32
  def clear_redo(filename)
33
- filename ||= Doing.config.settings['doing_file']
33
+ filename ||= Doing.setting('doing_file')
34
34
  backups = Dir.glob("undone*___#{File.basename(filename)}", base: backup_dir).sort.reverse
35
35
  backups.each do |file|
36
36
  FileUtils.rm(File.join(backup_dir, file))
@@ -44,7 +44,7 @@ module Doing
44
44
  ## @return [String] filename
45
45
  ##
46
46
  def last_backup(filename = nil, count: 1)
47
- filename ||= Doing.config.settings['doing_file']
47
+ filename ||= Doing.setting('doing_file')
48
48
 
49
49
  backup = get_backups(filename).slice(count - 1)
50
50
  backup.nil? ? nil : File.join(backup_dir, backup)
@@ -59,7 +59,7 @@ module Doing
59
59
  ##
60
60
  def restore_last_backup(filename = nil, count: 1)
61
61
  Doing.logger.benchmark(:restore_backup, :start)
62
- filename ||= Doing.config.settings['doing_file']
62
+ filename ||= Doing.setting('doing_file')
63
63
 
64
64
  backup_file = last_backup(filename, count: count)
65
65
  raise DoingRuntimeError, 'End of undo history' if backup_file.nil?
@@ -77,7 +77,7 @@ module Doing
77
77
  ## @param filename The filename
78
78
  ##
79
79
  def redo_backup(filename = nil, count: 1)
80
- filename ||= Doing.config.settings['doing_file']
80
+ filename ||= Doing.setting('doing_file')
81
81
  # redo_file = File.join(backup_dir, "undone___#{File.basename(filename)}")
82
82
  undones = Dir.glob("undone*#{File.basename(filename)}", base: backup_dir).sort.reverse
83
83
  total = undones.count
@@ -101,7 +101,7 @@ module Doing
101
101
  end
102
102
 
103
103
  def clear_undone(filename = nil)
104
- filename ||= Doing.config.settings['doing_file']
104
+ filename ||= Doing.setting('doing_file')
105
105
  # redo_file = File.join(backup_dir, "undone___#{File.basename(filename)}")
106
106
  Dir.glob("undone*#{File.basename(filename)}", base: backup_dir).each do |f|
107
107
  FileUtils.rm(File.join(backup_dir, f))
@@ -115,7 +115,7 @@ module Doing
115
115
  ## @param filename The filename to restore
116
116
  ##
117
117
  def select_redo(filename = nil)
118
- filename ||= Doing.config.settings['doing_file']
118
+ filename ||= Doing.setting('doing_file')
119
119
 
120
120
  undones = Dir.glob("undone*#{File.basename(filename)}", base: backup_dir).sort
121
121
 
@@ -155,7 +155,7 @@ module Doing
155
155
  ## @param filename The filename to restore
156
156
  ##
157
157
  def select_backup(filename = nil)
158
- filename ||= Doing.config.settings['doing_file']
158
+ filename ||= Doing.setting('doing_file')
159
159
 
160
160
  options = get_backups(filename).each_with_object([]) do |file, arr|
161
161
  d, _base = date_of_backup(file)
@@ -219,7 +219,7 @@ module Doing
219
219
  ##
220
220
  def write_backup(filename = nil)
221
221
  Doing.logger.benchmark(:_write_backup, :start)
222
- filename ||= Doing.config.settings['doing_file']
222
+ filename ||= Doing.setting('doing_file')
223
223
 
224
224
  unless File.exist?(filename)
225
225
  Doing.logger.debug('Backup:', "original file doesn't exist (#{filename})")
@@ -234,7 +234,7 @@ module Doing
234
234
 
235
235
  FileUtils.cp(filename, backup_file)
236
236
 
237
- prune_backups(filename, Doing.config.settings['history_size'].to_i)
237
+ prune_backups(filename, Doing.setting('history_size').to_i)
238
238
  clear_undone(filename)
239
239
  Doing.logger.benchmark(:_write_backup, :finish)
240
240
  end
@@ -246,13 +246,13 @@ module Doing
246
246
  end
247
247
 
248
248
  def get_backups(filename = nil, include_forward: false)
249
- filename ||= Doing.config.settings['doing_file']
249
+ filename ||= Doing.setting('doing_file')
250
250
  backups = Dir.glob("*___#{File.basename(filename)}", base: backup_dir).sort.reverse
251
251
  backups.delete_if { |f| f =~ /^undone/ } unless include_forward
252
252
  end
253
253
 
254
254
  def save_undone(filename = nil)
255
- filename ||= Doing.config.settings['doing_file']
255
+ filename ||= Doing.setting('doing_file')
256
256
  undone_file = File.join(backup_dir, "undone#{timestamp_filename}___#{File.basename(filename)}")
257
257
  FileUtils.cp(filename, undone_file)
258
258
  end
@@ -279,7 +279,7 @@ module Doing
279
279
  end
280
280
 
281
281
  def create_backup_dir
282
- dir = File.expand_path(Doing.config.settings['backup_dir']) || File.join(user_home, '.doing_backup')
282
+ dir = File.expand_path(Doing.setting('backup_dir')) || File.join(user_home, '.doing_backup')
283
283
  if File.exist?(dir) && !File.directory?(dir)
284
284
  raise DoingRuntimeError, "Backup error: #{dir} is not a directory"
285
285
 
data/lib/doing/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '2.1.27'
2
+ VERSION = '2.1.31pre'
3
3
  end