doing 2.1.25 → 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 +4 -4
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/CHANGELOG.md +283 -108
- data/Gemfile.lock +1 -1
- data/README.md +1 -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 +39 -3641
- data/docs/doc/Array.html +1 -1
- data/docs/doc/BooleanTermParser/Clause.html +1 -1
- data/docs/doc/BooleanTermParser/Operator.html +1 -1
- data/docs/doc/BooleanTermParser/Query.html +1 -1
- data/docs/doc/BooleanTermParser/QueryParser.html +1 -1
- data/docs/doc/BooleanTermParser/QueryTransformer.html +1 -1
- data/docs/doc/BooleanTermParser.html +1 -1
- data/docs/doc/Doing/Color.html +1 -1
- data/docs/doc/Doing/Completion.html +1 -1
- data/docs/doc/Doing/Configuration.html +2 -1
- data/docs/doc/Doing/Errors/DoingNoTraceError.html +1 -1
- data/docs/doc/Doing/Errors/DoingRuntimeError.html +1 -1
- data/docs/doc/Doing/Errors/DoingStandardError.html +1 -1
- data/docs/doc/Doing/Errors/EmptyInput.html +1 -1
- data/docs/doc/Doing/Errors/NoResults.html +1 -1
- data/docs/doc/Doing/Errors/PluginException.html +1 -1
- data/docs/doc/Doing/Errors/UserCancelled.html +1 -1
- data/docs/doc/Doing/Errors/WrongCommand.html +1 -1
- data/docs/doc/Doing/Errors.html +1 -1
- data/docs/doc/Doing/Hooks.html +1 -1
- data/docs/doc/Doing/Item.html +1 -1
- data/docs/doc/Doing/Items.html +1 -1
- data/docs/doc/Doing/LogAdapter.html +1 -1
- data/docs/doc/Doing/Note.html +1 -1
- data/docs/doc/Doing/Pager.html +1 -1
- data/docs/doc/Doing/Plugins.html +1 -1
- data/docs/doc/Doing/Prompt.html +46 -1
- data/docs/doc/Doing/Section.html +1 -1
- data/docs/doc/Doing/TemplateString.html +1 -1
- data/docs/doc/Doing/Types.html +1 -1
- data/docs/doc/Doing/Util/Backup.html +1 -1
- data/docs/doc/Doing/Util.html +1 -1
- data/docs/doc/Doing/WWID.html +1 -1
- data/docs/doc/Doing.html +2 -2
- data/docs/doc/FalseClass.html +201 -0
- data/docs/doc/GLI/Commands/Help.html +1 -1
- data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
- data/docs/doc/GLI/Commands.html +1 -1
- data/docs/doc/GLI.html +1 -1
- data/docs/doc/Hash.html +1 -1
- data/docs/doc/Numeric.html +1 -1
- data/docs/doc/Object.html +203 -0
- data/docs/doc/PhraseParser/Operator.html +1 -1
- data/docs/doc/PhraseParser/PhraseClause.html +1 -1
- data/docs/doc/PhraseParser/Query.html +1 -1
- data/docs/doc/PhraseParser/QueryParser.html +1 -1
- data/docs/doc/PhraseParser/QueryTransformer.html +1 -1
- data/docs/doc/PhraseParser/TermClause.html +1 -1
- data/docs/doc/PhraseParser.html +1 -1
- data/docs/doc/Status.html +1 -1
- data/docs/doc/String.html +1 -1
- data/docs/doc/Symbol.html +1 -1
- data/docs/doc/Time.html +1 -1
- data/docs/doc/TrueClass.html +201 -0
- data/docs/doc/_index.html +1 -1
- data/docs/doc/file.README.html +2 -2
- data/docs/doc/index.html +2 -2
- data/docs/doc/method_list.html +374 -366
- data/docs/doc/top-level-namespace.html +1 -1
- data/doing.rdoc +15 -5
- data/lib/completion/_doing.zsh +3 -3
- data/lib/completion/doing.fish +1 -1
- data/lib/doing/changelog/changes.rb +1 -1
- data/lib/doing/configuration.rb +1 -0
- data/lib/doing/pager.rb +1 -0
- data/lib/doing/prompt.rb +8 -0
- data/lib/doing/version.rb +1 -1
- data/lib/examples/commands/wiki.rb +6 -7
- data/lib/helpers/threaded_tests.rb +25 -19
- metadata +45 -1
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -8,7 +8,7 @@ _If you're one of the rare people like me who find this useful, feel free to
|
|
|
8
8
|
|
|
9
9
|
<!--README-->
|
|
10
10
|
|
|
11
|
-
The current version of `doing` is <!--VER-->2.1.
|
|
11
|
+
The current version of `doing` is <!--VER-->2.1.25<!--END VER-->.
|
|
12
12
|
|
|
13
13
|
Find all of the documentation in the [doing wiki][wiki].
|
|
14
14
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# @@add_section
|
|
2
|
+
desc 'Add a new section to the "doing" file'
|
|
3
|
+
arg_name 'SECTION_NAME'
|
|
4
|
+
command :add_section do |c|
|
|
5
|
+
c.example 'doing add_section Ideas', desc: 'Add a section called Ideas to the doing file'
|
|
6
|
+
|
|
7
|
+
c.action do |_global_options, _options, args|
|
|
8
|
+
raise InvalidArgument, "Section #{args[0]} already exists" if @wwid.sections.include?(args[0])
|
|
9
|
+
|
|
10
|
+
@wwid.content.add_section(args.join(' ').cap_first, log: true)
|
|
11
|
+
@wwid.write(@wwid.doing_file)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# @@again @@resume
|
|
2
|
+
desc 'Repeat last entry as new entry'
|
|
3
|
+
long_desc 'This command is designed to allow multiple time intervals to be created for an entry by duplicating it with a new start (and end, eventually) time'
|
|
4
|
+
command %i[again resume] do |c|
|
|
5
|
+
c.example 'doing resume', desc: 'Duplicate the most recent entry with a new start time, removing any @done tag'
|
|
6
|
+
c.example 'doing again', desc: 'again is an alias for resume'
|
|
7
|
+
c.example 'doing resume --editor', desc: 'Repeat the last entry, opening the new entry in the default editor'
|
|
8
|
+
c.example 'doing resume --tag project1 --in Projects', desc: 'Repeat the last entry tagged @project1, creating the new entry in the Projects section'
|
|
9
|
+
c.example 'doing resume --interactive', desc: 'Select the entry to repeat from a menu'
|
|
10
|
+
|
|
11
|
+
c.desc 'Get last entry from a specific section'
|
|
12
|
+
c.arg_name 'NAME'
|
|
13
|
+
c.flag %i[s section], default_value: 'All'
|
|
14
|
+
|
|
15
|
+
c.desc 'Add new entry to section (default: same section as repeated entry)'
|
|
16
|
+
c.arg_name 'SECTION_NAME'
|
|
17
|
+
c.flag [:in]
|
|
18
|
+
|
|
19
|
+
c.desc 'Backdate start date by interval or set to time [4pm|20m|2h|"yesterday noon"]'
|
|
20
|
+
c.arg_name 'DATE_STRING'
|
|
21
|
+
c.flag %i[b back started], type: DateBeginString
|
|
22
|
+
|
|
23
|
+
c.desc 'Repeat last entry matching tags. Combine multiple tags with a comma. Wildcards allowed (*, ?)'
|
|
24
|
+
c.arg_name 'TAG'
|
|
25
|
+
c.flag [:tag], type: TagArray
|
|
26
|
+
|
|
27
|
+
c.desc 'Repeat last entry matching search. Surround with
|
|
28
|
+
slashes for regex (e.g. "/query/"), start with a single quote for exact match ("\'query").'
|
|
29
|
+
c.arg_name 'QUERY'
|
|
30
|
+
c.flag [:search]
|
|
31
|
+
|
|
32
|
+
c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
|
|
33
|
+
c.arg_name 'QUERY'
|
|
34
|
+
c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
|
|
35
|
+
|
|
36
|
+
# c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
|
|
37
|
+
# c.switch [:fuzzy], default_value: false, negatable: false
|
|
38
|
+
|
|
39
|
+
c.desc 'Force exact search string matching (case sensitive)'
|
|
40
|
+
c.switch %i[x exact], default_value: @config.exact_match?, negatable: @config.exact_match?
|
|
41
|
+
|
|
42
|
+
c.desc 'Resume items that *don\'t* match search/tag filters'
|
|
43
|
+
c.switch [:not], default_value: false, negatable: false
|
|
44
|
+
|
|
45
|
+
c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
|
|
46
|
+
c.arg_name 'TYPE'
|
|
47
|
+
c.flag [:case], must_match: /^[csi]/, default_value: @settings.dig('search', 'case')
|
|
48
|
+
|
|
49
|
+
c.desc 'Boolean used to combine multiple tags. Use PATTERN to parse + and - as booleans'
|
|
50
|
+
c.arg_name 'BOOLEAN'
|
|
51
|
+
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
|
52
|
+
|
|
53
|
+
c.desc "Edit duplicated entry with #{Doing::Util.default_editor} before adding"
|
|
54
|
+
c.switch %i[e editor], negatable: false, default_value: false
|
|
55
|
+
|
|
56
|
+
c.desc 'Add a note'
|
|
57
|
+
c.arg_name 'TEXT'
|
|
58
|
+
c.flag %i[n note]
|
|
59
|
+
|
|
60
|
+
c.desc 'Prompt for note via multi-line input'
|
|
61
|
+
c.switch %i[ask], negatable: false, default_value: false
|
|
62
|
+
|
|
63
|
+
c.desc 'Select item to resume from a menu of matching entries'
|
|
64
|
+
c.switch %i[i interactive], negatable: false, default_value: false
|
|
65
|
+
|
|
66
|
+
c.action do |_global_options, options, _args|
|
|
67
|
+
options[:fuzzy] = false
|
|
68
|
+
tags = options[:tag].nil? ? [] : options[:tag]
|
|
69
|
+
|
|
70
|
+
options[:case] = options[:case].normalize_case
|
|
71
|
+
|
|
72
|
+
if options[:search]
|
|
73
|
+
search = options[:search]
|
|
74
|
+
search.sub!(/^'?/, "'") if options[:exact]
|
|
75
|
+
options[:search] = search
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
if options[:back]
|
|
79
|
+
date = options[:back]
|
|
80
|
+
raise InvalidTimeExpression, 'Unable to parse date string for --back' if date.nil?
|
|
81
|
+
else
|
|
82
|
+
date = Time.now
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
note = Doing::Note.new(options[:note])
|
|
86
|
+
note.add(Doing::Prompt.read_lines(prompt: 'Add a note')) if options[:ask]
|
|
87
|
+
|
|
88
|
+
options[:note] = note
|
|
89
|
+
|
|
90
|
+
opts = options.clone
|
|
91
|
+
|
|
92
|
+
opts[:tag] = tags
|
|
93
|
+
opts[:tag_bool] = options[:bool].normalize_bool
|
|
94
|
+
opts[:interactive] = options[:interactive]
|
|
95
|
+
opts[:date] = date
|
|
96
|
+
|
|
97
|
+
@wwid.repeat_last(opts)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# @@archive @@move
|
|
2
|
+
desc 'Move entries between sections'
|
|
3
|
+
long_desc %(Argument can be a section name to move all entries from a section,
|
|
4
|
+
or start with an "@" to move entries matching a tag.
|
|
5
|
+
|
|
6
|
+
Default with no argument moves items from the "#{@settings['current_section']}" section to Archive.)
|
|
7
|
+
arg_name 'SECTION_OR_TAG'
|
|
8
|
+
default_value @settings['current_section']
|
|
9
|
+
command %i[archive move] do |c|
|
|
10
|
+
c.example 'doing archive Currently', desc: 'Move all entries in the Currently section to Archive section'
|
|
11
|
+
c.example 'doing archive @done', desc: 'Move all entries tagged @done to Archive'
|
|
12
|
+
c.example 'doing archive --to Later @project1', desc: 'Move all entries tagged @project1 to Later section'
|
|
13
|
+
c.example 'doing move Later --tag project1 --to Currently', desc: 'Move entries in Later tagged @project1 to Currently (move is an alias for archive)'
|
|
14
|
+
|
|
15
|
+
c.desc 'How many items to keep (ignored if archiving by tag or search)'
|
|
16
|
+
c.arg_name 'X'
|
|
17
|
+
c.flag %i[k keep], must_match: /^\d+$/, type: Integer
|
|
18
|
+
|
|
19
|
+
c.desc 'Move entries to'
|
|
20
|
+
c.arg_name 'SECTION_NAME'
|
|
21
|
+
c.flag %i[t to], default_value: 'Archive'
|
|
22
|
+
|
|
23
|
+
c.desc 'Label moved items with @from(SECTION_NAME)'
|
|
24
|
+
c.switch [:label], default_value: true, negatable: true
|
|
25
|
+
|
|
26
|
+
c.desc 'Tag filter, combine multiple tags with a comma. Wildcards allowed (*, ?). Added for compatibility with other commands'
|
|
27
|
+
c.arg_name 'TAG'
|
|
28
|
+
c.flag [:tag], type: TagArray
|
|
29
|
+
|
|
30
|
+
c.desc 'Tag boolean (AND|OR|NOT). Use PATTERN to parse + and - as booleans'
|
|
31
|
+
c.arg_name 'BOOLEAN'
|
|
32
|
+
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
|
33
|
+
|
|
34
|
+
c.desc 'Search filter'
|
|
35
|
+
c.arg_name 'QUERY'
|
|
36
|
+
c.flag [:search]
|
|
37
|
+
|
|
38
|
+
c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
|
|
39
|
+
c.arg_name 'QUERY'
|
|
40
|
+
c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
|
|
41
|
+
|
|
42
|
+
# c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
|
|
43
|
+
# c.switch [:fuzzy], default_value: false, negatable: false
|
|
44
|
+
|
|
45
|
+
c.desc 'Force exact search string matching (case sensitive)'
|
|
46
|
+
c.switch %i[x exact], default_value: @config.exact_match?, negatable: @config.exact_match?
|
|
47
|
+
|
|
48
|
+
c.desc 'Show items that *don\'t* match search string'
|
|
49
|
+
c.switch [:not], default_value: false, negatable: false
|
|
50
|
+
|
|
51
|
+
c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
|
|
52
|
+
c.arg_name 'TYPE'
|
|
53
|
+
c.flag [:case], must_match: /^[csi]/, default_value: @settings.dig('search', 'case')
|
|
54
|
+
|
|
55
|
+
c.desc 'Archive entries older than date
|
|
56
|
+
(Flexible date format, e.g. 1/27/2021, 2020-07-19, or Monday 3pm)'
|
|
57
|
+
c.arg_name 'DATE_STRING'
|
|
58
|
+
c.flag [:before], type: DateEndString
|
|
59
|
+
|
|
60
|
+
c.action do |_global_options, options, args|
|
|
61
|
+
options[:fuzzy] = false
|
|
62
|
+
if args.empty?
|
|
63
|
+
section = @settings['current_section']
|
|
64
|
+
tags = []
|
|
65
|
+
elsif args[0] =~ /^all/i
|
|
66
|
+
section = 'all'
|
|
67
|
+
elsif args[0] =~ /^@\S+/
|
|
68
|
+
section = 'all'
|
|
69
|
+
tags = args.map { |t| t.sub(/^@/, '').strip }
|
|
70
|
+
else
|
|
71
|
+
section = args[0].cap_first
|
|
72
|
+
tags = args.length > 1 ? args[1..].map { |t| t.sub(/^@/, '').strip } : []
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
raise InvalidArgument, '--keep and --count can not be used together' if options[:keep] && options[:count]
|
|
76
|
+
|
|
77
|
+
tags.concat(options[:tag]) if options[:tag]
|
|
78
|
+
|
|
79
|
+
search = nil
|
|
80
|
+
|
|
81
|
+
options[:case] = options[:case].normalize_case
|
|
82
|
+
|
|
83
|
+
if options[:search]
|
|
84
|
+
search = options[:search]
|
|
85
|
+
search.sub!(/^'?/, "'") if options[:exact]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
opts = options.clone
|
|
89
|
+
opts[:search] = search
|
|
90
|
+
opts[:bool] = options[:bool].normalize_bool
|
|
91
|
+
opts[:destination] = options[:to]
|
|
92
|
+
opts[:tags] = tags
|
|
93
|
+
|
|
94
|
+
@wwid.archive(section, opts)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# @@cancel
|
|
2
|
+
desc 'End last X entries with no time tracked'
|
|
3
|
+
long_desc 'Adds @done tag without datestamp so no elapsed time is recorded. Alias for `doing finish --no-date`'
|
|
4
|
+
arg_name 'COUNT'
|
|
5
|
+
command :cancel do |c|
|
|
6
|
+
c.example 'doing cancel', desc: 'Cancel the last entry'
|
|
7
|
+
c.example 'doing cancel --tag project1 -u 5', desc: 'Cancel the last 5 unfinished entries containing @project1'
|
|
8
|
+
|
|
9
|
+
c.desc 'Archive entries'
|
|
10
|
+
c.switch %i[a archive], negatable: false, default_value: false
|
|
11
|
+
|
|
12
|
+
c.desc 'Section'
|
|
13
|
+
c.arg_name 'NAME'
|
|
14
|
+
c.flag %i[s section]
|
|
15
|
+
|
|
16
|
+
c.desc 'Cancel the last X entries containing TAG. Separate multiple tags with comma (--tag=tag1,tag2). Wildcards allowed (*, ?)'
|
|
17
|
+
c.arg_name 'TAG'
|
|
18
|
+
c.flag [:tag], type: TagArray
|
|
19
|
+
|
|
20
|
+
c.desc 'Boolean (AND|OR|NOT) with which to combine multiple tag filters. Use PATTERN to parse + and - as booleans'
|
|
21
|
+
c.arg_name 'BOOLEAN'
|
|
22
|
+
c.flag [:bool], must_match: REGEX_BOOL, default_value: 'PATTERN'
|
|
23
|
+
|
|
24
|
+
c.desc 'Cancel the last X entries matching search filter, surround with slashes for regex (e.g. "/query.*/"), start with single quote for exact match ("\'query")'
|
|
25
|
+
c.arg_name 'QUERY'
|
|
26
|
+
c.flag [:search]
|
|
27
|
+
|
|
28
|
+
c.desc 'Perform a tag value query ("@done > two hours ago" or "@progress < 50"). May be used multiple times, combined with --bool'
|
|
29
|
+
c.arg_name 'QUERY'
|
|
30
|
+
c.flag [:val], multiple: true, must_match: REGEX_VALUE_QUERY
|
|
31
|
+
|
|
32
|
+
# c.desc '[DEPRECATED] Use alternative fuzzy matching for search string'
|
|
33
|
+
# c.switch [:fuzzy], default_value: false, negatable: false
|
|
34
|
+
|
|
35
|
+
c.desc 'Force exact search string matching (case sensitive)'
|
|
36
|
+
c.switch %i[x exact], default_value: @config.exact_match?, negatable: @config.exact_match?
|
|
37
|
+
|
|
38
|
+
c.desc 'Finish items that *don\'t* match search/tag filters'
|
|
39
|
+
c.switch [:not], default_value: false, negatable: false
|
|
40
|
+
|
|
41
|
+
c.desc 'Case sensitivity for search string matching [(c)ase-sensitive, (i)gnore, (s)mart]'
|
|
42
|
+
c.arg_name 'TYPE'
|
|
43
|
+
c.flag [:case], must_match: /^[csi]/, default_value: @settings.dig('search', 'case')
|
|
44
|
+
|
|
45
|
+
c.desc 'Cancel last entry (or entries) not already marked @done'
|
|
46
|
+
c.switch %i[u unfinished], negatable: false, default_value: false
|
|
47
|
+
|
|
48
|
+
c.desc 'Select item(s) to cancel from a menu of matching entries'
|
|
49
|
+
c.switch %i[i interactive], negatable: false, default_value: false
|
|
50
|
+
|
|
51
|
+
c.action do |_global_options, options, args|
|
|
52
|
+
options[:fuzzy] = false
|
|
53
|
+
if options[:section]
|
|
54
|
+
section = @wwid.guess_section(options[:section]) || options[:section].cap_first
|
|
55
|
+
else
|
|
56
|
+
section = @settings['current_section']
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
if options[:tag].nil?
|
|
60
|
+
tags = []
|
|
61
|
+
else
|
|
62
|
+
tags = options[:tag]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
raise InvalidArgument, 'Only one argument allowed' if args.length > 1
|
|
66
|
+
|
|
67
|
+
raise InvalidArgument, 'Invalid argument (specify number of recent items to mark @done)' unless args.empty? || args[0] =~ /\d+/
|
|
68
|
+
|
|
69
|
+
if options[:interactive]
|
|
70
|
+
count = 0
|
|
71
|
+
else
|
|
72
|
+
count = args[0] ? args[0].to_i : 1
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
search = nil
|
|
76
|
+
|
|
77
|
+
if options[:search]
|
|
78
|
+
search = options[:search]
|
|
79
|
+
search.sub!(/^'?/, "'") if options[:exact]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
opts = {
|
|
83
|
+
archive: options[:archive],
|
|
84
|
+
case: options[:case].normalize_case,
|
|
85
|
+
count: count,
|
|
86
|
+
date: false,
|
|
87
|
+
fuzzy: options[:fuzzy],
|
|
88
|
+
interactive: options[:interactive],
|
|
89
|
+
not: options[:not],
|
|
90
|
+
search: search,
|
|
91
|
+
section: section,
|
|
92
|
+
sequential: false,
|
|
93
|
+
tag: tags,
|
|
94
|
+
tag_bool: options[:bool].normalize_bool,
|
|
95
|
+
tags: ['done'],
|
|
96
|
+
unfinished: options[:unfinished],
|
|
97
|
+
val: options[:val]
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@wwid.tag_last(opts)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# @@changelog @@changes
|
|
2
|
+
desc 'List recent changes in Doing'
|
|
3
|
+
long_desc %(Display a formatted list of changes in recent versions.
|
|
4
|
+
|
|
5
|
+
Without flags, displays only the most recent version.
|
|
6
|
+
Use --lookup or --all for history.)
|
|
7
|
+
command %i[changes changelog] do |c|
|
|
8
|
+
c.desc 'Display all versions'
|
|
9
|
+
c.switch %i[a all], default_value: false, negatable: false
|
|
10
|
+
|
|
11
|
+
c.desc %(Look up a specific version. Specify versions as "MAJ.MIN.PATCH", MIN
|
|
12
|
+
and PATCH are optional. Use > or < to see all changes since or prior
|
|
13
|
+
to a version.)
|
|
14
|
+
c.arg_name 'VERSION'
|
|
15
|
+
c.flag %i[l lookup], must_match: /^(?:(?:(?:[<>=]|p(?:rior)|b(?:efore)|o(?:lder)|s(?:ince)|a(?:fter)|n(?:ewer))? *[\d.*?]+ *)+|(?:[\d.]+ *-+ *[\d.]+))$/
|
|
16
|
+
|
|
17
|
+
c.desc %(Show changelogs matching search terms (uses pattern-based searching).
|
|
18
|
+
Add slashes to search with regular expressions, e.g. `--search "/output.*flag/"`)
|
|
19
|
+
c.flag %i[s search]
|
|
20
|
+
|
|
21
|
+
c.example 'doing changes', desc: 'View changes in the current version'
|
|
22
|
+
c.example 'doing changes --all', desc: 'See the entire changelog'
|
|
23
|
+
c.example 'doing changes --lookup 2.0.21', desc: 'See changes from version 2.0.21'
|
|
24
|
+
c.example 'doing changes --lookup "> 2.1"', desc: 'See all changes since 2.1.0'
|
|
25
|
+
c.example 'doing changes --search "tags +bool"', desc: 'See all changes containing "tags" and "bool"'
|
|
26
|
+
c.example 'doing changes -l "> 2.1" -s "pattern"', desc: 'Lookup and search can be combined'
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
c.action do |_global_options, options, args|
|
|
30
|
+
cl = Doing::Changes.new(lookup: options[:lookup], search: options[:search])
|
|
31
|
+
|
|
32
|
+
content = if options[:all] || options[:search] || options[:lookup]
|
|
33
|
+
cl.to_s
|
|
34
|
+
else
|
|
35
|
+
cl.latest
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
parsed = TTY::Markdown.parse(content, width: 80, symbols: {override: {bullet: "•"}})
|
|
39
|
+
Doing::Pager.paginate = true
|
|
40
|
+
Doing::Pager.page parsed
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# @@choose
|
|
2
|
+
desc 'Select a section to display from a menu'
|
|
3
|
+
command :choose do |c|
|
|
4
|
+
c.action do |_global_options, _options, _args|
|
|
5
|
+
section = @wwid.choose_section
|
|
6
|
+
|
|
7
|
+
Doing::Pager.page @wwid.list_section({ section: section.cap_first, count: 0 }) if section
|
|
8
|
+
end
|
|
9
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# @@colors
|
|
2
|
+
desc 'List available color variables for configuration templates and views'
|
|
3
|
+
command :colors do |c|
|
|
4
|
+
c.action do |_global_options, _options, _args|
|
|
5
|
+
bgs = []
|
|
6
|
+
fgs = []
|
|
7
|
+
@colors::attributes.each do |color|
|
|
8
|
+
if color.to_s =~ /bg/
|
|
9
|
+
bgs.push("#{@colors.send(color, " ")}#{@colors.default} <-- #{color.to_s}")
|
|
10
|
+
else
|
|
11
|
+
fgs.push("#{@colors.send(color, "XXXX")}#{@colors.default} <-- #{color.to_s}")
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
out = []
|
|
15
|
+
out << fgs.join("\n")
|
|
16
|
+
out << bgs.join("\n")
|
|
17
|
+
Doing::Pager.page out.join("\n")
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# @@commands
|
|
4
|
+
desc 'Enable and disable Doing commands'
|
|
5
|
+
command :commands do |c|
|
|
6
|
+
c.example 'doing commands add', desc: 'Get a menu of available commands'
|
|
7
|
+
c.example 'doing commands add COMMAND', desc: 'Specify a command to enable'
|
|
8
|
+
c.example 'doing commands remove COMMAND', desc: 'Specify a command to disable'
|
|
9
|
+
|
|
10
|
+
c.default_command :add
|
|
11
|
+
|
|
12
|
+
# @@commands.enable
|
|
13
|
+
c.desc 'Enable Doing commands'
|
|
14
|
+
c.long_desc 'Run without arguments to select commands from a list.'
|
|
15
|
+
c.arg_name 'COMMAND [COMMAND...]'
|
|
16
|
+
c.command %i[add enable] do |add|
|
|
17
|
+
add.action do |_global, _options, args|
|
|
18
|
+
cfg = @settings
|
|
19
|
+
custom_dir = @settings.dig('plugins', 'command_path')
|
|
20
|
+
|
|
21
|
+
available = cfg['disabled_commands']
|
|
22
|
+
raise UserCancelled, 'No commands available to enable' unless args.good? || available.good?
|
|
23
|
+
|
|
24
|
+
to_enable = if args.good?
|
|
25
|
+
args
|
|
26
|
+
else
|
|
27
|
+
Doing::Prompt.choose_from(available,
|
|
28
|
+
prompt: 'Select commands to enable',
|
|
29
|
+
multiple: true,
|
|
30
|
+
sorted: true).strip.split("\n")
|
|
31
|
+
end
|
|
32
|
+
to_enable.each do |cmd|
|
|
33
|
+
default_command = File.join(File.dirname(__FILE__), "#{cmd}.rb")
|
|
34
|
+
custom_command = File.join(File.expand_path(custom_dir), "#{cmd}.rb")
|
|
35
|
+
unless File.exist?(default_command) || File.exist?(custom_command)
|
|
36
|
+
raise InvalidArgument, "Command #{cmd} not found"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
raise InvalidArgument, "Command #{cmd} is not disabled" unless available.include?(cmd)
|
|
40
|
+
|
|
41
|
+
available.delete(cmd)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
cfg.deep_set(['disabled_commands'], available)
|
|
45
|
+
|
|
46
|
+
Doing::Util.write_to_file(@config.config_file, YAML.dump(cfg), backup: true)
|
|
47
|
+
Doing.logger.warn('Config:', "#{@config.config_file} updated")
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# @@commands.disable
|
|
52
|
+
c.desc 'Disable Doing commands'
|
|
53
|
+
c.command %i[remove disable] do |remove|
|
|
54
|
+
remove.action do |_global, _options, args|
|
|
55
|
+
available = Dir.glob(File.join(File.dirname(__FILE__), '*.rb')).map { |cmd| File.basename(cmd, '.rb') }
|
|
56
|
+
cfg = @settings
|
|
57
|
+
custom_dir = @settings.dig('plugins', 'command_path')
|
|
58
|
+
custom_commands = Dir.glob(File.join(File.expand_path(custom_dir), '*.rb'))
|
|
59
|
+
available.concat(custom_commands.map { |cmd| File.basename(cmd, '.rb') })
|
|
60
|
+
disabled = cfg['disabled_commands']
|
|
61
|
+
disabled.each { |cmd| available.delete(cmd) }
|
|
62
|
+
to_disable = if args.good?
|
|
63
|
+
args
|
|
64
|
+
else
|
|
65
|
+
Doing::Prompt.choose_from(available,
|
|
66
|
+
prompt: 'Select commands to enable',
|
|
67
|
+
multiple: true,
|
|
68
|
+
sorted: true).strip.split("\n")
|
|
69
|
+
end
|
|
70
|
+
to_disable.each do |cmd|
|
|
71
|
+
default_command = File.join(File.dirname(__FILE__), "#{cmd}.rb")
|
|
72
|
+
custom_command = File.join(File.expand_path(custom_dir), "#{cmd}.rb")
|
|
73
|
+
unless File.exist?(default_command) || File.exist?(custom_command)
|
|
74
|
+
raise InvalidArgument, "Command #{cmd} not found"
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
raise InvalidArgument, "Command #{cmd} is not enabled" unless available.include?(cmd)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
cfg.deep_set(['disabled_commands'], disabled.concat(to_disable))
|
|
82
|
+
|
|
83
|
+
Doing::Util.write_to_file(@config.config_file, YAML.dump(cfg), backup: true)
|
|
84
|
+
Doing.logger.warn('Config:', "#{@config.config_file} updated")
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# @@commands_accepting
|
|
2
|
+
arg_name 'OPTION'
|
|
3
|
+
command :commands_accepting do |c|
|
|
4
|
+
c.desc 'Output in single column for completion'
|
|
5
|
+
c.switch %i[c column]
|
|
6
|
+
|
|
7
|
+
c.action do |g, o, a|
|
|
8
|
+
a.each do |option|
|
|
9
|
+
cmds = []
|
|
10
|
+
commands.each do |cmd, v|
|
|
11
|
+
v.flags.merge(v.switches).each do |n, flag|
|
|
12
|
+
if flag.name == option.to_sym || flag.aliases&.include?(option.to_sym)
|
|
13
|
+
cmds.push(cmd)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
if o[:column]
|
|
19
|
+
puts cmds.sort
|
|
20
|
+
else
|
|
21
|
+
puts "Commands accepting --#{option}: #{cmds.sort.join(', ')}"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# @@completion
|
|
2
|
+
desc 'Generate shell completion scripts'
|
|
3
|
+
long_desc 'Generates the necessary scripts to add command line completion to various shells, so typing \'doing\' and hitting
|
|
4
|
+
tab will offer completions of subcommands and their options.'
|
|
5
|
+
command :completion do |c|
|
|
6
|
+
c.example 'doing completion', desc: 'Output zsh (default) to STDOUT'
|
|
7
|
+
c.example 'doing completion --type zsh --file ~/.zsh-completions/_doing.zsh', desc: 'Output zsh completions to file'
|
|
8
|
+
c.example 'doing completion --type fish --file ~/.config/fish/completions/doing.fish', desc: 'Output fish completions to file'
|
|
9
|
+
c.example 'doing completion --type bash --file ~/.bash_it/completion/enabled/doing.bash', desc: 'Output bash completions to file'
|
|
10
|
+
|
|
11
|
+
c.desc 'Shell to generate for (bash, zsh, fish)'
|
|
12
|
+
c.arg_name 'SHELL'
|
|
13
|
+
c.flag %i[t type], must_match: /^(?:[bzf](?:[ai]?sh)?|all)$/i, default_value: 'zsh'
|
|
14
|
+
|
|
15
|
+
c.desc 'File to write output to'
|
|
16
|
+
c.arg_name 'PATH'
|
|
17
|
+
c.flag %i[f file], default_value: 'STDOUT'
|
|
18
|
+
|
|
19
|
+
c.action do |_global_options, options, _args|
|
|
20
|
+
script_dir = File.join(File.dirname(__FILE__), '..', 'scripts')
|
|
21
|
+
|
|
22
|
+
Doing::Completion.generate_completion(type: options[:type], file: options[:file])
|
|
23
|
+
end
|
|
24
|
+
end
|