na 1.2.0 → 1.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +35 -0
- data/Gemfile.lock +3 -1
- data/README.md +46 -19
- data/bin/na +159 -65
- data/lib/na/action.rb +3 -1
- data/lib/na/next_action.rb +131 -55
- data/lib/na/project.rb +1 -1
- data/lib/na/version.rb +1 -1
- data/na.gemspec +1 -0
- data/src/README.md +15 -1
- metadata +22 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ba10397406ce9b754a63fcd7787eb5cc22923d5564de8eca50cb8bb6000115e7
|
4
|
+
data.tar.gz: c7c47d9531177787b1615857135d8bc69ab3b3a3595aad30d357fa39f9b41fe5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6861532283cf20d55f9fddff1979209024301863f01dfbe1d79d83096e397ab94b59a45715f1d1486939afce8e2fbb2b90196bbca5cb8a93ae5d02636804442d
|
7
|
+
data.tar.gz: 9ebceba70f481a722c616d1ad819c23bd9dab13abebf68371fd966f0834585826596084e27bf27cc632515a4a7c7b162abedc4f997672cb7439ab22bf5ace8f1
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,38 @@
|
|
1
|
+
### 1.2.2
|
2
|
+
|
3
|
+
2022-10-25 14:30
|
4
|
+
|
5
|
+
#### CHANGED
|
6
|
+
|
7
|
+
- `na update --done` now means "include @done actions in search"
|
8
|
+
- `na next --in QUERY` now searches for a known todo file (formerly required arguments, now both work)
|
9
|
+
|
10
|
+
#### NEW
|
11
|
+
|
12
|
+
- `--at [start|end]` switch for `add` and `update` to determine
|
13
|
+
- Global `--file PATH` flag to specify a single global todo file,
|
14
|
+
- `--add_at [start|end]` global flag that can be added to config to make permanent
|
15
|
+
- `--finish` switch for `na add` to immediately mark an action as @done
|
16
|
+
- `--cwd_as [project|tag]` global flag when using a global `--file` to determine if the current working directory (last element) is added as an @tag or parent project
|
17
|
+
|
18
|
+
#### IMPROVED
|
19
|
+
|
20
|
+
- Refactor `na add` to use improved task update code
|
21
|
+
- Confirm target file before requesting task when running `na
|
22
|
+
|
23
|
+
### 1.2.1
|
24
|
+
|
25
|
+
2022-10-22 10:18
|
26
|
+
|
27
|
+
#### NEW
|
28
|
+
|
29
|
+
- Added `--done` tag to next/find/tagged to include @done actions in the output
|
30
|
+
- Use `na changes` to view the changelog and see recent changes
|
31
|
+
|
32
|
+
#### IMPROVED
|
33
|
+
|
34
|
+
- You can run `na SAVED_SEARCH` using any saved search (same as running `na saved SAVED_SEARCH` but niftier)
|
35
|
+
|
1
36
|
### 1.2.0
|
2
37
|
|
3
38
|
2022-10-22 01:32
|
data/Gemfile.lock
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
na (1.2.
|
4
|
+
na (1.2.2)
|
5
5
|
chronic (~> 0.10, >= 0.10.2)
|
6
6
|
gli (~> 2.21.0)
|
7
|
+
mdless (~> 1.0, >= 1.0.32)
|
7
8
|
tty-reader (~> 0.9, >= 0.9.0)
|
8
9
|
tty-screen (~> 0.8, >= 0.8.1)
|
9
10
|
tty-which (~> 0.5, >= 0.5.0)
|
@@ -13,6 +14,7 @@ GEM
|
|
13
14
|
specs:
|
14
15
|
chronic (0.10.2)
|
15
16
|
gli (2.21.0)
|
17
|
+
mdless (1.0.32)
|
16
18
|
minitest (5.16.3)
|
17
19
|
rake (0.9.6)
|
18
20
|
rdoc (4.3.0)
|
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.2
|
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.
|
@@ -49,6 +49,10 @@ You can also quickly add todo items from the command line with the `add` subcomm
|
|
49
49
|
|
50
50
|
If found, it will try to locate an `Inbox:` project, or create one if it doesn't exist. Any arguments after `add` will be combined to create a new task in TaskPaper format. They will automatically be assigned as next actions (tagged `@na`) and will show up when `na` lists the tasks for the project.
|
51
51
|
|
52
|
+
#### Updating todos
|
53
|
+
|
54
|
+
You can mark todos as complete, delete them, add and remove tags, change priority, and even move them between projects with the `na update` command.
|
55
|
+
|
52
56
|
### Usage
|
53
57
|
|
54
58
|
```
|
@@ -59,13 +63,16 @@ SYNOPSIS
|
|
59
63
|
na [global options] command [command options] [arguments...]
|
60
64
|
|
61
65
|
VERSION
|
62
|
-
1.2.
|
66
|
+
1.2.2
|
63
67
|
|
64
68
|
GLOBAL OPTIONS
|
65
69
|
-a, --[no-]add - Add a next action (deprecated, for backwards compatibility)
|
70
|
+
--add_at=POSITION - Add all new/moved entries at [s]tart or [e]nd of target project (default: end)
|
71
|
+
--cwd_as=TYPE - Use current working directory as [p]roject, [t]ag, or [n]one (default: none)
|
66
72
|
-d, --depth=DEPTH - Recurse to depth (default: 1)
|
67
|
-
--[no-]debug - Display verbose output
|
73
|
+
--[no-]debug - Display verbose output (default: enabled)
|
68
74
|
--ext=EXT - File extension to consider a todo file (default: taskpaper)
|
75
|
+
-f, --file=PATH - Use a single file as global todo, use --initconfig to make permanent (default: none)
|
69
76
|
--help - Show this message
|
70
77
|
-n, --note - Prompt for additional notes (deprecated, for backwards compatibility)
|
71
78
|
-p, --priority=PRIORITY - Set a priority 0-5 (deprecated, for backwards compatibility) (default: none)
|
@@ -74,19 +81,20 @@ GLOBAL OPTIONS
|
|
74
81
|
--version - Display the program version
|
75
82
|
|
76
83
|
COMMANDS
|
77
|
-
add
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
84
|
+
add - Add a new next action
|
85
|
+
changes, changelog - Display the changelog
|
86
|
+
edit - Open a todo file in the default editor
|
87
|
+
find, grep - Find actions matching a search pattern
|
88
|
+
help - Shows a list of commands or help for one command
|
89
|
+
init, create - Create a new todo file in the current directory
|
90
|
+
initconfig - Initialize the config file using current global options
|
91
|
+
next, show - Show next actions
|
92
|
+
projects - Show list of projects for a file
|
93
|
+
prompt - Show or install prompt hooks for the current shell
|
94
|
+
saved - Execute a saved search
|
95
|
+
tagged - Find actions matching a tag
|
96
|
+
todos - Show list of known todo files
|
97
|
+
update - Update an existing action
|
90
98
|
```
|
91
99
|
|
92
100
|
#### Commands
|
@@ -109,8 +117,10 @@ DESCRIPTION
|
|
109
117
|
Provides an easy way to store todos while you work. Add quick reminders and (if you set up Prompt Hooks) they'll automatically display next time you enter the directory. If multiple todo files are found in the current directory, a menu will allow you to pick to which file the action gets added.
|
110
118
|
|
111
119
|
COMMAND OPTIONS
|
120
|
+
--at=POSITION - Add task at [s]tart or [e]nd of target project (default: none)
|
112
121
|
-d, --depth=DEPTH - Search for files X directories deep (default: 1)
|
113
122
|
-f, --file=PATH - Specify the file to which the task should be added (default: none)
|
123
|
+
--finish, --done - Mark task as @done with date
|
114
124
|
--in, --todo=TODO_FILE - Add to a known todo file, partial matches allowed (default: none)
|
115
125
|
-n, --note - Prompt for additional notes
|
116
126
|
-p, --priority=PRIO - Add a priority level 1-5 (default: 0)
|
@@ -177,6 +187,7 @@ DESCRIPTION
|
|
177
187
|
|
178
188
|
COMMAND OPTIONS
|
179
189
|
-d, --depth=DEPTH - Recurse to depth (default: none)
|
190
|
+
--[no-]done - Include @done actions
|
180
191
|
-e, --regex - Interpret search pattern as regular expression
|
181
192
|
--in=TODO_PATH - Show actions from a specific todo file in history. May use wildcards (* and ?) (default: none)
|
182
193
|
-o, --or - Combine search tokens with OR, displaying actions matching ANY of the terms
|
@@ -233,7 +244,9 @@ DESCRIPTION
|
|
233
244
|
Next actions are actions which contain the next action tag (default @na), do not contain @done, and are not in the Archive project. Arguments will target a todo file from history, whether it's in the current directory or not. Todo file queries can include path components separated by / or :, and may use wildcards (`*` to match any text, `?` to match a single character). Multiple queries allowed (separate arguments or separated by comma).
|
234
245
|
|
235
246
|
COMMAND OPTIONS
|
236
|
-
-d, --depth=DEPTH - Recurse to depth (default:
|
247
|
+
-d, --depth=DEPTH - Recurse to depth (default: none)
|
248
|
+
--[no-]done - Include @done actions
|
249
|
+
--in, --todo=TODO_FILE - Display matches from a known todo file (may be used more than once, default: none)
|
237
250
|
--proj, --project=PROJECT[/SUBPROJECT] - Show actions from a specific project (default: none)
|
238
251
|
-t, --tag=TAG - Alternate tag to search for (default: none)
|
239
252
|
|
@@ -323,7 +336,9 @@ DESCRIPTION
|
|
323
336
|
Next actions are actions which contain the next action tag (default @na), do not contain @done, and are not in the Archive project. Arguments will target a todo file from history, whether it's in the current directory or not. Todo file queries can include path components separated by / or :, and may use wildcards (`*` to match any text, `?` to match a single character). Multiple queries allowed (separate arguments or separated by comma).
|
324
337
|
|
325
338
|
COMMAND OPTIONS
|
326
|
-
-d, --depth=DEPTH - Recurse to depth (default:
|
339
|
+
-d, --depth=DEPTH - Recurse to depth (default: none)
|
340
|
+
--[no-]done - Include @done actions
|
341
|
+
--in, --todo=TODO_FILE - Display matches from a known todo file (may be used more than once, default: none)
|
327
342
|
--proj, --project=PROJECT[/SUBPROJECT] - Show actions from a specific project (default: none)
|
328
343
|
-t, --tag=TAG - Alternate tag to search for (default: none)
|
329
344
|
|
@@ -387,10 +402,12 @@ DESCRIPTION
|
|
387
402
|
COMMAND OPTIONS
|
388
403
|
-a, --archive - Add a @done tag to action and move to Archive
|
389
404
|
--all - Act on all matches immediately (no menu)
|
405
|
+
--at=POSITION - When moving task, add at [s]tart or [e]nd of target project (default: none)
|
390
406
|
-d, --depth=DEPTH - Search for files X directories deep (default: 1)
|
391
407
|
--delete - Delete an action
|
408
|
+
--[no-]done - Include @done actions
|
392
409
|
-e, --regex - Interpret search pattern as regular expression
|
393
|
-
-f, --finish
|
410
|
+
-f, --finish - Add a @done tag to action
|
394
411
|
--file=PATH - Specify the file to search for the task (default: none)
|
395
412
|
--in, --todo=TODO_FILE - Use a known todo file, partial matches allowed (default: none)
|
396
413
|
-n, --note - Prompt for additional notes. Input will be appended to any existing note.
|
@@ -440,6 +457,16 @@ Note that I created a new YAML dictionary inside of the `:next:` command, and ad
|
|
440
457
|
> **WARNING** Don't touch most of the settings at the top of the auto-generated file. Setting any of them to true will alter the way na interprets the commands you're running. Most of those options are there for backwards compatibility with the bash version of this tool and will eventually be removed.
|
441
458
|
|
442
459
|
|
460
|
+
#### Working with a single global file
|
461
|
+
|
462
|
+
na is designed to work with one or more TaskPaper files in each project directory, but if you prefer to use a single global TaskPaper file, you can add `--file PATH` as a global option and specify a single file. This will bypass the detection of any files in the current directory. Make it permanent by including the `--file` flag when running `initconfig`.
|
463
|
+
|
464
|
+
When using a global file, you can additionally include `--cwd_as TYPE` to determine whether the current working directory is used as a tag or a project (default is neither). If you add `--cwd_as tag` to the global options (before the command), the last element of the current working directory will be appended as an @tag (e.g. if you're in ~/Code/project/doing, the action would be tagged @doing). If you use `--cwd_as project` the action will be put into a project with the same name as the current directory (e.g. `Doing:` from the previous example).
|
465
|
+
|
466
|
+
#### Add tasks at the end of a project
|
467
|
+
|
468
|
+
By default, tasks are added at the top of the target project (Inbox, etc.). If you prefer new tasks to go at the bottom by default, include `--add_at end` as a global option when running `initconfig`.
|
469
|
+
|
443
470
|
### Prompt Hooks
|
444
471
|
|
445
472
|
You can add a prompt command to your shell to have na automatically list your next actions when you `cd` into a directory. To install a prompt command for your current shell, just run `na prompt install`. It works with Zsh, Bash, and Fish. If you'd rather make the changes to your startup file yourself, run `na prompt show` to get the hook and instructions printed out for copying.
|
data/bin/na
CHANGED
@@ -39,6 +39,18 @@ class App
|
|
39
39
|
arg_name 'PRIORITY'
|
40
40
|
flag %i[p priority]
|
41
41
|
|
42
|
+
desc 'Use a single file as global todo, use --initconfig to make permanent'
|
43
|
+
arg_name 'PATH'
|
44
|
+
flag %i[f file]
|
45
|
+
|
46
|
+
desc 'Use current working directory as [p]roject, [t]ag, or [n]one'
|
47
|
+
arg_name 'TYPE'
|
48
|
+
flag %i[cwd_as], must_match: /^[ptn].*?$/i, default_value: 'none'
|
49
|
+
|
50
|
+
desc 'Add all new/moved entries at [s]tart or [e]nd of target project'
|
51
|
+
arg_name 'POSITION'
|
52
|
+
flag %i[add_at], default_value: 'start'
|
53
|
+
|
42
54
|
desc 'Prompt for additional notes (deprecated, for backwards compatibility)'
|
43
55
|
switch %i[n note], negatable: false
|
44
56
|
|
@@ -70,6 +82,10 @@ class App
|
|
70
82
|
c.arg_name 'DEPTH'
|
71
83
|
c.flag %i[d depth], type: :integer, must_match: /^[1-9]$/
|
72
84
|
|
85
|
+
c.desc 'Display matches from a known todo file'
|
86
|
+
c.arg_name 'TODO_FILE'
|
87
|
+
c.flag %i[in todo], multiple: true
|
88
|
+
|
73
89
|
c.desc 'Alternate tag to search for'
|
74
90
|
c.arg_name 'TAG'
|
75
91
|
c.flag %i[t tag]
|
@@ -78,12 +94,15 @@ class App
|
|
78
94
|
c.arg_name 'PROJECT[/SUBPROJECT]'
|
79
95
|
c.flag %i[proj project]
|
80
96
|
|
97
|
+
c.desc 'Include @done actions'
|
98
|
+
c.switch %i[done]
|
99
|
+
|
81
100
|
c.action do |global_options, options, args|
|
82
101
|
if global_options[:add]
|
83
102
|
cmd = ['add']
|
84
103
|
cmd.push('--note') if global_options[:note]
|
85
104
|
cmd.concat(['--priority', global_options[:priority]]) if global_options[:priority]
|
86
|
-
cmd.push(ARGV.unshift(
|
105
|
+
cmd.push(ARGV.unshift(NA.command_line[0])) if NA.command_line.count > 1
|
87
106
|
|
88
107
|
exit run(cmd)
|
89
108
|
end
|
@@ -94,6 +113,7 @@ class App
|
|
94
113
|
options[:depth].nil? ? global_options[:depth].to_i : options[:depth].to_i
|
95
114
|
end
|
96
115
|
|
116
|
+
args.concat(options[:in])
|
97
117
|
if args.count.positive?
|
98
118
|
all_req = false
|
99
119
|
|
@@ -115,6 +135,7 @@ class App
|
|
115
135
|
|
116
136
|
tag = [{ tag: tag, value: nil }, { tag: 'done', value: nil, negate: true}]
|
117
137
|
files, actions, = NA.parse_actions(depth: depth,
|
138
|
+
done: options[:done],
|
118
139
|
query: tokens,
|
119
140
|
tag: tag,
|
120
141
|
project: options[:project],
|
@@ -151,6 +172,10 @@ class App
|
|
151
172
|
c.default_value 'Inbox'
|
152
173
|
c.flag %i[to project proj]
|
153
174
|
|
175
|
+
c.desc 'Add task at [s]tart or [e]nd of target project'
|
176
|
+
c.arg_name 'POSITION'
|
177
|
+
c.flag %i[at], must_match: /^[sbea].*?$/i
|
178
|
+
|
154
179
|
c.desc 'Add to a known todo file, partial matches allowed'
|
155
180
|
c.arg_name 'TODO_FILE'
|
156
181
|
c.flag %i[in todo]
|
@@ -166,64 +191,31 @@ class App
|
|
166
191
|
c.arg_name 'PATH'
|
167
192
|
c.flag %i[f file]
|
168
193
|
|
194
|
+
c.desc 'Mark task as @done with date'
|
195
|
+
c.switch %i[finish done], negatable: false
|
196
|
+
|
169
197
|
c.desc 'Search for files X directories deep'
|
170
198
|
c.arg_name 'DEPTH'
|
171
199
|
c.flag %i[d depth], must_match: /^[1-9]$/, type: :integer, default_value: 1
|
172
200
|
|
173
|
-
c.action do |
|
201
|
+
c.action do |global_options, options, args|
|
174
202
|
reader = TTY::Reader.new
|
175
|
-
|
176
|
-
args.join(' ').strip
|
177
|
-
elsif TTY::Which.exist?('gum')
|
178
|
-
`gum input --placeholder "Enter a task" --char-limit=500 --width=#{TTY::Screen.columns}`.strip
|
179
|
-
else
|
180
|
-
puts NA::Color.template('{bm}Enter task:{x}')
|
181
|
-
reader.read_line(NA::Color.template('{by}> {bw}')).strip
|
182
|
-
end
|
183
|
-
|
184
|
-
if action.nil? || action.empty?
|
185
|
-
puts 'Empty input, cancelled'
|
186
|
-
Process.exit 1
|
187
|
-
end
|
188
|
-
|
189
|
-
if options[:priority]&.to_i&.positive?
|
190
|
-
action = "#{action.gsub(/@priority\(\d+\)/, '')} @priority(#{options[:priority]})"
|
191
|
-
end
|
192
|
-
|
193
|
-
note_rx = /^(.+) \((.*?)\)$/
|
194
|
-
split_note = if action =~ note_rx
|
195
|
-
n = Regexp.last_match(2)
|
196
|
-
action.sub!(note_rx, '\1').strip!
|
197
|
-
n
|
198
|
-
end
|
203
|
+
append = options[:at] ? options[:at] =~ /^[ae]/i : global_options[:add_at] =~ /^[ae]/
|
199
204
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
args << '--width $(tput cols)'
|
215
|
-
`gum write #{args.join(' ')}`.strip.split("\n")
|
216
|
-
else
|
217
|
-
puts NA::Color.template('{bm}Enter a note, {bw}CTRL-d{bm} to end editing{bw}')
|
218
|
-
reader.read_multiline
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
|
-
note = split_note.nil? ? [] : [split_note]
|
223
|
-
note.concat(line_note) unless line_note.nil?
|
224
|
-
note = nil if note.empty?
|
225
|
-
|
226
|
-
if options[:file]
|
205
|
+
if NA.global_file
|
206
|
+
target = File.expand_path(NA.global_file)
|
207
|
+
unless File.exist?(target)
|
208
|
+
print NA::Color.template('{by}Specified file not found, create it? {w}(y/{g}N{w}){x} ')
|
209
|
+
res = reader.read_char
|
210
|
+
if res =~ /y/i
|
211
|
+
basename = File.basename(target, ".#{NA.extension}")
|
212
|
+
NA.create_todo(target, basename)
|
213
|
+
else
|
214
|
+
puts NA::Color.template('{r}Cancelled{x}')
|
215
|
+
Process.exit 1
|
216
|
+
end
|
217
|
+
end
|
218
|
+
elsif options[:file]
|
227
219
|
target = File.expand_path(options[:file])
|
228
220
|
unless File.exist?(target)
|
229
221
|
print NA::Color.template('{by}Specified file not found, create it? {w}(y/{g}N{w}){x} ')
|
@@ -283,7 +275,58 @@ class App
|
|
283
275
|
end
|
284
276
|
end
|
285
277
|
|
286
|
-
|
278
|
+
action = if args.count.positive?
|
279
|
+
args.join(' ').strip
|
280
|
+
elsif TTY::Which.exist?('gum')
|
281
|
+
`gum input --placeholder "Enter a task" --char-limit=500 --width=#{TTY::Screen.columns}`.strip
|
282
|
+
else
|
283
|
+
puts NA::Color.template('{bm}Enter task:{x}')
|
284
|
+
reader.read_line(NA::Color.template('{by}> {bw}')).strip
|
285
|
+
end
|
286
|
+
|
287
|
+
if action.nil? || action.empty?
|
288
|
+
puts 'Empty input, cancelled'
|
289
|
+
Process.exit 1
|
290
|
+
end
|
291
|
+
|
292
|
+
if options[:priority]&.to_i&.positive?
|
293
|
+
action = "#{action.gsub(/@priority\(\d+\)/, '')} @priority(#{options[:priority]})"
|
294
|
+
end
|
295
|
+
|
296
|
+
note_rx = /^(.+) \((.*?)\)$/
|
297
|
+
split_note = if action =~ note_rx
|
298
|
+
n = Regexp.last_match(2)
|
299
|
+
action.sub!(note_rx, '\1').strip!
|
300
|
+
n
|
301
|
+
end
|
302
|
+
|
303
|
+
na_tag = NA.na_tag
|
304
|
+
if options[:x]
|
305
|
+
na_tag = ''
|
306
|
+
else
|
307
|
+
na_tag = options[:tag] unless options[:tag].nil?
|
308
|
+
na_tag = " @#{na_tag}"
|
309
|
+
end
|
310
|
+
|
311
|
+
action = "#{action.gsub(/#{na_tag}\b/, '')}#{na_tag}"
|
312
|
+
|
313
|
+
line_note = if options[:note]
|
314
|
+
if TTY::Which.exist?('gum')
|
315
|
+
args = ['--placeholder "Enter a note, CTRL-d to save"']
|
316
|
+
args << '--char-limit 0'
|
317
|
+
args << '--width $(tput cols)'
|
318
|
+
`gum write #{args.join(' ')}`.strip.split("\n")
|
319
|
+
else
|
320
|
+
puts NA::Color.template('{bm}Enter a note, {bw}CTRL-d{bm} to end editing{bw}')
|
321
|
+
reader.read_multiline
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
note = split_note.nil? ? [] : [split_note]
|
326
|
+
note.concat(line_note) unless line_note.nil?
|
327
|
+
note = [] if note.empty?
|
328
|
+
|
329
|
+
NA.add_action(target, options[:project], action, note, finish: options[:finish], append: append)
|
287
330
|
end
|
288
331
|
end
|
289
332
|
|
@@ -309,6 +352,10 @@ class App
|
|
309
352
|
c.arg_name 'PRIO'
|
310
353
|
c.flag %i[p priority], must_match: /[1-5]/, type: :integer, default_value: 0
|
311
354
|
|
355
|
+
c.desc 'When moving task, add at [s]tart or [e]nd of target project'
|
356
|
+
c.arg_name 'POSITION'
|
357
|
+
c.flag %i[at], must_match: /^[sbea].*?$/i
|
358
|
+
|
312
359
|
c.desc 'Move action to specific project'
|
313
360
|
c.arg_name 'PROJECT'
|
314
361
|
c.flag %i[to project proj]
|
@@ -317,6 +364,9 @@ class App
|
|
317
364
|
c.arg_name 'TODO_FILE'
|
318
365
|
c.flag %i[in todo]
|
319
366
|
|
367
|
+
c.desc 'Include @done actions'
|
368
|
+
c.switch %i[done]
|
369
|
+
|
320
370
|
c.desc 'Add a tag to the action, @tag(values) allowed'
|
321
371
|
c.arg_name 'TAG'
|
322
372
|
c.flag %i[t tag], multiple: true
|
@@ -326,7 +376,7 @@ class App
|
|
326
376
|
c.flag %i[r remove], multiple: true
|
327
377
|
|
328
378
|
c.desc 'Add a @done tag to action'
|
329
|
-
c.switch %i[f finish
|
379
|
+
c.switch %i[f finish], negatable: false
|
330
380
|
|
331
381
|
c.desc 'Add a @done tag to action and move to Archive'
|
332
382
|
c.switch %i[a archive], negatable: false
|
@@ -355,8 +405,10 @@ class App
|
|
355
405
|
c.desc 'Match pattern exactly'
|
356
406
|
c.switch %i[x exact], negatable: false
|
357
407
|
|
358
|
-
c.action do |
|
408
|
+
c.action do |global_options, options, args|
|
359
409
|
reader = TTY::Reader.new
|
410
|
+
append = options[:at] ? options[:at] =~ /^[ae]/i : global_options[:add_at] =~ /^[ae]/i
|
411
|
+
|
360
412
|
action = if args.count.positive?
|
361
413
|
args.join(' ').strip
|
362
414
|
elsif TTY::Which.exist?('gum') && options[:tagged].empty?
|
@@ -429,6 +481,14 @@ class App
|
|
429
481
|
|
430
482
|
note = line_note.nil? || line_note.empty? ? [] : line_note
|
431
483
|
|
484
|
+
target_proj = if options[:project]
|
485
|
+
options[:project]
|
486
|
+
elsif NA.cwd_is == :project
|
487
|
+
NA.cwd
|
488
|
+
else
|
489
|
+
nil
|
490
|
+
end
|
491
|
+
|
432
492
|
if options[:file]
|
433
493
|
file = File.expand_path(options[:file])
|
434
494
|
NA.notify('{r}File not found', exit_code: 1) unless File.exist?(file)
|
@@ -474,12 +534,14 @@ class App
|
|
474
534
|
add_tag: add_tags,
|
475
535
|
remove_tag: remove_tags,
|
476
536
|
finish: options[:finish],
|
477
|
-
project:
|
537
|
+
project: target_proj,
|
478
538
|
delete: options[:delete],
|
479
539
|
note: note,
|
480
540
|
overwrite: options[:overwrite],
|
481
541
|
tagged: tags,
|
482
|
-
all: options[:all]
|
542
|
+
all: options[:all],
|
543
|
+
done: options[:done],
|
544
|
+
append: append)
|
483
545
|
end
|
484
546
|
end
|
485
547
|
end
|
@@ -513,6 +575,9 @@ class App
|
|
513
575
|
c.arg_name 'PROJECT[/SUBPROJECT]'
|
514
576
|
c.flag %i[proj project]
|
515
577
|
|
578
|
+
c.desc 'Include @done actions'
|
579
|
+
c.switch %i[done]
|
580
|
+
|
516
581
|
c.desc 'Show actions not matching search pattern'
|
517
582
|
c.switch %i[v invert], negatable: false
|
518
583
|
|
@@ -563,6 +628,7 @@ class App
|
|
563
628
|
end
|
564
629
|
|
565
630
|
files, actions, = NA.parse_actions(depth: depth,
|
631
|
+
done: options[:done],
|
566
632
|
query: todo,
|
567
633
|
search: tokens,
|
568
634
|
negate: options[:invert],
|
@@ -610,6 +676,9 @@ class App
|
|
610
676
|
c.arg_name 'PROJECT[/SUBPROJECT]'
|
611
677
|
c.flag %i[proj project]
|
612
678
|
|
679
|
+
c.desc 'Include @done actions'
|
680
|
+
c.switch %i[done]
|
681
|
+
|
613
682
|
c.desc 'Show actions not matching tags'
|
614
683
|
c.switch %i[v invert], negatable: false
|
615
684
|
|
@@ -661,6 +730,7 @@ class App
|
|
661
730
|
end
|
662
731
|
|
663
732
|
files, actions, = NA.parse_actions(depth: depth,
|
733
|
+
done: options[:done],
|
664
734
|
query: todo,
|
665
735
|
tag: tags,
|
666
736
|
negate: options[:invert],
|
@@ -850,6 +920,24 @@ class App
|
|
850
920
|
end
|
851
921
|
end
|
852
922
|
|
923
|
+
desc 'Display the changelog'
|
924
|
+
command %i[changes changelog] do |c|
|
925
|
+
c.action do |_, _, _|
|
926
|
+
changelog = File.expand_path(File.join(File.dirname(__FILE__), '..', 'CHANGELOG.md'))
|
927
|
+
pagers = [
|
928
|
+
'mdless',
|
929
|
+
'mdcat',
|
930
|
+
'bat',
|
931
|
+
ENV['PAGER'],
|
932
|
+
'less -FXr',
|
933
|
+
ENV['GIT_PAGER'],
|
934
|
+
'more -r'
|
935
|
+
]
|
936
|
+
pager = pagers.find { |cmd| TTY::Which.exist?(cmd.split.first) }
|
937
|
+
system %(#{pager} "#{changelog}")
|
938
|
+
end
|
939
|
+
end
|
940
|
+
|
853
941
|
desc 'Execute a saved search'
|
854
942
|
long_desc 'Run without argument to list saved searches'
|
855
943
|
arg_name 'SEARCH_TITLE', optional: true
|
@@ -892,21 +980,26 @@ class App
|
|
892
980
|
NA.verbose = global[:debug]
|
893
981
|
NA.extension = global[:ext]
|
894
982
|
NA.na_tag = global[:na_tag]
|
983
|
+
NA.global_file = global[:file]
|
984
|
+
NA.cwd = File.basename(ENV['PWD'])
|
985
|
+
NA.cwd_is = if global[:cwd_as] =~ /^n/
|
986
|
+
:none
|
987
|
+
else
|
988
|
+
global[:cwd_as] =~ /^p/ ? :project : :tag
|
989
|
+
end
|
895
990
|
NA.weed_cache_file
|
896
991
|
true
|
897
992
|
end
|
898
993
|
|
899
994
|
post do |global, command, options, args|
|
900
|
-
#
|
901
|
-
# Use skips_post before a command to skip this
|
902
|
-
# block on that command only
|
995
|
+
# post actions
|
903
996
|
end
|
904
997
|
|
905
998
|
on_error do |exception|
|
906
999
|
case exception
|
907
1000
|
when GLI::UnknownCommand
|
908
|
-
cmd = ['
|
909
|
-
cmd.concat(ARGV.unshift(
|
1001
|
+
cmd = ['saved']
|
1002
|
+
cmd.concat(ARGV.unshift(NA.command_line[0]))
|
910
1003
|
|
911
1004
|
exit run(cmd)
|
912
1005
|
when SystemExit
|
@@ -917,8 +1010,9 @@ class App
|
|
917
1010
|
end
|
918
1011
|
end
|
919
1012
|
|
920
|
-
NA.command_line = ARGV
|
1013
|
+
NA.command_line = ARGV.dup
|
1014
|
+
NA.globals = NA.command_line.filter { |arg| arg =~ /^-/ }
|
1015
|
+
NA.command_line.delete_if { |arg| arg =~ /^-/ }
|
921
1016
|
@command = ARGV[0]
|
922
|
-
$first_arg = ARGV[1]
|
923
1017
|
|
924
1018
|
exit App.run(ARGV)
|
data/lib/na/action.rb
CHANGED
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
module NA
|
4
4
|
class Action < Hash
|
5
|
-
attr_reader :file, :project, :parent, :
|
5
|
+
attr_reader :file, :project, :parent, :tags, :line, :note
|
6
|
+
|
7
|
+
attr_accessor :action
|
6
8
|
|
7
9
|
def initialize(file, project, parent, action, idx, note = [])
|
8
10
|
super()
|
data/lib/na/next_action.rb
CHANGED
@@ -3,21 +3,22 @@
|
|
3
3
|
# Next Action methods
|
4
4
|
module NA
|
5
5
|
class << self
|
6
|
-
attr_accessor :verbose, :extension, :na_tag, :command_line
|
6
|
+
attr_accessor :verbose, :extension, :na_tag, :command_line, :globals, :global_file, :cwd_is, :cwd
|
7
7
|
|
8
8
|
##
|
9
9
|
## Output to STDERR
|
10
10
|
##
|
11
11
|
## @param msg [String] The message
|
12
|
-
## @param exit_code [Number] The exit code, no
|
12
|
+
## @param exit_code [Number] The exit code, no
|
13
|
+
## exit if false
|
14
|
+
## @param debug [Boolean] only display message if running :verbose
|
13
15
|
##
|
14
16
|
def notify(msg, exit_code: false, debug: false)
|
15
17
|
return if debug && !@verbose
|
16
18
|
|
17
19
|
$stderr.puts NA::Color.template("{x}#{msg}{x}")
|
18
|
-
if exit_code
|
19
|
-
|
20
|
-
end
|
20
|
+
Process.exit exit_code if exit_code
|
21
|
+
|
21
22
|
end
|
22
23
|
|
23
24
|
##
|
@@ -99,6 +100,8 @@ module NA
|
|
99
100
|
## @param depth [Number] The depth at which to search
|
100
101
|
##
|
101
102
|
def find_files(depth: 1)
|
103
|
+
return [NA.global_file] if NA.global_file
|
104
|
+
|
102
105
|
files = `find . -name "*.#{NA.extension}" -maxdepth #{depth}`.strip.split("\n")
|
103
106
|
files.each { |f| save_working_dir(File.expand_path(f)) }
|
104
107
|
files
|
@@ -152,10 +155,14 @@ module NA
|
|
152
155
|
projects
|
153
156
|
end
|
154
157
|
|
155
|
-
def find_actions(target, search, tagged = nil, all: false)
|
156
|
-
_, actions, projects = parse_actions(search: search, require_na: false, file_path: target, tag: tagged)
|
158
|
+
def find_actions(target, search, tagged = nil, all: false, done: false)
|
159
|
+
_, actions, projects = parse_actions(search: search, require_na: false, file_path: target, tag: tagged, done: done)
|
160
|
+
|
161
|
+
unless actions.count.positive?
|
162
|
+
NA.notify("{r}No matching actions found in {bw}#{File.basename(target, ".#{NA.extension}")}")
|
163
|
+
return
|
164
|
+
end
|
157
165
|
|
158
|
-
NA.notify('{r}No matching actions found', exit_code: 1) unless actions.count.positive?
|
159
166
|
return [projects, actions] if actions.count == 1 || all
|
160
167
|
|
161
168
|
options = actions.map { |action| "#{action.line} % #{action.parent.join('/')} : #{action.action}" }
|
@@ -248,8 +255,35 @@ module NA
|
|
248
255
|
new_project
|
249
256
|
end
|
250
257
|
|
258
|
+
def process_action(action, priority: 0, finish: false, add_tag: [], remove_tag: [], note: [])
|
259
|
+
string = action.action
|
260
|
+
|
261
|
+
if priority&.positive?
|
262
|
+
string.gsub!(/(?<=\A| )@priority\(\d+\)/, '').strip!
|
263
|
+
string += " @priority(#{priority})"
|
264
|
+
end
|
265
|
+
|
266
|
+
add_tag.each do |tag|
|
267
|
+
string.gsub!(/(?<=\A| )@#{tag.gsub(/([()*?])/, '\\\\1')}(\(.*?\))?/, '')
|
268
|
+
string.strip!
|
269
|
+
string += " @#{tag}"
|
270
|
+
end
|
271
|
+
|
272
|
+
remove_tag.each do |tag|
|
273
|
+
string.gsub!(/(?<=\A| )@#{tag.gsub(/([()*?])/, '\\\\1')}(\(.*?\))?/, '')
|
274
|
+
string.strip!
|
275
|
+
end
|
276
|
+
|
277
|
+
string = "#{string.strip} @done(#{Time.now.strftime('%Y-%m-%d %H:%M')})" if finish && string !~ /(?<=\A| )@done/
|
278
|
+
|
279
|
+
action.action = string
|
280
|
+
|
281
|
+
action
|
282
|
+
end
|
283
|
+
|
251
284
|
def update_action(target,
|
252
285
|
search,
|
286
|
+
add: nil,
|
253
287
|
priority: 0,
|
254
288
|
add_tag: [],
|
255
289
|
remove_tag: [],
|
@@ -259,7 +293,9 @@ module NA
|
|
259
293
|
note: [],
|
260
294
|
overwrite: false,
|
261
295
|
tagged: nil,
|
262
|
-
all: false
|
296
|
+
all: false,
|
297
|
+
done: false,
|
298
|
+
append: false)
|
263
299
|
|
264
300
|
projects = find_projects(target)
|
265
301
|
|
@@ -277,35 +313,12 @@ module NA
|
|
277
313
|
end
|
278
314
|
end
|
279
315
|
|
280
|
-
projects, actions = find_actions(target, search, tagged, all: all)
|
281
|
-
|
282
316
|
contents = target.read_file.split(/\n/)
|
283
317
|
|
284
|
-
|
285
|
-
|
318
|
+
if add.is_a?(Action)
|
319
|
+
action = process_action(add, priority: priority, finish: finish, add_tag: add_tag, remove_tag: remove_tag)
|
286
320
|
|
287
|
-
|
288
|
-
string.gsub!(/@priority\(\d+\)/, '').strip!
|
289
|
-
string += " @priority(#{priority})"
|
290
|
-
end
|
291
|
-
|
292
|
-
add_tag.each do |tag|
|
293
|
-
string.gsub!(/@#{tag.gsub(/([()*?])/, '\\\\1')}(\(.*?\))?/, '')
|
294
|
-
string.strip!
|
295
|
-
string += " @#{tag}"
|
296
|
-
end
|
297
|
-
|
298
|
-
remove_tag.each do |tag|
|
299
|
-
string.gsub!(/@#{tag}(\(.*?\))?/, '')
|
300
|
-
string.strip!
|
301
|
-
end
|
302
|
-
|
303
|
-
string = "#{string.strip} @done(#{Time.now.strftime('%Y-%m-%d %H:%M')})" if finish && string !~ /@done/
|
304
|
-
|
305
|
-
contents.slice!(action.line, action.note.count + 1)
|
306
|
-
next if delete
|
307
|
-
|
308
|
-
projects = shift_index_after(projects, action.line, action.note.count + 1)
|
321
|
+
projects = find_projects(target)
|
309
322
|
|
310
323
|
target_proj = if target_proj
|
311
324
|
projects.select { |proj| proj.project =~ /^#{target_proj.project}$/ }.first
|
@@ -320,13 +333,74 @@ module NA
|
|
320
333
|
else
|
321
334
|
overwrite ? note : action.note.concat(note)
|
322
335
|
end
|
336
|
+
|
323
337
|
note = note.empty? ? '' : "\n#{indent}\t\t#{note.join("\n#{indent}\t\t").strip}"
|
324
|
-
|
338
|
+
|
339
|
+
if append
|
340
|
+
this_idx = 0
|
341
|
+
projects.each_with_index do |proj, idx|
|
342
|
+
if proj.line == target_proj.line
|
343
|
+
this_idx = idx
|
344
|
+
break
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
target_line = if this_idx == projects.length - 1
|
349
|
+
contents.count
|
350
|
+
else
|
351
|
+
projects[this_idx + 1].line - 1
|
352
|
+
end
|
353
|
+
else
|
354
|
+
target_line = target_proj.line
|
355
|
+
end
|
356
|
+
|
357
|
+
contents.insert(target_line, "#{indent}\t- #{action.action}#{note}")
|
358
|
+
else
|
359
|
+
projects, actions = find_actions(target, search, tagged, done: done, all: all)
|
360
|
+
|
361
|
+
return if actions.nil?
|
362
|
+
|
363
|
+
actions.sort_by(&:line).reverse.each do |action|
|
364
|
+
contents.slice!(action.line, action.note.count + 1)
|
365
|
+
next if delete
|
366
|
+
|
367
|
+
projects = shift_index_after(projects, action.line, action.note.count + 1)
|
368
|
+
|
369
|
+
action = process_action(action, priority: priority, finish: finish, add_tag: add_tag, remove_tag: remove_tag)
|
370
|
+
|
371
|
+
target_proj = if target_proj
|
372
|
+
projects.select { |proj| proj.project =~ /^#{target_proj.project}$/ }.first
|
373
|
+
else
|
374
|
+
projects.select { |proj| proj.project =~ /^#{action.parent.join(':')}$/ }.first
|
375
|
+
end
|
376
|
+
|
377
|
+
indent = "\t" * target_proj.indent
|
378
|
+
note = note.split("\n") unless note.is_a?(Array)
|
379
|
+
note = if note.empty?
|
380
|
+
action.note
|
381
|
+
else
|
382
|
+
overwrite ? note : action.note.concat(note)
|
383
|
+
end
|
384
|
+
note = note.empty? ? '' : "\n#{indent}\t\t#{note.join("\n#{indent}\t\t").strip}"
|
385
|
+
|
386
|
+
if append
|
387
|
+
this_idx = projects.index(target_proj)
|
388
|
+
if this_idx == projects.length - 1
|
389
|
+
target_line = contents.count
|
390
|
+
else
|
391
|
+
target_line = projects[this_idx + 1].line - 1
|
392
|
+
end
|
393
|
+
else
|
394
|
+
target_line = target_proj.line
|
395
|
+
end
|
396
|
+
|
397
|
+
contents.insert(target_line, "#{indent}\t- #{action.action}#{note}")
|
398
|
+
end
|
325
399
|
end
|
326
400
|
backup_file(target)
|
327
401
|
File.open(target, 'w') { |f| f.puts contents.join("\n") }
|
328
402
|
|
329
|
-
notify("{by}Task updated in {bw}#{target}")
|
403
|
+
add ? notify("{by}Task added to {bw}#{target}") : notify("{by}Task updated in {bw}#{target}")
|
330
404
|
end
|
331
405
|
|
332
406
|
##
|
@@ -337,24 +411,22 @@ module NA
|
|
337
411
|
## @param action [String] The action
|
338
412
|
## @param note [String] The note
|
339
413
|
##
|
340
|
-
def add_action(file, project, action, note =
|
341
|
-
|
342
|
-
# Insert the target project at the top if it doesn't exist
|
343
|
-
unless content =~ /^[ \t]*#{project}:/i
|
344
|
-
content = "#{project.cap_first}:\n#{content}"
|
345
|
-
end
|
414
|
+
def add_action(file, project, action, note = [], priority: 0, finish: false, append: false)
|
415
|
+
parent = project.split(%r{[:/]})
|
346
416
|
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
417
|
+
if NA.global_file
|
418
|
+
puts NA.global_file
|
419
|
+
if NA.cwd_is == :tag
|
420
|
+
add_tag = [NA.cwd]
|
421
|
+
else
|
422
|
+
project = NA.cwd
|
423
|
+
end
|
424
|
+
puts [add_tag, project]
|
353
425
|
end
|
354
426
|
|
355
|
-
|
427
|
+
action = Action.new(file, project, parent, action, nil, note)
|
356
428
|
|
357
|
-
|
429
|
+
update_action(file, nil, add: action, project: project, add_tag: add_tag, priority: priority, finish: finish, append: append)
|
358
430
|
end
|
359
431
|
|
360
432
|
##
|
@@ -394,6 +466,7 @@ module NA
|
|
394
466
|
##
|
395
467
|
## @param depth [Number] The directory depth
|
396
468
|
## to search for files
|
469
|
+
## @param done [Boolean] include @done actions
|
397
470
|
## @param query [Hash] The todo file query
|
398
471
|
## @param tag [Array] Tags to search for
|
399
472
|
## @param search [String] A search string
|
@@ -402,9 +475,9 @@ module NA
|
|
402
475
|
## regular expression
|
403
476
|
## @param project [String] The project
|
404
477
|
## @param require_na [Boolean] Require @na tag
|
405
|
-
## @param
|
478
|
+
## @param file_path [String] file path to parse
|
406
479
|
##
|
407
|
-
def parse_actions(depth: 1, query: nil, tag: nil, search: nil, negate: false, regex: false, project: nil, require_na: true, file_path: nil)
|
480
|
+
def parse_actions(depth: 1, done: false, query: nil, tag: nil, search: nil, negate: false, regex: false, project: nil, require_na: true, file_path: nil)
|
408
481
|
actions = []
|
409
482
|
required = []
|
410
483
|
optional = []
|
@@ -482,7 +555,7 @@ module NA
|
|
482
555
|
in_action = false
|
483
556
|
# search_for_done = false
|
484
557
|
# optional_tag.each { |t| search_for_done = true if t[:tag] =~ /done/ }
|
485
|
-
|
558
|
+
next if line =~ /@done/ && !done
|
486
559
|
|
487
560
|
next if require_na && line !~ /@#{NA.na_tag}\b/
|
488
561
|
|
@@ -552,7 +625,9 @@ module NA
|
|
552
625
|
end
|
553
626
|
|
554
627
|
def list_projects(query: [], file_path: nil, depth: 1, paths: true)
|
555
|
-
files = if
|
628
|
+
files = if NA.global_file
|
629
|
+
[NA.global_file]
|
630
|
+
elsif !file_path.nil?
|
556
631
|
[file_path]
|
557
632
|
elsif query.nil?
|
558
633
|
find_files(depth: depth)
|
@@ -740,6 +815,7 @@ module NA
|
|
740
815
|
|
741
816
|
default_args = [%(--prompt="#{prompt}"), "--height=#{options.count + 2}", '--info=inline']
|
742
817
|
default_args << '--multi' if multiple
|
818
|
+
default_args << '--bind ctrl-a:select-all'
|
743
819
|
header = "esc: cancel,#{multiple ? ' tab: multi-select, ctrl-a: select all,' : ''} return: confirm"
|
744
820
|
default_args << %(--header="#{header}")
|
745
821
|
default_args.concat(fzf_args)
|
data/lib/na/project.rb
CHANGED
data/lib/na/version.rb
CHANGED
data/na.gemspec
CHANGED
@@ -31,4 +31,5 @@ spec = Gem::Specification.new do |s|
|
|
31
31
|
s.add_runtime_dependency('tty-screen', '~> 0.8', '>= 0.8.1')
|
32
32
|
s.add_runtime_dependency('tty-which', '~> 0.5', '>= 0.5.0')
|
33
33
|
s.add_runtime_dependency('chronic', '~> 0.10', '>= 0.10.2')
|
34
|
+
s.add_runtime_dependency('mdless', '~> 1.0', '>= 1.0.32')
|
34
35
|
end
|
data/src/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 <!--VER-->1.1
|
12
|
+
The current version of `na` is <!--VER-->1.2.1<!--END VER-->.
|
13
13
|
|
14
14
|
`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.
|
15
15
|
|
@@ -48,6 +48,10 @@ You can also quickly add todo items from the command line with the `add` subcomm
|
|
48
48
|
|
49
49
|
If found, it will try to locate an `Inbox:` project, or create one if it doesn't exist. Any arguments after `add` will be combined to create a new task in TaskPaper format. They will automatically be assigned as next actions (tagged `@na`) and will show up when `na` lists the tasks for the project.
|
50
50
|
|
51
|
+
#### Updating todos
|
52
|
+
|
53
|
+
You can mark todos as complete, delete them, add and remove tags, change priority, and even move them between projects with the `na update` command.
|
54
|
+
|
51
55
|
### Usage
|
52
56
|
|
53
57
|
```
|
@@ -190,6 +194,16 @@ Note that I created a new YAML dictionary inside of the `:next:` command, and ad
|
|
190
194
|
> **WARNING** Don't touch most of the settings at the top of the auto-generated file. Setting any of them to true will alter the way na interprets the commands you're running. Most of those options are there for backwards compatibility with the bash version of this tool and will eventually be removed.
|
191
195
|
<!--JEKYLL{:.warn}-->
|
192
196
|
|
197
|
+
#### Working with a single global file
|
198
|
+
|
199
|
+
na is designed to work with one or more TaskPaper files in each project directory, but if you prefer to use a single global TaskPaper file, you can add `--file PATH` as a global option and specify a single file. This will bypass the detection of any files in the current directory. Make it permanent by including the `--file` flag when running `initconfig`.
|
200
|
+
|
201
|
+
When using a global file, you can additionally include `--cwd_as TYPE` to determine whether the current working directory is used as a tag or a project (default is neither). If you add `--cwd_as tag` to the global options (before the command), the last element of the current working directory will be appended as an @tag (e.g. if you're in ~/Code/project/doing, the action would be tagged @doing). If you use `--cwd_as project` the action will be put into a project with the same name as the current directory (e.g. `Doing:` from the previous example).
|
202
|
+
|
203
|
+
#### Add tasks at the end of a project
|
204
|
+
|
205
|
+
By default, tasks are added at the top of the target project (Inbox, etc.). If you prefer new tasks to go at the bottom by default, include `--add_at end` as a global option when running `initconfig`.
|
206
|
+
|
193
207
|
### Prompt Hooks
|
194
208
|
|
195
209
|
You can add a prompt command to your shell to have na automatically list your next actions when you `cd` into a directory. To install a prompt command for your current shell, just run `na prompt install`. It works with Zsh, Bash, and Fish. If you'd rather make the changes to your startup file yourself, run `na prompt show` to get the hook and instructions printed out for copying.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: na
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brett Terpstra
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-10-
|
11
|
+
date: 2022-10-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -166,6 +166,26 @@ dependencies:
|
|
166
166
|
- - ">="
|
167
167
|
- !ruby/object:Gem::Version
|
168
168
|
version: 0.10.2
|
169
|
+
- !ruby/object:Gem::Dependency
|
170
|
+
name: mdless
|
171
|
+
requirement: !ruby/object:Gem::Requirement
|
172
|
+
requirements:
|
173
|
+
- - "~>"
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: '1.0'
|
176
|
+
- - ">="
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: 1.0.32
|
179
|
+
type: :runtime
|
180
|
+
prerelease: false
|
181
|
+
version_requirements: !ruby/object:Gem::Requirement
|
182
|
+
requirements:
|
183
|
+
- - "~>"
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '1.0'
|
186
|
+
- - ">="
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
version: 1.0.32
|
169
189
|
description: A tool for managing a TaskPaper file of project todos for the current
|
170
190
|
directory. Easily create "next actions" to come back to, add tags and priorities,
|
171
191
|
and notes. Add prompt hooks to display your next actions automatically when cd'ing
|