doing 2.1.89 → 2.1.90
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 +2 -0
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +251 -0
- data/CHANGELOG.md +22 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +1 -1
- data/Rakefile +5 -3
- data/bin/commands/changes.rb +3 -1
- data/bin/commands/choose.rb +2 -0
- data/bin/commands/colors.rb +5 -3
- data/bin/commands/commands_accepting.rb +3 -3
- data/bin/commands/completion.rb +2 -1
- data/bin/commands/config.rb +8 -6
- data/bin/commands/done.rb +19 -12
- data/bin/commands/finish.rb +4 -2
- data/bin/commands/grep.rb +9 -5
- data/bin/commands/import.rb +14 -11
- data/bin/commands/install_fzf.rb +4 -2
- data/bin/commands/last.rb +31 -27
- data/bin/commands/meanwhile.rb +6 -2
- data/bin/commands/note.rb +6 -3
- data/bin/commands/now.rb +2 -0
- data/bin/commands/open.rb +6 -1
- data/bin/commands/plugins.rb +2 -0
- data/bin/commands/recent.rb +47 -33
- data/bin/commands/reset.rb +7 -3
- data/bin/commands/rotate.rb +6 -3
- data/bin/commands/sections.rb +3 -3
- data/bin/commands/select.rb +2 -0
- data/bin/commands/show.rb +24 -20
- data/bin/commands/since.rb +10 -3
- data/bin/commands/tag.rb +18 -16
- data/bin/commands/tag_dir.rb +5 -2
- data/bin/commands/tags.rb +17 -17
- data/bin/commands/template.rb +8 -2
- data/bin/commands/today.rb +10 -2
- data/bin/commands/undo.rb +2 -0
- data/bin/commands/update.rb +9 -7
- data/bin/commands/view.rb +11 -8
- data/bin/commands/views.rb +2 -0
- data/bin/commands/yesterday.rb +6 -1
- data/bin/doing +54 -57
- data/docs/doc/Array.html +3 -3
- data/docs/doc/BooleanTermParser/Clause.html +3 -3
- data/docs/doc/BooleanTermParser/Operator.html +3 -3
- data/docs/doc/BooleanTermParser/Query.html +3 -3
- data/docs/doc/BooleanTermParser/QueryParser.html +3 -3
- data/docs/doc/BooleanTermParser/QueryTransformer.html +3 -3
- data/docs/doc/BooleanTermParser.html +3 -3
- data/docs/doc/Doing/ArrayCleanup.html +3 -3
- data/docs/doc/Doing/ArrayNestedHash.html +3 -3
- data/docs/doc/Doing/ArrayTags.html +9 -9
- data/docs/doc/Doing/ByDayExport.html +3 -3
- data/docs/doc/Doing/CSVExport.html +4 -4
- data/docs/doc/Doing/CalendarImport.html +4 -4
- data/docs/doc/Doing/Change.html +3 -3
- data/docs/doc/Doing/Changes.html +3 -3
- data/docs/doc/Doing/ChronifyArray.html +3 -3
- data/docs/doc/Doing/ChronifyNumeric.html +3 -3
- data/docs/doc/Doing/ChronifyString.html +6 -6
- data/docs/doc/Doing/Color.html +88 -47
- data/docs/doc/Doing/Completion/BashCompletions.html +3 -3
- data/docs/doc/Doing/Completion/FigCompletions.html +3 -3
- data/docs/doc/Doing/Completion/FishCompletions.html +3 -3
- data/docs/doc/Doing/Completion/StringUtils.html +3 -3
- data/docs/doc/Doing/Completion/ZshCompletions.html +3 -3
- data/docs/doc/Doing/Completion.html +5 -5
- data/docs/doc/Doing/Configuration.html +6 -6
- data/docs/doc/Doing/DayOneRenderer.html +3 -3
- data/docs/doc/Doing/DayoneExport.html +4 -4
- data/docs/doc/Doing/DoingExport.html +5 -5
- data/docs/doc/Doing/DoingImport.html +4 -4
- data/docs/doc/Doing/Entry.html +3 -3
- data/docs/doc/Doing/Errors/DoingNoTraceError.html +3 -3
- data/docs/doc/Doing/Errors/DoingRuntimeError.html +3 -3
- data/docs/doc/Doing/Errors/DoingStandardError.html +3 -3
- data/docs/doc/Doing/Errors/EmptyInput.html +3 -3
- data/docs/doc/Doing/Errors/HistoryLimitError.html +3 -3
- data/docs/doc/Doing/Errors/InvalidPlugin.html +3 -3
- data/docs/doc/Doing/Errors/MissingBackupFile.html +3 -3
- data/docs/doc/Doing/Errors/NoResults.html +3 -3
- data/docs/doc/Doing/Errors/PluginException.html +3 -3
- data/docs/doc/Doing/Errors/UserCancelled.html +3 -3
- data/docs/doc/Doing/Errors/WrongCommand.html +3 -3
- data/docs/doc/Doing/Errors.html +3 -3
- data/docs/doc/Doing/HTMLExport.html +4 -4
- data/docs/doc/Doing/Hooks.html +3 -16
- data/docs/doc/Doing/Item.html +4 -4
- data/docs/doc/Doing/ItemDates.html +3 -3
- data/docs/doc/Doing/ItemQuery.html +3 -3
- data/docs/doc/Doing/ItemState.html +3 -3
- data/docs/doc/Doing/ItemTags.html +3 -3
- data/docs/doc/Doing/Items.html +3 -3
- data/docs/doc/Doing/JSONExport.html +4 -4
- data/docs/doc/Doing/JSONImport.html +4 -4
- data/docs/doc/Doing/Logger.html +183 -3
- data/docs/doc/Doing/MarkdownExport.html +4 -4
- data/docs/doc/Doing/Note.html +3 -3
- data/docs/doc/Doing/Pager.html +54 -58
- data/docs/doc/Doing/Plugins.html +3 -3
- data/docs/doc/Doing/Prompt.html +4 -4
- data/docs/doc/Doing/PromptChoose.html +3 -3
- data/docs/doc/Doing/PromptFZF.html +3 -3
- data/docs/doc/Doing/PromptInput.html +3 -3
- data/docs/doc/Doing/PromptSTD.html +3 -3
- data/docs/doc/Doing/PromptYN.html +3 -3
- data/docs/doc/Doing/Section.html +3 -3
- data/docs/doc/Doing/StringHighlight.html +3 -3
- data/docs/doc/Doing/StringNormalize.html +3 -3
- data/docs/doc/Doing/StringQuery.html +4 -4
- data/docs/doc/Doing/StringTags.html +3 -3
- data/docs/doc/Doing/StringTransform.html +3 -3
- data/docs/doc/Doing/StringTruncate.html +3 -3
- data/docs/doc/Doing/StringURL.html +3 -3
- data/docs/doc/Doing/SymbolNormalize.html +5 -5
- data/docs/doc/Doing/TaskPaperExport.html +4 -4
- data/docs/doc/Doing/TemplateExport.html +5 -5
- data/docs/doc/Doing/TemplateString.html +7 -7
- data/docs/doc/Doing/TimingImport.html +4 -4
- data/docs/doc/Doing/Types.html +3 -3
- data/docs/doc/Doing/Util/Backup.html +4 -17
- data/docs/doc/Doing/Util.html +56 -61
- data/docs/doc/Doing/Version.html +3 -3
- data/docs/doc/Doing/WWID.html +6 -4
- data/docs/doc/Doing.html +4 -4
- data/docs/doc/FalseClass.html +3 -3
- data/docs/doc/GLI/Commands/Help.html +5 -5
- data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +3 -3
- data/docs/doc/GLI/Commands.html +3 -3
- data/docs/doc/GLI.html +3 -3
- data/docs/doc/Hash.html +4 -4
- data/docs/doc/Numeric.html +3 -3
- data/docs/doc/Object.html +3 -3
- data/docs/doc/PhraseParser/Operator.html +3 -3
- data/docs/doc/PhraseParser/PhraseClause.html +3 -3
- data/docs/doc/PhraseParser/Query.html +3 -3
- data/docs/doc/PhraseParser/QueryParser.html +3 -3
- data/docs/doc/PhraseParser/QueryTransformer.html +3 -3
- data/docs/doc/PhraseParser/TermClause.html +3 -3
- data/docs/doc/PhraseParser.html +3 -3
- data/docs/doc/Status.html +3 -3
- data/docs/doc/String.html +51 -5
- data/docs/doc/Symbol.html +3 -3
- data/docs/doc/Time.html +3 -3
- data/docs/doc/TrueClass.html +3 -3
- data/docs/doc/_index.html +4 -4
- data/docs/doc/class_list.html +6 -3
- data/docs/doc/css/full_list.css +3 -3
- data/docs/doc/css/style.css +6 -0
- data/docs/doc/file.README.html +3 -3
- data/docs/doc/file_list.html +5 -2
- data/docs/doc/frames.html +1 -1
- data/docs/doc/index.html +3 -3
- data/docs/doc/js/app.js +294 -264
- data/docs/doc/js/full_list.js +30 -4
- data/docs/doc/method_list.html +443 -392
- data/docs/doc/top-level-namespace.html +3 -3
- data/doing.gemspec +2 -0
- data/doing.rdoc +1 -1
- data/example_plugin.rb +1 -4
- data/lib/doing/add_options.rb +2 -2
- data/lib/doing/array/cleanup.rb +2 -0
- data/lib/doing/array/nested_hash.rb +2 -0
- data/lib/doing/boolean_term_parser.rb +3 -3
- data/lib/doing/changelog/changes.rb +4 -5
- data/lib/doing/changelog/version.rb +8 -11
- data/lib/doing/chronify/array.rb +4 -4
- data/lib/doing/chronify/string.rb +5 -4
- data/lib/doing/cli_status.rb +7 -2
- data/lib/doing/colors.rb +93 -51
- data/lib/doing/completion/bash_completion.rb +36 -39
- data/lib/doing/completion/completion_string.rb +2 -1
- data/lib/doing/completion/fig_completion.rb +33 -33
- data/lib/doing/completion/fish_completion.rb +22 -23
- data/lib/doing/completion/zsh_completion.rb +5 -5
- data/lib/doing/completion.rb +7 -4
- data/lib/doing/configuration.rb +21 -13
- data/lib/doing/errors.rb +1 -4
- data/lib/doing/good.rb +1 -1
- data/lib/doing/hash.rb +4 -4
- data/lib/doing/help_monkey_patch.rb +1 -1
- data/lib/doing/hooks.rb +6 -2
- data/lib/doing/item/dates.rb +3 -1
- data/lib/doing/item/query.rb +10 -10
- data/lib/doing/item/state.rb +2 -0
- data/lib/doing/logger.rb +113 -45
- data/lib/doing/markdown_document_listener.rb +25 -25
- data/lib/doing/normalize.rb +1 -1
- data/lib/doing/pager.rb +73 -29
- data/lib/doing/plugin_manager.rb +4 -5
- data/lib/doing/plugins/export/byday.rb +1 -1
- data/lib/doing/plugins/export/dayone_export.rb +28 -27
- data/lib/doing/plugins/export/doing_export.rb +1 -1
- data/lib/doing/plugins/export/html_export.rb +3 -3
- data/lib/doing/plugins/export/json_export.rb +4 -5
- data/lib/doing/plugins/export/markdown_export.rb +10 -2
- data/lib/doing/plugins/export/taskpaper_export.rb +1 -0
- data/lib/doing/plugins/export/template_export.rb +110 -107
- data/lib/doing/plugins/import/calendar_import.rb +1 -1
- data/lib/doing/plugins/import/doing_import.rb +2 -2
- data/lib/doing/plugins/import/timing_import.rb +3 -3
- data/lib/doing/prompt/choose.rb +5 -6
- data/lib/doing/prompt/fzf.rb +3 -2
- data/lib/doing/prompt/input.rb +7 -6
- data/lib/doing/prompt/yn.rb +9 -11
- data/lib/doing/string/tags.rb +7 -4
- data/lib/doing/string/transform.rb +15 -10
- data/lib/doing/string/truncate.rb +1 -0
- data/lib/doing/string/url.rb +1 -1
- data/lib/doing/template_string.rb +13 -9
- data/lib/doing/time.rb +4 -2
- data/lib/doing/util.rb +12 -11
- data/lib/doing/util_backup.rb +29 -26
- data/lib/doing/version.rb +3 -1
- data/lib/doing/wwid/display.rb +182 -151
- data/lib/doing/wwid/editor.rb +13 -12
- data/lib/doing/wwid/filetools.rb +13 -11
- data/lib/doing/wwid/filter.rb +41 -40
- data/lib/doing/wwid/guess.rb +6 -8
- data/lib/doing/wwid/interactive.rb +9 -9
- data/lib/doing/wwid/modify.rb +53 -53
- data/lib/doing/wwid/timers.rb +4 -5
- data/lib/doing/wwid/wwid.rb +0 -0
- data/lib/doing/wwid/wwidutil.rb +8 -10
- data/lib/examples/commands/wiki.rb +2 -0
- data/lib/examples/plugins/capture_thing_import.rb +1 -1
- data/lib/examples/plugins/say_export.rb +1 -2
- data/lib/examples/plugins/wiki_export/wiki_export.rb +3 -4
- data/lib/helpers/fzf/test/test_go.rb +5 -5
- data/lib/helpers/threaded_tests.rb +20 -20
- data/lib/helpers/threaded_tests_string.rb +2 -0
- data/rdoc_to_mmd.rb +5 -4
- data/rdocfixer.rb +1 -2
- data/scripts/deploy.rb +3 -4
- data/scripts/generate_bash_completions.rb +40 -43
- data/scripts/generate_fish_completions.rb +17 -15
- data/scripts/generate_zsh_completions.rb +9 -7
- data/scripts/setting_replace.rb +1 -0
- data/scripts/sort_commands.rb +4 -2
- data/yard_templates/default/method_details/setup.rb +3 -1
- metadata +3 -1
data/lib/doing/wwid/filter.rb
CHANGED
|
@@ -13,7 +13,9 @@ module Doing
|
|
|
13
13
|
# @return [Items] Filtered Items array
|
|
14
14
|
#
|
|
15
15
|
def fuzzy_filter_items(items, query, case_type: :smart)
|
|
16
|
-
scannable = items.map.with_index
|
|
16
|
+
scannable = items.map.with_index do |item, idx|
|
|
17
|
+
"#{item.title} #{item.note.join(' ')}".gsub(/[|*?!]/, '') + "|#{idx}"
|
|
18
|
+
end.join("\n")
|
|
17
19
|
|
|
18
20
|
res = `echo #{Shellwords.escape(scannable)}|#{Prompt.fzf} #{fuzzy_filter_args(query, case_type).join(' ')}`
|
|
19
21
|
selected = Items.new
|
|
@@ -59,59 +61,58 @@ module Doing
|
|
|
59
61
|
## @option opt [Array] :val (nil) Array of tag value queries
|
|
60
62
|
##
|
|
61
63
|
def filter_items(items = Items.new, opt: {})
|
|
62
|
-
logger.
|
|
63
|
-
|
|
64
|
+
logger.measure(:filter_items) do
|
|
65
|
+
time_rx = /^(\d{1,2}+(:\d{1,2}+)?( *(am|pm))?|midnight|noon)$/i
|
|
64
66
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
if items.nil? || items.empty?
|
|
68
|
+
section = !opt[:section] || opt[:section].empty? ? 'All' : guess_section(opt[:section])
|
|
69
|
+
if section.is_a?(Array)
|
|
70
|
+
section.each do |s|
|
|
71
|
+
s = s[0] if s.is_a?(Array)
|
|
72
|
+
items.concat(s =~ /^all$/i ? @content.clone : @content.in_section(s))
|
|
73
|
+
end
|
|
74
|
+
else
|
|
75
|
+
items = section =~ /^all$/i ? @content.clone : @content.in_section(section)
|
|
71
76
|
end
|
|
72
|
-
else
|
|
73
|
-
items = section =~ /^all$/i ? @content.clone : @content.in_section(section)
|
|
74
77
|
end
|
|
75
|
-
end
|
|
76
78
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
unless opt[:time_filter]
|
|
80
|
+
opt[:time_filter] = [nil, nil]
|
|
81
|
+
if opt[:from] && !opt[:date_filter]
|
|
82
|
+
if opt[:from][0].is_a?(String) && opt[:from][0] =~ time_rx
|
|
83
|
+
opt[:time_filter] = opt[:from]
|
|
84
|
+
elsif opt[:from][0].is_a?(Time)
|
|
85
|
+
opt[:date_filter] = opt[:from]
|
|
86
|
+
end
|
|
84
87
|
end
|
|
85
88
|
end
|
|
86
|
-
end
|
|
87
89
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if opt[:after].is_a?(String) && opt[:after] =~ time_rx
|
|
94
|
-
opt[:time_filter][0] = opt[:after]
|
|
95
|
-
opt[:after] = nil
|
|
96
|
-
end
|
|
90
|
+
if opt[:before].is_a?(String) && opt[:before] =~ time_rx
|
|
91
|
+
opt[:time_filter][1] = opt[:before]
|
|
92
|
+
opt[:before] = nil
|
|
93
|
+
end
|
|
97
94
|
|
|
98
|
-
|
|
95
|
+
if opt[:after].is_a?(String) && opt[:after] =~ time_rx
|
|
96
|
+
opt[:time_filter][0] = opt[:after]
|
|
97
|
+
opt[:after] = nil
|
|
98
|
+
end
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
items.sort_by! { |item| [item.date, item.title.downcase] }.reverse
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
filtered_items = items.select { |item| item.keep_item?(opt) }
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
count = opt[:count].to_i&.positive? ? opt[:count].to_i : filtered_items.count
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
output.concat(filtered_items.slice(0, count).reverse)
|
|
108
|
-
else
|
|
109
|
-
output.concat(filtered_items.reverse.slice(0, count))
|
|
110
|
-
end
|
|
106
|
+
output = Items.new
|
|
111
107
|
|
|
112
|
-
|
|
108
|
+
if opt[:age] && opt[:age].normalize_age == :oldest
|
|
109
|
+
output.concat(filtered_items.slice(0, count).reverse)
|
|
110
|
+
else
|
|
111
|
+
output.concat(filtered_items.reverse.slice(0, count))
|
|
112
|
+
end
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
output
|
|
115
|
+
end
|
|
115
116
|
end
|
|
116
117
|
end
|
|
117
118
|
end
|
data/lib/doing/wwid/guess.rb
CHANGED
|
@@ -9,9 +9,7 @@ module Doing
|
|
|
9
9
|
## @param guessed [Boolean] already guessed and failed
|
|
10
10
|
##
|
|
11
11
|
def guess_section(frag, guessed: false, suggest: false)
|
|
12
|
-
if frag.is_a?(Array) && frag.count == 1
|
|
13
|
-
frag = frag[0]
|
|
14
|
-
end
|
|
12
|
+
frag = frag[0] if frag.is_a?(Array) && frag.count == 1
|
|
15
13
|
|
|
16
14
|
frag = frag.split(/ *, */).map(&:strip) if frag.is_a?(String) && frag =~ /,/
|
|
17
15
|
|
|
@@ -25,7 +23,7 @@ module Doing
|
|
|
25
23
|
|
|
26
24
|
found = @content.guess_section(frag, distance: 2)
|
|
27
25
|
|
|
28
|
-
section = found
|
|
26
|
+
section = found&.title
|
|
29
27
|
|
|
30
28
|
if section && suggest
|
|
31
29
|
Doing.logger.debug('Match:', %(Assuming "#{section}" from "#{frag}"))
|
|
@@ -38,12 +36,12 @@ module Doing
|
|
|
38
36
|
prompt = Color.template("{bw}Did you mean `{xy}doing {by}view {xy}#{alt}`{bw}?{x}")
|
|
39
37
|
meant_view = Prompt.yn(prompt, default_response: 'n')
|
|
40
38
|
|
|
41
|
-
msg = format('%<y>srun with `%<w>sdoing view %<alt>s%<y>s`', w: boldwhite, y: yellow, alt: alt)
|
|
39
|
+
msg = format('%<y>srun with `%<w>sdoing view %<alt>s%<y>s`', w: Color.boldwhite, y: Color.yellow, alt: alt)
|
|
42
40
|
raise Errors::WrongCommand.new(msg, topic: 'Try again:') if meant_view
|
|
43
41
|
|
|
44
42
|
end
|
|
45
43
|
|
|
46
|
-
res = Prompt.yn("#{boldwhite}Section #{
|
|
44
|
+
res = Prompt.yn("#{Color.boldwhite}Section #{Color.yellow(frag)}#{Color.boldwhite} not found, create it", default_response: 'n')
|
|
47
45
|
|
|
48
46
|
if res
|
|
49
47
|
@content.add_section(frag.cap_first, log: true)
|
|
@@ -53,7 +51,7 @@ module Doing
|
|
|
53
51
|
|
|
54
52
|
raise Errors::InvalidSection.new("unknown section #{frag.bold.white}", topic: 'Missing:')
|
|
55
53
|
end
|
|
56
|
-
section
|
|
54
|
+
section&.cap_first
|
|
57
55
|
end
|
|
58
56
|
|
|
59
57
|
##
|
|
@@ -82,7 +80,7 @@ module Doing
|
|
|
82
80
|
meant_view = Prompt.yn(prompt, default_response: 'n')
|
|
83
81
|
|
|
84
82
|
if meant_view
|
|
85
|
-
msg = format('%<y>srun with `%<w>sdoing show %<alt>s%<y>s`', w: boldwhite, y: yellow, alt: alt)
|
|
83
|
+
msg = format('%<y>srun with `%<w>sdoing show %<alt>s%<y>s`', w: Color.boldwhite, y: Color.yellow, alt: alt)
|
|
86
84
|
raise Errors::WrongCommand.new(msg, topic: 'Try again:')
|
|
87
85
|
|
|
88
86
|
end
|
|
@@ -25,14 +25,14 @@ module Doing
|
|
|
25
25
|
opt[:query] = "!#{opt[:query]}" if opt[:query] && opt[:not]
|
|
26
26
|
opt[:multiple] = true
|
|
27
27
|
opt[:show_if_single] = true
|
|
28
|
-
filter_options = %i[after before case date_filter from fuzzy not search section val].each_with_object({})
|
|
28
|
+
filter_options = %i[after before case date_filter from fuzzy not search section val].each_with_object({}) do
|
|
29
29
|
|k, hsh| hsh[k] = opt[k]
|
|
30
|
-
|
|
30
|
+
end
|
|
31
31
|
items = filter_items(Items.new, opt: filter_options)
|
|
32
32
|
|
|
33
|
-
menu_options = %i[search query exact multiple show_if_single menu sort case].each_with_object({})
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
menu_options = %i[search query exact multiple show_if_single menu sort case].each_with_object({}) do |k, hsh|
|
|
34
|
+
hsh[k] = opt[k]
|
|
35
|
+
end
|
|
36
36
|
include_section = (opt[:section].is_a?(Array) && opt[:section][0] =~ /^all$/i) || (opt[:section].is_a?(String) && opt[:section] =~ /^all$/i)
|
|
37
37
|
|
|
38
38
|
selection = Prompt.choose_from_items(items, include_section: include_section, **menu_options)
|
|
@@ -118,7 +118,7 @@ module Doing
|
|
|
118
118
|
tags = type == 'add' ? all_tags(@content) : all_tags(items)
|
|
119
119
|
|
|
120
120
|
add_msg = type == 'add' ? ', include values with tag(value)' : ''
|
|
121
|
-
puts "#{yellow}Separate multiple tags with spaces, hit tab to complete known tags#{add_msg}"
|
|
121
|
+
puts "#{Color.yellow}Separate multiple tags with spaces, hit tab to complete known tags#{add_msg}"
|
|
122
122
|
puts "#{boldgreen}Available tags: #{boldwhite}#{tags.sort.map(&:add_at).join(', ')}" if type == 'remove'
|
|
123
123
|
tag = Prompt.read_line(prompt: "Tags to #{type}", completions: tags)
|
|
124
124
|
|
|
@@ -255,8 +255,8 @@ module Doing
|
|
|
255
255
|
|
|
256
256
|
if opt[:editor]
|
|
257
257
|
sleep 2 # This seems to be necessary between running fzf
|
|
258
|
-
|
|
259
|
-
|
|
258
|
+
# and forking the editor, otherwise vim gets all
|
|
259
|
+
# screwy and I can't figure out why
|
|
260
260
|
edit_items(items) # hooked
|
|
261
261
|
|
|
262
262
|
write(@doing_file)
|
|
@@ -367,7 +367,7 @@ module Doing
|
|
|
367
367
|
if max_elapsed.positive? && (elapsed > max_elapsed)
|
|
368
368
|
puts boldwhite(title) if title
|
|
369
369
|
human = elapsed.time_string(format: :natural)
|
|
370
|
-
res = Prompt.yn(yellow("Did this entry actually take #{human}"), default_response: true)
|
|
370
|
+
res = Prompt.yn(Color.yellow("Did this entry actually take #{human}"), default_response: true)
|
|
371
371
|
unless res
|
|
372
372
|
new_elapsed = Prompt.enter_text('How long did it take?').chronify_qty
|
|
373
373
|
raise InvalidTimeExpression, 'Unrecognized time span entry' unless new_elapsed.positive?
|
data/lib/doing/wwid/modify.rb
CHANGED
|
@@ -19,7 +19,7 @@ module Doing
|
|
|
19
19
|
opt ||= {}
|
|
20
20
|
section ||= Doing.setting('current_section')
|
|
21
21
|
@content.add_section(section, log: false)
|
|
22
|
-
opt[:back] ||= opt[:date]
|
|
22
|
+
opt[:back] ||= opt[:date] || Time.now
|
|
23
23
|
opt[:date] ||= Time.now
|
|
24
24
|
note = Note.new
|
|
25
25
|
opt[:timed] ||= false
|
|
@@ -78,8 +78,8 @@ module Doing
|
|
|
78
78
|
if finish_date
|
|
79
79
|
item.tag('done', remove: true)
|
|
80
80
|
item.tag('done', value: finish_date.strftime('%F %R'))
|
|
81
|
-
|
|
82
|
-
item.tag('done', remove: true)
|
|
81
|
+
elsif resume
|
|
82
|
+
item.tag('done', remove: true)
|
|
83
83
|
end
|
|
84
84
|
logger.info('Reset:', %(Reset #{resume ? 'and resumed ' : ''} "#{item.title}" in #{item.section}))
|
|
85
85
|
item
|
|
@@ -118,7 +118,7 @@ module Doing
|
|
|
118
118
|
note = opt[:note] || Note.new
|
|
119
119
|
|
|
120
120
|
if opt[:editor]
|
|
121
|
-
start = opt[:date]
|
|
121
|
+
start = opt[:date] || Time.now
|
|
122
122
|
to_edit = "#{start.strftime('%F %R')} | #{title}"
|
|
123
123
|
to_edit += "\n#{note.strip_lines.join("\n")}" unless note.empty?
|
|
124
124
|
new_item = fork_editor(to_edit)
|
|
@@ -168,7 +168,8 @@ module Doing
|
|
|
168
168
|
##
|
|
169
169
|
## @see #filter_items
|
|
170
170
|
##
|
|
171
|
-
|
|
171
|
+
# hooked
|
|
172
|
+
def tag_last(opt)
|
|
172
173
|
opt ||= {}
|
|
173
174
|
opt[:count] ||= 1
|
|
174
175
|
opt[:archive] ||= false
|
|
@@ -186,11 +187,11 @@ module Doing
|
|
|
186
187
|
|
|
187
188
|
if opt[:interactive]
|
|
188
189
|
items = Prompt.choose_from_items(items, include_section: opt[:section] =~ /^all$/i, menu: true,
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
190
|
+
header: '',
|
|
191
|
+
prompt: 'Select entries to tag > ',
|
|
192
|
+
multiple: true,
|
|
193
|
+
sort: true,
|
|
194
|
+
show_if_single: true)
|
|
194
195
|
|
|
195
196
|
raise NoResults, 'no items selected' if items.empty?
|
|
196
197
|
|
|
@@ -201,9 +202,9 @@ module Doing
|
|
|
201
202
|
if opt[:tags].empty? && !opt[:autotag]
|
|
202
203
|
completions = opt[:remove] ? all_tags(items) : all_tags(@content)
|
|
203
204
|
if opt[:remove]
|
|
204
|
-
puts "#{yellow}Available tags: #{boldwhite}#{completions.map(&:add_at).join(', ')}"
|
|
205
|
+
puts "#{Color.yellow}Available tags: #{Color.boldwhite}#{completions.map(&:add_at).join(', ')}"
|
|
205
206
|
else
|
|
206
|
-
puts "#{yellow}Use tab to complete known tags"
|
|
207
|
+
puts "#{Color.yellow}Use tab to complete known tags"
|
|
207
208
|
end
|
|
208
209
|
opt[:tags] = Doing::Prompt.read_line(prompt: "Enter tag(s) to #{opt[:remove] ? 'remove' : 'add'}",
|
|
209
210
|
completions: completions,
|
|
@@ -267,10 +268,10 @@ module Doing
|
|
|
267
268
|
if max_elapsed.positive? && (elapsed > max_elapsed) && !opt[:took]
|
|
268
269
|
puts boldwhite(item.title)
|
|
269
270
|
human = elapsed.time_string(format: :natural)
|
|
270
|
-
res = Prompt.yn(yellow("Did this actually take #{human}"), default_response: true)
|
|
271
|
+
res = Prompt.yn(Color.yellow("Did this actually take #{human}"), default_response: true)
|
|
271
272
|
unless res
|
|
272
273
|
new_elapsed = Prompt.enter_text('How long did it take?').chronify_qty
|
|
273
|
-
raise InvalidTimeExpression, 'Unrecognized time span entry' unless new_elapsed
|
|
274
|
+
raise InvalidTimeExpression, 'Unrecognized time span entry' unless new_elapsed.positive?
|
|
274
275
|
|
|
275
276
|
opt[:took] = new_elapsed
|
|
276
277
|
done_date = item.calculate_end_date(opt) if opt[:took]
|
|
@@ -289,7 +290,8 @@ module Doing
|
|
|
289
290
|
end
|
|
290
291
|
old_title = item.title.dup
|
|
291
292
|
force = opt[:value].nil? ? false : true
|
|
292
|
-
item.title.tag!(tag, remove: opt[:remove], rename_to: rename_to, regex: opt[:regex], value: opt[:value],
|
|
293
|
+
item.title.tag!(tag, remove: opt[:remove], rename_to: rename_to, regex: opt[:regex], value: opt[:value],
|
|
294
|
+
force: force)
|
|
293
295
|
if old_title != item.title
|
|
294
296
|
removed << tag
|
|
295
297
|
added << rename_to if rename_to
|
|
@@ -310,7 +312,7 @@ module Doing
|
|
|
310
312
|
|
|
311
313
|
item.note.add(opt[:note]) if opt[:note]
|
|
312
314
|
|
|
313
|
-
if opt[:archive] && opt[:section] != 'Archive' &&
|
|
315
|
+
if opt[:archive] && opt[:section] != 'Archive' && opt[:count].positive?
|
|
314
316
|
item.move_to('Archive', label: true)
|
|
315
317
|
elsif opt[:archive] && opt[:count].zero?
|
|
316
318
|
logger.warn('Skipped:', 'Archiving is skipped when operating on all entries')
|
|
@@ -376,7 +378,6 @@ module Doing
|
|
|
376
378
|
Hooks.trigger :post_entry_updated, self, item, old_item
|
|
377
379
|
end
|
|
378
380
|
|
|
379
|
-
|
|
380
381
|
logger.debug('Skipped:', "No active @#{tag} tasks found.") if found_items.zero?
|
|
381
382
|
|
|
382
383
|
if opt[:new_item]
|
|
@@ -431,12 +432,13 @@ module Doing
|
|
|
431
432
|
|
|
432
433
|
destination = guess_section(destination)
|
|
433
434
|
|
|
434
|
-
|
|
435
|
-
do_archive(section, destination, { count: count, tags: tags, bool: bool, search: options[:search], label: options[:label], before: options[:before], after: options[:after], from: options[:from] })
|
|
436
|
-
write(doing_file)
|
|
437
|
-
else
|
|
435
|
+
unless @content.section?(destination) && (@content.section?(section) || archive_all)
|
|
438
436
|
raise InvalidArgument, 'Either source or destination does not exist'
|
|
439
437
|
end
|
|
438
|
+
|
|
439
|
+
do_archive(section, destination,
|
|
440
|
+
{ count: count, tags: tags, bool: bool, search: options[:search], label: options[:label], before: options[:before], after: options[:after], from: options[:from] })
|
|
441
|
+
write(doing_file)
|
|
440
442
|
end
|
|
441
443
|
|
|
442
444
|
##
|
|
@@ -483,43 +485,41 @@ module Doing
|
|
|
483
485
|
end
|
|
484
486
|
end
|
|
485
487
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
next unless tag =~ /\S+:\S+/
|
|
488
|
+
Doing.setting('autotag.transform')&.each do |tag|
|
|
489
|
+
next unless tag =~ /\S+:\S+/
|
|
489
490
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
491
|
+
if tag =~ /::/
|
|
492
|
+
rx, r = tag.split(/::/)
|
|
493
|
+
else
|
|
494
|
+
rx, r = tag.split(/:/)
|
|
495
|
+
end
|
|
495
496
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
497
|
+
flag_rx = %r{/(r+)$}
|
|
498
|
+
if r =~ flag_rx
|
|
499
|
+
flags = r.match(flag_rx)[1].split(//)
|
|
500
|
+
r.sub!(flag_rx, '')
|
|
501
|
+
end
|
|
502
|
+
r.gsub!(/\$/, '\\')
|
|
503
|
+
rx.sub!(/^@?/, '@')
|
|
504
|
+
regex = Regexp.new("(?<= |\\A)#{rx}(?= |\\Z)")
|
|
504
505
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
506
|
+
text.sub!(regex) do
|
|
507
|
+
m = Regexp.last_match
|
|
508
|
+
new_tag = r
|
|
508
509
|
|
|
509
|
-
|
|
510
|
-
|
|
510
|
+
m.to_a.slice(1, m.length - 1).each_with_index do |v, idx|
|
|
511
|
+
next if v.nil?
|
|
511
512
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
end
|
|
513
|
+
new_tag.gsub!("\\#{idx + 1}", v)
|
|
514
|
+
end
|
|
515
|
+
# Replace original tag if /r
|
|
516
|
+
if flags&.include?('r')
|
|
517
|
+
tagged[:replaced].concat(new_tag.split(/ /).map { |t| t.sub(/^@/, '') })
|
|
518
|
+
new_tag.split(/ /).map { |t| t.sub(/^@?/, '@') }.join(' ')
|
|
519
|
+
else
|
|
520
|
+
tagged[:transformed].concat(new_tag.split(/ /).map { |t| t.sub(/^@/, '') })
|
|
521
|
+
tagged[:transformed] = tagged[:transformed].uniq
|
|
522
|
+
m[0]
|
|
523
523
|
end
|
|
524
524
|
end
|
|
525
525
|
end
|
data/lib/doing/wwid/timers.rb
CHANGED
|
@@ -69,13 +69,11 @@ EOTAIL
|
|
|
69
69
|
pad = sorted_tags_data.map { |k, _| k }.group_by(&:size).max.last[0].length
|
|
70
70
|
pad = 7 if pad < 7
|
|
71
71
|
output = <<~EOHEADER
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
| #{' ' * (pad - 7)}project | time |
|
|
73
|
+
| #{'-' * (pad - 1)}: | :------- |
|
|
74
74
|
EOHEADER
|
|
75
75
|
sorted_tags_data.reverse.each do |k, v|
|
|
76
|
-
if v.positive?
|
|
77
|
-
output += "| #{' ' * (pad - k.length)}#{k} | #{v.time_string(format: :clock)} |\n"
|
|
78
|
-
end
|
|
76
|
+
output += "| #{' ' * (pad - k.length)}#{k} | #{v.time_string(format: :clock)} |\n" if v.positive?
|
|
79
77
|
end
|
|
80
78
|
tail = '[Tag Totals]'
|
|
81
79
|
output + tail
|
|
@@ -173,6 +171,7 @@ EOTAIL
|
|
|
173
171
|
def record_tag_times(item, seconds)
|
|
174
172
|
item_hash = "#{item.date.strftime('%s')}#{item.title}#{item.section}"
|
|
175
173
|
return if @recorded_items.include?(item_hash)
|
|
174
|
+
|
|
176
175
|
item.title.scan(/(?mi)@(\S+?)(\(.*\))?(?=\s|$)/).each do |m|
|
|
177
176
|
k = m[0] == 'done' ? 'All' : m[0].downcase
|
|
178
177
|
if @timers.key?(k)
|
data/lib/doing/wwid/wwid.rb
CHANGED
|
File without changes
|
data/lib/doing/wwid/wwidutil.rb
CHANGED
|
@@ -32,7 +32,7 @@ module Doing
|
|
|
32
32
|
##
|
|
33
33
|
def import(paths, opt)
|
|
34
34
|
opt ||= {}
|
|
35
|
-
Plugins.plugins[:import].
|
|
35
|
+
Plugins.plugins[:import].each_value do |options|
|
|
36
36
|
next unless opt[:type] =~ /^(#{options[:trigger].normalize_trigger})$/i
|
|
37
37
|
|
|
38
38
|
if paths.count.positive?
|
|
@@ -54,17 +54,15 @@ module Doing
|
|
|
54
54
|
## alternative config file
|
|
55
55
|
##
|
|
56
56
|
def configure(filename = nil)
|
|
57
|
-
logger.
|
|
57
|
+
logger.measure(:configure) do
|
|
58
|
+
if filename
|
|
59
|
+
Doing.config_with(filename, { ignore_local: true })
|
|
60
|
+
elsif ENV['DOING_CONFIG']
|
|
61
|
+
Doing.config_with(ENV['DOING_CONFIG'], { ignore_local: true })
|
|
62
|
+
end
|
|
58
63
|
|
|
59
|
-
|
|
60
|
-
Doing.config_with(filename, { ignore_local: true })
|
|
61
|
-
elsif ENV['DOING_CONFIG']
|
|
62
|
-
Doing.config_with(ENV['DOING_CONFIG'], { ignore_local: true })
|
|
64
|
+
Doing.set('backup_dir', ENV['DOING_BACKUP_DIR']) if ENV['DOING_BACKUP_DIR']
|
|
63
65
|
end
|
|
64
|
-
|
|
65
|
-
logger.benchmark(:configure, :finish)
|
|
66
|
-
|
|
67
|
-
Doing.set('backup_dir', ENV['DOING_BACKUP_DIR']) if ENV['DOING_BACKUP_DIR']
|
|
68
66
|
end
|
|
69
67
|
|
|
70
68
|
##
|
|
@@ -50,7 +50,7 @@ module Doing
|
|
|
50
50
|
new_items = wwid.filter_items(new_items, opt: options)
|
|
51
51
|
|
|
52
52
|
skipped = total - new_items.count
|
|
53
|
-
Doing.logger.debug('Skipped:'
|
|
53
|
+
Doing.logger.debug('Skipped:', %(#{skipped} items that didn't match filter criteria)) if skipped.positive?
|
|
54
54
|
|
|
55
55
|
imported = []
|
|
56
56
|
|
|
@@ -81,7 +81,6 @@ module Doing
|
|
|
81
81
|
}
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
-
|
|
85
84
|
#-------------------------------------------------------
|
|
86
85
|
## Output a template. Only required if template(s) are
|
|
87
86
|
## included in settings. The method should return a
|
|
@@ -100,10 +99,10 @@ module Doing
|
|
|
100
99
|
##
|
|
101
100
|
def self.template(trigger)
|
|
102
101
|
return unless trigger =~ /^say(it)?$/
|
|
102
|
+
|
|
103
103
|
'On %date, you were %title, recorded in section %section%took'
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
-
|
|
107
106
|
##
|
|
108
107
|
## Render data received from an output
|
|
109
108
|
## command
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
# url: https://brettterpstra.com
|
|
7
7
|
module Doing
|
|
8
8
|
class WikiExport
|
|
9
|
-
|
|
10
9
|
def self.settings
|
|
11
10
|
{
|
|
12
11
|
trigger: 'wiki',
|
|
@@ -55,7 +54,7 @@ module Doing
|
|
|
55
54
|
|
|
56
55
|
items_out << {
|
|
57
56
|
date: i.date.strftime('%a %-I:%M%p'),
|
|
58
|
-
title: title,
|
|
57
|
+
title: title, # + " #{note}"
|
|
59
58
|
note: note,
|
|
60
59
|
time: interval,
|
|
61
60
|
section: i.section
|
|
@@ -78,10 +77,10 @@ module Doing
|
|
|
78
77
|
engine = Haml::Engine.new(template)
|
|
79
78
|
Doing.logger.debug('Wiki Export:', "#{items_out.count} items output to #{variables[:page_title]} wiki page")
|
|
80
79
|
@out = engine.render(Object.new,
|
|
81
|
-
|
|
80
|
+
{ :@items => items_out, :@page_title => variables[:page_title], :@style => style,
|
|
81
|
+
:@totals => totals })
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
Doing::Plugins.register 'wiki', :export, self
|
|
85
85
|
end
|
|
86
86
|
end
|
|
87
|
-
|
|
@@ -890,7 +890,7 @@ class TestGoFZF < TestBase
|
|
|
890
890
|
end
|
|
891
891
|
wait do
|
|
892
892
|
assert_path_exists history_file
|
|
893
|
-
assert_equal input[1
|
|
893
|
+
assert_equal input[1..], File.readlines(history_file, chomp: true)
|
|
894
894
|
end
|
|
895
895
|
|
|
896
896
|
# Update history entries (not changed on disk)
|
|
@@ -2212,7 +2212,7 @@ module TestShell
|
|
|
2212
2212
|
tmux.prepare
|
|
2213
2213
|
tmux.send_keys :Escape, :c
|
|
2214
2214
|
lines = tmux.until { |lines| assert_operator lines.match_count, :>, 0 }
|
|
2215
|
-
expected = lines.reverse.find { |l| l.start_with?('> ') }[2
|
|
2215
|
+
expected = lines.reverse.find { |l| l.start_with?('> ') }[2..]
|
|
2216
2216
|
tmux.send_keys :Enter
|
|
2217
2217
|
tmux.prepare
|
|
2218
2218
|
tmux.send_keys :pwd, :Enter
|
|
@@ -2265,7 +2265,7 @@ module TestShell
|
|
|
2265
2265
|
|
|
2266
2266
|
def test_ctrl_r_multiline
|
|
2267
2267
|
tmux.send_keys 'echo "foo', :Enter, 'bar"', :Enter
|
|
2268
|
-
tmux.until { |lines| assert_equal %w[foo bar], lines[-2
|
|
2268
|
+
tmux.until { |lines| assert_equal %w[foo bar], lines[-2..] }
|
|
2269
2269
|
tmux.prepare
|
|
2270
2270
|
tmux.send_keys 'C-r'
|
|
2271
2271
|
tmux.until { |lines| assert_equal '>', lines[-1] }
|
|
@@ -2274,7 +2274,7 @@ module TestShell
|
|
|
2274
2274
|
tmux.send_keys :Enter
|
|
2275
2275
|
tmux.until { |lines| assert lines[-1]&.end_with?('bar"') }
|
|
2276
2276
|
tmux.send_keys :Enter
|
|
2277
|
-
tmux.until { |lines| assert_equal %w[foo bar], lines[-2
|
|
2277
|
+
tmux.until { |lines| assert_equal %w[foo bar], lines[-2..] }
|
|
2278
2278
|
end
|
|
2279
2279
|
|
|
2280
2280
|
def test_ctrl_r_abort
|
|
@@ -2465,7 +2465,7 @@ module CompletionTest
|
|
|
2465
2465
|
tmux.send_keys :Enter
|
|
2466
2466
|
tmux.until(true) { |lines| assert_match(/cat .*fzf-unicode.*1.* .*fzf-unicode.*2/, lines[-1]) }
|
|
2467
2467
|
tmux.send_keys :Enter
|
|
2468
|
-
tmux.until { |lines| assert_equal %w[test3 test4], lines[-2
|
|
2468
|
+
tmux.until { |lines| assert_equal %w[test3 test4], lines[-2..] }
|
|
2469
2469
|
end
|
|
2470
2470
|
|
|
2471
2471
|
def test_custom_completion_api
|