na 1.2.29 → 1.2.30
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 +28 -20
- data/bin/commands/add.rb +167 -164
- data/bin/commands/archive.rb +54 -51
- data/bin/commands/changes.rb +18 -15
- data/bin/commands/complete.rb +50 -47
- data/bin/commands/completed.rb +99 -0
- data/bin/commands/edit.rb +37 -34
- data/bin/commands/find.rb +109 -106
- data/bin/commands/init.rb +22 -19
- data/bin/commands/next.rb +135 -131
- data/bin/commands/projects.rb +27 -24
- data/bin/commands/prompt.rb +41 -38
- data/bin/commands/saved.rb +42 -34
- data/bin/commands/tagged.rb +137 -134
- data/bin/commands/todos.rb +23 -20
- data/bin/commands/update.rb +215 -207
- data/bin/na +7 -1166
- data/lib/na/array.rb +13 -0
- data/lib/na/help_monkey_patch.rb +32 -0
- data/lib/na/next_action.rb +3 -2
- data/lib/na/pager.rb +94 -0
- data/lib/na/string.rb +10 -0
- data/lib/na/version.rb +1 -1
- data/lib/na.rb +2 -0
- metadata +7 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3d0dbc271a5a8f1812c5ef0596031d5ca9fc726efe0cde91e1172840d15acb61
|
|
4
|
+
data.tar.gz: 44599dadd458ebfcb610fcf80b5326231404f199f61b6e195b103bb4a095ff06
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 448bea330450c05446027995d4ea6ccdb5cdf80fa43672d8ccb08a808ca9a171fbd80aa2d7e2054568c458411b25037db66b644e0bde43e8ac614b9b469d97cc
|
|
7
|
+
data.tar.gz: 146ed95b595f010a5964134f4eba2701ccd7a9b103c692941a8fb68052023f29b09ffabffba74dbc93a20a64397fe8417f9ab0343bde9a3af8d292bfa2351e6f
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
### 1.2.30
|
|
2
|
+
|
|
3
|
+
2023-08-29 06:50
|
|
4
|
+
|
|
5
|
+
#### NEW
|
|
6
|
+
|
|
7
|
+
- `na completed` to show completed actions with date ranges and search patterns
|
|
8
|
+
- Pagination using system pager
|
|
9
|
+
|
|
10
|
+
#### IMPROVED
|
|
11
|
+
|
|
12
|
+
- When replacing a priority tag, remove any space before it the action text
|
|
13
|
+
- Restore command decomposition
|
|
14
|
+
- Allow multiple saved searches to be executed at once
|
|
15
|
+
- `--restore` flag for update command to remove @done tags
|
|
16
|
+
- Pagination for help output
|
|
17
|
+
|
|
18
|
+
#### FIXED
|
|
19
|
+
|
|
20
|
+
- `--done` flag not working on `na next`
|
|
21
|
+
- Missing descriptions in help examples
|
|
22
|
+
|
|
1
23
|
### 1.2.29
|
|
2
24
|
|
|
3
25
|
2023-08-21 11:08
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
_If you're one of the rare people like me who find this useful, feel free to
|
|
10
10
|
[buy me some coffee][donate]._
|
|
11
11
|
|
|
12
|
-
The current version of `na` is 1.2.
|
|
12
|
+
The current version of `na` is 1.2.30
|
|
13
13
|
.
|
|
14
14
|
|
|
15
15
|
`na` ("next action") is a command line tool designed to make it easy to see what your next actions are for any project, right from the command line. It works with TaskPaper-formatted files (but any plain text format will do), looking for `@na` tags (or whatever you specify) in todo files in your current folder.
|
|
@@ -77,42 +77,44 @@ SYNOPSIS
|
|
|
77
77
|
na [global options] command [command options] [arguments...]
|
|
78
78
|
|
|
79
79
|
VERSION
|
|
80
|
-
1.2.
|
|
80
|
+
1.2.30
|
|
81
81
|
|
|
82
82
|
GLOBAL OPTIONS
|
|
83
83
|
-a, --add - Add a next action (deprecated, for backwards compatibility)
|
|
84
84
|
--add_at=POSITION - Add all new/moved entries at [s]tart or [e]nd of target project (default: start)
|
|
85
85
|
--[no-]color - Colorize output (default: enabled)
|
|
86
86
|
--cwd_as=TYPE - Use current working directory as [p]roject, [t]ag, or [n]one (default: none)
|
|
87
|
-
-d, --depth=DEPTH - Recurse to depth (default:
|
|
87
|
+
-d, --depth=DEPTH - Recurse to depth (default: 1)
|
|
88
88
|
--[no-]debug - Display verbose output
|
|
89
89
|
--ext=EXT - File extension to consider a todo file (default: taskpaper)
|
|
90
90
|
-f, --file=PATH - Use a single file as global todo, use initconfig to make permanent (default: none)
|
|
91
91
|
--help - Show this message
|
|
92
92
|
-n, --note - Prompt for additional notes (deprecated, for backwards compatibility)
|
|
93
93
|
-p, --priority=PRIORITY - Set a priority 0-5 (deprecated, for backwards compatibility) (default: none)
|
|
94
|
+
--[no-]pager - Enable pagination (default: enabled)
|
|
94
95
|
-r, --[no-]recurse - Recurse 3 directories deep (deprecated, for backwards compatability)
|
|
95
96
|
-t, --na_tag=TAG - Tag to consider a next action (default: na)
|
|
96
97
|
--template=PATH - Provide a template for new/blank todo files, use initconfig to make permanent (default: none)
|
|
97
98
|
--version - Display the program version
|
|
98
99
|
|
|
99
100
|
COMMANDS
|
|
100
|
-
add
|
|
101
|
-
archive
|
|
102
|
-
changes, changelog
|
|
103
|
-
complete, finish
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
101
|
+
add - Add a new next action
|
|
102
|
+
archive - Mark an action as @done and archive
|
|
103
|
+
changes, changelog - Display the changelog
|
|
104
|
+
complete, finish - Find and mark an action as @done
|
|
105
|
+
completed, finished - Display completed actions
|
|
106
|
+
edit - Open a todo file in the default editor
|
|
107
|
+
find, grep - Find actions matching a search pattern
|
|
108
|
+
help - Shows a list of commands or help for one command
|
|
109
|
+
init, create - Create a new todo file in the current directory
|
|
110
|
+
initconfig - Initialize the config file using current global options
|
|
111
|
+
next, show - Show next actions
|
|
112
|
+
projects - Show list of projects for a file
|
|
113
|
+
prompt - Show or install prompt hooks for the current shell
|
|
114
|
+
saved - Execute a saved search
|
|
115
|
+
tagged - Find actions matching a tag
|
|
116
|
+
todos - Show list of known todo files
|
|
117
|
+
update - Update an existing action
|
|
116
118
|
```
|
|
117
119
|
|
|
118
120
|
#### Commands
|
|
@@ -339,7 +341,7 @@ NAME
|
|
|
339
341
|
|
|
340
342
|
SYNOPSIS
|
|
341
343
|
|
|
342
|
-
na [global options] saved [command options] [SEARCH_TITLE]
|
|
344
|
+
na [global options] saved [command options] [SEARCH_TITLE]...
|
|
343
345
|
|
|
344
346
|
DESCRIPTION
|
|
345
347
|
Run without argument to list saved searches
|
|
@@ -350,14 +352,19 @@ COMMAND OPTIONS
|
|
|
350
352
|
|
|
351
353
|
EXAMPLES
|
|
352
354
|
|
|
355
|
+
# save a search called "maybelater"
|
|
353
356
|
na tagged "+maybe,+priority<=3" --save maybelater
|
|
354
357
|
|
|
358
|
+
# perform the search named "maybelater"
|
|
355
359
|
na saved maybelater
|
|
356
360
|
|
|
361
|
+
# perform the search named "maybelater", assuming no other searches match "maybe"
|
|
357
362
|
na saved maybe
|
|
358
363
|
|
|
364
|
+
# na run with no command and a single argument automatically performs a matching saved search
|
|
359
365
|
na maybe
|
|
360
366
|
|
|
367
|
+
# list available searches
|
|
361
368
|
na saved
|
|
362
369
|
```
|
|
363
370
|
|
|
@@ -484,6 +491,7 @@ COMMAND OPTIONS
|
|
|
484
491
|
-o, --overwrite - Overwrite note instead of appending
|
|
485
492
|
-p, --priority=PRIO - Add/change a priority level 1-5 (default: 0)
|
|
486
493
|
-r, --remove=TAG - Remove a tag to the action (may be used more than once, default: none)
|
|
494
|
+
--restore - Remove @done tag from action
|
|
487
495
|
-t, --tag=TAG - Add a tag to the action, @tag(values) allowed (may be used more than once, default: none)
|
|
488
496
|
--tagged=TAG - Match actions containing tag. Allows value comparisons (may be used more than once, default: none)
|
|
489
497
|
--to, --project, --proj=PROJECT - Move action to specific project (default: none)
|
data/bin/commands/add.rb
CHANGED
|
@@ -1,183 +1,186 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
target = File.expand_path(options[:file])
|
|
74
|
-
unless File.exist?(target)
|
|
75
|
-
res = NA.yn(NA::Color.template('{by}Specified file not found, create it'), default: true)
|
|
76
|
-
if res
|
|
77
|
-
basename = File.basename(target, ".#{NA.extension}")
|
|
78
|
-
NA.create_todo(target, basename, template: global_options[:template])
|
|
79
|
-
else
|
|
80
|
-
puts NA::Color.template('{r}Cancelled{x}')
|
|
81
|
-
Process.exit 1
|
|
3
|
+
class App
|
|
4
|
+
extend GLI::App
|
|
5
|
+
desc 'Add a new next action'
|
|
6
|
+
long_desc 'Provides an easy way to store todos while you work. Add quick
|
|
7
|
+
reminders and (if you set up Prompt Hooks) they\'ll automatically display
|
|
8
|
+
next time you enter the directory.
|
|
9
|
+
|
|
10
|
+
If multiple todo files are found in the current directory, a menu will
|
|
11
|
+
allow you to pick to which file the action gets added.'
|
|
12
|
+
arg_name 'ACTION'
|
|
13
|
+
command :add do |c|
|
|
14
|
+
c.example 'na add "A cool feature I thought of @idea"', desc: 'Add a new action to the Inbox, including a tag'
|
|
15
|
+
c.example 'na add "A bug I need to fix" -p 4 -n',
|
|
16
|
+
desc: 'Add a new action to the Inbox, set its @priority to 4, and prompt for an additional note.'
|
|
17
|
+
c.example 'na add "An action item (with a note)"',
|
|
18
|
+
desc: 'A parenthetical at the end of an action is interpreted as a note'
|
|
19
|
+
|
|
20
|
+
c.desc 'Prompt for additional notes. STDIN input (piped) will be treated as a note if present.'
|
|
21
|
+
c.switch %i[n note], negatable: false
|
|
22
|
+
|
|
23
|
+
c.desc 'Add a priority level 1-5'
|
|
24
|
+
c.arg_name 'PRIO'
|
|
25
|
+
c.flag %i[p priority], must_match: /[1-5]/, type: :integer, default_value: 0
|
|
26
|
+
|
|
27
|
+
c.desc 'Add action to specific project'
|
|
28
|
+
c.arg_name 'PROJECT'
|
|
29
|
+
c.default_value 'Inbox'
|
|
30
|
+
c.flag %i[to project proj]
|
|
31
|
+
|
|
32
|
+
c.desc 'Add task at [s]tart or [e]nd of target project'
|
|
33
|
+
c.arg_name 'POSITION'
|
|
34
|
+
c.flag %i[at], must_match: /^[sbea].*?$/i
|
|
35
|
+
|
|
36
|
+
c.desc 'Add to a known todo file, partial matches allowed'
|
|
37
|
+
c.arg_name 'TODO_FILE'
|
|
38
|
+
c.flag %i[in todo]
|
|
39
|
+
|
|
40
|
+
c.desc 'Use a tag other than the default next action tag'
|
|
41
|
+
c.arg_name 'TAG'
|
|
42
|
+
c.flag %i[t tag]
|
|
43
|
+
|
|
44
|
+
c.desc 'Don\'t add next action tag to new entry'
|
|
45
|
+
c.switch %i[x], negatable: false
|
|
46
|
+
|
|
47
|
+
c.desc 'Specify the file to which the task should be added'
|
|
48
|
+
c.arg_name 'PATH'
|
|
49
|
+
c.flag %i[f file]
|
|
50
|
+
|
|
51
|
+
c.desc 'Mark task as @done with date'
|
|
52
|
+
c.switch %i[finish done], negatable: false
|
|
53
|
+
|
|
54
|
+
c.desc 'Search for files X directories deep'
|
|
55
|
+
c.arg_name 'DEPTH'
|
|
56
|
+
c.flag %i[d depth], must_match: /^[1-9]$/, type: :integer, default_value: 1
|
|
57
|
+
|
|
58
|
+
c.action do |global_options, options, args|
|
|
59
|
+
reader = TTY::Reader.new
|
|
60
|
+
append = options[:at] ? options[:at] =~ /^[ae]/i : global_options[:add_at] =~ /^[ae]/
|
|
61
|
+
|
|
62
|
+
if NA.global_file
|
|
63
|
+
target = File.expand_path(NA.global_file)
|
|
64
|
+
unless File.exist?(target)
|
|
65
|
+
res = NA.yn(NA::Color.template('{by}Specified file not found, create it'), default: true)
|
|
66
|
+
if res
|
|
67
|
+
basename = File.basename(target, ".#{NA.extension}")
|
|
68
|
+
NA.create_todo(target, basename, template: global_options[:template])
|
|
69
|
+
else
|
|
70
|
+
puts NA::Color.template('{r}Cancelled{x}')
|
|
71
|
+
Process.exit 1
|
|
72
|
+
end
|
|
82
73
|
end
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
todo = []
|
|
86
|
-
all_req = options[:todo] !~ /[+!\-]/
|
|
87
|
-
options[:todo].split(/ *, */).each do |a|
|
|
88
|
-
m = a.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
|
|
89
|
-
todo.push({
|
|
90
|
-
token: m['tok'],
|
|
91
|
-
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
|
92
|
-
negate: !m['req'].nil? && m['req'] =~ /[!\-]/
|
|
93
|
-
})
|
|
94
|
-
end
|
|
95
|
-
dirs = NA.match_working_dir(todo)
|
|
96
|
-
if dirs.count.positive?
|
|
97
|
-
target = dirs[0]
|
|
98
|
-
else
|
|
99
|
-
todo = "#{options[:todo].sub(/#{NA.extension}$/, '')}.#{NA.extension}"
|
|
100
|
-
target = File.expand_path(todo)
|
|
74
|
+
elsif options[:file]
|
|
75
|
+
target = File.expand_path(options[:file])
|
|
101
76
|
unless File.exist?(target)
|
|
77
|
+
res = NA.yn(NA::Color.template('{by}Specified file not found, create it'), default: true)
|
|
78
|
+
if res
|
|
79
|
+
basename = File.basename(target, ".#{NA.extension}")
|
|
80
|
+
NA.create_todo(target, basename, template: global_options[:template])
|
|
81
|
+
else
|
|
82
|
+
puts NA::Color.template('{r}Cancelled{x}')
|
|
83
|
+
Process.exit 1
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
elsif options[:todo]
|
|
87
|
+
todo = []
|
|
88
|
+
all_req = options[:todo] !~ /[+!\-]/
|
|
89
|
+
options[:todo].split(/ *, */).each do |a|
|
|
90
|
+
m = a.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
|
|
91
|
+
todo.push({
|
|
92
|
+
token: m['tok'],
|
|
93
|
+
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
|
94
|
+
negate: !m['req'].nil? && m['req'] =~ /[!\-]/
|
|
95
|
+
})
|
|
96
|
+
end
|
|
97
|
+
dirs = NA.match_working_dir(todo)
|
|
98
|
+
if dirs.count.positive?
|
|
99
|
+
target = dirs[0]
|
|
100
|
+
else
|
|
101
|
+
todo = "#{options[:todo].sub(/#{NA.extension}$/, '')}.#{NA.extension}"
|
|
102
|
+
target = File.expand_path(todo)
|
|
103
|
+
unless File.exist?(target)
|
|
102
104
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
+
res = NA.yn(NA::Color.template("{by}Specified file not found, create #{todo}"), default: true)
|
|
106
|
+
NA.notify('{r}Cancelled{x}', exit_code: 1) unless res
|
|
105
107
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
108
|
+
basename = File.basename(target, ".#{NA.extension}")
|
|
109
|
+
NA.create_todo(target, basename, template: global_options[:template])
|
|
110
|
+
end
|
|
109
111
|
|
|
110
|
-
end
|
|
111
|
-
else
|
|
112
|
-
files = NA.find_files(depth: options[:depth])
|
|
113
|
-
if files.count.zero?
|
|
114
|
-
res = NA.yn(NA::Color.template('{by}No todo file found, create one'), default: true)
|
|
115
|
-
if res
|
|
116
|
-
basename = File.expand_path('.').split('/').last
|
|
117
|
-
target = "#{basename}.#{NA.extension}"
|
|
118
|
-
NA.create_todo(target, basename, template: global_options[:template])
|
|
119
|
-
files = NA.find_files(depth: 1)
|
|
120
112
|
end
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
113
|
+
else
|
|
114
|
+
files = NA.find_files(depth: options[:depth])
|
|
115
|
+
if files.count.zero?
|
|
116
|
+
res = NA.yn(NA::Color.template('{by}No todo file found, create one'), default: true)
|
|
117
|
+
if res
|
|
118
|
+
basename = File.expand_path('.').split('/').last
|
|
119
|
+
target = "#{basename}.#{NA.extension}"
|
|
120
|
+
NA.create_todo(target, basename, template: global_options[:template])
|
|
121
|
+
files = NA.find_files(depth: 1)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
target = files.count > 1 ? NA.select_file(files) : files[0]
|
|
125
|
+
NA.notify('{r}Cancelled{x}', exit_code: 1) unless files.count.positive? && File.exist?(target)
|
|
126
126
|
|
|
127
|
-
|
|
128
|
-
args.join(' ').strip
|
|
129
|
-
elsif $stdin.isatty && TTY::Which.exist?('gum')
|
|
130
|
-
`gum input --placeholder "Enter a task" --char-limit=500 --width=#{TTY::Screen.columns}`.strip
|
|
131
|
-
elsif $stdin.isatty
|
|
132
|
-
puts NA::Color.template('{bm}Enter task:{x}')
|
|
133
|
-
reader.read_line(NA::Color.template('{by}> {bw}')).strip
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
if action.nil? || action.empty?
|
|
137
|
-
puts 'Empty input, cancelled'
|
|
138
|
-
Process.exit 1
|
|
139
|
-
end
|
|
127
|
+
end
|
|
140
128
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
129
|
+
action = if args.count.positive?
|
|
130
|
+
args.join(' ').strip
|
|
131
|
+
elsif $stdin.isatty && TTY::Which.exist?('gum')
|
|
132
|
+
`gum input --placeholder "Enter a task" --char-limit=500 --width=#{TTY::Screen.columns}`.strip
|
|
133
|
+
elsif $stdin.isatty
|
|
134
|
+
puts NA::Color.template('{bm}Enter task:{x}')
|
|
135
|
+
reader.read_line(NA::Color.template('{by}> {bw}')).strip
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
if action.nil? || action.empty?
|
|
139
|
+
puts 'Empty input, cancelled'
|
|
140
|
+
Process.exit 1
|
|
141
|
+
end
|
|
144
142
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
action.sub!(note_rx, '\1').strip!
|
|
149
|
-
n
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
na_tag = NA.na_tag
|
|
153
|
-
if options[:x]
|
|
154
|
-
na_tag = ''
|
|
155
|
-
else
|
|
156
|
-
na_tag = options[:tag] unless options[:tag].nil?
|
|
157
|
-
na_tag = " @#{na_tag}"
|
|
158
|
-
end
|
|
143
|
+
if options[:priority]&.to_i&.positive?
|
|
144
|
+
action = "#{action.gsub(/@priority\(\d+\)/, '')} @priority(#{options[:priority]})"
|
|
145
|
+
end
|
|
159
146
|
|
|
160
|
-
|
|
147
|
+
note_rx = /^(.+) \((.*?)\)$/
|
|
148
|
+
split_note = if action =~ note_rx
|
|
149
|
+
n = Regexp.last_match(2)
|
|
150
|
+
action.sub!(note_rx, '\1').strip!
|
|
151
|
+
n
|
|
152
|
+
end
|
|
161
153
|
|
|
162
|
-
|
|
154
|
+
na_tag = NA.na_tag
|
|
155
|
+
if options[:x]
|
|
156
|
+
na_tag = ''
|
|
157
|
+
else
|
|
158
|
+
na_tag = options[:tag] unless options[:tag].nil?
|
|
159
|
+
na_tag = " @#{na_tag}"
|
|
160
|
+
end
|
|
163
161
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
162
|
+
action = "#{action.gsub(/#{na_tag}\b/, '')}#{na_tag}"
|
|
163
|
+
|
|
164
|
+
stdin_note = NA.stdin ? NA.stdin.split("\n") : []
|
|
165
|
+
|
|
166
|
+
line_note = if options[:note] && $stdin.isatty
|
|
167
|
+
puts stdin_note unless stdin_note.nil?
|
|
168
|
+
if TTY::Which.exist?('gum')
|
|
169
|
+
args = ['--placeholder "Enter additional note, CTRL-d to save"']
|
|
170
|
+
args << '--char-limit 0'
|
|
171
|
+
args << '--width $(tput cols)'
|
|
172
|
+
`gum write #{args.join(' ')}`.strip.split("\n")
|
|
173
|
+
else
|
|
174
|
+
puts NA::Color.template('{bm}Enter a note, {bw}CTRL-d{bm} to end editing{bw}')
|
|
175
|
+
reader.read_multiline
|
|
176
|
+
end
|
|
174
177
|
end
|
|
175
|
-
end
|
|
176
178
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
179
|
+
note = stdin_note.empty? ? [] : stdin_note
|
|
180
|
+
note.concat(split_note) unless split_note.nil?
|
|
181
|
+
note.concat(line_note) unless line_note.nil?
|
|
180
182
|
|
|
181
|
-
|
|
183
|
+
NA.add_action(target, options[:project], action, note, finish: options[:finish], append: append)
|
|
184
|
+
end
|
|
182
185
|
end
|
|
183
186
|
end
|
data/bin/commands/archive.rb
CHANGED
|
@@ -1,56 +1,59 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
options[:
|
|
3
|
+
class App
|
|
4
|
+
extend GLI::App
|
|
5
|
+
desc 'Mark an action as @done and archive'
|
|
6
|
+
arg_name 'ACTION'
|
|
7
|
+
command %i[archive] do |c|
|
|
8
|
+
c.example 'na archive "An existing task"',
|
|
9
|
+
desc: 'Find "An existing task", mark @done if needed, and move to archive'
|
|
10
|
+
|
|
11
|
+
c.desc 'Prompt for additional notes. Input will be appended to any existing note.
|
|
12
|
+
If STDIN input (piped) is detected, it will be used as a note.'
|
|
13
|
+
c.switch %i[n note], negatable: false
|
|
14
|
+
|
|
15
|
+
c.desc 'Overwrite note instead of appending'
|
|
16
|
+
c.switch %i[o overwrite], negatable: false
|
|
17
|
+
|
|
18
|
+
c.desc 'Archive all done tasks'
|
|
19
|
+
c.switch %i[done], negatable: false
|
|
20
|
+
|
|
21
|
+
c.desc 'Specify the file to search for the task'
|
|
22
|
+
c.arg_name 'PATH'
|
|
23
|
+
c.flag %i[file]
|
|
24
|
+
|
|
25
|
+
c.desc 'Search for files X directories deep'
|
|
26
|
+
c.arg_name 'DEPTH'
|
|
27
|
+
c.flag %i[d depth], must_match: /^[1-9]$/, type: :integer, default_value: 1
|
|
28
|
+
|
|
29
|
+
c.desc 'Match actions containing tag. Allows value comparisons'
|
|
30
|
+
c.arg_name 'TAG'
|
|
31
|
+
c.flag %i[tagged], multiple: true
|
|
32
|
+
|
|
33
|
+
c.desc 'Act on all matches immediately (no menu)'
|
|
34
|
+
c.switch %i[all], negatable: false
|
|
35
|
+
|
|
36
|
+
c.desc 'Interpret search pattern as regular expression'
|
|
37
|
+
c.switch %i[e regex], negatable: false
|
|
38
|
+
|
|
39
|
+
c.desc 'Match pattern exactly'
|
|
40
|
+
c.switch %i[x exact], negatable: false
|
|
41
|
+
|
|
42
|
+
c.action do |global, options, args|
|
|
43
|
+
if options[:done]
|
|
44
|
+
options[:tagged] = ['done']
|
|
45
|
+
options[:all] = true
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
options[:done] = true
|
|
49
|
+
options[:finish] = true
|
|
50
|
+
options[:project] = 'Archive'
|
|
51
|
+
options[:archive] = true
|
|
52
|
+
options[:a] = true
|
|
53
|
+
|
|
54
|
+
cmd = commands[:update]
|
|
55
|
+
action = cmd.send(:get_action, nil)
|
|
56
|
+
action.call(global, options, args)
|
|
44
57
|
end
|
|
45
|
-
|
|
46
|
-
options[:done] = true
|
|
47
|
-
options[:finish] = true
|
|
48
|
-
options[:project] = 'Archive'
|
|
49
|
-
options[:archive] = true
|
|
50
|
-
options[:a] = true
|
|
51
|
-
|
|
52
|
-
cmd = commands[:update]
|
|
53
|
-
action = cmd.send(:get_action, nil)
|
|
54
|
-
action.call(global, options, args)
|
|
55
58
|
end
|
|
56
59
|
end
|