doing 2.1.21 → 2.1.25
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardoc/checksums +19 -16
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/CHANGELOG.md +51 -13
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/Rakefile +6 -3
- data/bin/doing +254 -103
- data/docs/doc/Array.html +74 -34
- data/docs/doc/BooleanTermParser/Clause.html +5 -5
- data/docs/doc/BooleanTermParser/Operator.html +4 -4
- data/docs/doc/BooleanTermParser/Query.html +8 -8
- data/docs/doc/BooleanTermParser/QueryParser.html +2 -2
- data/docs/doc/BooleanTermParser/QueryTransformer.html +2 -2
- data/docs/doc/BooleanTermParser.html +1 -1
- data/docs/doc/Doing/Color.html +4 -4
- data/docs/doc/Doing/Completion.html +2 -2
- data/docs/doc/Doing/Configuration.html +16 -18
- data/docs/doc/Doing/Errors/DoingNoTraceError.html +2 -2
- data/docs/doc/Doing/Errors/DoingRuntimeError.html +2 -2
- data/docs/doc/Doing/Errors/DoingStandardError.html +2 -2
- data/docs/doc/Doing/Errors/EmptyInput.html +2 -2
- data/docs/doc/Doing/Errors/NoResults.html +2 -2
- data/docs/doc/Doing/Errors/PluginException.html +3 -3
- data/docs/doc/Doing/Errors/UserCancelled.html +2 -2
- data/docs/doc/Doing/Errors/WrongCommand.html +2 -2
- data/docs/doc/Doing/Errors.html +1 -1
- data/docs/doc/Doing/Hooks.html +6 -6
- data/docs/doc/Doing/Item.html +50 -16
- data/docs/doc/Doing/Items.html +10 -10
- data/docs/doc/Doing/LogAdapter.html +24 -24
- data/docs/doc/Doing/Note.html +7 -7
- data/docs/doc/Doing/Pager.html +4 -4
- data/docs/doc/Doing/Plugins.html +7 -7
- data/docs/doc/Doing/Prompt.html +16 -16
- data/docs/doc/Doing/Section.html +6 -6
- data/docs/doc/Doing/TemplateString.html +8 -8
- data/docs/doc/Doing/Types.html +206 -0
- data/docs/doc/Doing/Util/Backup.html +10 -10
- data/docs/doc/Doing/Util.html +16 -19
- data/docs/doc/Doing/WWID.html +65 -53
- data/docs/doc/Doing.html +4 -4
- data/docs/doc/GLI/Commands/Help.html +185 -0
- data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +17 -17
- data/docs/doc/GLI/Commands.html +5 -3
- data/docs/doc/GLI.html +4 -2
- data/docs/doc/Hash.html +119 -21
- data/docs/doc/Numeric.html +5 -5
- data/docs/doc/PhraseParser/Operator.html +4 -4
- data/docs/doc/PhraseParser/PhraseClause.html +5 -5
- data/docs/doc/PhraseParser/Query.html +10 -10
- data/docs/doc/PhraseParser/QueryParser.html +2 -2
- data/docs/doc/PhraseParser/QueryTransformer.html +2 -2
- data/docs/doc/PhraseParser/TermClause.html +5 -5
- data/docs/doc/PhraseParser.html +1 -1
- data/docs/doc/Status.html +7 -7
- data/docs/doc/String.html +206 -51
- data/docs/doc/Symbol.html +8 -8
- data/docs/doc/Time.html +6 -6
- data/docs/doc/_index.html +51 -14
- data/docs/doc/class_list.html +1 -1
- data/docs/doc/file.README.html +2 -2
- data/docs/doc/index.html +2 -2
- data/docs/doc/method_list.html +348 -252
- data/docs/doc/top-level-namespace.html +2 -93
- data/docs/index.md +1 -1
- data/doing.rdoc +177 -20
- data/example_plugin.rb +2 -2
- data/lib/completion/_doing.zsh +24 -24
- data/lib/completion/doing.bash +31 -20
- data/lib/completion/doing.fish +32 -10
- data/lib/doing/array.rb +5 -4
- data/lib/doing/array_chronify.rb +4 -3
- data/lib/doing/changelog/change.rb +115 -0
- data/lib/doing/changelog/changes.rb +73 -0
- data/lib/doing/changelog/entry.rb +21 -0
- data/lib/doing/changelog/version.rb +97 -0
- data/lib/doing/changelog.rb +6 -0
- data/lib/doing/completion/fish_completion.rb +2 -1
- data/lib/doing/configuration.rb +20 -14
- data/lib/doing/good.rb +64 -0
- data/lib/doing/hash.rb +28 -5
- data/lib/doing/help_monkey_patch.rb +31 -0
- data/lib/doing/hooks.rb +8 -4
- data/lib/doing/item.rb +24 -35
- data/lib/doing/log_adapter.rb +1 -1
- data/lib/doing/pager.rb +1 -1
- data/lib/doing/plugins/export/template_export.rb +9 -3
- data/lib/doing/plugins/import/calendar_import.rb +1 -1
- data/lib/doing/plugins/import/doing_import.rb +1 -1
- data/lib/doing/plugins/import/timing_import.rb +1 -1
- data/lib/doing/prompt.rb +4 -2
- data/lib/doing/string.rb +30 -12
- data/lib/doing/string_chronify.rb +1 -1
- data/lib/doing/template_string.rb +9 -2
- data/lib/doing/types.rb +23 -16
- data/lib/doing/util.rb +12 -11
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +65 -46
- data/lib/doing.rb +3 -0
- data/lib/helpers/threaded_tests.rb +106 -99
- data/lib/helpers/threaded_tests_string.rb +50 -0
- metadata +12 -2
data/lib/doing/item.rb
CHANGED
@@ -125,11 +125,11 @@ module Doing
|
|
125
125
|
return true if same_time?(item_b)
|
126
126
|
|
127
127
|
start_a = date
|
128
|
-
|
129
|
-
end_a =
|
128
|
+
a_interval = interval
|
129
|
+
end_a = a_interval ? start_a + a_interval.to_i : start_a
|
130
130
|
start_b = item_b.date
|
131
|
-
|
132
|
-
end_b =
|
131
|
+
b_interval = item_b.interval
|
132
|
+
end_b = b_interval ? start_b + b_interval.to_i : start_b
|
133
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)
|
134
134
|
end
|
135
135
|
|
@@ -216,8 +216,8 @@ module Doing
|
|
216
216
|
##
|
217
217
|
def tags?(tags, bool = :and, negate: false)
|
218
218
|
if bool == :pattern
|
219
|
-
tags = tags.join(' ')
|
220
|
-
matches = tag_pattern?(tags
|
219
|
+
tags = tags.to_tags.tags_to_array.join(' ')
|
220
|
+
matches = tag_pattern?(tags)
|
221
221
|
|
222
222
|
return negate ? !matches : matches
|
223
223
|
end
|
@@ -283,7 +283,7 @@ module Doing
|
|
283
283
|
new_title = @title.gsub(rx) { |m| yellow(m) }
|
284
284
|
new_note.add(@note.to_s.gsub(rx) { |m| yellow(m) })
|
285
285
|
else
|
286
|
-
query =
|
286
|
+
query = search.strip.to_phrase_query
|
287
287
|
|
288
288
|
if query[:must].nil? && query[:must_not].nil?
|
289
289
|
query[:must] = query[:should]
|
@@ -319,7 +319,7 @@ module Doing
|
|
319
319
|
if search.is_rx? || matching == :fuzzy
|
320
320
|
matches = @title + @note.to_s =~ search.to_rx(distance: distance, case_type: case_type)
|
321
321
|
else
|
322
|
-
query =
|
322
|
+
query = search.strip.to_phrase_query
|
323
323
|
|
324
324
|
if query[:must].nil? && query[:must_not].nil?
|
325
325
|
query[:must] = query[:should]
|
@@ -399,7 +399,7 @@ module Doing
|
|
399
399
|
|
400
400
|
# outputs item in Doing file format, including leading tab
|
401
401
|
def to_s
|
402
|
-
"\t- #{@date.strftime('%Y-%m-%d %H:%M')} | #{@title}#{@note.
|
402
|
+
"\t- #{@date.strftime('%Y-%m-%d %H:%M')} | #{@title}#{@note.good? ? "\n#{@note}" : ''}"
|
403
403
|
end
|
404
404
|
|
405
405
|
##
|
@@ -429,6 +429,10 @@ module Doing
|
|
429
429
|
%(<Doing::Item @date=#{@date}>)
|
430
430
|
end
|
431
431
|
|
432
|
+
def clone
|
433
|
+
Marshal.load(Marshal.dump(self))
|
434
|
+
end
|
435
|
+
|
432
436
|
private
|
433
437
|
|
434
438
|
def should?(key)
|
@@ -457,7 +461,7 @@ module Doing
|
|
457
461
|
end
|
458
462
|
|
459
463
|
def all_searches?(searches, case_type: :smart)
|
460
|
-
return true
|
464
|
+
return true unless searches.good?
|
461
465
|
|
462
466
|
text = @title + @note.to_s
|
463
467
|
searches.each do |s|
|
@@ -468,7 +472,7 @@ module Doing
|
|
468
472
|
end
|
469
473
|
|
470
474
|
def no_searches?(searches, case_type: :smart)
|
471
|
-
return true
|
475
|
+
return true unless searches.good?
|
472
476
|
|
473
477
|
text = @title + @note.to_s
|
474
478
|
searches.each do |s|
|
@@ -479,7 +483,7 @@ module Doing
|
|
479
483
|
end
|
480
484
|
|
481
485
|
def any_searches?(searches, case_type: :smart)
|
482
|
-
return true
|
486
|
+
return true unless searches.good?
|
483
487
|
|
484
488
|
text = @title + @note.to_s
|
485
489
|
searches.each do |s|
|
@@ -490,7 +494,7 @@ module Doing
|
|
490
494
|
end
|
491
495
|
|
492
496
|
def all_tags?(tags)
|
493
|
-
return true
|
497
|
+
return true unless tags.good?
|
494
498
|
|
495
499
|
tags.each do |tag|
|
496
500
|
return false unless @title =~ /@#{tag.wildcard_to_rx}(?= |\(|\Z)/i
|
@@ -499,7 +503,7 @@ module Doing
|
|
499
503
|
end
|
500
504
|
|
501
505
|
def no_tags?(tags)
|
502
|
-
return true
|
506
|
+
return true unless tags.good?
|
503
507
|
|
504
508
|
tags.each do |tag|
|
505
509
|
return false if @title =~ /@#{tag.wildcard_to_rx}(?= |\(|\Z)/i
|
@@ -508,7 +512,7 @@ module Doing
|
|
508
512
|
end
|
509
513
|
|
510
514
|
def any_tags?(tags)
|
511
|
-
return true
|
515
|
+
return true unless tags.good?
|
512
516
|
|
513
517
|
tags.each do |tag|
|
514
518
|
return true if @title =~ /@#{tag.wildcard_to_rx}(?= |\(|\Z)/i
|
@@ -537,7 +541,7 @@ module Doing
|
|
537
541
|
end
|
538
542
|
|
539
543
|
def any_values?(queries)
|
540
|
-
return true
|
544
|
+
return true unless queries.good?
|
541
545
|
|
542
546
|
queries.each do |q|
|
543
547
|
parts = split_value_query(q)
|
@@ -547,7 +551,7 @@ module Doing
|
|
547
551
|
end
|
548
552
|
|
549
553
|
def all_values?(queries)
|
550
|
-
return true
|
554
|
+
return true unless queries.good?
|
551
555
|
|
552
556
|
queries.each do |q|
|
553
557
|
parts = split_value_query(q)
|
@@ -557,7 +561,7 @@ module Doing
|
|
557
561
|
end
|
558
562
|
|
559
563
|
def no_values?(queries)
|
560
|
-
return true
|
564
|
+
return true unless queries.good?
|
561
565
|
|
562
566
|
queries.each do |q|
|
563
567
|
parts = split_value_query(q)
|
@@ -612,29 +616,14 @@ module Doing
|
|
612
616
|
end
|
613
617
|
end
|
614
618
|
|
615
|
-
def to_query(query)
|
616
|
-
parser = BooleanTermParser::QueryParser.new
|
617
|
-
transformer = BooleanTermParser::QueryTransformer.new
|
618
|
-
parse_tree = parser.parse(query)
|
619
|
-
transformer.apply(parse_tree).to_elasticsearch
|
620
|
-
end
|
621
|
-
|
622
|
-
def to_phrase_query(query)
|
623
|
-
parser = PhraseParser::QueryParser.new
|
624
|
-
transformer = PhraseParser::QueryTransformer.new
|
625
|
-
parse_tree = parser.parse(query)
|
626
|
-
transformer.apply(parse_tree).to_elasticsearch
|
627
|
-
end
|
628
|
-
|
629
619
|
def tag_pattern?(tags)
|
630
|
-
query = to_query
|
620
|
+
query = tags.to_query
|
631
621
|
|
632
622
|
no_tags?(query[:must_not]) && all_tags?(query[:must]) && any_tags?(query[:should])
|
633
623
|
end
|
634
624
|
|
635
625
|
def split_tags(tags)
|
636
|
-
tags
|
637
|
-
tags.map { |t| t.strip.add_at }
|
626
|
+
tags.to_tags.tags_to_array
|
638
627
|
end
|
639
628
|
end
|
640
629
|
end
|
data/lib/doing/log_adapter.rb
CHANGED
@@ -356,7 +356,7 @@ module Doing
|
|
356
356
|
next if data[:count].zero?
|
357
357
|
|
358
358
|
count = data[:count]
|
359
|
-
tags = data[:tag] ? data[:tag].uniq.map { |t|
|
359
|
+
tags = data[:tag] ? data[:tag].uniq.map { |t| t.add_at.cyan }.join(', ') : 'tags'
|
360
360
|
topic, m = format_counter(key, data)
|
361
361
|
message = m.dup
|
362
362
|
message.sub!(/%count/, count.to_s)
|
data/lib/doing/pager.rb
CHANGED
@@ -49,6 +49,8 @@ module Doing
|
|
49
49
|
note = []
|
50
50
|
end
|
51
51
|
|
52
|
+
placeholders['tags'] = item.tags
|
53
|
+
|
52
54
|
placeholders['date'] = item.date.strftime(opt[:format])
|
53
55
|
|
54
56
|
interval = wwid.get_interval(item, record: true, formatted: false) if opt[:times]
|
@@ -56,8 +58,10 @@ module Doing
|
|
56
58
|
interval = case opt[:interval_format].to_sym
|
57
59
|
when :human
|
58
60
|
interval.time_string(format: :hm)
|
59
|
-
|
61
|
+
when :text
|
60
62
|
interval.time_string(format: :clock)
|
63
|
+
else
|
64
|
+
interval.time_string(format: opt[:interval_format].to_sym)
|
61
65
|
end
|
62
66
|
end
|
63
67
|
|
@@ -69,8 +73,10 @@ module Doing
|
|
69
73
|
duration = case opt[:interval_format].to_sym
|
70
74
|
when :human
|
71
75
|
duration.time_string(format: :hm)
|
72
|
-
|
76
|
+
when :text
|
73
77
|
duration.time_string(format: :clock)
|
78
|
+
else
|
79
|
+
duration.time_string(format: opt[:interval_format].to_sym)
|
74
80
|
end
|
75
81
|
end
|
76
82
|
duration ||= ''
|
@@ -119,7 +125,7 @@ module Doing
|
|
119
125
|
|
120
126
|
output.gsub!(/\\%/, '%')
|
121
127
|
|
122
|
-
output.highlight_search!(opt[:search]) if opt[:search] && !opt[:not] && opt[:hilite]
|
128
|
+
output.highlight_search!(opt[:search]) if opt[:template] =~ /^temp/ && opt[:search] && !opt[:not] && opt[:hilite]
|
123
129
|
|
124
130
|
out += "#{output}\n"
|
125
131
|
end
|
@@ -89,7 +89,7 @@ module Doing
|
|
89
89
|
|
90
90
|
wwid.content.concat(new_items)
|
91
91
|
|
92
|
-
new_items.map { |item| Hooks.trigger :post_entry_added, self, item
|
92
|
+
new_items.map { |item| Hooks.trigger :post_entry_added, self, item }
|
93
93
|
|
94
94
|
Doing.logger.info(%(Imported #{new_items.count} items to #{section}))
|
95
95
|
end
|
@@ -93,7 +93,7 @@ module Doing
|
|
93
93
|
wwid.content.add_section(item.section) unless wwid.content.section?(item.section)
|
94
94
|
Hooks.trigger :pre_entry_add, self, item
|
95
95
|
wwid.content.push(item)
|
96
|
-
Hooks.trigger :post_entry_added, self, item
|
96
|
+
Hooks.trigger :post_entry_added, self, item
|
97
97
|
end
|
98
98
|
|
99
99
|
Doing.logger.info('Imported:', "#{imported.count} items")
|
@@ -93,7 +93,7 @@ module Doing
|
|
93
93
|
|
94
94
|
wwid.content.concat(new_items)
|
95
95
|
|
96
|
-
new_items.map { |item| Hooks.trigger :post_entry_added, self, item
|
96
|
+
new_items.map { |item| Hooks.trigger :post_entry_added, self, item }
|
97
97
|
|
98
98
|
Doing.logger.info('Imported:', %(#{new_items.count} items to #{section}))
|
99
99
|
end
|
data/lib/doing/prompt.rb
CHANGED
@@ -42,7 +42,7 @@ module Doing
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
def read_lines(prompt: 'Enter text', completions: [])
|
45
|
+
def read_lines(prompt: 'Enter text', completions: [], default_response: '')
|
46
46
|
$stdin.reopen('/dev/tty')
|
47
47
|
return default_response if @default_answer
|
48
48
|
|
@@ -72,8 +72,10 @@ module Doing
|
|
72
72
|
res.join("\n").strip
|
73
73
|
end
|
74
74
|
|
75
|
-
def request_lines(prompt: 'Enter text')
|
75
|
+
def request_lines(prompt: 'Enter text', default_response: '')
|
76
76
|
$stdin.reopen('/dev/tty')
|
77
|
+
return default_response if @default_answer
|
78
|
+
|
77
79
|
ask_note = []
|
78
80
|
reader = TTY::Reader.new(interrupt: -> { raise Errors::UserCancelled }, track_history: false)
|
79
81
|
puts "#{boldgreen(prompt.sub(/:?$/, ':'))} #{yellow('Hit return for a new line, ')}#{boldwhite('enter a blank line (')}#{boldyellow('return twice')}#{boldwhite(') to end editing')}"
|
data/lib/doing/string.rb
CHANGED
@@ -20,7 +20,9 @@ module Doing
|
|
20
20
|
## can be separated by up to *distance* characters in
|
21
21
|
## haystack, spaces indicate unlimited distance.
|
22
22
|
##
|
23
|
-
## @example
|
23
|
+
## @example
|
24
|
+
## "this word".to_rx(3)
|
25
|
+
## # => /t.{0,3}h.{0,3}i.{0,3}s.{0,3}.*?w.{0,3}o.{0,3}r.{0,3}d/
|
24
26
|
##
|
25
27
|
## @param distance [Integer] Allowed distance
|
26
28
|
## between characters
|
@@ -53,6 +55,20 @@ module Doing
|
|
53
55
|
Regexp.new(pattern, !case_sensitive)
|
54
56
|
end
|
55
57
|
|
58
|
+
def to_phrase_query
|
59
|
+
parser = PhraseParser::QueryParser.new
|
60
|
+
transformer = PhraseParser::QueryTransformer.new
|
61
|
+
parse_tree = parser.parse(self)
|
62
|
+
transformer.apply(parse_tree).to_elasticsearch
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_query
|
66
|
+
parser = BooleanTermParser::QueryParser.new
|
67
|
+
transformer = BooleanTermParser::QueryTransformer.new
|
68
|
+
parse_tree = parser.parse(self)
|
69
|
+
transformer.apply(parse_tree).to_elasticsearch
|
70
|
+
end
|
71
|
+
|
56
72
|
##
|
57
73
|
## Test string for truthiness (0, "f", "false", "n", "no" all return false, case insensitive, otherwise true)
|
58
74
|
##
|
@@ -92,7 +108,7 @@ module Doing
|
|
92
108
|
escapes = scan(/(\e\[[\d;]+m)[^\e]+@/)
|
93
109
|
color = color.split(' ') unless color.is_a?(Array)
|
94
110
|
tag_color = color.each_with_object([]) { |c, arr| arr << Doing::Color.send(c) }.join('')
|
95
|
-
last_color = if
|
111
|
+
last_color = if escapes.good?
|
96
112
|
(escapes.count > 1 ? escapes[-2..-1] : [escapes[-1]]).map { |v| v[0] }.join('')
|
97
113
|
else
|
98
114
|
Doing::Color.default
|
@@ -101,13 +117,6 @@ module Doing
|
|
101
117
|
gsub(/(\s|m)(@[^ ("']+)/, "\\1#{tag_color}\\2#{last_color}")
|
102
118
|
end
|
103
119
|
|
104
|
-
def to_phrase_query(query)
|
105
|
-
parser = PhraseParser::QueryParser.new
|
106
|
-
transformer = PhraseParser::QueryTransformer.new
|
107
|
-
parse_tree = parser.parse(query)
|
108
|
-
transformer.apply(parse_tree).to_elasticsearch
|
109
|
-
end
|
110
|
-
|
111
120
|
def ignore_case(search, case_type)
|
112
121
|
(case_type == :smart && search !~ /[A-Z]/) || case_type == :ignore
|
113
122
|
end
|
@@ -127,7 +136,7 @@ module Doing
|
|
127
136
|
rx = search.to_rx(distance: distance, case_type: case_type)
|
128
137
|
out.gsub!(rx) { |m| m.bgyellow.black }
|
129
138
|
else
|
130
|
-
query =
|
139
|
+
query = search.strip.to_phrase_query
|
131
140
|
|
132
141
|
if query[:must].nil? && query[:must_not].nil?
|
133
142
|
query[:must] = query[:should]
|
@@ -449,7 +458,7 @@ module Doing
|
|
449
458
|
## @return [String] Regular expression string
|
450
459
|
##
|
451
460
|
def wildcard_to_rx
|
452
|
-
gsub(/\?/, '\S').gsub(/\*/, '\S*?')
|
461
|
+
gsub(/\?/, '\S').gsub(/\*/, '\S*?').gsub(/\]\]/, '--')
|
453
462
|
end
|
454
463
|
|
455
464
|
##
|
@@ -458,7 +467,16 @@ module Doing
|
|
458
467
|
## @return [String] @string
|
459
468
|
##
|
460
469
|
def add_at
|
461
|
-
strip.sub(/^([+-]*)
|
470
|
+
strip.sub(/^([+-]*)@?/, '\1@')
|
471
|
+
end
|
472
|
+
|
473
|
+
##
|
474
|
+
## Removes @ prefix if needed, maintains +/- prefix
|
475
|
+
##
|
476
|
+
## @return [String] string without @ prefix
|
477
|
+
##
|
478
|
+
def remove_at
|
479
|
+
strip.sub(/^([+-]*)@?/, '\1')
|
462
480
|
end
|
463
481
|
|
464
482
|
##
|
@@ -173,7 +173,7 @@ module Doing
|
|
173
173
|
## @return [Array<DateTime>] Start and end dates as
|
174
174
|
## array
|
175
175
|
## @example Process a natural language date range
|
176
|
-
##
|
176
|
+
## "mon 3pm to mon 5pm".split_date_range
|
177
177
|
##
|
178
178
|
def split_date_range
|
179
179
|
time_rx = /^(\d{1,2}+(:\d{1,2}+)?( *(am|pm))?|midnight|noon)$/
|
@@ -131,7 +131,7 @@ module Doing
|
|
131
131
|
|
132
132
|
after = m['after']
|
133
133
|
|
134
|
-
if value.
|
134
|
+
if !value.good?
|
135
135
|
after
|
136
136
|
else
|
137
137
|
pad = m['width'].to_i
|
@@ -146,6 +146,13 @@ module Doing
|
|
146
146
|
end
|
147
147
|
indent ||= placeholder =~ /^title/ ? '' : "\t"
|
148
148
|
prefix = m['prefix']
|
149
|
+
|
150
|
+
if placeholder =~ /^tags/
|
151
|
+
prefix ||= ''
|
152
|
+
value = value.map { |t| "#{prefix}#{t.sub(/^#{prefix}?/, '')}" }.join(' ')
|
153
|
+
prefix = ''
|
154
|
+
end
|
155
|
+
|
149
156
|
if placeholder =~ /^title/
|
150
157
|
color = last_color + color
|
151
158
|
|
@@ -176,7 +183,7 @@ module Doing
|
|
176
183
|
' '
|
177
184
|
else
|
178
185
|
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 || tags_color.
|
186
|
+
line.highlight_tags!(tags_color, last_color: last_color) unless !tags_color || !tags_color.good?
|
180
187
|
"#{line} "
|
181
188
|
end
|
182
189
|
end.join("\n")
|
data/lib/doing/types.rb
CHANGED
@@ -1,19 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
3
|
+
module Doing
|
4
|
+
module Types
|
5
|
+
REGEX_BOOL = /^(?:and|all|any|or|not|none|p(?:at(?:tern)?)?)$/i.freeze
|
6
|
+
REGEX_SORT_ORDER = /^(?:a(?:sc)?|d(?:esc)?)$/i.freeze
|
7
|
+
REGEX_VALUE_QUERY = /^(?:!)?@?(?:\S+) +(?:!?[<>=][=*]?|[$*^]=) +(?:.*?)$/.freeze
|
8
|
+
REGEX_CLOCK = '(?:\d{1,2}+(?::\d{1,2}+)?(?: *(?:am|pm))?|midnight|noon)'
|
9
|
+
REGEX_TIME = /^#{REGEX_CLOCK}$/i.freeze
|
10
|
+
REGEX_DAY = /^(mon|tue|wed|thur?|fri|sat|sun)(\w+(day)?)?$/i.freeze
|
11
|
+
REGEX_RANGE_INDICATOR = ' +(?:to|through|thru|(?:un)?til|-+) +'
|
12
|
+
REGEX_RANGE = /^\S+#{REGEX_RANGE_INDICATOR}+\S+/i.freeze
|
13
|
+
REGEX_TIME_RANGE = /^#{REGEX_CLOCK}#{REGEX_RANGE_INDICATOR}#{REGEX_CLOCK}$/i.freeze
|
12
14
|
|
13
|
-
InvalidExportType = Class.new(RuntimeError)
|
14
|
-
MissingConfigFile = Class.new(RuntimeError)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
InvalidExportType = Class.new(RuntimeError)
|
16
|
+
MissingConfigFile = Class.new(RuntimeError)
|
17
|
+
|
18
|
+
TagArray = Class.new(Array)
|
19
|
+
TemplateName = Class.new(String)
|
20
|
+
DateBeginString = Class.new(DateTime)
|
21
|
+
DateEndString = Class.new(DateTime)
|
22
|
+
DateRangeString = Class.new(Array)
|
23
|
+
DateRangeOptionalString = Class.new(Array)
|
24
|
+
DateIntervalString = Class.new(DateTime)
|
25
|
+
end
|
26
|
+
end
|
data/lib/doing/util.rb
CHANGED
@@ -19,7 +19,7 @@ module Doing
|
|
19
19
|
## @param cli [String] The name or path of the cli
|
20
20
|
##
|
21
21
|
def exec_available(cli)
|
22
|
-
return false
|
22
|
+
return false unless cli.good?
|
23
23
|
|
24
24
|
!TTY::Which.which(cli).nil?
|
25
25
|
end
|
@@ -27,11 +27,12 @@ module Doing
|
|
27
27
|
##
|
28
28
|
## Return the first valid executable from a list of commands
|
29
29
|
##
|
30
|
-
## @example
|
30
|
+
## @example
|
31
|
+
## Doing::Util.first_available_exec('bat', 'less -Xr', 'more -r', 'cat')
|
31
32
|
##
|
32
33
|
def first_available_exec(*commands)
|
33
34
|
commands.compact.map(&:strip).reject(&:empty?).uniq
|
34
|
-
|
35
|
+
.find { |cmd| exec_available(cmd.split.first) }
|
35
36
|
end
|
36
37
|
|
37
38
|
def merge_default_proc(target, overwrite)
|
@@ -55,7 +56,7 @@ module Doing
|
|
55
56
|
# @param [Hash] other_hash The other hash
|
56
57
|
#
|
57
58
|
def deep_merge_hashes(master_hash, other_hash)
|
58
|
-
deep_merge_hashes!(master_hash.
|
59
|
+
deep_merge_hashes!(master_hash.clone, other_hash)
|
59
60
|
end
|
60
61
|
|
61
62
|
# Merges a master hash with another hash, recursively.
|
@@ -156,32 +157,32 @@ module Doing
|
|
156
157
|
def find_default_editor(editor_for = 'default')
|
157
158
|
# return nil unless $stdout.isatty || ENV['DOING_EDITOR_TEST']
|
158
159
|
|
159
|
-
if ENV['DOING_EDITOR_TEST']
|
160
|
-
return ENV['EDITOR']
|
161
|
-
end
|
160
|
+
return ENV['EDITOR'] if ENV['DOING_EDITOR_TEST']
|
162
161
|
|
163
162
|
editor_config = Doing.config.settings['editors']
|
164
163
|
|
165
164
|
if editor_config.is_a?(String)
|
166
|
-
|
165
|
+
msg = "Please update your configuration, 'editors' should be a mapping."
|
166
|
+
msg << ' Delete the key and run `doing config --update`.'
|
167
|
+
Doing.logger.warn('Deprecated:', msg)
|
167
168
|
return editor_config
|
168
169
|
end
|
169
170
|
|
170
171
|
if editor_config[editor_for]
|
171
172
|
editor = editor_config[editor_for]
|
172
173
|
# Doing.logger.debug('Editor:', "Using #{editor} from config 'editors->#{editor_for}'")
|
173
|
-
return editor unless editor.
|
174
|
+
return editor unless editor.good?
|
174
175
|
end
|
175
176
|
|
176
177
|
if editor_for != 'editor' && editor_config['default']
|
177
178
|
editor = editor_config['default']
|
178
179
|
# Doing.logger.debug('Editor:', "Using #{editor} from config: 'editors->default'")
|
179
|
-
return editor unless editor.
|
180
|
+
return editor unless editor.good?
|
180
181
|
end
|
181
182
|
|
182
183
|
editor ||= ENV['DOING_EDITOR'] || ENV['GIT_EDITOR'] || ENV['EDITOR']
|
183
184
|
|
184
|
-
unless editor.
|
185
|
+
unless editor.good?
|
185
186
|
# Doing.logger.debug('Editor:', "Found editor in environment variables: #{editor}")
|
186
187
|
return editor
|
187
188
|
end
|
data/lib/doing/version.rb
CHANGED