doing 2.1.4pre → 2.1.7
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.
- checksums.yaml +4 -4
- data/.yardoc/checksums +14 -13
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/.yardopts +1 -1
- data/CHANGELOG.md +37 -1
- data/Gemfile.lock +3 -1
- data/README.md +5 -1
- data/bin/doing +192 -95
- data/docs/_config.yml +1 -0
- data/{doc → docs/doc}/Array.html +63 -1
- data/docs/doc/BooleanTermParser/Clause.html +293 -0
- data/docs/doc/BooleanTermParser/Operator.html +172 -0
- data/docs/doc/BooleanTermParser/Query.html +417 -0
- data/docs/doc/BooleanTermParser/QueryParser.html +135 -0
- data/docs/doc/BooleanTermParser/QueryTransformer.html +124 -0
- data/docs/doc/BooleanTermParser.html +115 -0
- data/docs/doc/Doing/CLIFormat.html +131 -0
- data/{doc → docs/doc}/Doing/Color.html +2 -2
- data/{doc → docs/doc}/Doing/Completion.html +1 -1
- data/{doc → docs/doc}/Doing/Configuration.html +117 -12
- data/{doc → docs/doc}/Doing/Content.html +0 -0
- data/{doc → docs/doc}/Doing/Errors/DoingNoTraceError.html +1 -1
- data/{doc → docs/doc}/Doing/Errors/DoingRuntimeError.html +1 -1
- data/{doc → docs/doc}/Doing/Errors/DoingStandardError.html +1 -1
- data/{doc → docs/doc}/Doing/Errors/EmptyInput.html +1 -1
- data/{doc → docs/doc}/Doing/Errors/NoResults.html +1 -1
- data/{doc → docs/doc}/Doing/Errors/PluginException.html +1 -1
- data/{doc → docs/doc}/Doing/Errors/UserCancelled.html +1 -1
- data/{doc → docs/doc}/Doing/Errors/WrongCommand.html +1 -1
- data/{doc → docs/doc}/Doing/Errors.html +1 -1
- data/{doc → docs/doc}/Doing/Hooks.html +1 -1
- data/{doc → docs/doc}/Doing/Item.html +100 -73
- data/{doc → docs/doc}/Doing/Items.html +2 -2
- data/{doc → docs/doc}/Doing/LogAdapter.html +70 -1
- data/{doc → docs/doc}/Doing/Note.html +5 -134
- data/{doc → docs/doc}/Doing/Pager.html +1 -1
- data/{doc → docs/doc}/Doing/Plugins.html +431 -35
- data/{doc → docs/doc}/Doing/Prompt.html +1 -1
- data/{doc → docs/doc}/Doing/Section.html +1 -1
- data/docs/doc/Doing/TemplateString.html +713 -0
- data/docs/doc/Doing/Util/Backup.html +686 -0
- data/{doc → docs/doc}/Doing/Util.html +1 -1
- data/{doc → docs/doc}/Doing/WWID.html +5 -5
- data/{doc → docs/doc}/Doing/WWIDFile.html +0 -0
- data/{doc → docs/doc}/Doing.html +4 -4
- data/{doc → docs/doc}/GLI/Commands/MarkdownDocumentListener.html +1 -1
- data/{doc → docs/doc}/GLI/Commands.html +1 -1
- data/{doc → docs/doc}/GLI.html +1 -1
- data/{doc → docs/doc}/Hash.html +1 -1
- data/docs/doc/PhraseParser/Operator.html +172 -0
- data/docs/doc/PhraseParser/PhraseClause.html +303 -0
- data/docs/doc/PhraseParser/Query.html +495 -0
- data/docs/doc/PhraseParser/QueryParser.html +136 -0
- data/docs/doc/PhraseParser/QueryTransformer.html +124 -0
- data/docs/doc/PhraseParser/TermClause.html +293 -0
- data/docs/doc/PhraseParser.html +115 -0
- data/{doc → docs/doc}/Status.html +1 -1
- data/{doc → docs/doc}/String.html +182 -12
- data/{doc → docs/doc}/Symbol.html +35 -1
- data/{doc → docs/doc}/Time.html +1 -1
- data/{doc → docs/doc}/_index.html +21 -14
- data/{doc → docs/doc}/class_list.html +1 -1
- data/{doc → docs/doc}/css/common.css +0 -0
- data/{doc → docs/doc}/css/full_list.css +0 -0
- data/{doc → docs/doc}/css/style.css +0 -0
- data/{doc → docs/doc}/file.README.html +6 -2
- data/{doc → docs/doc}/file_list.html +0 -0
- data/{doc → docs/doc}/frames.html +0 -0
- data/{doc → docs/doc}/index.html +6 -2
- data/{doc → docs/doc}/js/app.js +0 -0
- data/{doc → docs/doc}/js/full_list.js +0 -0
- data/{doc → docs/doc}/js/jquery.js +0 -0
- data/{doc → docs/doc}/method_list.html +313 -161
- data/{doc → docs/doc}/top-level-namespace.html +1 -1
- data/docs/index.md +60 -0
- data/doing.gemspec +1 -0
- data/doing.rdoc +74 -15
- data/example_plugin.rb +3 -1
- data/lib/completion/_doing.zsh +53 -41
- data/lib/completion/doing.bash +17 -6
- data/lib/completion/doing.fish +321 -2
- data/lib/doing/array.rb +9 -0
- data/lib/doing/completion/fish_completion.rb +46 -3
- data/lib/doing/completion/zsh_completion.rb +1 -1
- data/lib/doing/configuration.rb +33 -11
- data/lib/doing/item.rb +12 -3
- data/lib/doing/log_adapter.rb +28 -0
- data/lib/doing/note.rb +31 -30
- data/lib/doing/plugin_manager.rb +84 -21
- data/lib/doing/plugins/export/dayone_export.rb +209 -0
- data/lib/doing/plugins/export/html_export.rb +2 -2
- data/lib/doing/plugins/export/json_export.rb +1 -0
- data/lib/doing/plugins/export/markdown_export.rb +1 -1
- data/lib/doing/plugins/export/template_export.rb +90 -85
- data/lib/doing/prompt.rb +9 -6
- data/lib/doing/string.rb +68 -27
- data/lib/doing/symbol.rb +4 -0
- data/lib/doing/template_string.rb +197 -0
- data/lib/doing/util.rb +4 -2
- data/lib/doing/util_backup.rb +55 -3
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +37 -22
- data/lib/doing.rb +3 -0
- data/lib/examples/plugins/say_export.rb +1 -1
- data/lib/examples/plugins/wiki_export/wiki_export.rb +3 -3
- data/lib/templates/doing-dayone-entry.erb +6 -0
- data/lib/templates/doing-dayone.erb +5 -0
- metadata +95 -53
data/lib/doing/log_adapter.rb
CHANGED
|
@@ -38,6 +38,7 @@ module Doing
|
|
|
38
38
|
rotated
|
|
39
39
|
skipped
|
|
40
40
|
updated
|
|
41
|
+
exported
|
|
41
42
|
].freeze
|
|
42
43
|
|
|
43
44
|
#
|
|
@@ -265,6 +266,31 @@ module Doing
|
|
|
265
266
|
end
|
|
266
267
|
end
|
|
267
268
|
|
|
269
|
+
def benchmark(key, state)
|
|
270
|
+
return unless ENV['DOING_BENCHMARK']
|
|
271
|
+
|
|
272
|
+
@benchmarks ||= {}
|
|
273
|
+
@benchmarks[key] ||= { start: nil, finish: nil }
|
|
274
|
+
@benchmarks[key][state] = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def log_benchmarks
|
|
278
|
+
if ENV['DOING_BENCHMARK']
|
|
279
|
+
output = []
|
|
280
|
+
@benchmarks.each do |k, timers|
|
|
281
|
+
if timers[:finish] && timers[:start]
|
|
282
|
+
output << "#{k}: #{timers[:finish] - timers[:start]}"
|
|
283
|
+
else
|
|
284
|
+
output << "#{k}: error"
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
output.each do |msg|
|
|
288
|
+
$stdout.puts color_message(:debug, 'Benchmark:', msg)
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
|
|
268
294
|
def log_change(tags_added: [], tags_removed: [], count: 1, item: nil, single: false)
|
|
269
295
|
if tags_added.empty? && tags_removed.empty?
|
|
270
296
|
count(:skipped, level: :debug, message: '%count %items with no change', count: count)
|
|
@@ -319,6 +345,8 @@ module Doing
|
|
|
319
345
|
['Archived:', data[:message] || 'completed and archived %count %items']
|
|
320
346
|
when :skipped
|
|
321
347
|
['Skipped:', data[:message] || '%count %items were unchanged']
|
|
348
|
+
when :exported
|
|
349
|
+
['Exported:', data[:message] || '%count %items were exported']
|
|
322
350
|
end
|
|
323
351
|
end
|
|
324
352
|
|
data/lib/doing/note.rb
CHANGED
|
@@ -22,7 +22,7 @@ module Doing
|
|
|
22
22
|
## Add note contents, optionally replacing existing note
|
|
23
23
|
##
|
|
24
24
|
## @param note [Array] The note to add, can be
|
|
25
|
-
##
|
|
25
|
+
## String, Array, or Note
|
|
26
26
|
## @param replace [Boolean] replace existing
|
|
27
27
|
## content
|
|
28
28
|
##
|
|
@@ -36,32 +36,7 @@ module Doing
|
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
##
|
|
39
|
-
##
|
|
40
|
-
##
|
|
41
|
-
## @param lines [Array] Array of strings
|
|
42
|
-
##
|
|
43
|
-
def append(lines)
|
|
44
|
-
concat(lines)
|
|
45
|
-
replace compress
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
##
|
|
49
|
-
## Append a string to the note content
|
|
50
|
-
##
|
|
51
|
-
## @param input [String] The input string,
|
|
52
|
-
## newlines will be split
|
|
53
|
-
##
|
|
54
|
-
def append_string(input)
|
|
55
|
-
concat(input.split(/\n/).map(&:strip))
|
|
56
|
-
replace compress
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def compress!
|
|
60
|
-
replace compress
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
##
|
|
64
|
-
## Remove blank lines and comment lines (#)
|
|
39
|
+
## Remove blank lines and comments (#)
|
|
65
40
|
##
|
|
66
41
|
## @return [Array] compressed array
|
|
67
42
|
##
|
|
@@ -69,8 +44,8 @@ module Doing
|
|
|
69
44
|
delete_if { |l| l =~ /^\s*$/ || l =~ /^#/ }
|
|
70
45
|
end
|
|
71
46
|
|
|
72
|
-
def
|
|
73
|
-
replace
|
|
47
|
+
def compress!
|
|
48
|
+
replace compress
|
|
74
49
|
end
|
|
75
50
|
|
|
76
51
|
##
|
|
@@ -83,6 +58,10 @@ module Doing
|
|
|
83
58
|
map(&:strip)
|
|
84
59
|
end
|
|
85
60
|
|
|
61
|
+
def strip_lines!
|
|
62
|
+
replace strip_lines
|
|
63
|
+
end
|
|
64
|
+
|
|
86
65
|
##
|
|
87
66
|
## Note as multi-line string
|
|
88
67
|
def to_s
|
|
@@ -101,11 +80,33 @@ module Doing
|
|
|
101
80
|
## @param other [Note] The other Note
|
|
102
81
|
##
|
|
103
82
|
## @return [Boolean] true if equal
|
|
104
|
-
##
|
|
105
83
|
def equal?(other)
|
|
106
84
|
return false unless other.is_a?(Note)
|
|
107
85
|
|
|
108
86
|
to_s == other.to_s
|
|
109
87
|
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
##
|
|
92
|
+
## Append an array of strings to note
|
|
93
|
+
##
|
|
94
|
+
## @param lines [Array] Array of strings
|
|
95
|
+
##
|
|
96
|
+
def append(lines)
|
|
97
|
+
concat(lines)
|
|
98
|
+
replace compress
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
##
|
|
102
|
+
## Append a string to the note content
|
|
103
|
+
##
|
|
104
|
+
## @param input [String] The input string,
|
|
105
|
+
## newlines will be split
|
|
106
|
+
##
|
|
107
|
+
def append_string(input)
|
|
108
|
+
concat(input.split(/\n/).map(&:strip))
|
|
109
|
+
replace compress
|
|
110
|
+
end
|
|
110
111
|
end
|
|
111
112
|
end
|
data/lib/doing/plugin_manager.rb
CHANGED
|
@@ -28,26 +28,30 @@ module Doing
|
|
|
28
28
|
plugins
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
#
|
|
31
|
+
# Setup the plugin search path
|
|
32
|
+
#
|
|
33
|
+
# @param add_dir [String] optional additional
|
|
34
|
+
# path to include
|
|
35
|
+
#
|
|
36
|
+
# @return [Array] Returns an Array of plugin search paths
|
|
32
37
|
#
|
|
33
|
-
# Returns an Array of plugin search paths
|
|
34
38
|
def plugins_path(add_dir = nil)
|
|
35
39
|
paths = Array(File.join(File.dirname(__FILE__), 'plugins'))
|
|
36
40
|
paths << File.join(add_dir) if add_dir
|
|
37
41
|
paths.map { |d| File.expand_path(d) }
|
|
38
42
|
end
|
|
39
43
|
|
|
40
|
-
|
|
44
|
+
|
|
41
45
|
# Register a plugin
|
|
42
46
|
#
|
|
43
|
-
# param
|
|
44
|
-
#
|
|
45
|
-
# param
|
|
47
|
+
# @param title [String|Array] The name of the
|
|
48
|
+
# plugin (can be an array of names)
|
|
49
|
+
# @param type [Symbol] The plugin type
|
|
50
|
+
# (:import, :export)
|
|
51
|
+
# @param klass [Class] The class responding to
|
|
52
|
+
# :render or :import
|
|
46
53
|
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
# returns: Success boolean
|
|
54
|
+
# @return [Boolean] Success boolean
|
|
51
55
|
#
|
|
52
56
|
def register(title, type, klass)
|
|
53
57
|
type = validate_plugin(title, type, klass)
|
|
@@ -90,6 +94,15 @@ module Doing
|
|
|
90
94
|
type
|
|
91
95
|
end
|
|
92
96
|
|
|
97
|
+
##
|
|
98
|
+
## Converts a partial symbol to a valid plugin type,
|
|
99
|
+
## e.g. :imp => :import
|
|
100
|
+
##
|
|
101
|
+
## @param type [Symbol] the symbol to test
|
|
102
|
+
## @param default [Symbol] fallback value
|
|
103
|
+
##
|
|
104
|
+
## @return [Symbol] :import or :export
|
|
105
|
+
##
|
|
93
106
|
def valid_type(type, default: nil)
|
|
94
107
|
type ||= default
|
|
95
108
|
|
|
@@ -154,10 +167,13 @@ module Doing
|
|
|
154
167
|
end
|
|
155
168
|
|
|
156
169
|
##
|
|
157
|
-
## Return a regular expression of all
|
|
158
|
-
##
|
|
170
|
+
## Return a regular expression of all plugin triggers
|
|
171
|
+
## for type
|
|
172
|
+
##
|
|
173
|
+
## @param type [Symbol] The type :import or
|
|
174
|
+
## :export
|
|
159
175
|
##
|
|
160
|
-
## @
|
|
176
|
+
## @return [Regexp] regular expression
|
|
161
177
|
##
|
|
162
178
|
def plugin_regex(type: :export)
|
|
163
179
|
type = valid_type(type)
|
|
@@ -168,24 +184,43 @@ module Doing
|
|
|
168
184
|
Regexp.new("^(?:#{pattern.join('|')})$", true)
|
|
169
185
|
end
|
|
170
186
|
|
|
187
|
+
##
|
|
188
|
+
## Return array of available template names
|
|
189
|
+
##
|
|
190
|
+
## @param type [Symbol] Plugin type (:import,
|
|
191
|
+
## :export)
|
|
192
|
+
##
|
|
193
|
+
## @return [Array<String>] template names
|
|
194
|
+
##
|
|
171
195
|
def plugin_templates(type: :export)
|
|
172
196
|
type = valid_type(type)
|
|
173
197
|
templates = []
|
|
174
198
|
plugs = plugins[type].clone
|
|
175
199
|
plugs.delete_if { |_t, o| o[:templates].nil? }.each do |_, options|
|
|
176
200
|
options[:templates].each do |t|
|
|
177
|
-
|
|
201
|
+
out = t[:name]
|
|
202
|
+
out += " (#{t[:format]})" if t.key?(:format)
|
|
203
|
+
templates << out
|
|
178
204
|
end
|
|
179
205
|
end
|
|
180
206
|
|
|
181
|
-
templates
|
|
207
|
+
templates.sort.uniq
|
|
182
208
|
end
|
|
183
209
|
|
|
210
|
+
##
|
|
211
|
+
## Return a regular expression of all template
|
|
212
|
+
## triggers for type
|
|
213
|
+
##
|
|
214
|
+
## @param type [Symbol] The type :import or
|
|
215
|
+
## :export
|
|
216
|
+
##
|
|
217
|
+
## @return [Regexp] regular expression
|
|
218
|
+
##
|
|
184
219
|
def template_regex(type: :export)
|
|
185
220
|
type = valid_type(type)
|
|
186
221
|
pattern = []
|
|
187
222
|
plugs = plugins[type].clone
|
|
188
|
-
plugs.delete_if { |
|
|
223
|
+
plugs.delete_if { |_, o| o[:templates].nil? }.each do |_, options|
|
|
189
224
|
options[:templates].each do |t|
|
|
190
225
|
pattern << t[:trigger].normalize_trigger
|
|
191
226
|
end
|
|
@@ -193,16 +228,44 @@ module Doing
|
|
|
193
228
|
Regexp.new("^(?:#{pattern.join('|')})$", true)
|
|
194
229
|
end
|
|
195
230
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
231
|
+
##
|
|
232
|
+
## Find and return the appropriate template for a
|
|
233
|
+
## trigger string. Outputs a string that can be
|
|
234
|
+
## written out to the terminal for redirection
|
|
235
|
+
##
|
|
236
|
+
## @param trigger [String] The trigger to test
|
|
237
|
+
## @param type [Symbol] the plugin type
|
|
238
|
+
## (:import, :export)
|
|
239
|
+
##
|
|
240
|
+
## @return [String] string content of template for trigger
|
|
241
|
+
##
|
|
242
|
+
def template_for_trigger(trigger, type: :export, save_to: nil)
|
|
243
|
+
plugins[valid_type(type)].clone.delete_if { |_t, o| o[:templates].nil? }.each do |_, options|
|
|
200
244
|
options[:templates].each do |t|
|
|
201
|
-
|
|
245
|
+
next unless trigger =~ /^(?:#{t[:trigger].normalize_trigger})$/
|
|
246
|
+
|
|
247
|
+
tpl = options[:class].template(trigger)
|
|
248
|
+
return tpl unless save_to
|
|
249
|
+
|
|
250
|
+
raise PluginException.new('No default filename defined', :export, t[:name]) unless t.key?(:filename)
|
|
251
|
+
|
|
252
|
+
return save_template(tpl, save_to, t[:filename])
|
|
202
253
|
end
|
|
203
254
|
end
|
|
204
255
|
raise Errors::InvalidArgument, "No template type matched \"#{trigger}\""
|
|
205
256
|
end
|
|
257
|
+
|
|
258
|
+
def save_template(tpl, dir, filename)
|
|
259
|
+
dir = File.expand_path(dir)
|
|
260
|
+
FileUtils.mkdir_p(dir) unless File.exist?(dir)
|
|
261
|
+
raise DoingRuntimeError, "Path #{dir} exists but is not a directory" unless File.directory?(dir)
|
|
262
|
+
|
|
263
|
+
file = File.join(dir, filename)
|
|
264
|
+
File.open(file, 'w') do |f|
|
|
265
|
+
f.puts(tpl)
|
|
266
|
+
Doing.logger.warn('File update:', "Template written to #{file}")
|
|
267
|
+
end
|
|
268
|
+
end
|
|
206
269
|
end
|
|
207
270
|
end
|
|
208
271
|
end
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
# title: Day One Export
|
|
6
|
+
# description: Export entries to Day One plist for auto import
|
|
7
|
+
# author: Brett Terpstra
|
|
8
|
+
# url: https://brettterpstra.com
|
|
9
|
+
module Doing
|
|
10
|
+
class DayOneRenderer
|
|
11
|
+
attr_accessor :items, :page_title, :totals
|
|
12
|
+
|
|
13
|
+
def initialize(page_title, items, totals)
|
|
14
|
+
@page_title = page_title
|
|
15
|
+
@items = items
|
|
16
|
+
@totals = totals
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def get_binding
|
|
20
|
+
binding()
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class DayoneExport
|
|
25
|
+
include Doing::Util
|
|
26
|
+
|
|
27
|
+
def self.settings
|
|
28
|
+
{
|
|
29
|
+
trigger: 'day(?:one)?(?:-(?:days?|entries))?',
|
|
30
|
+
templates: [
|
|
31
|
+
{ name: 'dayone', trigger: 'day(?:one)?$', format: 'erb', filename: 'dayone.erb' },
|
|
32
|
+
{ name: 'dayone_entry', trigger: 'day(?:one)-entr(?:y|ies)?$', format: 'erb', filename: 'dayone-entry.erb' }
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.template(trigger)
|
|
38
|
+
case trigger
|
|
39
|
+
when /day(?:one)-entr(?:y|ies)?$/
|
|
40
|
+
IO.read(File.join(File.dirname(__FILE__), '../../../templates/doing-dayone-entry.erb'))
|
|
41
|
+
else
|
|
42
|
+
IO.read(File.join(File.dirname(__FILE__), '../../../templates/doing-dayone.erb'))
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.render(wwid, items, variables: {})
|
|
47
|
+
|
|
48
|
+
return if items.nil?
|
|
49
|
+
|
|
50
|
+
opt = variables[:options]
|
|
51
|
+
trigger = opt[:output]
|
|
52
|
+
digest = case trigger
|
|
53
|
+
when /-days?$/
|
|
54
|
+
:day
|
|
55
|
+
when /-entries$/
|
|
56
|
+
:entries
|
|
57
|
+
else
|
|
58
|
+
:digest
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
all_items = []
|
|
62
|
+
days = {}
|
|
63
|
+
flagged = false
|
|
64
|
+
tags = []
|
|
65
|
+
|
|
66
|
+
items.each do |i|
|
|
67
|
+
day_flagged = false
|
|
68
|
+
date_key = i.date.strftime('%Y-%m-%d')
|
|
69
|
+
|
|
70
|
+
if String.method_defined? :force_encoding
|
|
71
|
+
title = i.title.force_encoding('utf-8').link_urls(format: :markdown)
|
|
72
|
+
note = i.note.map { |line| line.force_encoding('utf-8').strip.link_urls(format: :markdown) } if i.note
|
|
73
|
+
else
|
|
74
|
+
title = i.title.link_urls(format: :markdown)
|
|
75
|
+
note = i.note.map { |line| line.strip.link_urls(format: :markdown) } if i.note
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
title = "#{title} @project(#{i.section})" unless variables[:is_single]
|
|
79
|
+
|
|
80
|
+
tags.concat(i.tag_array).sort!.uniq!
|
|
81
|
+
flagged = day_flagged = true if i.tags?(wwid.config['marker_tag'])
|
|
82
|
+
|
|
83
|
+
interval = wwid.get_interval(i, record: true) if i.title =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/ && opt[:times]
|
|
84
|
+
interval ||= false
|
|
85
|
+
human_time = false
|
|
86
|
+
if interval
|
|
87
|
+
d, h, m = wwid.format_time(wwid.get_interval(i, formatted: false))
|
|
88
|
+
human_times = []
|
|
89
|
+
human_times << format('%<d>d day%<p>s', d: d, p: d == 1 ? '' : 's') if d > 0
|
|
90
|
+
human_times << format('%<h>d hour%<p>s', h: h, p: h == 1 ? '' : 's') if h > 0
|
|
91
|
+
human_times << format('%<m>d minute%<p>s', m: m, p: m == 1 ? '' : 's') if m > 0
|
|
92
|
+
human_time = human_times.join(', ')
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
done = i.tags?('done') ? ' ' : ' '
|
|
96
|
+
|
|
97
|
+
item = {
|
|
98
|
+
date_object: i.date,
|
|
99
|
+
date: i.date.strftime('%a %-I:%M%p'),
|
|
100
|
+
shortdate: i.date.relative_date,
|
|
101
|
+
done: done,
|
|
102
|
+
note: note,
|
|
103
|
+
section: i.section,
|
|
104
|
+
time: interval,
|
|
105
|
+
human_time: human_time,
|
|
106
|
+
title: title.strip,
|
|
107
|
+
starred: day_flagged,
|
|
108
|
+
tags: i.tag_array
|
|
109
|
+
}
|
|
110
|
+
all_items << item
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
if days.key?(date_key)
|
|
114
|
+
days[date_key][:starred] = true if day_flagged
|
|
115
|
+
days[date_key][:tags] = days[date_key][:tags].concat(i.tag_array).sort.uniq
|
|
116
|
+
days[date_key][:entries].push(item)
|
|
117
|
+
else
|
|
118
|
+
days[date_key] ||= { tags: [], entries: [], starred: false }
|
|
119
|
+
days[date_key][:starred] = true if day_flagged
|
|
120
|
+
days[date_key][:tags] = days[date_key][:tags].concat(i.tag_array).sort.uniq
|
|
121
|
+
days[date_key][:entries].push(item)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
|
|
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
|
+
else
|
|
129
|
+
self.template('dayone')
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
totals = opt[:totals] ? wwid.tag_times(format: :markdown, sort_by_name: opt[:sort_tags], sort_order: opt[:tag_order]) : ''
|
|
133
|
+
|
|
134
|
+
case digest
|
|
135
|
+
when :day
|
|
136
|
+
days.each do |k, hsh|
|
|
137
|
+
title = "#{k}: #{variables[:page_title]}"
|
|
138
|
+
to_dayone(template: template,
|
|
139
|
+
title: title,
|
|
140
|
+
items: hsh[:entries],
|
|
141
|
+
totals: '',
|
|
142
|
+
date: Time.parse(k),
|
|
143
|
+
tags: tags,
|
|
144
|
+
starred: hsh[:starred])
|
|
145
|
+
end
|
|
146
|
+
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
|
+
else
|
|
150
|
+
self.template('dayone-entry')
|
|
151
|
+
end
|
|
152
|
+
all_items.each do |item|
|
|
153
|
+
to_dayone(template: entry_template,
|
|
154
|
+
title: '',
|
|
155
|
+
items: [item],
|
|
156
|
+
totals: '',
|
|
157
|
+
date: item[:date_object],
|
|
158
|
+
tags: item[:tags],
|
|
159
|
+
starred: item[:starred])
|
|
160
|
+
end
|
|
161
|
+
else
|
|
162
|
+
to_dayone(template: template,
|
|
163
|
+
title: variables[:page_title],
|
|
164
|
+
items: all_items,
|
|
165
|
+
totals: totals,
|
|
166
|
+
date: Time.now,
|
|
167
|
+
tags: tags,
|
|
168
|
+
starred: flagged)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
@out = ''
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def self.to_dayone(template: self.template(nil), title: 'doing', items: [], totals: '', date: Time.now, tags: [], starred: false)
|
|
175
|
+
mdx = DayOneRenderer.new(title, items, totals)
|
|
176
|
+
|
|
177
|
+
engine = ERB.new(template)
|
|
178
|
+
content = engine.result(mdx.get_binding)
|
|
179
|
+
|
|
180
|
+
uuid = SecureRandom.uuid
|
|
181
|
+
# uuid = `uuidgen`.strip
|
|
182
|
+
|
|
183
|
+
plist = {
|
|
184
|
+
'Creation Date' => date,
|
|
185
|
+
'Creator' => { 'Software Agent' => 'Doing/2.0.0' },
|
|
186
|
+
'Entry Text' => content,
|
|
187
|
+
'Starred' => starred,
|
|
188
|
+
'Tags' => tags.sort.uniq.delete_if { |t| t =~ /(done|cancell?ed|from)/ },
|
|
189
|
+
'UUID' => uuid
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
container = File.expand_path('~/Library/Group Containers/')
|
|
193
|
+
dayone_dir = Dir.glob('*.dayoneapp2', base: container).first
|
|
194
|
+
import_dir = File.join(container, dayone_dir, 'Data', 'Auto Import', 'Default Journal.dayone', 'entries')
|
|
195
|
+
FileUtils.mkdir_p(import_dir) unless File.exist?(import_dir)
|
|
196
|
+
entry_file = File.join(import_dir, "#{uuid}.doentry")
|
|
197
|
+
Doing.logger.debug('Day One Export:', "Exporting to #{entry_file}")
|
|
198
|
+
File.open(entry_file, 'w') do |f|
|
|
199
|
+
f.puts plist.to_plist
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
Doing.logger.count(:exported, level: :info, count: items.count, message: '%count %items exported to Day One import folder')
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
Doing::Plugins.register 'dayone', :export, self
|
|
206
|
+
Doing::Plugins.register 'dayone-days', :export, self
|
|
207
|
+
Doing::Plugins.register 'dayone-entries', :export, self
|
|
208
|
+
end
|
|
209
|
+
end
|
|
@@ -12,8 +12,8 @@ module Doing
|
|
|
12
12
|
{
|
|
13
13
|
trigger: 'html?|web(?:page)?',
|
|
14
14
|
templates: [
|
|
15
|
-
{ name: '
|
|
16
|
-
{ name: '
|
|
15
|
+
{ name: 'html', trigger: 'h[ta]ml?|web', format: 'haml', filename: 'html_export.haml' },
|
|
16
|
+
{ name: 'html_style', trigger: 'css|styl(?:e|us)', format: 'css', filename: 'html_export.css' }
|
|
17
17
|
]
|
|
18
18
|
}
|
|
19
19
|
end
|