doing 1.0.93 → 2.0.6.pre

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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/AUTHORS +19 -0
  3. data/CHANGELOG.md +616 -0
  4. data/COMMANDS.md +1181 -0
  5. data/Gemfile +2 -0
  6. data/Gemfile.lock +110 -0
  7. data/LICENSE +23 -0
  8. data/README.md +15 -699
  9. data/Rakefile +79 -0
  10. data/_config.yml +1 -0
  11. data/bin/doing +1055 -494
  12. data/doing.gemspec +34 -0
  13. data/doing.rdoc +1839 -0
  14. data/example_plugin.rb +209 -0
  15. data/generate_completions.sh +5 -0
  16. data/img/doing-colors.jpg +0 -0
  17. data/img/doing-printf-wrap-800.jpg +0 -0
  18. data/img/doing-show-note-formatting-800.jpg +0 -0
  19. data/lib/completion/_doing.zsh +203 -0
  20. data/lib/completion/doing.bash +449 -0
  21. data/lib/completion/doing.fish +329 -0
  22. data/lib/doing/array.rb +8 -0
  23. data/lib/doing/cli_status.rb +70 -0
  24. data/lib/doing/colors.rb +136 -0
  25. data/lib/doing/configuration.rb +312 -0
  26. data/lib/doing/errors.rb +109 -0
  27. data/lib/doing/hash.rb +31 -0
  28. data/lib/doing/hooks.rb +59 -0
  29. data/lib/doing/item.rb +155 -0
  30. data/lib/doing/log_adapter.rb +344 -0
  31. data/lib/doing/markdown_document_listener.rb +174 -0
  32. data/lib/doing/note.rb +59 -0
  33. data/lib/doing/pager.rb +95 -0
  34. data/lib/doing/plugin_manager.rb +208 -0
  35. data/lib/doing/plugins/export/csv_export.rb +48 -0
  36. data/lib/doing/plugins/export/html_export.rb +83 -0
  37. data/lib/doing/plugins/export/json_export.rb +140 -0
  38. data/lib/doing/plugins/export/markdown_export.rb +85 -0
  39. data/lib/doing/plugins/export/taskpaper_export.rb +34 -0
  40. data/lib/doing/plugins/export/template_export.rb +141 -0
  41. data/lib/doing/plugins/import/cal_to_json.scpt +0 -0
  42. data/lib/doing/plugins/import/calendar_import.rb +76 -0
  43. data/lib/doing/plugins/import/doing_import.rb +144 -0
  44. data/lib/doing/plugins/import/timing_import.rb +78 -0
  45. data/lib/doing/string.rb +348 -0
  46. data/lib/doing/symbol.rb +16 -0
  47. data/lib/doing/time.rb +18 -0
  48. data/lib/doing/util.rb +186 -0
  49. data/lib/doing/version.rb +1 -1
  50. data/lib/doing/wwid.rb +1868 -2349
  51. data/lib/doing/wwidfile.rb +117 -0
  52. data/lib/doing.rb +43 -3
  53. data/lib/examples/commands/autotag.rb +63 -0
  54. data/lib/examples/commands/wiki.rb +81 -0
  55. data/lib/examples/plugins/hooks.rb +22 -0
  56. data/lib/examples/plugins/say_export.rb +202 -0
  57. data/lib/examples/plugins/templates/wiki.css +169 -0
  58. data/lib/examples/plugins/templates/wiki.haml +27 -0
  59. data/lib/examples/plugins/templates/wiki_index.haml +18 -0
  60. data/lib/examples/plugins/wiki_export.rb +87 -0
  61. data/lib/templates/doing-markdown.erb +5 -0
  62. data/man/doing.1 +964 -0
  63. data/man/doing.1.html +711 -0
  64. data/man/doing.1.ronn +600 -0
  65. data/package-lock.json +3 -0
  66. data/rdoc_to_mmd.rb +42 -0
  67. data/rdocfixer.rb +13 -0
  68. data/scripts/generate_bash_completions.rb +211 -0
  69. data/scripts/generate_fish_completions.rb +204 -0
  70. data/scripts/generate_zsh_completions.rb +168 -0
  71. metadata +82 -7
  72. data/lib/doing/helpers.rb +0 -191
  73. data/lib/doing/markdown_export.rb +0 -16
