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.
- checksums.yaml +4 -4
- data/.yardoc/checksums +14 -13
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/CHANGELOG.md +21 -0
- data/Gemfile.lock +3 -1
- data/README.md +1 -1
- data/bin/doing +149 -91
- data/doc/Array.html +63 -1
- data/doc/BooleanTermParser/Clause.html +293 -0
- data/doc/BooleanTermParser/Operator.html +172 -0
- data/doc/BooleanTermParser/Query.html +417 -0
- data/doc/BooleanTermParser/QueryParser.html +135 -0
- data/doc/BooleanTermParser/QueryTransformer.html +124 -0
- data/doc/BooleanTermParser.html +115 -0
- data/doc/Doing/CLIFormat.html +131 -0
- data/doc/Doing/Color.html +2 -2
- data/doc/Doing/Completion.html +1 -1
- data/doc/Doing/Configuration.html +116 -12
- data/doc/Doing/Errors/DoingNoTraceError.html +1 -1
- data/doc/Doing/Errors/DoingRuntimeError.html +1 -1
- data/doc/Doing/Errors/DoingStandardError.html +1 -1
- data/doc/Doing/Errors/EmptyInput.html +1 -1
- data/doc/Doing/Errors/NoResults.html +1 -1
- data/doc/Doing/Errors/PluginException.html +1 -1
- data/doc/Doing/Errors/UserCancelled.html +1 -1
- data/doc/Doing/Errors/WrongCommand.html +1 -1
- data/doc/Doing/Errors.html +1 -1
- data/doc/Doing/Hooks.html +1 -1
- data/doc/Doing/Item.html +100 -73
- data/doc/Doing/Items.html +2 -2
- data/doc/Doing/LogAdapter.html +70 -1
- data/doc/Doing/Note.html +5 -134
- data/doc/Doing/Pager.html +1 -1
- data/doc/Doing/Plugins.html +380 -40
- data/doc/Doing/Prompt.html +1 -1
- data/doc/Doing/Section.html +1 -1
- data/doc/Doing/TemplateString.html +713 -0
- data/doc/Doing/Util/Backup.html +686 -0
- data/doc/Doing/Util.html +1 -1
- data/doc/Doing/WWID.html +5 -5
- data/doc/Doing.html +4 -4
- data/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
- data/doc/GLI/Commands.html +1 -1
- data/doc/GLI.html +1 -1
- data/doc/Hash.html +1 -1
- data/doc/PhraseParser/Operator.html +172 -0
- data/doc/PhraseParser/PhraseClause.html +303 -0
- data/doc/PhraseParser/Query.html +495 -0
- data/doc/PhraseParser/QueryParser.html +136 -0
- data/doc/PhraseParser/QueryTransformer.html +124 -0
- data/doc/PhraseParser/TermClause.html +293 -0
- data/doc/PhraseParser.html +115 -0
- data/doc/Status.html +1 -1
- data/doc/String.html +182 -12
- data/doc/Symbol.html +35 -1
- data/doc/Time.html +1 -1
- data/doc/_index.html +21 -14
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +2 -2
- data/doc/index.html +2 -2
- data/doc/method_list.html +319 -175
- data/doc/top-level-namespace.html +1 -1
- data/doing.gemspec +1 -0
- data/doing.rdoc +56 -9
- data/lib/doing/array.rb +9 -0
- data/lib/doing/configuration.rb +30 -8
- 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 +57 -13
- data/lib/doing/plugins/export/dayone_export.rb +209 -0
- 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 +27 -18
- data/lib/doing.rb +3 -0
- data/lib/templates/doing-dayone-entry.erb +6 -0
- data/lib/templates/doing-dayone.erb +5 -0
- 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)
|
data/lib/doing/util_backup.rb
CHANGED
|
@@ -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
|
-
'--
|
|
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,
|
|
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
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
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(
|
|
1534
|
+
items = filter_items(items, opt: opt)
|
|
1527
1535
|
|
|
1528
|
-
items.reverse!
|
|
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.
|
|
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-
|
|
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
|