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.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +1 -1
  5. data/bin/commands/again.rb +1 -3
  6. data/bin/commands/changes.rb +50 -34
  7. data/bin/commands/commands.rb +77 -52
  8. data/bin/commands/commands_accepting.rb +57 -53
  9. data/bin/commands/config.rb +2 -2
  10. data/bin/commands/finish.rb +94 -68
  11. data/bin/commands/flag.rb +5 -1
  12. data/bin/commands/now.rb +151 -107
  13. data/bin/commands/on.rb +7 -4
  14. data/bin/commands/undo.rb +4 -6
  15. data/docs/doc/Array.html +3 -2
  16. data/docs/doc/BooleanTermParser/Clause.html +1 -1
  17. data/docs/doc/BooleanTermParser/Operator.html +1 -1
  18. data/docs/doc/BooleanTermParser/Query.html +1 -1
  19. data/docs/doc/BooleanTermParser/QueryParser.html +1 -1
  20. data/docs/doc/BooleanTermParser/QueryTransformer.html +1 -1
  21. data/docs/doc/BooleanTermParser.html +1 -1
  22. data/docs/doc/Doing/ArrayNestedHash.html +1 -1
  23. data/docs/doc/Doing/ArrayTags.html +1 -1
  24. data/docs/doc/Doing/CSVExport.html +1 -1
  25. data/docs/doc/Doing/CalendarImport.html +1 -1
  26. data/docs/doc/Doing/Change.html +1 -1
  27. data/docs/doc/Doing/Changes.html +1 -1
  28. data/docs/doc/Doing/ChronifyArray.html +1 -1
  29. data/docs/doc/Doing/ChronifyNumeric.html +1 -1
  30. data/docs/doc/Doing/ChronifyString.html +1 -1
  31. data/docs/doc/Doing/Color.html +1 -1
  32. data/docs/doc/Doing/Completion/BashCompletions.html +1 -1
  33. data/docs/doc/Doing/Completion/FishCompletions.html +1 -1
  34. data/docs/doc/Doing/Completion/StringUtils.html +1 -1
  35. data/docs/doc/Doing/Completion/ZshCompletions.html +1 -1
  36. data/docs/doc/Doing/Completion.html +1 -1
  37. data/docs/doc/Doing/Configuration.html +3 -2
  38. data/docs/doc/Doing/DayOneRenderer.html +1 -1
  39. data/docs/doc/Doing/DayoneExport.html +1 -1
  40. data/docs/doc/Doing/DoingImport.html +1 -1
  41. data/docs/doc/Doing/Entry.html +1 -1
  42. data/docs/doc/Doing/Errors/DoingNoTraceError.html +1 -1
  43. data/docs/doc/Doing/Errors/DoingRuntimeError.html +1 -1
  44. data/docs/doc/Doing/Errors/DoingStandardError.html +1 -1
  45. data/docs/doc/Doing/Errors/EmptyInput.html +1 -1
  46. data/docs/doc/Doing/Errors/HistoryLimitError.html +1 -1
  47. data/docs/doc/Doing/Errors/InvalidPlugin.html +1 -1
  48. data/docs/doc/Doing/Errors/MissingBackupFile.html +1 -1
  49. data/docs/doc/Doing/Errors/NoResults.html +1 -1
  50. data/docs/doc/Doing/Errors/PluginException.html +1 -1
  51. data/docs/doc/Doing/Errors/UserCancelled.html +1 -1
  52. data/docs/doc/Doing/Errors/WrongCommand.html +1 -1
  53. data/docs/doc/Doing/Errors.html +1 -1
  54. data/docs/doc/Doing/HTMLExport.html +1 -1
  55. data/docs/doc/Doing/Hooks.html +1 -1
  56. data/docs/doc/Doing/Item.html +1 -1
  57. data/docs/doc/Doing/ItemDates.html +1 -1
  58. data/docs/doc/Doing/ItemQuery.html +1 -1
  59. data/docs/doc/Doing/ItemState.html +1 -1
  60. data/docs/doc/Doing/ItemTags.html +1 -1
  61. data/docs/doc/Doing/Items.html +2 -1
  62. data/docs/doc/Doing/JSONExport.html +1 -1
  63. data/docs/doc/Doing/Logger.html +1 -1
  64. data/docs/doc/Doing/MarkdownExport.html +1 -1
  65. data/docs/doc/Doing/Note.html +3 -2
  66. data/docs/doc/Doing/Pager.html +1 -1
  67. data/docs/doc/Doing/Plugins.html +181 -76
  68. data/docs/doc/Doing/Prompt.html +1 -1
  69. data/docs/doc/Doing/PromptChoose.html +1 -1
  70. data/docs/doc/Doing/PromptFZF.html +1 -1
  71. data/docs/doc/Doing/PromptInput.html +1 -1
  72. data/docs/doc/Doing/PromptSTD.html +1 -1
  73. data/docs/doc/Doing/PromptYN.html +1 -1
  74. data/docs/doc/Doing/Section.html +1 -1
  75. data/docs/doc/Doing/StringHighlight.html +1 -1
  76. data/docs/doc/Doing/StringNormalize.html +1 -1
  77. data/docs/doc/Doing/StringQuery.html +1 -1
  78. data/docs/doc/Doing/StringTags.html +1 -1
  79. data/docs/doc/Doing/StringTransform.html +35 -1
  80. data/docs/doc/Doing/StringTruncate.html +1 -1
  81. data/docs/doc/Doing/StringURL.html +1 -1
  82. data/docs/doc/Doing/SymbolNormalize.html +1 -1
  83. data/docs/doc/Doing/TaskPaperExport.html +1 -1
  84. data/docs/doc/Doing/TemplateExport.html +1 -1
  85. data/docs/doc/Doing/TemplateString.html +2 -2
  86. data/docs/doc/Doing/TimingImport.html +1 -1
  87. data/docs/doc/Doing/Types.html +1 -1
  88. data/docs/doc/Doing/Util/Backup.html +2 -156
  89. data/docs/doc/Doing/Util.html +66 -9
  90. data/docs/doc/Doing/Version.html +1 -1
  91. data/docs/doc/Doing/WWID.html +14 -1
  92. data/docs/doc/Doing.html +4 -4
  93. data/docs/doc/FalseClass.html +1 -1
  94. data/docs/doc/GLI/Commands/Help.html +1 -1
  95. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
  96. data/docs/doc/GLI/Commands.html +1 -1
  97. data/docs/doc/GLI.html +1 -1
  98. data/docs/doc/Hash.html +1 -1
  99. data/docs/doc/Numeric.html +1 -1
  100. data/docs/doc/Object.html +1 -1
  101. data/docs/doc/PhraseParser/Operator.html +1 -1
  102. data/docs/doc/PhraseParser/PhraseClause.html +1 -1
  103. data/docs/doc/PhraseParser/Query.html +1 -1
  104. data/docs/doc/PhraseParser/QueryParser.html +1 -1
  105. data/docs/doc/PhraseParser/QueryTransformer.html +1 -1
  106. data/docs/doc/PhraseParser/TermClause.html +1 -1
  107. data/docs/doc/PhraseParser.html +1 -1
  108. data/docs/doc/Status.html +1 -1
  109. data/docs/doc/String.html +2 -2
  110. data/docs/doc/Symbol.html +1 -1
  111. data/docs/doc/Time.html +1 -1
  112. data/docs/doc/TrueClass.html +1 -1
  113. data/docs/doc/_index.html +16 -9
  114. data/docs/doc/class_list.html +1 -1
  115. data/docs/doc/file.README.html +2 -2
  116. data/docs/doc/index.html +2 -2
  117. data/docs/doc/method_list.html +289 -281
  118. data/docs/doc/top-level-namespace.html +9 -1
  119. data/doing.rdoc +7 -7
  120. data/lib/doing/add_options.rb +8 -0
  121. data/lib/doing/array/array.rb +2 -0
  122. data/lib/doing/array/cleanup.rb +31 -0
  123. data/lib/doing/configuration.rb +7 -3
  124. data/lib/doing/note.rb +1 -1
  125. data/lib/doing/pager.rb +9 -3
  126. data/lib/doing/plugin_manager.rb +30 -5
  127. data/lib/doing/prompt/choose.rb +1 -1
  128. data/lib/doing/prompt/input.rb +1 -1
  129. data/lib/doing/string/transform.rb +6 -0
  130. data/lib/doing/util.rb +12 -6
  131. data/lib/doing/util_backup.rb +55 -48
  132. data/lib/doing/version.rb +1 -1
  133. data/lib/doing/wwid/editor.rb +6 -3
  134. data/lib/doing/wwid/interactive.rb +10 -20
  135. data/lib/doing/wwid/modify.rb +2 -0
  136. data/lib/doing.rb +3 -3
  137. metadata +3 -2
