doing 2.1.14 → 2.1.18
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/.irbrc +1 -0
- data/.yardoc/checksums +14 -12
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/CHANGELOG.md +66 -0
- data/Gemfile.lock +3 -2
- data/README.md +56 -19
- data/bin/doing +134 -47
- data/docs/doc/Array.html +117 -3
- data/docs/doc/BooleanTermParser/Clause.html +1 -1
- data/docs/doc/BooleanTermParser/Operator.html +1 -1
- data/docs/doc/BooleanTermParser/Query.html +1 -1
- data/docs/doc/BooleanTermParser/QueryParser.html +1 -1
- data/docs/doc/BooleanTermParser/QueryTransformer.html +1 -1
- data/docs/doc/BooleanTermParser.html +1 -1
- data/docs/doc/Doing/Color.html +6 -2
- data/docs/doc/Doing/Completion.html +1 -1
- data/docs/doc/Doing/Configuration.html +8 -4
- data/docs/doc/Doing/Errors/DoingNoTraceError.html +1 -1
- data/docs/doc/Doing/Errors/DoingRuntimeError.html +1 -1
- data/docs/doc/Doing/Errors/DoingStandardError.html +1 -1
- data/docs/doc/Doing/Errors/EmptyInput.html +1 -1
- data/docs/doc/Doing/Errors/NoResults.html +1 -1
- data/docs/doc/Doing/Errors/PluginException.html +1 -1
- data/docs/doc/Doing/Errors/UserCancelled.html +1 -1
- data/docs/doc/Doing/Errors/WrongCommand.html +1 -1
- data/docs/doc/Doing/Errors.html +1 -1
- data/docs/doc/Doing/Hooks.html +1 -1
- data/docs/doc/Doing/Item.html +224 -2
- data/docs/doc/Doing/Items.html +2 -2
- data/docs/doc/Doing/LogAdapter.html +1 -1
- data/docs/doc/Doing/Note.html +2 -2
- data/docs/doc/Doing/Pager.html +1 -1
- data/docs/doc/Doing/Plugins.html +1 -1
- data/docs/doc/Doing/Prompt.html +69 -1
- data/docs/doc/Doing/Section.html +1 -1
- data/docs/doc/Doing/TemplateString.html +2 -2
- data/docs/doc/Doing/Util/Backup.html +1 -1
- data/docs/doc/Doing/Util.html +1 -1
- data/docs/doc/Doing/WWID.html +71 -67
- data/docs/doc/Doing.html +3 -3
- data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
- data/docs/doc/GLI/Commands.html +1 -1
- data/docs/doc/GLI.html +1 -1
- data/docs/doc/Hash.html +1 -1
- data/docs/doc/Numeric.html +279 -0
- data/docs/doc/PhraseParser/Operator.html +1 -1
- data/docs/doc/PhraseParser/PhraseClause.html +1 -1
- data/docs/doc/PhraseParser/Query.html +1 -1
- data/docs/doc/PhraseParser/QueryParser.html +1 -1
- data/docs/doc/PhraseParser/QueryTransformer.html +1 -1
- data/docs/doc/PhraseParser/TermClause.html +1 -1
- data/docs/doc/PhraseParser.html +1 -1
- data/docs/doc/Status.html +1 -1
- data/docs/doc/String.html +997 -118
- data/docs/doc/Symbol.html +1 -1
- data/docs/doc/Time.html +1 -1
- data/docs/doc/_index.html +14 -9
- data/docs/doc/class_list.html +1 -1
- data/docs/doc/file.README.html +41 -15
- data/docs/doc/index.html +41 -15
- data/docs/doc/method_list.html +448 -312
- data/docs/doc/top-level-namespace.html +2 -2
- data/docs/index.md +56 -19
- data/doing.gemspec +1 -0
- data/doing.rdoc +36 -6
- data/example_plugin.rb +2 -4
- data/lib/completion/_doing.zsh +8 -8
- data/lib/completion/doing.bash +12 -12
- data/lib/completion/doing.fish +8 -3
- data/lib/doing/array_chronify.rb +57 -0
- data/lib/doing/colors.rb +4 -0
- data/lib/doing/configuration.rb +6 -2
- data/lib/doing/item.rb +83 -0
- data/lib/doing/log_adapter.rb +3 -3
- data/lib/doing/numeric_chronify.rb +40 -0
- data/lib/doing/plugins/export/dayone_export.rb +1 -1
- data/lib/doing/plugins/export/json_export.rb +2 -2
- data/lib/doing/plugins/export/template_export.rb +49 -90
- data/lib/doing/prompt.rb +52 -0
- data/lib/doing/string.rb +137 -33
- data/lib/doing/string_chronify.rb +112 -14
- data/lib/doing/template_string.rb +1 -1
- data/lib/doing/time.rb +4 -4
- data/lib/doing/util_backup.rb +1 -1
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +107 -101
- data/lib/doing.rb +35 -31
- data/lib/examples/plugins/say_export.rb +1 -4
- metadata +26 -2
data/lib/doing/item.rb
CHANGED
@@ -9,6 +9,8 @@ module Doing
|
|
9
9
|
|
10
10
|
# attr_reader :id
|
11
11
|
|
12
|
+
include Color
|
13
|
+
|
12
14
|
##
|
13
15
|
## Initialize an item with date, title, section, and
|
14
16
|
## optional note
|
@@ -57,6 +59,25 @@ module Doing
|
|
57
59
|
@end_date ||= Time.parse(Regexp.last_match(1)) if @title =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/
|
58
60
|
end
|
59
61
|
|
62
|
+
def calculate_end_date(opt)
|
63
|
+
if opt[:took]
|
64
|
+
if @date + opt[:took] > Time.now
|
65
|
+
@date = Time.now - opt[:took]
|
66
|
+
Time.now
|
67
|
+
else
|
68
|
+
@date + opt[:took]
|
69
|
+
end
|
70
|
+
elsif opt[:back]
|
71
|
+
if opt[:back].is_a? Integer
|
72
|
+
@date + opt[:back]
|
73
|
+
else
|
74
|
+
@date + (opt[:back] - @date)
|
75
|
+
end
|
76
|
+
else
|
77
|
+
Time.now
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
60
81
|
# Generate a hash that represents the entry
|
61
82
|
#
|
62
83
|
# @return [String] entry hash
|
@@ -112,6 +133,19 @@ module Doing
|
|
112
133
|
(start_a >= start_b && start_a <= end_b) || (end_a >= start_b && end_a <= end_b) || (start_a < start_b && end_a > end_b)
|
113
134
|
end
|
114
135
|
|
136
|
+
##
|
137
|
+
## Updates the title of the Item by expanding natural
|
138
|
+
## language dates within configured date tags (tags
|
139
|
+
## whose value is expected to be a date)
|
140
|
+
##
|
141
|
+
## @param additional_tags An array of additional
|
142
|
+
## tag names to consider
|
143
|
+
## dates
|
144
|
+
##
|
145
|
+
def expand_date_tags(additional_tags = nil)
|
146
|
+
@title.expand_date_tags(additional_tags)
|
147
|
+
end
|
148
|
+
|
115
149
|
##
|
116
150
|
## Add (or remove) tags from the title of the item
|
117
151
|
##
|
@@ -237,6 +271,34 @@ module Doing
|
|
237
271
|
(case_type == :smart && search !~ /[A-Z]/) || case_type == :ignore
|
238
272
|
end
|
239
273
|
|
274
|
+
def highlight_search(search, distance: nil, negate: false, case_type: nil)
|
275
|
+
prefs = Doing.config.settings['search'] || {}
|
276
|
+
matching = prefs.fetch('matching', 'pattern').normalize_matching
|
277
|
+
distance ||= prefs.fetch('distance', 3).to_i
|
278
|
+
case_type ||= prefs.fetch('case', 'smart').normalize_case
|
279
|
+
new_note = Note.new
|
280
|
+
|
281
|
+
if search.is_rx? || matching == :fuzzy
|
282
|
+
rx = search.to_rx(distance: distance, case_type: case_type)
|
283
|
+
new_title = @title.gsub(rx) { |m| yellow(m) }
|
284
|
+
new_note.add(@note.to_s.gsub(rx) { |m| yellow(m) })
|
285
|
+
else
|
286
|
+
query = to_phrase_query(search.strip)
|
287
|
+
|
288
|
+
if query[:must].nil? && query[:must_not].nil?
|
289
|
+
query[:must] = query[:should]
|
290
|
+
query[:should] = []
|
291
|
+
end
|
292
|
+
query[:must].concat(query[:should]).each do |s|
|
293
|
+
rx = Regexp.new(s.wildcard_to_rx, ignore_case(s, case_type))
|
294
|
+
new_title = @title.gsub(rx) { |m| yellow(m) }
|
295
|
+
new_note.add(@note.to_s.gsub(rx) { |m| yellow(m) })
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
Item.new(@date, new_title, @section, new_note)
|
300
|
+
end
|
301
|
+
|
240
302
|
##
|
241
303
|
## Test if item matches search string
|
242
304
|
##
|
@@ -340,6 +402,27 @@ module Doing
|
|
340
402
|
"\t- #{@date.strftime('%Y-%m-%d %H:%M')} | #{@title}#{@note.empty? ? '' : "\n#{@note}"}"
|
341
403
|
end
|
342
404
|
|
405
|
+
##
|
406
|
+
## outputs a colored string with relative date and highlighted tags
|
407
|
+
##
|
408
|
+
## @return Pretty representation of the object.
|
409
|
+
##
|
410
|
+
def to_pretty(elements: %i[date title section])
|
411
|
+
output = []
|
412
|
+
elements.each do |e|
|
413
|
+
case e
|
414
|
+
when :date
|
415
|
+
output << format('%13s |', @date.relative_date).cyan
|
416
|
+
when :section
|
417
|
+
output << "#{magenta}(#{white(@section)}#{magenta})"
|
418
|
+
when :title
|
419
|
+
output << @title.white.highlight_tags('cyan')
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
output.join(' ')
|
424
|
+
end
|
425
|
+
|
343
426
|
# @private
|
344
427
|
def inspect
|
345
428
|
# %(<Doing::Item @date=#{@date} @title="#{@title}" @section:"#{@section}" @note:#{@note.to_s}>)
|
data/lib/doing/log_adapter.rb
CHANGED
@@ -52,7 +52,7 @@ module Doing
|
|
52
52
|
COUNT_KEYS.each { |key| @counters[key] = { tag: [], count: 0 } }
|
53
53
|
@results = []
|
54
54
|
@logdev = $stderr
|
55
|
-
@max_length =
|
55
|
+
@max_length = TTY::Screen.columns - 5 || 85
|
56
56
|
self.log_level = level
|
57
57
|
@prev_level = level
|
58
58
|
end
|
@@ -398,9 +398,9 @@ module Doing
|
|
398
398
|
return topic.ljust(TOPIC_WIDTH) if topic && message.strip.empty?
|
399
399
|
|
400
400
|
topic = formatted_topic(topic, colon: block_given?)
|
401
|
-
message.truncmiddle!(@max_length - TOPIC_WIDTH - 5)
|
401
|
+
# message.truncmiddle!(@max_length - TOPIC_WIDTH - 5)
|
402
402
|
out = topic + message
|
403
|
-
out.truncate!(@max_length) if @max_length.positive?
|
403
|
+
# out.truncate!(@max_length) if @max_length.positive?
|
404
404
|
messages << out
|
405
405
|
out
|
406
406
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doing
|
4
|
+
##
|
5
|
+
## Number helpers
|
6
|
+
##
|
7
|
+
class ::Numeric
|
8
|
+
##
|
9
|
+
## Format human readable time from seconds
|
10
|
+
##
|
11
|
+
## @param seconds [Integer] Seconds
|
12
|
+
##
|
13
|
+
def format_time(human: false)
|
14
|
+
return [0, 0, 0] if nil?
|
15
|
+
|
16
|
+
seconds = dup.to_i
|
17
|
+
minutes = (seconds / 60).to_i
|
18
|
+
hours = (minutes / 60).to_i
|
19
|
+
if human
|
20
|
+
minutes = (minutes % 60).to_i
|
21
|
+
[0, hours, minutes]
|
22
|
+
else
|
23
|
+
days = (hours / 24).to_i
|
24
|
+
hours = (hours % 24).to_i
|
25
|
+
minutes = (minutes % 60).to_i
|
26
|
+
[days, hours, minutes]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
## Format seconds as natural language time string
|
32
|
+
##
|
33
|
+
## @param format [Symbol] The format to output
|
34
|
+
## (:dhm, :hm, :m, :clock, :natural)
|
35
|
+
##
|
36
|
+
def time_string(format: :dhm)
|
37
|
+
format_time(human: true).time_string(format: format)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -84,7 +84,7 @@ module Doing
|
|
84
84
|
interval ||= false
|
85
85
|
human_time = false
|
86
86
|
if interval
|
87
|
-
d, h, m = wwid.
|
87
|
+
d, h, m = wwid.get_interval(i, formatted: false).format_time
|
88
88
|
human_times = []
|
89
89
|
human_times << format('%<d>d day%<p>s', d: d, p: d == 1 ? '' : 's') if d > 0
|
90
90
|
human_times << format('%<h>d hour%<p>s', h: h, p: h == 1 ? '' : 's') if h > 0
|
@@ -56,7 +56,7 @@ module Doing
|
|
56
56
|
end_date: end_date,
|
57
57
|
title: title.strip, #+ " #{note}"
|
58
58
|
note: note.instance_of?(Array) ? note.to_s : note,
|
59
|
-
time:
|
59
|
+
time: interval.time_string(format: :clock),
|
60
60
|
tags: tags
|
61
61
|
}
|
62
62
|
|
@@ -68,7 +68,7 @@ module Doing
|
|
68
68
|
new_item = {
|
69
69
|
'id' => index + 1,
|
70
70
|
'content' => title.strip, #+ " #{note}"
|
71
|
-
'title' => title.strip + " (#{
|
71
|
+
'title' => title.strip + " (#{interval.time_string(format: :clock)})",
|
72
72
|
'start' => i.date.strftime('%F %T'),
|
73
73
|
'type' => 'box',
|
74
74
|
'style' => 'color:#4c566b;background-color:#d8dee9;'
|
@@ -5,6 +5,7 @@
|
|
5
5
|
# author: Brett Terpstra
|
6
6
|
# url: https://brettterpstra.com
|
7
7
|
module Doing
|
8
|
+
# Template Export
|
8
9
|
class TemplateExport
|
9
10
|
include Doing::Color
|
10
11
|
include Doing::Util
|
@@ -32,7 +33,7 @@ module Doing
|
|
32
33
|
|
33
34
|
placeholders = {}
|
34
35
|
|
35
|
-
if
|
36
|
+
if !item.note.empty? && wwid.config['include_notes']
|
36
37
|
note = item.note.map(&:strip).delete_if(&:empty?)
|
37
38
|
note.map! { |line| "#{line.sub(/^\t*/, '')} " }
|
38
39
|
|
@@ -42,122 +43,74 @@ module Doing
|
|
42
43
|
line.simple_wrap(width)
|
43
44
|
# line.chomp.gsub(/(.{1,#{width}})(\s+|\Z)/, "\\1\n")
|
44
45
|
end
|
45
|
-
note
|
46
|
+
note.delete_if(&:empty?)
|
46
47
|
end
|
47
48
|
else
|
48
49
|
note = []
|
49
50
|
end
|
50
51
|
|
51
|
-
# output.sub!(/%(\d+)?date/) do
|
52
|
-
# pad = Regexp.last_match(1).to_i
|
53
|
-
# format("%#{pad}s", item.date.strftime(opt[:format]))
|
54
|
-
# end
|
55
52
|
placeholders['date'] = item.date.strftime(opt[:format])
|
56
53
|
|
57
54
|
interval = wwid.get_interval(item, record: true, formatted: false) if opt[:times]
|
58
55
|
if interval
|
59
|
-
case opt[:interval_format].to_sym
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
interval = format('%<d>02d:%<h>02d:%<m>02d', d: d, h: h, m: m)
|
66
|
-
end
|
56
|
+
interval = case opt[:interval_format].to_sym
|
57
|
+
when :human
|
58
|
+
interval.time_string(format: :hm)
|
59
|
+
else
|
60
|
+
interval.time_string(format: :clock)
|
61
|
+
end
|
67
62
|
end
|
68
63
|
|
69
64
|
interval ||= ''
|
70
|
-
# output.sub!(/%interval/, interval)
|
71
65
|
placeholders['interval'] = interval
|
72
66
|
|
73
67
|
duration = item.duration if opt[:duration]
|
74
68
|
if duration
|
75
|
-
case opt[:interval_format].to_sym
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
duration = format('%<d>02d:%<h>02d:%<m>02d', d: d, h: h, m: m)
|
82
|
-
end
|
69
|
+
duration = case opt[:interval_format].to_sym
|
70
|
+
when :human
|
71
|
+
duration.time_string(format: :hm)
|
72
|
+
else
|
73
|
+
duration.time_string(format: :clock)
|
74
|
+
end
|
83
75
|
end
|
84
76
|
duration ||= ''
|
85
|
-
# output.sub!(/%duration/, duration)
|
86
77
|
placeholders['duration'] = duration
|
87
78
|
|
88
|
-
|
89
|
-
# pad = Regexp.last_match(1) || 13
|
90
|
-
# format("%#{pad}s", item.date.relative_date)
|
91
|
-
# end
|
92
|
-
placeholders['shortdate'] = format("%13s", item.date.relative_date)
|
93
|
-
# output.sub!(/%section/, item.section) if item.section
|
79
|
+
placeholders['shortdate'] = format('%13s', item.date.relative_date)
|
94
80
|
placeholders['section'] = item.section || ''
|
95
81
|
placeholders['title'] = item.title
|
96
|
-
|
97
|
-
# title_rx = /(?mi)%(?<width>-?\d+)?(?:(?<ichar>[ _t])(?<icount>\d+))?(?<prefix>.[ _t]?)?title(?<after>.*?)$/
|
98
|
-
# title_color = Doing::Color.reset + output.match(/(?mi)^(.*?)(%.*?title)/)[1].last_color
|
99
|
-
|
100
|
-
# title_offset = Doing::Color.uncolor(output).match(title_rx).begin(0)
|
101
|
-
|
102
|
-
# output.sub!(title_rx) do
|
103
|
-
# m = Regexp.last_match
|
104
|
-
|
105
|
-
# after = m['after']
|
106
|
-
# pad = m['width'].to_i
|
107
|
-
# indent = ''
|
108
|
-
# if m['ichar']
|
109
|
-
# char = m['ichar'] =~ /t/ ? "\t" : ' '
|
110
|
-
# indent = char * m['icount'].to_i
|
111
|
-
# end
|
112
|
-
# prefix = m['prefix']
|
113
|
-
# if opt[:wrap_width]&.positive? || pad.positive?
|
114
|
-
# width = pad.positive? ? pad : opt[:wrap_width]
|
115
|
-
# item.title.wrap(width, pad: pad, indent: indent, offset: title_offset, prefix: prefix, color: title_color, after: after, reset: reset)
|
116
|
-
# # flag + item.title.gsub(/(.{#{opt[:wrap_width]}})(?=\s+|\Z)/, "\\1\n ").sub(/\s*$/, '') + reset
|
117
|
-
# else
|
118
|
-
# format("%s%#{pad}s%s", prefix, item.title.sub(/\s*$/, ''), after)
|
119
|
-
# end
|
120
|
-
# end
|
121
|
-
|
122
|
-
|
123
|
-
|
124
82
|
placeholders['note'] = note
|
125
83
|
placeholders['idnote'] = note.empty? ? '' : "\n#{note.map { |l| "\t\t#{l.strip} " }.join("\n")}"
|
126
84
|
placeholders['odnote'] = note.empty? ? '' : "\n#{note.map { |l| "#{l.strip} " }.join("\n")}"
|
127
|
-
placeholders['chompnote'] = note.empty? ? '' : note.map { |l| l.gsub(/\n+/, ' ').gsub(/(^\s*|\s*$)/, '').gsub(/\s+/, ' ') }.join(' ')
|
128
|
-
|
129
|
-
# if note.empty?
|
130
|
-
# output.gsub!(/%(chomp|[io]d|(\^.)?(([ _t]|[^a-z0-9])?\d+)?(.[ _t]?)?)?note/, '')
|
131
|
-
# else
|
132
|
-
# output.sub!(/%note/, "\n#{note.map { |l| "\t#{l.strip} " }.join("\n")}")
|
133
|
-
# output.sub!(/%idnote/, "\n#{note.map { |l| "\t\t#{l.strip} " }.join("\n")}")
|
134
|
-
# output.sub!(/%odnote/, "\n#{note.map { |l| "#{l.strip} " }.join("\n")}")
|
135
|
-
# output.sub!(/(?mi)%(?:\^(?<mchar>.))?(?:(?<ichar>[ _t]|[^a-z0-9])?(?<icount>\d+))?(?<prefix>.[ _t]?)?note/) do
|
136
|
-
# m = Regexp.last_match
|
137
|
-
# mark = m['mchar'] || ''
|
138
|
-
# indent = if m['ichar']
|
139
|
-
# char = m['ichar'] =~ /t/ ? "\t" : ' '
|
140
|
-
# char * m['icount'].to_i
|
141
|
-
# else
|
142
|
-
# ''
|
143
|
-
# end
|
144
|
-
# prefix = m['prefix'] || ''
|
145
|
-
# "\n#{note.map { |l| "#{mark}#{indent}#{prefix}#{l.strip} " }.join("\n")}"
|
146
|
-
# end
|
147
|
-
|
148
|
-
# output.sub!(/%chompnote/) do
|
149
|
-
# note.map { |l| l.gsub(/\n+/, ' ').gsub(/(^\s*|\s*$)/, '').gsub(/\s+/, ' ') }.join(' ')
|
150
|
-
# end
|
151
|
-
# end
|
152
85
|
|
153
|
-
|
154
|
-
|
155
|
-
|
86
|
+
chompnote = []
|
87
|
+
unless note.empty?
|
88
|
+
chompnote = note.map do |l|
|
89
|
+
l.gsub(/\n+/, ' ').gsub(/(^\s*|\s*$)/, '').gsub(/\s+/, ' ')
|
90
|
+
end
|
91
|
+
end
|
92
|
+
placeholders['chompnote'] = chompnote.join(' ')
|
156
93
|
|
157
|
-
|
94
|
+
template = opt[:template].dup
|
95
|
+
note_rx = /(?i-m)(?x:^([\s\S]*?)
|
96
|
+
(%(?:[io]d|(?:\^[\s\S])?
|
97
|
+
(?:(?:[ _t]|[^a-z0-9])?\d+)?
|
98
|
+
(?:[\s\S][ _t]?)?)?note)
|
99
|
+
([\s\S]*?)$)/
|
100
|
+
template.sub!(note_rx, '\1\3\2')
|
101
|
+
output = Doing::TemplateString.new(template,
|
102
|
+
color: flag,
|
103
|
+
placeholders: placeholders,
|
104
|
+
reset: reset,
|
105
|
+
tags_color: opt[:tags_color],
|
106
|
+
wrap_width: opt[:wrap_width]).colored
|
107
|
+
|
108
|
+
output.gsub!(/(?<!\\)%(\S)?hr(_under)?/) do
|
158
109
|
o = ''
|
159
|
-
|
160
|
-
|
110
|
+
TTY::Screen.columns.to_i.times do
|
111
|
+
char = Regexp.last_match(2).nil? ? '-' : '_'
|
112
|
+
char = Regexp.last_match(1).nil? ? char : Regexp.last_match(1)
|
113
|
+
o += char
|
161
114
|
end
|
162
115
|
o
|
163
116
|
end
|
@@ -166,11 +119,17 @@ module Doing
|
|
166
119
|
|
167
120
|
output.gsub!(/\\%/, '%')
|
168
121
|
|
122
|
+
output.highlight_search!(opt[:search]) if opt[:search] && !opt[:not] && opt[:hilite]
|
123
|
+
|
169
124
|
out += "#{output}\n"
|
170
125
|
end
|
171
126
|
|
172
127
|
# Doing.logger.debug('Template Export:', "#{items.count} items output to template #{opt[:template]}")
|
173
|
-
|
128
|
+
if opt[:totals]
|
129
|
+
out += wwid.tag_times(format: wwid.config['timer_format'].to_sym,
|
130
|
+
sort_by_name: opt[:sort_tags],
|
131
|
+
sort_order: opt[:tag_order])
|
132
|
+
end
|
174
133
|
out
|
175
134
|
end
|
176
135
|
|
data/lib/doing/prompt.rb
CHANGED
@@ -17,13 +17,63 @@ module Doing
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def enter_text(prompt, default_response: '')
|
20
|
+
$stdin.reopen('/dev/tty')
|
20
21
|
return default_response if @default_answer
|
21
22
|
|
22
23
|
print "#{yellow(prompt).sub(/:?$/, ':')} #{reset}"
|
23
24
|
$stdin.gets.strip
|
24
25
|
end
|
25
26
|
|
27
|
+
def read_line(prompt: 'Enter text', completions: [], default_response: '')
|
28
|
+
$stdin.reopen('/dev/tty')
|
29
|
+
return default_response if @default_answer
|
30
|
+
|
31
|
+
unless completions.empty?
|
32
|
+
completions.sort!
|
33
|
+
comp = proc { |s| completions.grep(/^#{Regexp.escape(s)}/) }
|
34
|
+
Readline.completion_append_character = ' '
|
35
|
+
Readline.completion_proc = comp
|
36
|
+
end
|
37
|
+
|
38
|
+
begin
|
39
|
+
Readline.readline("#{yellow(prompt).sub(/:?$/, ':')} #{reset}", true).strip
|
40
|
+
rescue Interrupt
|
41
|
+
raise UserCancelled
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def read_lines(prompt: 'Enter text', completions: [])
|
46
|
+
$stdin.reopen('/dev/tty')
|
47
|
+
return default_response if @default_answer
|
48
|
+
|
49
|
+
completions.sort!
|
50
|
+
comp = proc { |s| completions.grep(/^#{Regexp.escape(s)}/) }
|
51
|
+
Readline.completion_append_character = ' '
|
52
|
+
Readline.completion_proc = comp
|
53
|
+
prompt_text = []
|
54
|
+
prompt_text << boldgreen(prompt.sub(/:?$/, ':'))
|
55
|
+
prompt_text << yellow(' Enter a blank line (')
|
56
|
+
prompt_text << boldwhite('return twice')
|
57
|
+
prompt_text << yellow(') to end editing')
|
58
|
+
puts prompt_text.join('')
|
59
|
+
|
60
|
+
res = []
|
61
|
+
|
62
|
+
begin
|
63
|
+
while (line = Readline.readline('> ', true))
|
64
|
+
break if line.strip.empty?
|
65
|
+
|
66
|
+
res << line.chomp
|
67
|
+
end
|
68
|
+
rescue Interrupt
|
69
|
+
raise UserCancelled
|
70
|
+
end
|
71
|
+
|
72
|
+
res.join("\n").strip
|
73
|
+
end
|
74
|
+
|
26
75
|
def request_lines(prompt: 'Enter text')
|
76
|
+
$stdin.reopen('/dev/tty')
|
27
77
|
ask_note = []
|
28
78
|
reader = TTY::Reader.new(interrupt: -> { raise Errors::UserCancelled }, track_history: false)
|
29
79
|
puts "#{boldgreen(prompt.sub(/:?$/, ':'))} #{yellow('Hit return for a new line, ')}#{boldwhite('enter a blank line (')}#{boldyellow('return twice')}#{boldwhite(') to end editing')}"
|
@@ -51,6 +101,8 @@ module Doing
|
|
51
101
|
return @force_answer
|
52
102
|
end
|
53
103
|
|
104
|
+
$stdin.reopen('/dev/tty')
|
105
|
+
|
54
106
|
default = if default_response.is_a?(String)
|
55
107
|
default_response =~ /y/i ? true : false
|
56
108
|
else
|