doing 2.1.22 → 2.1.26
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 +17 -14
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/CHANGELOG.md +323 -111
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/Rakefile +2 -1
- data/bin/commands/add_section.rb +13 -0
- data/bin/commands/again.rb +99 -0
- data/bin/commands/archive.rb +96 -0
- data/bin/commands/cancel.rb +102 -0
- data/bin/commands/changes.rb +42 -0
- data/bin/commands/choose.rb +9 -0
- data/bin/commands/colors.rb +19 -0
- data/bin/commands/commands.rb +87 -0
- data/bin/commands/commands_accepting.rb +25 -0
- data/bin/commands/completion.rb +24 -0
- data/bin/commands/config.rb +245 -0
- data/bin/commands/done.rb +249 -0
- data/bin/commands/finish.rb +149 -0
- data/bin/commands/flag.rb +126 -0
- data/bin/commands/grep.rb +124 -0
- data/bin/commands/import.rb +101 -0
- data/bin/commands/install_fzf.rb +17 -0
- data/bin/commands/last.rb +114 -0
- data/bin/commands/meanwhile.rb +86 -0
- data/bin/commands/note.rb +130 -0
- data/bin/commands/now.rb +151 -0
- data/bin/commands/on.rb +66 -0
- data/bin/commands/open.rb +53 -0
- data/bin/commands/plugins.rb +23 -0
- data/bin/commands/recent.rb +78 -0
- data/bin/commands/redo.rb +22 -0
- data/bin/commands/reset.rb +106 -0
- data/bin/commands/rotate.rb +73 -0
- data/bin/commands/sections.rb +11 -0
- data/bin/commands/select.rb +123 -0
- data/bin/commands/show.rb +231 -0
- data/bin/commands/since.rb +64 -0
- data/bin/commands/tag.rb +179 -0
- data/bin/commands/tag_dir.rb +29 -0
- data/bin/commands/tags.rb +93 -0
- data/bin/commands/template.rb +61 -0
- data/bin/commands/today.rb +65 -0
- data/bin/commands/undo.rb +49 -0
- data/bin/commands/view.rb +238 -0
- data/bin/commands/views.rb +11 -0
- data/bin/commands/yesterday.rb +73 -0
- data/bin/doing +54 -3505
- data/docs/doc/Array.html +79 -11
- 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 +17 -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 +59 -14
- 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 +3 -3
- data/docs/doc/FalseClass.html +201 -0
- 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 +47 -21
- data/docs/doc/Numeric.html +5 -5
- data/docs/doc/Object.html +203 -0
- 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 +144 -51
- data/docs/doc/Symbol.html +8 -8
- data/docs/doc/Time.html +6 -6
- data/docs/doc/TrueClass.html +201 -0
- data/docs/doc/_index.html +46 -16
- 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 +292 -212
- data/docs/doc/top-level-namespace.html +2 -2
- data/docs/index.md +1 -1
- data/doing.rdoc +178 -16
- data/example_plugin.rb +2 -2
- data/lib/completion/_doing.zsh +27 -27
- data/lib/completion/doing.bash +31 -20
- data/lib/completion/doing.fish +33 -11
- data/lib/doing/array.rb +2 -2
- 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 -13
- data/lib/doing/good.rb +64 -0
- data/lib/doing/hash.rb +7 -2
- 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/pager.rb +1 -0
- data/lib/doing/plugins/export/template_export.rb +1 -1
- 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 +8 -0
- data/lib/doing/string.rb +20 -11
- data/lib/doing/string_chronify.rb +1 -1
- data/lib/doing/template_string.rb +2 -2
- data/lib/doing/types.rb +3 -0
- data/lib/doing/util.rb +12 -11
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +62 -37
- data/lib/doing.rb +2 -0
- data/lib/examples/commands/wiki.rb +6 -7
- data/lib/helpers/threaded_tests.rb +61 -71
- data/lib/helpers/threaded_tests_string.rb +50 -0
- metadata +56 -2
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doing
|
|
4
|
+
# A single version's entries
|
|
5
|
+
class Change
|
|
6
|
+
attr_reader :version, :content
|
|
7
|
+
|
|
8
|
+
attr_accessor :entries
|
|
9
|
+
|
|
10
|
+
def initialize(version, content)
|
|
11
|
+
@version = Version.new(version)
|
|
12
|
+
@content = content
|
|
13
|
+
parse_entries
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def parse_entries
|
|
17
|
+
@entries = []
|
|
18
|
+
types = @content.scan(/(?<=\n|\A)#### (NEW|IMPROVED|FIXED)(.*?)(?=\n####|\Z)/m)
|
|
19
|
+
types.each do |type|
|
|
20
|
+
type[1].scan(/\s*- +(.*?)$/).each do |entry|
|
|
21
|
+
@entries << Entry.new(entry[0].strip, type[0])
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def search_entries(search_string)
|
|
27
|
+
case_type = :ignore
|
|
28
|
+
|
|
29
|
+
matches = []
|
|
30
|
+
|
|
31
|
+
if search_string.is_rx?
|
|
32
|
+
matches = @entries.select { |e| e.string =~ search_string.to_rx(distance: 2, case_type: case_type) }
|
|
33
|
+
else
|
|
34
|
+
query = search_string.gsub(/(-)?--/, '\1]]').to_phrase_query
|
|
35
|
+
|
|
36
|
+
if query[:must].nil? && query[:must_not].nil?
|
|
37
|
+
query[:must] = query[:should]
|
|
38
|
+
query[:should] = []
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
@entries.each do |entry|
|
|
42
|
+
m = no_searches?(entry.string, query[:must_not])
|
|
43
|
+
m &&= all_searches?(entry.string, query[:must])
|
|
44
|
+
m &&= any_searches?(entry.string, query[:should])
|
|
45
|
+
matches << entry if m
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
@entries = matches.count.positive? ? matches : nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def to_h
|
|
53
|
+
{ version: @version, content: @content }
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def to_s
|
|
57
|
+
out = ["### #{@version}"]
|
|
58
|
+
items = {
|
|
59
|
+
new: [],
|
|
60
|
+
improved: [],
|
|
61
|
+
fixed: [],
|
|
62
|
+
other: []
|
|
63
|
+
}
|
|
64
|
+
@entries.each do |e|
|
|
65
|
+
type = e.type.downcase.to_sym
|
|
66
|
+
if items.key?(type)
|
|
67
|
+
items[type] << e
|
|
68
|
+
else
|
|
69
|
+
items[:other] << e
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
items.each do |type, members|
|
|
74
|
+
if members.count.positive?
|
|
75
|
+
out << "#### #{type.to_s.capitalize}"
|
|
76
|
+
out << members.map(&:to_s).join("\n")
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
out.join("\n\n")
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
def all_searches?(text, searches)
|
|
86
|
+
return true if searches.nil? || searches.empty?
|
|
87
|
+
|
|
88
|
+
searches.each do |s|
|
|
89
|
+
rx = Regexp.new(s.wildcard_to_rx, true)
|
|
90
|
+
return false unless text =~ rx
|
|
91
|
+
end
|
|
92
|
+
true
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def no_searches?(text, searches)
|
|
96
|
+
return true if searches.nil? || searches.empty?
|
|
97
|
+
|
|
98
|
+
searches.each do |s|
|
|
99
|
+
rx = Regexp.new(s.wildcard_to_rx, true)
|
|
100
|
+
return false if text =~ rx
|
|
101
|
+
end
|
|
102
|
+
true
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def any_searches?(text, searches)
|
|
106
|
+
return true if searches.nil? || searches.empty?
|
|
107
|
+
|
|
108
|
+
searches.each do |s|
|
|
109
|
+
rx = Regexp.new(s.wildcard_to_rx, true)
|
|
110
|
+
return true if text =~ rx
|
|
111
|
+
end
|
|
112
|
+
false
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doing
|
|
4
|
+
# A collection of Changes
|
|
5
|
+
class Changes
|
|
6
|
+
attr_reader :changes
|
|
7
|
+
|
|
8
|
+
def initialize(lookup: nil, search: nil)
|
|
9
|
+
changelog = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'CHANGELOG.md'))
|
|
10
|
+
raise 'Error locating changelog' unless File.exist?(changelog)
|
|
11
|
+
|
|
12
|
+
@content = IO.read(changelog)
|
|
13
|
+
parse_changes(lookup, search)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def latest
|
|
17
|
+
@changes[0].to_s.force_encoding('utf-8')
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def to_s
|
|
21
|
+
@changes.map(&:to_s).join("\n\n").force_encoding('utf-8')
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def parse_changes(lookup, search)
|
|
27
|
+
change_rx = /(?<=\n|\A)### (\d+\.\d+\.\d+(?:\w*))(.*?)(?=\n### |\Z)/m
|
|
28
|
+
@changes = @content.scan(change_rx).each_with_object([]) do |m, a|
|
|
29
|
+
next if m[0].nil? || m[1].nil?
|
|
30
|
+
|
|
31
|
+
a << Change.new(m[0], m[1].strip)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
lookup(lookup) unless lookup.nil?
|
|
35
|
+
search(search) unless search.nil?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def lookup(lookup_version)
|
|
39
|
+
range = []
|
|
40
|
+
|
|
41
|
+
if lookup_version =~ /([\d.]+) *-+ *([\d.]+)/
|
|
42
|
+
m = Regexp.last_match
|
|
43
|
+
lookup("> #{m[1]}")
|
|
44
|
+
lookup("< #{m[2]}")
|
|
45
|
+
elsif lookup_version.scan(/[<>]/).count > 1
|
|
46
|
+
params = lookup_version.scan(/[<>] [\d.]+/)
|
|
47
|
+
params.each { |query| lookup(query) }
|
|
48
|
+
else
|
|
49
|
+
comp = case lookup_version
|
|
50
|
+
when /(<|prior|before|older)/
|
|
51
|
+
:older
|
|
52
|
+
when />|since|after|newer/
|
|
53
|
+
:newer
|
|
54
|
+
else
|
|
55
|
+
:equal
|
|
56
|
+
end
|
|
57
|
+
version = Version.new(lookup_version)
|
|
58
|
+
|
|
59
|
+
@changes.select! do |change|
|
|
60
|
+
change.version.compare(version, comp)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def search(query)
|
|
66
|
+
@changes.map do |c|
|
|
67
|
+
c.entries = c.search_entries(query)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
@changes.delete_if { |c| c.nil? || c.entries.nil? }
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doing
|
|
4
|
+
# An individual changelog item
|
|
5
|
+
class Entry
|
|
6
|
+
attr_reader :type, :string
|
|
7
|
+
|
|
8
|
+
def initialize(string, type)
|
|
9
|
+
@string = string
|
|
10
|
+
@type = type
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def clean(string)
|
|
14
|
+
string.gsub(/\|/, '\|')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def to_s
|
|
18
|
+
"- #{clean(@string)}"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doing
|
|
4
|
+
# Semantic versioning
|
|
5
|
+
class Version
|
|
6
|
+
attr_reader :maj, :min, :patch
|
|
7
|
+
|
|
8
|
+
def initialize(string)
|
|
9
|
+
@maj, @min, @patch = version_to_a(string)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def version_to_a(string)
|
|
13
|
+
raise 'Version not a string' unless string.is_a?(String)
|
|
14
|
+
|
|
15
|
+
v = string.match(/(?<maj>\d+)(?:\.(?<min>[\d*?]+))?(?:\.(?<patch>[\d*?]+))?/)
|
|
16
|
+
|
|
17
|
+
raise 'Error parsing semantic version string' if v.nil?
|
|
18
|
+
|
|
19
|
+
maj = v['maj'].to_i
|
|
20
|
+
min = case v['min']
|
|
21
|
+
when /[*?]/
|
|
22
|
+
v['min'].sub(/(\d+)?[^\d]/, '\1\d+')
|
|
23
|
+
when /^[0-9]+$/
|
|
24
|
+
v['min'].to_i
|
|
25
|
+
end
|
|
26
|
+
pat = case v['patch']
|
|
27
|
+
when /[*?]/
|
|
28
|
+
v['patch'].sub(/(\d+)?[^\d]/, '\1\d+')
|
|
29
|
+
when /^[0-9]+$/
|
|
30
|
+
v['patch'].to_i
|
|
31
|
+
end
|
|
32
|
+
[maj, min, pat]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def wild?(val)
|
|
36
|
+
val.is_a?(String)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def compare(other, comp)
|
|
41
|
+
case comp
|
|
42
|
+
when :older
|
|
43
|
+
if @maj <= other.maj
|
|
44
|
+
if @maj < other.maj
|
|
45
|
+
true
|
|
46
|
+
elsif @maj == other.maj && (other.min.nil? || @min < other.min)
|
|
47
|
+
true
|
|
48
|
+
elsif @maj == other.maj && @min == other.min
|
|
49
|
+
other.patch.nil? ? false : @patch < other.patch
|
|
50
|
+
else
|
|
51
|
+
false
|
|
52
|
+
end
|
|
53
|
+
else
|
|
54
|
+
false
|
|
55
|
+
end
|
|
56
|
+
when :newer
|
|
57
|
+
if @maj >= other.maj
|
|
58
|
+
if @maj > other.maj
|
|
59
|
+
true
|
|
60
|
+
elsif @maj == other.maj && (other.min.nil? || @min > other.min)
|
|
61
|
+
true
|
|
62
|
+
elsif @maj == other.maj && @min == other.min
|
|
63
|
+
other.patch.nil? || @patch >= other.patch
|
|
64
|
+
else
|
|
65
|
+
false
|
|
66
|
+
end
|
|
67
|
+
else
|
|
68
|
+
false
|
|
69
|
+
end
|
|
70
|
+
when :equal
|
|
71
|
+
if @maj == other.maj
|
|
72
|
+
if other.min.nil?
|
|
73
|
+
true
|
|
74
|
+
elsif wild?(other.min)
|
|
75
|
+
@min.to_s =~ /^#{other.min}/ ? true : false
|
|
76
|
+
else
|
|
77
|
+
if @min == other.min
|
|
78
|
+
if other.patch.nil?
|
|
79
|
+
true
|
|
80
|
+
elsif wild?(other.patch)
|
|
81
|
+
@patch.to_s =~ /^#{other.patch}/ ? true : false
|
|
82
|
+
else
|
|
83
|
+
@patch == other.patch
|
|
84
|
+
end
|
|
85
|
+
else
|
|
86
|
+
false
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def to_s
|
|
94
|
+
"#{@maj}.#{@min || 0}.#{@patch || 0}"
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -123,8 +123,9 @@ module Doing
|
|
|
123
123
|
complete -f -c doing -n '__fish_doing_using_command view' -a '(__fish_doing_complete_views)'
|
|
124
124
|
complete -f -c doing -n '__fish_doing_using_command template' -a '(__fish_doing_complete_templates)'
|
|
125
125
|
complete -f -c doing -s t -l type -x -n '__fish_doing_using_command import' -a '(__fish_doing_import_plugins)'
|
|
126
|
+
complete -f -c doing -n '__fish_doing_using_command help' -a '(__fish_doing_subcommands)'
|
|
126
127
|
|
|
127
|
-
complete -xc doing -n '__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from (doing help -c)' -a "(doing help -c)"
|
|
128
|
+
# complete -xc doing -n '__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from (doing help -c)' -a "(doing help -c)"
|
|
128
129
|
|
|
129
130
|
function __fish_doing_complete_args
|
|
130
131
|
for cmd in (doing commands_accepting -c $argv[1])
|
data/lib/doing/configuration.rb
CHANGED
|
@@ -29,6 +29,7 @@ module Doing
|
|
|
29
29
|
'plugin_path' => File.join(Util.user_home, '.config', 'doing', 'plugins'),
|
|
30
30
|
'command_path' => File.join(Util.user_home, '.config', 'doing', 'commands')
|
|
31
31
|
},
|
|
32
|
+
'disabled_commands' => [],
|
|
32
33
|
'doing_file' => '~/.local/share/doing/what_was_i_doing.md',
|
|
33
34
|
'doing_file_sort' => 'desc',
|
|
34
35
|
'backup_dir' => '~/.local/share/doing/doing_backup',
|
|
@@ -45,8 +46,7 @@ module Doing
|
|
|
45
46
|
'templates' => {
|
|
46
47
|
'default' => {
|
|
47
48
|
'date_format' => '%Y-%m-%d %H:%M',
|
|
48
|
-
'template' => '%reset%cyan%shortdate %boldwhite%80║ title %
|
|
49
|
-
%yellow%interval%boldred%duration%dark%white%80_14┃ note',
|
|
49
|
+
'template' => '%reset%cyan%shortdate %boldwhite%80║ title %boldmagenta[%boldwhite%-10section%boldmagenta]%reset %yellow%interval%boldred%duration%white%80_14┃ note',
|
|
50
50
|
'wrap_width' => 0,
|
|
51
51
|
'order' => 'asc'
|
|
52
52
|
},
|
|
@@ -63,8 +63,7 @@ module Doing
|
|
|
63
63
|
},
|
|
64
64
|
'recent' => {
|
|
65
65
|
'date_format' => '%_I:%M%P',
|
|
66
|
-
'template' => '%reset%cyan%shortdate %boldwhite%80║ title %
|
|
67
|
-
%yellow%interval%boldred%duration%dark%white%80_14┃ note',
|
|
66
|
+
'template' => '%reset%cyan%shortdate %boldwhite%80║ title %boldmagenta[%boldwhite%-10section%boldmagenta]%reset %yellow%interval%boldred%duration%white%80_14┃ note',
|
|
68
67
|
'wrap_width' => 88,
|
|
69
68
|
'count' => 10,
|
|
70
69
|
'order' => 'asc'
|
|
@@ -190,7 +189,7 @@ module Doing
|
|
|
190
189
|
## matched, first match wins)
|
|
191
190
|
## @return [Array] ordered array of resolved keys
|
|
192
191
|
##
|
|
193
|
-
def resolve_key_path(keypath, create: false)
|
|
192
|
+
def resolve_key_path(keypath, create: false, distance: 2)
|
|
194
193
|
cfg = @settings
|
|
195
194
|
real_path = []
|
|
196
195
|
unless keypath =~ /^[.*]?$/
|
|
@@ -198,16 +197,24 @@ module Doing
|
|
|
198
197
|
while paths.length.positive? && !cfg.nil?
|
|
199
198
|
path = paths.shift
|
|
200
199
|
new_cfg = nil
|
|
201
|
-
cfg.each do |key, val|
|
|
202
|
-
next unless key =~ path.to_rx(distance: 4)
|
|
203
200
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
201
|
+
if cfg.is_a?(Hash)
|
|
202
|
+
matches = cfg.select { |key, val| key =~ path.to_rx(distance: distance) }
|
|
203
|
+
if matches.count.positive?
|
|
204
|
+
shortest = matches.keys.group_by(&:length).min.last[0]
|
|
205
|
+
real_path << shortest
|
|
206
|
+
new_cfg = matches[shortest]
|
|
207
|
+
end
|
|
208
|
+
else
|
|
209
|
+
new_cfg = cfg
|
|
207
210
|
end
|
|
208
211
|
|
|
209
212
|
if new_cfg.nil?
|
|
210
|
-
|
|
213
|
+
if distance < 5 && !create
|
|
214
|
+
return resolve_key_path(keypath, create: false, distance: distance + 1)
|
|
215
|
+
else
|
|
216
|
+
return nil unless create
|
|
217
|
+
end
|
|
211
218
|
|
|
212
219
|
resolved = real_path.count.positive? ? "Resolved #{real_path.join('->')}, but " : ''
|
|
213
220
|
Doing.logger.log_now(:warn, "#{resolved}#{path} is unknown")
|
|
@@ -306,7 +313,7 @@ module Doing
|
|
|
306
313
|
|
|
307
314
|
@ignore_local = opt[:ignore_local] if opt[:ignore_local]
|
|
308
315
|
|
|
309
|
-
config = read_config.
|
|
316
|
+
config = read_config.clone
|
|
310
317
|
|
|
311
318
|
plugin_config = Util.deep_merge_hashes(DEFAULTS['plugins'], config['plugins'] || {})
|
|
312
319
|
|
|
@@ -314,7 +321,7 @@ module Doing
|
|
|
314
321
|
|
|
315
322
|
Plugins.plugins.each do |_type, plugins|
|
|
316
323
|
plugins.each do |title, plugin|
|
|
317
|
-
plugin_config[title] = plugin[:config] if plugin[:config]
|
|
324
|
+
plugin_config[title] = plugin[:config] if plugin[:config].good?
|
|
318
325
|
config['export_templates'][title] ||= nil if plugin[:templates] && !plugin[:templates].empty?
|
|
319
326
|
end
|
|
320
327
|
end
|
data/lib/doing/good.rb
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doing
|
|
4
|
+
# Object helpers
|
|
5
|
+
class ::Object
|
|
6
|
+
##
|
|
7
|
+
## Tests if object is nil or empty
|
|
8
|
+
##
|
|
9
|
+
## @return [Boolean] true if object is defined and
|
|
10
|
+
## has content
|
|
11
|
+
##
|
|
12
|
+
def good?
|
|
13
|
+
!nil? && !empty?
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class ::String
|
|
18
|
+
##
|
|
19
|
+
## Tests if object is nil or empty
|
|
20
|
+
##
|
|
21
|
+
## @return [Boolean] true if object is defined and
|
|
22
|
+
## has content
|
|
23
|
+
##
|
|
24
|
+
def good?
|
|
25
|
+
!strip.empty?
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class ::Array
|
|
30
|
+
##
|
|
31
|
+
## Tests if object is nil or empty
|
|
32
|
+
##
|
|
33
|
+
## @return [Boolean] true if object is defined and
|
|
34
|
+
## has content
|
|
35
|
+
##
|
|
36
|
+
def good?
|
|
37
|
+
!nil? && !empty?
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
class ::FalseClass
|
|
42
|
+
##
|
|
43
|
+
## Tests if object is nil or empty
|
|
44
|
+
##
|
|
45
|
+
## @return [Boolean] true if object is defined and
|
|
46
|
+
## has content
|
|
47
|
+
##
|
|
48
|
+
def good?
|
|
49
|
+
false
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class ::TrueClass
|
|
54
|
+
##
|
|
55
|
+
## Tests if object is nil or empty
|
|
56
|
+
##
|
|
57
|
+
## @return [Boolean] true if object is defined and
|
|
58
|
+
## has content
|
|
59
|
+
##
|
|
60
|
+
def good?
|
|
61
|
+
true
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
data/lib/doing/hash.rb
CHANGED
|
@@ -34,6 +34,10 @@ module Doing
|
|
|
34
34
|
replace deep_thaw
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
def clone
|
|
38
|
+
Marshal.load(Marshal.dump(self))
|
|
39
|
+
end
|
|
40
|
+
|
|
37
41
|
# Turn all keys into string
|
|
38
42
|
#
|
|
39
43
|
# Return a copy of the hash where all its keys are strings
|
|
@@ -48,8 +52,9 @@ module Doing
|
|
|
48
52
|
|
|
49
53
|
# Set a nested hash value using an array
|
|
50
54
|
#
|
|
51
|
-
# @example
|
|
52
|
-
#
|
|
55
|
+
# @example
|
|
56
|
+
# {}.deep_set(['one', 'two'], 'value')
|
|
57
|
+
# # => { 'one' => { 'two' => 'value' } }
|
|
53
58
|
#
|
|
54
59
|
# @param path [Array] key path
|
|
55
60
|
# @param value The value
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GLI
|
|
4
|
+
module Commands
|
|
5
|
+
# Help Command Monkeypatch for paginated output
|
|
6
|
+
class Help < Command
|
|
7
|
+
def show_help(global_options,options,arguments,out,error)
|
|
8
|
+
Doing::Pager.paginate = true
|
|
9
|
+
|
|
10
|
+
command_finder = HelpModules::CommandFinder.new(@app,arguments,error)
|
|
11
|
+
if options[:c]
|
|
12
|
+
help_output = HelpModules::HelpCompletionFormat.new(@app,command_finder,arguments).format
|
|
13
|
+
out.puts help_output unless help_output.nil?
|
|
14
|
+
elsif arguments.empty? || options[:c]
|
|
15
|
+
Doing::Pager.page HelpModules::GlobalHelpFormat.new(@app,@sorter,@text_wrapping_class).format
|
|
16
|
+
else
|
|
17
|
+
name = arguments.shift
|
|
18
|
+
command = command_finder.find_command(name)
|
|
19
|
+
unless command.nil?
|
|
20
|
+
Doing::Pager.page HelpModules::CommandHelpFormat.new(
|
|
21
|
+
command,
|
|
22
|
+
@app,
|
|
23
|
+
@sorter,
|
|
24
|
+
@synopsis_formatter_class,
|
|
25
|
+
@text_wrapping_class).format
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
data/lib/doing/hooks.rb
CHANGED
|
@@ -10,8 +10,8 @@ module Doing
|
|
|
10
10
|
post_local_config: [], # wwid
|
|
11
11
|
post_read: [], # wwid
|
|
12
12
|
pre_entry_add: [], # wwid, new_entry
|
|
13
|
-
post_entry_added: [], # wwid, new_entry
|
|
14
|
-
post_entry_updated: [], # wwid, entry
|
|
13
|
+
post_entry_added: [], # wwid, new_entry
|
|
14
|
+
post_entry_updated: [], # wwid, entry, old_entry
|
|
15
15
|
post_entry_removed: [], # wwid, entry.dup
|
|
16
16
|
pre_export: [], # wwid, format, entries
|
|
17
17
|
pre_write: [], # wwid, file
|
|
@@ -23,7 +23,11 @@ module Doing
|
|
|
23
23
|
|
|
24
24
|
# register hook(s) to be called later, public API
|
|
25
25
|
def self.register(event, priority: DEFAULT_PRIORITY, &block)
|
|
26
|
-
|
|
26
|
+
if event.is_a?(Array)
|
|
27
|
+
event.each { |ev| register_one(ev, priority_value(priority), &block) }
|
|
28
|
+
else
|
|
29
|
+
register_one(event, priority_value(priority), &block)
|
|
30
|
+
end
|
|
27
31
|
end
|
|
28
32
|
|
|
29
33
|
# Ensure the priority is a Fixnum
|
|
@@ -53,7 +57,7 @@ module Doing
|
|
|
53
57
|
|
|
54
58
|
def self.trigger(event, *args)
|
|
55
59
|
hooks = @registry[event]
|
|
56
|
-
return
|
|
60
|
+
return unless hooks.good?
|
|
57
61
|
|
|
58
62
|
# sort and call hooks according to priority and load order
|
|
59
63
|
hooks.sort_by { |h| @hook_priority[h] }.each do |hook|
|