@@ -1,43 +1,97 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # @@finish
2
- desc 'Mark last X entries as @done'
3
- long_desc 'Marks the last X entries with a @done tag and current date. Does not alter already completed entries.'
4
- arg_name 'COUNT', optional: true
5
- command :finish do |c|
6
- c.example 'doing finish', desc: 'Mark the last entry @done'
7
- c.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'
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
- c.desc 'Include date'
11
- c.switch [:date], negatable: true, default_value: true
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
- c.desc 'Backdate completed date to date string [4pm|20m|2h|yesterday noon]'
14
- c.arg_name 'DATE_STRING'
15
- c.flag %i[b back started], type: DateBeginString
17
+ def add_options(cmd)
18
+ cmd.desc 'Include date'
19
+ cmd.switch [:date], negatable: true, default_value: true
16
20
 
17
- c.desc 'Overwrite existing @done tag with new date'
18
- c.switch %i[update], negatable: false, default_value: false
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
- c.desc 'Remove @done tag'
21
- c.switch %i[r remove], negatable: false, default_value: false
25
+ cmd.desc 'Overwrite existing @done tag with new date'
26
+ cmd.switch %i[update], negatable: false, default_value: false
22
27
 
23
- c.desc 'Finish last entry (or entries) not already marked @done'
24
- c.switch %i[u unfinished], negatable: false, default_value: false
28
+ cmd.desc 'Remove @done tag'
29
+ cmd.switch %i[r remove], negatable: false, default_value: false
25
30
 