@@ -0,0 +1,208 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doing
4
+ # Plugin handling
5
+ module Plugins
6
+ class << self
7
+ def user_home
8
+ @user_home ||= Util.user_home
9
+ end
10
+
11
+ def plugins
12
+ @plugins ||= {
13
+ import: {},
14
+ export: {}
15
+ }
16
+ end
17
+
18
+ ##
19
+ # Load plugins from plugins folder
20
+ #
21
+ def load_plugins(add_dir = nil)
22
+ plugins_path(add_dir).each do |plugin_search_path|
23
+ Dir.glob(File.join(plugin_search_path, '**', '*.rb')).sort.each do |plugin|
24
+ require plugin
25
+ end
26
+ end
27
+
28
+ plugins
29
+ end
30
+
31
+ # Public: Setup the plugin search path
32
+ #
33
+ # Returns an Array of plugin search paths
34
+ def plugins_path(add_dir = nil)
35
+ paths = Array(File.join(File.dirname(__FILE__), 'plugins'))
36
+ paths << File.join(add_dir) if add_dir
37
+ paths.map { |d| File.expand_path(d) }
38
+ end
39
+
40
+ ##
41
+ # Register a plugin
42
+ #
43
+ # param: +[String|Array]+ title The name of the plugin (can be an array of names)
44
+ #
45
+ # param: +type+ The plugin type (:import, :export)
46
+ #
47
+ # param: +klass+ The class responding to :render or :import
48
+ #
49
+ #
50
+ # returns: Success boolean
51
+ #
52
+ def register(title, type, klass)
53
+ type = validate_plugin(title, type, klass)
54
+ return unless type
55
+
56
+ if title.is_a?(Array)
57
+ title.each { |t| register(t, type, klass) }
58
+ return
59
+ end
60
+
61
+ settings = if klass.respond_to? :settings
62
+ klass.settings
63
+ else
64
+ { trigger: title.normalize_trigger, config: {} }
65
+ end
66
+
67
+ plugins[type] ||= {}
68
+ plugins[type][title] = {
69
+ trigger: settings[:trigger].normalize_trigger || title.normalize_trigger,
70
+ class: klass,
71
+ templates: settings[:templates] || nil,
72
+ config: settings[:config] || {}
73
+ }
74
+
75
+ return unless ENV['DOING_PLUGIN_DEBUG']
76
+
77
+ Doing.logger.debug('Plugin Manager:', "Registered #{type} plugin \"#{title}\"")
78
+ end
79
+
80
+ def validate_plugin(title, type, klass)
81
+ type = valid_type(type)
82
+ if type == :import && !klass.respond_to?(:import)
83
+ raise Errors::PluginUncallable.new('Import plugins must respond to :import', type: type, plugin: title)
84
+ end
85
+
86
+ if type == :export && !klass.respond_to?(:render)
87
+ raise Errors::PluginUncallable.new('Export plugins must respond to :render', type: type, plugin: title)
88
+ end
89
+
90
+ type
91
+ end
92
+
93
+ def valid_type(type, default: nil)
94
+ type ||= default
95
+
96
+ t = type.to_s
97
+ type = case t
98
+ when /^i(m(p(o(r(t)?)?)?)?)?$/
99
+ :import
100
+ when /^e(x(p(o(r(t)?)?)?)?)?$/
101
+ :export
102
+ else
103
+ raise Errors::InvalidPluginType, 'Invalid plugin type'
104
+ end
105
+
106
+ type.to_sym
107
+ end
108
+
109
+ ##
110
+ ## @brief List available plugins to stdout
111
+ ##
112
+ ## @param options { type, separator }
113
+ ##
114
+ def list_plugins(options = {})
115
+ separator = options[:column] ? "\n" : "\t"
116
+ type = options[:type].nil? || options[:type] =~ /all/i ? 'all' : valid_type(options[:type])
117
+
118
+ case type
119
+ when :import
120
+ puts plugin_names(type: :import, separator: separator)
121
+ when :export
122
+ puts plugin_names(type: :export, separator: separator)
123
+ else
124
+ print 'Import plugins: '
125
+ puts plugin_names(type: :import, separator: ', ')
126
+ print 'Export plugins: '
127
+ puts plugin_names(type: :export, separator: ', ')
128
+ end
129
+ end
130
+
131
+ ##
132
+ ## @brief Return array of available plugin names
133
+ ##
134
+ ## @param type Plugin type (:import, :export)
135
+ ##
136
+ ## @returns [Array<String>] plugin names
137
+ ##
138
+ def available_plugins(type: :export)
139
+ type = valid_type(type)
140
+ plugins[type].keys.sort
141
+ end
142
+
143
+ ##
144
+ ## @brief Return string version of plugin names
145
+ ##
146
+ ## @param type Plugin type (:import, :export)
147
+ ## @param separator The separator to join names with
148
+ ##
149
+ ## @return [String] Plugin names
150
+ ##
151
+ def plugin_names(type: :export, separator: '|')
152
+ type = valid_type(type)
153
+ available_plugins(type: type).join(separator)
154
+ end
155
+
156
+ ##
157
+ ## @brief Return a regular expression of all
158
+ ## plugin triggers for type
159
+ ##
160
+ ## @param type The type :import or :export
161
+ ##
162
+ def plugin_regex(type: :export)
163
+ type = valid_type(type)
164
+ pattern = []
165
+ plugins[type].each do |_, options|
166
+ pattern << options[:trigger].normalize_trigger
167
+ end
168
+ Regexp.new("^(?:#{pattern.join('|')})$", true)
169
+ end
170
+
171
+ def plugin_templates(type: :export)
172
+ type = valid_type(type)
173
+ templates = []
174
+ plugs = plugins[type].clone
175
+ plugs.delete_if { |_t, o| o[:templates].nil? }.each do |_, options|
176
+ options[:templates].each do |t|
177
+ templates << t[:name]
178
+ end
179
+ end
180
+
181
+ templates
182
+ end
183
+
184
+ def template_regex(type: :export)
185
+ type = valid_type(type)
186
+ pattern = []
187
+ plugs = plugins[type].clone
188
+ plugs.delete_if { |_t, o| o[:templates].nil? }.each do |_, options|
189
+ options[:templates].each do |t|
190
+ pattern << t[:trigger].normalize_trigger
191
+ end
192
+ end
193
+ Regexp.new("^(?:#{pattern.join('|')})$", true)
194
+ end
195
+
196
+ def template_for_trigger(trigger, type: :export)
197
+ type = valid_type(type)
198
+ plugs = plugins[type].clone
199
+ plugs.delete_if { |_t, o| o[:templates].nil? }.each do |_, options|
200
+ options[:templates].each do |t|
201
+ return options[:class].template(trigger) if trigger =~ /^(?:#{t[:trigger].normalize_trigger})$/
202
+ end
203
+ end
204
+ raise Errors::InvalidArgument, "No template type matched \"#{trigger}\""
205
+ end
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ # title: CSV Export
4
+ # description: Export CSV formatted data with header row
5
+ # author: Brett Terpstra
6
+ # url: https://brettterpstra.com
7
+ module Doing
8
+ ##
9
+ ## @brief CSV Export
10
+ ##
11
+ class CSVExport
12
+ include Doing::Util
13
+
14
+ def self.settings
15
+ {
16
+ trigger: 'csv'
17
+ }
18
+ end
19
+
20
+ def self.render(wwid, items, variables: {})
21
+ return if items.nil?
22
+
23
+ opt = variables[:options]
24
+
25
+ output = [CSV.generate_line(%w[start end title note timer section])]
26
+ items.each do |i|
27
+ note = format_note(i.note)
28
+ end_date = i.end_date
29
+ interval = end_date && opt[:times] ? wwid.get_interval(i, formatted: false) : 0
30
+ output.push(CSV.generate_line([i.date, end_date, i.title, note, interval, i.section]))
31
+ end
32
+ Doing.logger.debug('CSV Export:', "#{items.count} items output to CSV")
33
+ output.join('')
34
+ end
35
+
36
+ def self.format_note(note)
37
+ out = ''
38
+ if note
39
+ arr = note.map(&:strip).delete_if { |e| e =~ /^\s*$/ }
40
+ out = arr.join("\n") unless arr.empty?
41
+ end
42
+
43
+ out
44
+ end
45
+
46
+ Doing::Plugins.register 'csv', :export, self
47
+ end
48
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ # title: HTML Export
4
+ # description: Export styled HTML view of data
5
+ # author: Brett Terpstra
6
+ # url: https://brettterpstra.com
7
+ module Doing
8
+ class HTMLExport
9
+ include Doing::Util
10
+
11
+ def self.settings
12
+ {
13
+ trigger: 'html?|web(?:page)?',
14
+ templates: [
15
+ { name: 'haml', trigger: 'h[ta]ml?|web' },
16
+ { name: 'css', trigger: 'css|styl(?:e|us)' }
17
+ ]
18
+ }
19
+ end
20
+
21
+ def self.template(trigger)
22
+ if trigger =~ /^(css|sty)/
23
+ IO.read(File.join(File.dirname(__FILE__), '../../../templates/doing.css'))
24
+ else
25
+ IO.read(File.join(File.dirname(__FILE__), '../../../templates/doing.haml'))
26
+ end
27
+ end
28
+
29
+ def self.render(wwid, items, variables: {})
30
+ return if items.nil?
31
+
32
+ opt = variables[:options]
33
+
34
+ items_out = []
35
+ items.each do |i|
36
+ # if i.has_key?('note')
37
+ # note = '<span class="note">' + i.note.map{|n| n.strip }.join('<br>') + '</span>'
38
+ # else
39
+ # note = ''
40
+ # end
41
+ if String.method_defined? :force_encoding
42
+ title = i.title.force_encoding('utf-8').link_urls
43
+ note = i.note.map { |line| line.force_encoding('utf-8').strip.link_urls } if i.note
44
+ else
45
+ title = i.title.link_urls
46
+ note = i.note.map { |line| line.strip.link_urls } if i.note
47
+ end
48
+
49
+ interval = wwid.get_interval(i) if i.title =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
50
+ interval ||= false
51
+
52
+ items_out << {
53
+ date: i.date.strftime('%a %-I:%M%p'),
54
+ title: title.gsub(/(@[^ (]+(\(.*?\))?)/im, '<span class="tag">\1</span>').strip, #+ " #{note}"
55
+ note: note,
56
+ time: interval,
57
+ section: i.section
58
+ }
59
+ end
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']))
63
+ else
64
+ self.template('html')
65
+ end
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']))
69
+ else
70
+ self.template('css')
71
+ end
72
+
73
+ totals = opt[:totals] ? wwid.tag_times(format: :html, sort_by_name: opt[:sort_tags], sort_order: opt[:tag_order]) : ''
74
+ engine = Haml::Engine.new(template)
75
+ Doing.logger.debug('HTML Export:', "#{items_out.count} items output to HTML")
76
+ @out = engine.render(Object.new,
77
+ { :@items => items_out, :@page_title => variables[:page_title], :@style => style, :@totals => totals })
78
+ end
79
+
80
+ Doing::Plugins.register 'html', :export, self
81
+ end
82
+ end
83
+
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ # title: JSON Export
4
+ # description: Export JSON-formatted data, including entry durations and tag totals
5
+ # author: Brett Terpstra
6
+ # url: https://brettterpstra.com
7
+ module Doing
8
+ class JSONExport
9
+ include Doing::Util
10
+
11
+ def self.settings
12
+ {
13
+ trigger: 'json|time(?:line)?'
14
+ }
15
+ end
16
+
17
+ def self.render(wwid, items, variables: {})
18
+ return if items.nil?
19
+
20
+ opt = variables[:options]
21
+ opt[:output] = case opt[:output]
22
+ when /^t/
23
+ 'timeline'
24
+ else
25
+ 'json'
26
+ end
27
+ items_out = []
28
+ last_date = items[-1].date + (60 * 60 * 24)
29
+ max = last_date.strftime('%F')
30
+ min = items[0].date.strftime('%F')
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
39
+
40
+ end_date = i.end_date || ''
41
+ interval = wwid.get_interval(i, formatted: false) || 0
42
+ note ||= ''
43
+
44
+ tags = []
45
+ attributes = {}
46
+ skip_tags = %w[meanwhile done cancelled flagged]
47
+ i.title.scan(/@([^(\s]+)(?:\((.*?)\))?/).each do |tag|
48
+ tags.push(tag[0]) unless skip_tags.include?(tag[0])
49
+ attributes[tag[0]] = tag[1] if tag[1]
50
+ end
51
+
52
+ if opt[:output] == 'json'
53
+
54
+ i = {
55
+ date: i.date,
56
+ end_date: end_date,
57
+ title: title.strip, #+ " #{note}"
58
+ note: note.instance_of?(Array) ? note.to_s : note,
59
+ time: '%02d:%02d:%02d' % wwid.format_time(interval),
60
+ tags: tags
61
+ }
62
+
63
+ attributes.each { |attr, val| i[attr.to_sym] = val }
64
+
65
+ items_out << i
66
+
67
+ elsif opt[:output] == 'timeline'
68
+ new_item = {
69
+ 'id' => index + 1,
70
+ 'content' => title.strip, #+ " #{note}"
71
+ 'title' => title.strip + " (#{'%02d:%02d:%02d' % wwid.format_time(interval)})",
72
+ 'start' => i.date.strftime('%F %T'),
73
+ 'type' => 'box',
74
+ 'style' => 'color:#4c566b;background-color:#d8dee9;'
75
+ }
76
+
77
+
78
+ if interval && interval.to_i > 0
79
+ new_item['end'] = end_date.strftime('%F %T')
80
+ if interval.to_i > 3600
81
+ new_item['type'] = 'range'
82
+ new_item['style'] = 'color:white;background-color:#a2bf8a;'
83
+ end
84
+ end
85
+ new_item['style'] = 'color:white;background-color:#f7921e;' if i.tags?(wwid.config['marker_tag'])
86
+ items_out.push(new_item)
87
+ end
88
+ end
89
+ if opt[:output] == 'json'
90
+ Doing.logger.debug('JSON Export:', "#{items_out.count} items output to JSON")
91
+ JSON.pretty_generate({
92
+ 'section' => variables[:page_title],
93
+ 'items' => items_out,
94
+ 'timers' => wwid.tag_times(format: :json, sort_by_name: opt[:sort_tags], sort_order: opt[:tag_order])
95
+ })
96
+ elsif opt[:output] == 'timeline'
97
+ template = <<~EOTEMPLATE
98
+ <!doctype html>
99
+ <html>
100
+ <head>
101
+ <link href="https://unpkg.com/vis-timeline@7.4.9/dist/vis-timeline-graph2d.min.css" rel="stylesheet" type="text/css" />
102
+ <script src="https://unpkg.com/vis-timeline@7.4.9/dist/vis-timeline-graph2d.min.js"></script>
103
+ </head>
104
+ <body>
105
+ <div id="mytimeline"></div>
106
+ #{' '}
107
+ <script type="text/javascript">
108
+ // DOM element where the Timeline will be attached
109
+ var container = document.getElementById('mytimeline');
110
+ #{' '}
111
+ // Create a DataSet with data (enables two way data binding)
112
+ var data = new vis.DataSet(#{items_out.to_json});
113
+ #{' '}
114
+ // Configuration for the Timeline
115
+ var options = {
116
+ width: '100%',
117
+ height: '800px',
118
+ margin: {
119
+ item: 20
120
+ },
121
+ stack: true,
122
+ min: '#{min}',
123
+ max: '#{max}'
124
+ };
125
+ #{' '}
126
+ // Create a Timeline
127
+ var timeline = new vis.Timeline(container, data, options);
128
+ </script>
129
+ </body>
130
+ </html>
131
+ EOTEMPLATE
132
+ Doing.logger.debug('Timeline Export:', "#{items_out.count} items output to Timeline")
133
+ template
134
+ end
135
+ end
136
+
137
+ Doing::Plugins.register 'timeline', :export, self
138
+ end
139
+ end
140
+
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ # title: Markdown Export
4
+ # description: Export GFM-style task list
5
+ # author: Brett Terpstra
6
+ # url: https://brettterpstra.com
7
+ module Doing
8
+ class MarkdownRenderer
9
+ attr_accessor :items, :page_title, :totals
10
+
11
+ def initialize(page_title, items, totals)
12
+ @page_title = page_title
13
+ @items = items
14
+ @totals = totals
15
+ end
16
+
17
+ def get_binding
18
+ binding()
19
+ end
20
+ end
21
+
22
+ class MarkdownExport
23
+ include Doing::Util
24
+
25
+ def self.settings
26
+ {
27
+ trigger: 'markdown|mk?d|gfm',
28
+ templates: [{ name: 'markdown', trigger: 'mk?d|markdown' }]
29
+ }
30
+ end
31
+
32
+ def self.template(_trigger)
33
+ IO.read(File.join(File.dirname(__FILE__), '../../../templates/doing-markdown.erb'))
34
+ end
35
+
36
+ def self.render(wwid, items, variables: {})
37
+ return if items.nil?
38
+
39
+ opt = variables[:options]
40
+
41
+ all_items = []
42
+ items.each do |i|
43
+ if String.method_defined? :force_encoding
44
+ title = i.title.force_encoding('utf-8').link_urls({format: :markdown})
45
+ note = i.note.map { |line| line.force_encoding('utf-8').strip.link_urls({format: :markdown}) } if i.note
46
+ else
47
+ title = i.title.link_urls({format: :markdown})
48
+ note = i.note.map { |line| line.strip.link_urls({format: :markdown}) } if i.note
49
+ end
50
+
51
+ title = "#{title} @project(#{i.section})" unless variables[:is_single]
52
+
53
+ interval = wwid.get_interval(i, record: true) if i.title =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
54
+ interval ||= false
55
+
56
+ done = i.title =~ /(?<= |^)@done/ ? 'x' : ' '
57
+
58
+ all_items << {
59
+ date: i.date.strftime('%a %-I:%M%p'),
60
+ shortdate: i.date.relative_date,
61
+ done: done,
62
+ note: note,
63
+ section: i.section,
64
+ time: interval,
65
+ title: title.strip
66
+ }
67
+ end
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']))
71
+ else
72
+ self.template(nil)
73
+ end
74
+
75
+ totals = opt[:totals] ? wwid.tag_times(format: :markdown, sort_by_name: opt[:sort_tags], sort_order: opt[:tag_order]) : ''
76
+
77
+ mdx = MarkdownRenderer.new(variables[:page_title], all_items, totals)
78
+ Doing.logger.debug('Markdown Export:', "#{all_items.count} items output to Markdown")
79
+ engine = ERB.new(template)
80
+ @out = engine.result(mdx.get_binding)
81
+ end
82
+
83
+ Doing::Plugins.register 'markdown', :export, self
84
+ end
85
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ # title: TaskPaper Export
4
+ # description: Export TaskPaper-friendly data
5
+ # author: Brett Terpstra
6
+ # url: https://brettterpstra.com
7
+ module Doing
8
+ class TaskPaperExport
9
+ include Doing::Util
10
+
11
+ def self.settings
12
+ {
13
+ trigger: 'task(?:paper)?|tp'
14
+ }
15
+ end
16
+
17
+ def self.render(wwid, items, variables: {})
18
+ return if items.nil?
19
+
20
+ options = variables[:options]
21
+
22
+ options[:highlight] = false
23
+ options[:wrap_width] = 0
24
+ options[:tags_color] = false
25
+ options[:output] = 'template'
26
+ options[:template] = '- %title @date(%date)%note'
27
+
28
+ Doing.logger.debug('TaskPaper Export:', "#{items.count} items output to TaskPaper format")
29
+ @out = wwid.list_section(options)
30
+ end
31
+
32
+ Doing::Plugins.register 'taskpaper', :export, self
33
+ end
34
+ end