doing 2.1.41 → 2.1.42
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/CHANGELOG.md +22 -0
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/bin/commands/again.rb +1 -3
- data/bin/commands/changes.rb +50 -34
- data/bin/commands/commands.rb +77 -52
- data/bin/commands/commands_accepting.rb +57 -53
- data/bin/commands/config.rb +2 -2
- data/bin/commands/finish.rb +94 -68
- data/bin/commands/flag.rb +5 -1
- data/bin/commands/now.rb +151 -107
- data/bin/commands/on.rb +7 -4
- data/bin/commands/undo.rb +4 -6
- data/docs/doc/Array.html +3 -2
- 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/ArrayNestedHash.html +1 -1
- data/docs/doc/Doing/ArrayTags.html +1 -1
- data/docs/doc/Doing/CSVExport.html +1 -1
- data/docs/doc/Doing/CalendarImport.html +1 -1
- data/docs/doc/Doing/Change.html +1 -1
- data/docs/doc/Doing/Changes.html +1 -1
- data/docs/doc/Doing/ChronifyArray.html +1 -1
- data/docs/doc/Doing/ChronifyNumeric.html +1 -1
- data/docs/doc/Doing/ChronifyString.html +1 -1
- data/docs/doc/Doing/Color.html +1 -1
- data/docs/doc/Doing/Completion/BashCompletions.html +1 -1
- data/docs/doc/Doing/Completion/FishCompletions.html +1 -1
- data/docs/doc/Doing/Completion/StringUtils.html +1 -1
- data/docs/doc/Doing/Completion/ZshCompletions.html +1 -1
- data/docs/doc/Doing/Completion.html +1 -1
- data/docs/doc/Doing/Configuration.html +3 -2
- data/docs/doc/Doing/DayOneRenderer.html +1 -1
- data/docs/doc/Doing/DayoneExport.html +1 -1
- data/docs/doc/Doing/DoingImport.html +1 -1
- data/docs/doc/Doing/Entry.html +1 -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/HistoryLimitError.html +1 -1
- data/docs/doc/Doing/Errors/InvalidPlugin.html +1 -1
- data/docs/doc/Doing/Errors/MissingBackupFile.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/HTMLExport.html +1 -1
- data/docs/doc/Doing/Hooks.html +1 -1
- data/docs/doc/Doing/Item.html +1 -1
- data/docs/doc/Doing/ItemDates.html +1 -1
- data/docs/doc/Doing/ItemQuery.html +1 -1
- data/docs/doc/Doing/ItemState.html +1 -1
- data/docs/doc/Doing/ItemTags.html +1 -1
- data/docs/doc/Doing/Items.html +2 -1
- data/docs/doc/Doing/JSONExport.html +1 -1
- data/docs/doc/Doing/Logger.html +1 -1
- data/docs/doc/Doing/MarkdownExport.html +1 -1
- data/docs/doc/Doing/Note.html +3 -2
- data/docs/doc/Doing/Pager.html +1 -1
- data/docs/doc/Doing/Plugins.html +181 -76
- data/docs/doc/Doing/Prompt.html +1 -1
- data/docs/doc/Doing/PromptChoose.html +1 -1
- data/docs/doc/Doing/PromptFZF.html +1 -1
- data/docs/doc/Doing/PromptInput.html +1 -1
- data/docs/doc/Doing/PromptSTD.html +1 -1
- data/docs/doc/Doing/PromptYN.html +1 -1
- data/docs/doc/Doing/Section.html +1 -1
- data/docs/doc/Doing/StringHighlight.html +1 -1
- data/docs/doc/Doing/StringNormalize.html +1 -1
- data/docs/doc/Doing/StringQuery.html +1 -1
- data/docs/doc/Doing/StringTags.html +1 -1
- data/docs/doc/Doing/StringTransform.html +35 -1
- data/docs/doc/Doing/StringTruncate.html +1 -1
- data/docs/doc/Doing/StringURL.html +1 -1
- data/docs/doc/Doing/SymbolNormalize.html +1 -1
- data/docs/doc/Doing/TaskPaperExport.html +1 -1
- data/docs/doc/Doing/TemplateExport.html +1 -1
- data/docs/doc/Doing/TemplateString.html +2 -2
- data/docs/doc/Doing/TimingImport.html +1 -1
- data/docs/doc/Doing/Types.html +1 -1
- data/docs/doc/Doing/Util/Backup.html +2 -156
- data/docs/doc/Doing/Util.html +66 -9
- data/docs/doc/Doing/Version.html +1 -1
- data/docs/doc/Doing/WWID.html +14 -1
- data/docs/doc/Doing.html +4 -4
- data/docs/doc/FalseClass.html +1 -1
- 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 +1 -1
- 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 +2 -2
- data/docs/doc/Symbol.html +1 -1
- data/docs/doc/Time.html +1 -1
- data/docs/doc/TrueClass.html +1 -1
- data/docs/doc/_index.html +16 -9
- 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 +289 -281
- data/docs/doc/top-level-namespace.html +9 -1
- data/doing.rdoc +7 -7
- data/lib/doing/add_options.rb +8 -0
- data/lib/doing/array/array.rb +2 -0
- data/lib/doing/array/cleanup.rb +31 -0
- data/lib/doing/configuration.rb +7 -3
- data/lib/doing/note.rb +1 -1
- data/lib/doing/pager.rb +9 -3
- data/lib/doing/plugin_manager.rb +30 -5
- data/lib/doing/prompt/choose.rb +1 -1
- data/lib/doing/prompt/input.rb +1 -1
- data/lib/doing/string/transform.rb +6 -0
- data/lib/doing/util.rb +12 -6
- data/lib/doing/util_backup.rb +55 -48
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid/editor.rb +6 -3
- data/lib/doing/wwid/interactive.rb +10 -20
- data/lib/doing/wwid/modify.rb +2 -0
- data/lib/doing.rb +3 -3
- metadata +3 -2
data/bin/commands/finish.rb
CHANGED
|
@@ -1,43 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# @@finish
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
c.example 'doing finish --search "a specific entry" --at "yesterday 3pm"', desc: 'Search for an entry containing string and set its @done time to yesterday at 3pm'
|
|
4
|
+
module Doing
|
|
5
|
+
# finish command methods
|
|
6
|
+
class FinishCommand
|
|
7
|
+
def initialize(wwid)
|
|
8
|
+
@wwid = wwid
|
|
9
|
+
end
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
def add_examples(cmd)
|
|
12
|
+
cmd.example 'doing finish', desc: 'Mark the last entry @done'
|
|
13
|
+
cmd.example 'doing finish --auto --section Later 10', desc: 'Add @done to any unfinished entries in the last 10 in Later, setting the finish time based on the start time of the task after it'
|
|
14
|
+
cmd.example 'doing finish --search "a specific entry" --at "yesterday 3pm"', desc: 'Search for an entry containing string and set its @done time to yesterday at 3pm'
|
|
15
|
+
end
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
def add_options(cmd)
|
|
18
|
+
cmd.desc 'Include date'
|
|
19
|
+
cmd.switch [:date], negatable: true, default_value: true
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
cmd.desc 'Backdate completed date to date string [4pm|20m|2h|yesterday noon]'
|
|
22
|
+
cmd.arg_name 'DATE_STRING'
|
|
23
|
+
cmd.flag %i[b back started], type: DateBeginString
|
|
19
24
|
|
|
20
|
-
|
|
21
|
-
|
|
25
|
+
cmd.desc 'Overwrite existing @done tag with new date'
|
|
26
|
+
cmd.switch %i[update], negatable: false, default_value: false
|
|
22
27
|
|
|
23
|
-
|
|
24
|
-
|
|
28
|
+
cmd.desc 'Remove @done tag'
|
|
29
|
+
cmd.switch %i[r remove], negatable: false, default_value: false
|
|
25
30
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
--auto overrides the --date and --back parameters.)
|
|
29
|
-
c.switch [:auto], negatable: false, default_value: false
|
|
31
|
+
cmd.desc 'Finish last entry (or entries) not already marked @done'
|
|
32
|
+
cmd.switch %i[u unfinished], negatable: false, default_value: false
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
cmd.desc %(Auto-generate finish dates from next entry's start time.
|
|
35
|
+
Automatically generate completion dates 1 minute before next item (in any section) began.
|
|
36
|
+
--auto overrides the --date and --back parameters.)
|
|
37
|
+
cmd.switch [:auto], negatable: false, default_value: false
|
|
33
38
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
c.flag %i[s section]
|
|
39
|
+
cmd.desc 'Archive entries'
|
|
40
|
+
cmd.switch %i[a archive], negatable: false, default_value: false
|
|
37
41
|
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
cmd.desc 'Section'
|
|
43
|
+
cmd.arg_name 'NAME'
|
|
44
|
+
cmd.flag %i[s section]
|
|
40
45
|
|
|
46
|
+
cmd.desc 'Select item(s) to finish from a menu of matching entries'
|
|
47
|
+
cmd.switch %i[i interactive], negatable: false, default_value: false
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def handle_from(options)
|
|
51
|
+
options[:from] = options[:from].split(/#{REGEX_RANGE_INDICATOR}/).map do |time|
|
|
52
|
+
time =~ REGEX_TIME ? "today #{time.sub(/(?mi)(^.*?(?=\d+)|(?<=[ap]m).*?$)/, '')}" : time
|
|
53
|
+
end.join(' to ').split_date_range
|
|
54
|
+
start_date, finish_date = options[:from]
|
|
55
|
+
finish_date ||= Time.now
|
|
56
|
+
[start_date, finish_date]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def handle_date_options(options)
|
|
60
|
+
if options[:took]
|
|
61
|
+
took = options[:took]
|
|
62
|
+
raise InvalidTimeExpression, 'Unable to parse date string for --took' if took.nil?
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
if options[:at]
|
|
67
|
+
finish_date = options[:at]
|
|
68
|
+
finish_date = finish_date.chronify(guess: :begin) if finish_date.is_a? String
|
|
69
|
+
raise InvalidTimeExpression, 'Unable to parse date string for --at' if finish_date.nil?
|
|
70
|
+
|
|
71
|
+
start_date = options[:took] ? finish_date - took : nil
|
|
72
|
+
elsif options[:back]
|
|
73
|
+
start_date = options[:back]
|
|
74
|
+
finish_date = options[:took] ? start_date + took : Time.now
|
|
75
|
+
|
|
76
|
+
raise InvalidTimeExpression, 'Unable to parse date string' if start_date.nil?
|
|
77
|
+
|
|
78
|
+
else
|
|
79
|
+
start_date = options[:took] ? Time.now - took : nil
|
|
80
|
+
finish_date = Time.now
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
[start_date, finish_date]
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
desc 'Mark last X entries as @done'
|
|
89
|
+
long_desc 'Marks the last X entries with a @done tag and current date. Does not alter already completed entries.'
|
|
90
|
+
arg_name 'COUNT', optional: true
|
|
91
|
+
command :finish do |c|
|
|
92
|
+
cmd = Doing::FinishCommand.new(@wwid)
|
|
93
|
+
cmd.add_examples(c)
|
|
94
|
+
cmd.add_options(c)
|
|
41
95
|
add_options(:search, c)
|
|
42
96
|
add_options(:tag_filter, c)
|
|
43
97
|
add_options(:finish_entry, c)
|
|
@@ -46,55 +100,27 @@ command :finish do |c|
|
|
|
46
100
|
options[:fuzzy] = false
|
|
47
101
|
unless options[:auto]
|
|
48
102
|
if options[:from]
|
|
49
|
-
|
|
50
|
-
time =~ REGEX_TIME ? "today #{time.sub(/(?mi)(^.*?(?=\d+)|(?<=[ap]m).*?$)/, '')}" : time
|
|
51
|
-
end.join(' to ').split_date_range
|
|
52
|
-
start_date, finish_date = options[:from]
|
|
53
|
-
finish_date ||= Time.now
|
|
103
|
+
start_date, finish_date = cmd.handle_from(options)
|
|
54
104
|
else
|
|
55
|
-
|
|
56
|
-
took = options[:took]
|
|
57
|
-
raise InvalidTimeExpression, 'Unable to parse date string for --took' if took.nil?
|
|
58
|
-
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
if options[:at]
|
|
62
|
-
finish_date = options[:at]
|
|
63
|
-
finish_date = finish_date.chronify(guess: :begin) if finish_date.is_a? String
|
|
64
|
-
raise InvalidTimeExpression, 'Unable to parse date string for --at' if finish_date.nil?
|
|
65
|
-
|
|
66
|
-
start_date = options[:took] ? finish_date - took : nil
|
|
67
|
-
elsif options[:back]
|
|
68
|
-
start_date = options[:back]
|
|
69
|
-
finish_date = options[:took] ? start_date + took : Time.now
|
|
70
|
-
|
|
71
|
-
raise InvalidTimeExpression, 'Unable to parse date string' if start_date.nil?
|
|
72
|
-
|
|
73
|
-
else
|
|
74
|
-
start_date = options[:took] ? Time.now - took : nil
|
|
75
|
-
finish_date = Time.now
|
|
76
|
-
end
|
|
105
|
+
start_date, finish_date = cmd.handle_date_options(options)
|
|
77
106
|
end
|
|
78
|
-
|
|
79
|
-
|
|
80
107
|
end
|
|
81
108
|
|
|
82
|
-
|
|
83
|
-
tags = []
|
|
84
|
-
else
|
|
85
|
-
tags = options[:tag]
|
|
86
|
-
end
|
|
109
|
+
tags = options[:tag] || []
|
|
87
110
|
|
|
88
111
|
raise InvalidArgument, 'Only one argument allowed' if args.length > 1
|
|
89
112
|
|
|
90
|
-
|
|
113
|
+
unless args.empty? || args[0] =~ /\d+/
|
|
114
|
+
raise InvalidArgument, 'Invalid argument (specify number of recent items to mark @done)'
|
|
91
115
|
|
|
92
|
-
if options[:interactive]
|
|
93
|
-
count = 0
|
|
94
|
-
else
|
|
95
|
-
count = args[0] ? args[0].to_i : 1
|
|
96
116
|
end
|
|
97
117
|
|
|
118
|
+
count = if options[:interactive]
|
|
119
|
+
0
|
|
120
|
+
else
|
|
121
|
+
args[0] ? args[0].to_i : 1
|
|
122
|
+
end
|
|
123
|
+
|
|
98
124
|
search = nil
|
|
99
125
|
|
|
100
126
|
if options[:search]
|
data/bin/commands/flag.rb
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# @@mark @@flag
|
|
2
4
|
desc 'Mark last entry as flagged'
|
|
3
5
|
command %i[mark flag] do |c|
|
|
4
6
|
c.example 'doing flag', desc: 'Add @flagged to the last entry created'
|
|
5
7
|
c.example 'doing mark', desc: 'mark is an alias for flag'
|
|
6
8
|
c.example 'doing flag --tag project1 --count 2', desc: 'Add @flagged to the last 2 entries tagged @project1'
|
|
7
|
-
c.example 'doing flag --interactive --search "/(develop|cod)ing/"',
|
|
9
|
+
c.example 'doing flag --interactive --search "/(develop|cod)ing/"',
|
|
10
|
+
desc: 'Find entries matching regular expression and create a menu allowing multiple selections,
|
|
11
|
+
selected items will be @flagged'
|
|
8
12
|
|
|
9
13
|
c.desc 'Section'
|
|
10
14
|
c.arg_name 'SECTION_NAME'
|
data/bin/commands/now.rb
CHANGED
|
@@ -1,141 +1,185 @@
|
|
|
1
1
|
# @@now @@next
|
|
2
|
-
desc 'Add an entry'
|
|
3
|
-
long_desc %(Record what you're starting now, or backdate the start time using natural language.
|
|
4
|
-
|
|
5
|
-
A parenthetical at the end of the entry will be converted to a note.
|
|
6
2
|
|
|
7
|
-
|
|
3
|
+
module Doing
|
|
4
|
+
# Methods for the now command
|
|
5
|
+
class NowCommand
|
|
6
|
+
def initialize(wwid)
|
|
7
|
+
@wwid = wwid
|
|
8
|
+
end
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
c.example 'doing now -e', desc: "Open #{Doing::Util.default_editor} to input an entry and optional note"
|
|
14
|
-
c.example 'doing now working on a new project', desc: 'Add a new entry at the current time'
|
|
15
|
-
c.example 'doing now debugging @project2', desc: 'Add an entry with a tag'
|
|
16
|
-
c.example 'doing now adding an entry (with a note)', desc: 'Parenthetical at end is converted to note'
|
|
17
|
-
c.example 'doing now --back 2pm A thing I started at 2:00 and am still doing...', desc: 'Backdate an entry'
|
|
18
|
-
|
|
19
|
-
c.desc 'Section'
|
|
20
|
-
c.arg_name 'NAME'
|
|
21
|
-
c.flag %i[s section]
|
|
22
|
-
|
|
23
|
-
c.desc %(
|
|
24
|
-
Set a start and optionally end time as a date range ("from 1pm to 2:30pm").
|
|
25
|
-
If an end time is provided, a dated @done tag will be added
|
|
26
|
-
)
|
|
27
|
-
c.arg_name 'TIME_RANGE'
|
|
28
|
-
c.flag [:from], type: DateRangeString
|
|
29
|
-
|
|
30
|
-
c.desc 'Timed entry, marks last entry in section as @done'
|
|
31
|
-
c.switch %i[f finish_last], negatable: false, default_value: false
|
|
10
|
+
def setup(cmd)
|
|
11
|
+
add_examples(cmd)
|
|
12
|
+
add_options(cmd)
|
|
13
|
+
end
|
|
32
14
|
|
|
33
|
-
|
|
15
|
+
def process_now_options(options)
|
|
16
|
+
raise InvalidArgument, '--back and --from cannot be used together' if options[:back] && options[:from]
|
|
34
17
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
18
|
+
if options[:back]
|
|
19
|
+
options[:date] = options[:back]
|
|
20
|
+
elsif options[:from]
|
|
21
|
+
options[:date], finish_date = options[:from]
|
|
22
|
+
options[:done] = finish_date
|
|
23
|
+
else
|
|
24
|
+
options[:date] = Time.now
|
|
25
|
+
end
|
|
26
|
+
raise InvalidTimeExpression.new('unable to parse date string', topic: 'Parser:') if options[:date].nil?
|
|
38
27
|
|
|
39
|
-
|
|
40
|
-
|
|
28
|
+
options[:section] = if options[:section]
|
|
29
|
+
@wwid.guess_section(options[:section]) || options[:section].cap_first
|
|
30
|
+
else
|
|
31
|
+
Doing.setting('current_section')
|
|
32
|
+
end
|
|
41
33
|
|
|
42
|
-
|
|
34
|
+
options[:ask_note] = if options[:ask] && !options[:editor] && options[:has_args]
|
|
35
|
+
Doing::Prompt.read_lines(prompt: 'Add a note')
|
|
36
|
+
else
|
|
37
|
+
''
|
|
38
|
+
end
|
|
43
39
|
|
|
44
|
-
|
|
45
|
-
date = options[:back]
|
|
46
|
-
elsif options[:from]
|
|
47
|
-
date, finish_date = options[:from]
|
|
48
|
-
options[:done] = finish_date
|
|
49
|
-
else
|
|
50
|
-
date = Time.now
|
|
40
|
+
options
|
|
51
41
|
end
|
|
52
|
-
raise InvalidTimeExpression.new('unable to parse date string', topic: 'Parser:') if date.nil?
|
|
53
|
-
|
|
54
|
-
section = if options[:section]
|
|
55
|
-
@wwid.guess_section(options[:section]) || options[:section].cap_first
|
|
56
|
-
else
|
|
57
|
-
Doing.setting('current_section')
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
ask_note = if options[:ask] && !options[:editor] && args.count.positive?
|
|
61
|
-
Doing::Prompt.read_lines(prompt: 'Add a note')
|
|
62
|
-
else
|
|
63
|
-
''
|
|
64
|
-
end
|
|
65
42
|
|
|
66
|
-
|
|
43
|
+
def now_with_editor(options, args)
|
|
67
44
|
raise MissingEditor, 'No EDITOR variable defined in environment' if Doing::Util.default_editor.nil?
|
|
68
45
|
|
|
69
|
-
input = date.strftime('%F %R | ')
|
|
46
|
+
input = options[:date].strftime('%F %R | ')
|
|
70
47
|
input += args.join(' ') unless args.empty?
|
|
71
48
|
input += " @done(#{options[:done].strftime('%F %R')})" if options[:done]
|
|
72
49
|
input += "\n#{options[:note]}" if options[:note]
|
|
73
|
-
input += "\n#{ask_note}" if ask_note.good?
|
|
50
|
+
input += "\n#{options[:ask_note]}" if options[:ask_note].good?
|
|
74
51
|
input = @wwid.fork_editor(input).strip
|
|
75
52
|
|
|
76
53
|
d, title, note = @wwid.format_input(input)
|
|
77
54
|
raise EmptyInput, 'No content' unless title.good?
|
|
78
55
|
|
|
79
|
-
|
|
80
|
-
ask_note = Doing::Prompt.read_lines(prompt: 'Add a note')
|
|
81
|
-
note.add(ask_note) if ask_note.good?
|
|
82
|
-
end
|
|
56
|
+
note = ask_note(options, note, prompt: false)
|
|
83
57
|
|
|
84
|
-
date = d.nil? ? date : d
|
|
85
|
-
|
|
86
|
-
|
|
58
|
+
options[:date] = d.nil? ? options[:date] : d
|
|
59
|
+
opts = { note: note, back: options[:date], timed: options[:finish_last] }
|
|
60
|
+
@wwid.add_item(title.cap_first, options[:section], opts)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def now_with_args(options, args)
|
|
87
64
|
d, title, note = @wwid.format_input(args.join(' '))
|
|
88
|
-
date = d.nil? ? date : d
|
|
89
|
-
|
|
90
|
-
note
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
65
|
+
options[:date] = d.nil? ? options[:date] : d
|
|
66
|
+
|
|
67
|
+
note = ask_note(options, note, prompt: false)
|
|
68
|
+
|
|
69
|
+
opts = { note: note, back: options[:date], timed: options[:finish_last] }
|
|
70
|
+
entry = @wwid.add_item(title.cap_first, options[:section], opts)
|
|
71
|
+
return unless options[:done] && entry.should_finish?
|
|
72
|
+
|
|
73
|
+
entry.should_time? ? entry.tag('done', value: options[:done]) : entry.tag('done')
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def now_with_stdin(global_options, options, _args)
|
|
77
|
+
d, title, note = @wwid.format_input(global_options[:stdin])
|
|
78
|
+
|
|
102
79
|
unless d.nil?
|
|
103
80
|
Doing.logger.debug('Parser:', 'Date detected in input, overriding command line values')
|
|
104
|
-
date = d
|
|
105
|
-
end
|
|
106
|
-
note.add(options[:note]) if options[:note]
|
|
107
|
-
if ask_note.empty? && options[:ask]
|
|
108
|
-
ask_note = Doing::Prompt.read_lines(prompt: 'Add a note')
|
|
109
|
-
note.add(ask_note) if ask_note.good?
|
|
110
|
-
end
|
|
111
|
-
entry = @wwid.add_item(title.cap_first, section, { note: note, back: date, timed: options[:finish_last] })
|
|
112
|
-
if options[:done] && entry.should_finish?
|
|
113
|
-
if entry.should_time?
|
|
114
|
-
entry.tag('done', value: options[:done])
|
|
115
|
-
else
|
|
116
|
-
entry.tag('done')
|
|
117
|
-
end
|
|
81
|
+
options[:date] = d
|
|
118
82
|
end
|
|
119
|
-
|
|
83
|
+
|
|
84
|
+
note = ask_note(options, note, prompt: false)
|
|
85
|
+
|
|
86
|
+
opts = { note: note, back: options[:date], timed: options[:finish_last] }
|
|
87
|
+
entry = @wwid.add_item(title.cap_first, options[:section], opts)
|
|
88
|
+
return unless options[:done] && entry.should_finish?
|
|
89
|
+
|
|
90
|
+
entry.should_time? ? entry.tag('done', value: options[:done]) : entry.tag('done')
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def interactive_now(options, _args)
|
|
120
94
|
tags = @wwid.all_tags(@wwid.content)
|
|
121
|
-
|
|
95
|
+
puts Doing::Color.boldgreen('Add a new entry. Tab will autocomplete known tags. Ctrl-c to cancel.')
|
|
122
96
|
title = Doing::Prompt.read_line(prompt: 'Entry content', completions: tags)
|
|
123
97
|
raise EmptyInput, 'You must provide content when creating a new entry' unless title.good?
|
|
124
98
|
|
|
125
|
-
note =
|
|
99
|
+
note = ask_note(options, prompt: true)
|
|
100
|
+
|
|
101
|
+
opts = { note: note, back: options[:date], timed: options[:finish_last] }
|
|
102
|
+
entry = @wwid.add_item(title.cap_first, options[:section], opts)
|
|
103
|
+
return unless options[:done] && entry.should_finish?
|
|
104
|
+
|
|
105
|
+
if entry.should_time?
|
|
106
|
+
entry.tag('done', value: options[:done])
|
|
107
|
+
else
|
|
108
|
+
entry.tag('done')
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
private
|
|
113
|
+
|
|
114
|
+
def ask_note(options, note = nil, prompt: false)
|
|
115
|
+
note ||= Doing::Note.new
|
|
126
116
|
note.add(options[:note]) if options[:note]
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if options[:done] && entry.should_finish?
|
|
133
|
-
if entry.should_time?
|
|
134
|
-
entry.tag('done', value: options[:done])
|
|
135
|
-
else
|
|
136
|
-
entry.tag('done')
|
|
137
|
-
end
|
|
117
|
+
|
|
118
|
+
res = prompt ? Doing::Prompt.yn('Add a note', default_response: false) : false
|
|
119
|
+
|
|
120
|
+
if options[:ask_note].empty? && (res || options[:ask])
|
|
121
|
+
options[:ask_note] = Doing::Prompt.read_lines(prompt: 'Enter note')
|
|
138
122
|
end
|
|
123
|
+
|
|
124
|
+
note.add(options[:ask_note]) if options[:ask_note].good?
|
|
125
|
+
note
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def add_examples(cmd)
|
|
129
|
+
cmd.example 'doing now', desc: 'Create a new entry with interactive prompts'
|
|
130
|
+
cmd.example 'doing now -e', desc: "Open #{Doing::Util.default_editor} to input an entry and optional note"
|
|
131
|
+
cmd.example 'doing now working on a new project', desc: 'Add a new entry at the current time'
|
|
132
|
+
cmd.example 'doing now debugging @project2', desc: 'Add an entry with a tag'
|
|
133
|
+
cmd.example 'doing now adding an entry (with a note)', desc: 'Parenthetical at end is converted to note'
|
|
134
|
+
cmd.example 'doing now --back 2pm A thing I started at 2:00 and am still doing...', desc: 'Backdate an entry'
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def add_options(cmd)
|
|
138
|
+
cmd.desc 'Section'
|
|
139
|
+
cmd.arg_name 'NAME'
|
|
140
|
+
cmd.flag %i[s section]
|
|
141
|
+
|
|
142
|
+
cmd.desc %(Set a start and optionally end time as a date range ("from 1pm to 2:30pm").
|
|
143
|
+
If an end time is provided, a dated @done tag will be added)
|
|
144
|
+
cmd.arg_name 'TIME_RANGE'
|
|
145
|
+
cmd.flag [:from], type: DateRangeString
|
|
146
|
+
|
|
147
|
+
cmd.desc 'Timed entry, marks last entry in section as @done'
|
|
148
|
+
cmd.switch %i[f finish_last], negatable: false, default_value: false
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
desc 'Add an entry'
|
|
154
|
+
long_desc %(Record what you're starting now, or backdate the start time using natural language.
|
|
155
|
+
|
|
156
|
+
A parenthetical at the end of the entry will be converted to a note.
|
|
157
|
+
|
|
158
|
+
Run without arguments to create a new entry interactively.
|
|
159
|
+
|
|
160
|
+
Run with --editor to create a new entry using #{Doing::Util.default_editor}.)
|
|
161
|
+
arg_name 'ENTRY'
|
|
162
|
+
command %i[now next] do |c|
|
|
163
|
+
cmd = Doing::NowCommand.new(@wwid)
|
|
164
|
+
cmd.setup(c)
|
|
165
|
+
add_options(:add_entry, c)
|
|
166
|
+
|
|
167
|
+
# c.desc "Edit entry with specified app"
|
|
168
|
+
# c.arg_name 'editor_app'
|
|
169
|
+
# # c.flag [:a, :app]
|
|
170
|
+
c.action do |global_options, options, args|
|
|
171
|
+
Doing.auto_tag = !options[:noauto]
|
|
172
|
+
options[:has_args] = args.count.positive?
|
|
173
|
+
options = cmd.process_now_options(options)
|
|
174
|
+
|
|
175
|
+
if options[:editor]
|
|
176
|
+
cmd.now_with_editor(options, args)
|
|
177
|
+
elsif args.length.positive?
|
|
178
|
+
cmd.now_with_args(options, args)
|
|
179
|
+
elsif global_options[:stdin]
|
|
180
|
+
cmd.now_with_stdin(global_options, options, args)
|
|
181
|
+
else
|
|
182
|
+
cmd.interactive_now(options, args)
|
|
139
183
|
end
|
|
140
184
|
|
|
141
185
|
@wwid.write(@wwid.doing_file)
|
data/bin/commands/on.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# @@on
|
|
2
4
|
desc 'List entries for a date'
|
|
3
5
|
long_desc %(Date argument can be natural language. "thursday" would be interpreted as "last thursday,"
|
|
@@ -20,14 +22,15 @@ command :on do |c|
|
|
|
20
22
|
add_options(:time_filter, c)
|
|
21
23
|
|
|
22
24
|
c.action do |_global_options, options, args|
|
|
23
|
-
|
|
25
|
+
if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
|
|
26
|
+
raise InvalidPlugin.new('output', options[:output])
|
|
27
|
+
|
|
28
|
+
end
|
|
24
29
|
|
|
25
30
|
raise MissingArgument, 'Missing date argument' if args.empty?
|
|
26
31
|
|
|
27
32
|
date_string = args.join(' ').strip
|
|
28
|
-
if date_string =~ /^tod(?:ay)?/i
|
|
29
|
-
date_string = 'midnight to today 23:59'
|
|
30
|
-
end
|
|
33
|
+
date_string = 'midnight to today 23:59' if date_string =~ /^tod(?:ay)?/i
|
|
31
34
|
|
|
32
35
|
start, finish = date_string.split_date_range
|
|
33
36
|
|
data/bin/commands/undo.rb
CHANGED
|
@@ -28,7 +28,7 @@ command :undo do |c|
|
|
|
28
28
|
c.action do |_global_options, options, args|
|
|
29
29
|
file = options[:file] || @wwid.doing_file
|
|
30
30
|
count = args.empty? ? 1 : args[0].to_i
|
|
31
|
-
raise InvalidArgument,
|
|
31
|
+
raise InvalidArgument, 'Invalid count specified for undo' unless count&.positive?
|
|
32
32
|
|
|
33
33
|
if options[:prune]
|
|
34
34
|
Doing::Util::Backup.prune_backups(file, options[:prune])
|
|
@@ -38,12 +38,10 @@ command :undo do |c|
|
|
|
38
38
|
else
|
|
39
39
|
Doing::Util::Backup.redo_backup(file, count: count)
|
|
40
40
|
end
|
|
41
|
+
elsif options[:interactive]
|
|
42
|
+
Doing::Util::Backup.select_backup(file)
|
|
41
43
|
else
|
|
42
|
-
|
|
43
|
-
Doing::Util::Backup.select_backup(file)
|
|
44
|
-
else
|
|
45
|
-
Doing::Util::Backup.restore_last_backup(file, count: count)
|
|
46
|
-
end
|
|
44
|
+
Doing::Util::Backup.restore_last_backup(file, count: count)
|
|
47
45
|
end
|
|
48
46
|
end
|
|
49
47
|
end
|
data/docs/doc/Array.html
CHANGED
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
|
|
90
90
|
<dl>
|
|
91
91
|
<dt>Includes:</dt>
|
|
92
|
-
<dd>ArrayNestedHash, ArrayTags, <span class='object_link'><a href="Doing/ChronifyArray.html" title="Doing::ChronifyArray (module)">Doing::ChronifyArray</a></span></dd>
|
|
92
|
+
<dd>ArrayCleanup, ArrayNestedHash, ArrayTags, <span class='object_link'><a href="Doing/ChronifyArray.html" title="Doing::ChronifyArray (module)">Doing::ChronifyArray</a></span></dd>
|
|
93
93
|
</dl>
|
|
94
94
|
|
|
95
95
|
|
|
@@ -188,6 +188,7 @@
|
|
|
188
188
|
|
|
189
189
|
|
|
190
190
|
|
|
191
|
+
|
|
191
192
|
|
|
192
193
|
<div id="instance_method_details" class="method_details_list">
|
|
193
194
|
<h2>Instance Method Details</h2>
|
|
@@ -277,7 +278,7 @@ has content</p>
|
|
|
277
278
|
</div>
|
|
278
279
|
|
|
279
280
|
<div id="footer">
|
|
280
|
-
Generated on
|
|
281
|
+
Generated on Fri Mar 18 12:56:58 2022 by
|
|
281
282
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
|
282
283
|
0.9.27 (ruby-3.0.1).
|
|
283
284
|
</div>
|
|
@@ -283,7 +283,7 @@
|
|
|
283
283
|
</div>
|
|
284
284
|
|
|
285
285
|
<div id="footer">
|
|
286
|
-
Generated on
|
|
286
|
+
Generated on Fri Mar 18 12:56:58 2022 by
|
|
287
287
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
|
288
288
|
0.9.27 (ruby-3.0.1).
|
|
289
289
|
</div>
|
|
@@ -162,7 +162,7 @@
|
|
|
162
162
|
</div>
|
|
163
163
|
|
|
164
164
|
<div id="footer">
|
|
165
|
-
Generated on
|
|
165
|
+
Generated on Fri Mar 18 12:56:58 2022 by
|
|
166
166
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
|
167
167
|
0.9.27 (ruby-3.0.1).
|
|
168
168
|
</div>
|
|
@@ -407,7 +407,7 @@
|
|
|
407
407
|
</div>
|
|
408
408
|
|
|
409
409
|
<div id="footer">
|
|
410
|
-
Generated on
|
|
410
|
+
Generated on Fri Mar 18 12:56:58 2022 by
|
|
411
411
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
|
412
412
|
0.9.27 (ruby-3.0.1).
|
|
413
413
|
</div>
|
|
@@ -125,7 +125,7 @@ parser. In order to do that, a new "clause" node is added to the parse
|
|
|
125
125
|
</div>
|
|
126
126
|
|
|
127
127
|
<div id="footer">
|
|
128
|
-
Generated on
|
|
128
|
+
Generated on Fri Mar 18 12:56:58 2022 by
|
|
129
129
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
|
130
130
|
0.9.27 (ruby-3.0.1).
|
|
131
131
|
</div>
|
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
</div>
|
|
115
115
|
|
|
116
116
|
<div id="footer">
|
|
117
|
-
Generated on
|
|
117
|
+
Generated on Fri Mar 18 12:56:58 2022 by
|
|
118
118
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
|
119
119
|
0.9.27 (ruby-3.0.1).
|
|
120
120
|
</div>
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
</div>
|
|
106
106
|
|
|
107
107
|
<div id="footer">
|
|
108
|
-
Generated on
|
|
108
|
+
Generated on Fri Mar 18 12:56:58 2022 by
|
|
109
109
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
|
110
110
|
0.9.27 (ruby-3.0.1).
|
|
111
111
|
</div>
|
|
@@ -188,7 +188,7 @@
|
|
|
188
188
|
</div>
|
|
189
189
|
|
|
190
190
|
<div id="footer">
|
|
191
|
-
Generated on
|
|
191
|
+
Generated on Fri Mar 18 12:56:58 2022 by
|
|
192
192
|
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
|
193
193
|
0.9.27 (ruby-3.0.1).
|
|
194
194
|
</div>
|