26
- c.desc %(Auto-generate finish dates from next entry's start time.
27
- Automatically generate completion dates 1 minute before next item (in any section) began.
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
- c.desc 'Archive entries'
32
- c.switch %i[a archive], negatable: false, default_value: false
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
- c.desc 'Section'
35
- c.arg_name 'NAME'
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
- c.desc 'Select item(s) to finish from a menu of matching entries'
39
- c.switch %i[i interactive], negatable: false, default_value: false
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
- options[:from] = options[:from].split(/#{REGEX_RANGE_INDICATOR}/).map do |time|
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
- if options[:took]
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
- if options[:tag].nil?
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
- raise InvalidArgument, 'Invalid argument (specify number of recent items to mark @done)' unless args.length == 0 || args[0] =~ /\d+/
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/"', desc: 'Find entries matching regular expression and create a menu allowing multiple selections, selected items will be @flagged'
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
- Run without arguments to create a new entry interactively.
3
+ module Doing
4
+ # Methods for the now command
5
+ class NowCommand
6
+ def initialize(wwid)
7
+ @wwid = wwid
8
+ end
8
9
 
9
- Run with --editor to create a new entry using #{Doing::Util.default_editor}.)
10
- arg_name 'ENTRY'
11
- command %i[now next] do |c|
12
- c.example 'doing now', desc: 'Create a new entry with interactive prompts'
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
- add_options(:add_entry, c)
15
+ def process_now_options(options)
16
+ raise InvalidArgument, '--back and --from cannot be used together' if options[:back] && options[:from]
34
17
 
35
- # c.desc "Edit entry with specified app"
36
- # c.arg_name 'editor_app'
37
- # # c.flag [:a, :app]
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
- c.action do |global_options, options, args|
40
- Doing.auto_tag = !options[:noauto]
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
- raise InvalidArgument, '--back and --from cannot be used together' if options[:back] && options[:from]
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
- if options[:back]
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
- if options[:editor]
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
- if ask_note.empty? && options[:ask]
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
- @wwid.add_item(title.cap_first, section, { note: note, back: date, timed: options[:finish_last] })
86
- elsif args.length.positive?
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
- note.add(options[:note]) if options[:note]
90
- note.add(ask_note) if ask_note.good?
91
- entry = @wwid.add_item(title.cap_first, section, { note: note, back: date, timed: options[:finish_last] })
92
- if options[:done] && entry.should_finish?
93
- if entry.should_time?
94
- entry.tag('done', value: options[:done])
95
- else
96
- entry.tag('done')
97
- end
98
- end
99
- elsif global_options[:stdin]
100
- input = global_options[:stdin]
101
- d, title, note = @wwid.format_input(input)
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
- else
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
- $stderr.puts Doing::Color.boldgreen("Add a new entry. Tab will autocomplete known tags. Ctrl-c to cancel.")
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 = Doing::Note.new
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
- res = Doing::Prompt.yn('Add a note', default_response: false)
128
- ask_note = res ? Doing::Prompt.read_lines(prompt: 'Enter note') : []
129
- note.add(ask_note)
130
-
131
- entry = @wwid.add_item(title.cap_first, section, { note: note, back: date, timed: options[:finish_last] })
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
- raise InvalidPlugin.new('output', options[:output]) if options[:output] && options[:output] !~ Doing::Plugins.plugin_regex(type: :export)
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, "Invalid count specified for undo" unless count&.positive?
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
- if options[:interactive]
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 Wed Mar 16 09:42:15 2022 by
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 Wed Mar 16 09:42:15 2022 by
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 Wed Mar 16 09:42:15 2022 by
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 Wed Mar 16 09:42:15 2022 by
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 &quot;clause&quot; node is added to the parse
125
125
  </div>
126
126
 
127
127
  <div id="footer">
128
- Generated on Wed Mar 16 09:42:15 2022 by
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 Wed Mar 16 09:42:15 2022 by
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 Wed Mar 16 09:42:15 2022 by
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 Wed Mar 16 09:42:15 2022 by
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>