doing 2.1.21 → 2.1.25
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 +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