na 1.0.5 → 1.0.7
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 +12 -0
- data/Gemfile.lock +1 -1
- data/README.md +1 -2
- data/bin/na +74 -22
- data/lib/na/next_action.rb +20 -16
- data/lib/na/prompt.rb +61 -0
- data/lib/na/version.rb +1 -1
- data/lib/na.rb +1 -0
- data/src/README.md +1 -2
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9aab87ece3f35afbe5280d6c1b777c9d8dece4916f796eedb3dfebdbbeb5032e
|
4
|
+
data.tar.gz: 46b7eef3d84ede3a69f9497e4d0bb4fcc772fd159fbffe23f9749f3172bc2cdf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 05bda9033431ce005ad32fb9cd1c711642504972ffa73131d1c989b90dd4b50089b53d9e6746df4555d87e9b65d8b3c2c3707023dd8a8287f8596f4583a727f5
|
7
|
+
data.tar.gz: d474663a84ca7ef0287f05c3c2ed6fa63b0fb3d6482337b33343bbfa71a7a7d1c4fe542f91d9c75797c48a4f073079b85a96ef6704d2056b193b7f891596cbf9
|
data/CHANGELOG.md
CHANGED
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.0.
|
12
|
+
The current version of `na` is 1.0.6.
|
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
|
|
@@ -293,7 +293,6 @@ Fish (in ~/.config/fish/conf.d/*.fish):
|
|
293
293
|
|
294
294
|
```fish
|
295
295
|
function __should_na --on-variable PWD
|
296
|
-
# function __should_na --on-event fish_prompt
|
297
296
|
test -s (basename $PWD)".taskpaper" && na
|
298
297
|
end
|
299
298
|
```
|
data/bin/na
CHANGED
@@ -48,7 +48,7 @@ class App
|
|
48
48
|
flag %i[d depth], type: :integer, must_match: /^\d+$/
|
49
49
|
|
50
50
|
desc 'Display verbose output'
|
51
|
-
switch %i[
|
51
|
+
switch %i[debug]
|
52
52
|
|
53
53
|
desc 'Show next actions'
|
54
54
|
arg_name 'OPTIONAL_QUERY'
|
@@ -91,14 +91,12 @@ class App
|
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
|
-
tag = options[:tag] ==
|
94
|
+
tag = options[:tag] == NA.na_tag ? nil : options[:tag]
|
95
95
|
files, actions = NA.parse_actions(depth: depth,
|
96
96
|
query: tokens,
|
97
|
-
extension: global_options[:ext],
|
98
|
-
na_tag: global_options[:na_tag],
|
99
97
|
tag: tag)
|
100
98
|
|
101
|
-
NA.output_actions(actions, depth,
|
99
|
+
NA.output_actions(actions, depth, files: files)
|
102
100
|
end
|
103
101
|
end
|
104
102
|
|
@@ -124,6 +122,9 @@ class App
|
|
124
122
|
c.arg_name 'TAG'
|
125
123
|
c.flag %i[t tag]
|
126
124
|
|
125
|
+
c.desc 'Don\'t add next action tag to new entry'
|
126
|
+
c.switch %i[x]
|
127
|
+
|
127
128
|
c.desc 'Specify the file to which the task should be added'
|
128
129
|
c.arg_name 'PATH'
|
129
130
|
c.flag %i[f file]
|
@@ -148,10 +149,15 @@ class App
|
|
148
149
|
action = "#{action.gsub(/@priority\(\d+\)/, '')} @priority(#{options[:priority]})"
|
149
150
|
end
|
150
151
|
|
151
|
-
na_tag =
|
152
|
-
|
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
|
153
159
|
|
154
|
-
action = "#{action.gsub(
|
160
|
+
action = "#{action.gsub(/#{na_tag}/, '')}#{na_tag}"
|
155
161
|
|
156
162
|
note = if options[:note]
|
157
163
|
if TTY::Which.exist?('gum')
|
@@ -167,7 +173,7 @@ class App
|
|
167
173
|
print NA::Color.template('{by}Specified file not found, create it? {w}(y/{g}N{w}){x} ')
|
168
174
|
res = reader.read_char
|
169
175
|
if res =~ /y/i
|
170
|
-
basename = File.basename(target, ".#{
|
176
|
+
basename = File.basename(target, ".#{NA.extension}")
|
171
177
|
NA.create_todo(target, basename)
|
172
178
|
else
|
173
179
|
puts NA::Color.template('{r}Cancelled{x}')
|
@@ -175,15 +181,15 @@ class App
|
|
175
181
|
end
|
176
182
|
end
|
177
183
|
else
|
178
|
-
files = NA.find_files(depth: 1
|
184
|
+
files = NA.find_files(depth: 1)
|
179
185
|
if files.count == 0
|
180
186
|
print NA::Color.template('{by}No todo file found, create one? {w}(y/{g}N{w}){x} ')
|
181
187
|
res = reader.read_char
|
182
188
|
if res =~ /y/i
|
183
189
|
basename = File.expand_path('.').split('/').last
|
184
|
-
target = "#{basename}.#{
|
190
|
+
target = "#{basename}.#{NA.extension}"
|
185
191
|
NA.create_todo(target, basename)
|
186
|
-
files = NA.find_files(depth: 1
|
192
|
+
files = NA.find_files(depth: 1)
|
187
193
|
end
|
188
194
|
end
|
189
195
|
target = files.count > 1 ? NA.select_file(files) : files[0]
|
@@ -193,7 +199,6 @@ class App
|
|
193
199
|
end
|
194
200
|
end
|
195
201
|
|
196
|
-
NA.save_working_dir(File.expand_path(target))
|
197
202
|
NA.add_action(target, action, note)
|
198
203
|
end
|
199
204
|
end
|
@@ -236,10 +241,8 @@ class App
|
|
236
241
|
end
|
237
242
|
|
238
243
|
files, actions = NA.parse_actions(depth: depth,
|
239
|
-
extension: global_options[:ext],
|
240
|
-
na_tag: global_options[:na_tag],
|
241
244
|
search: tokens)
|
242
|
-
NA.output_actions(actions, depth,
|
245
|
+
NA.output_actions(actions, depth, files: files)
|
243
246
|
end
|
244
247
|
end
|
245
248
|
|
@@ -278,10 +281,8 @@ class App
|
|
278
281
|
end
|
279
282
|
|
280
283
|
files, actions = NA.parse_actions(depth: depth,
|
281
|
-
extension: global_options[:ext],
|
282
|
-
na_tag: global_options[:na_tag],
|
283
284
|
tag: tags)
|
284
|
-
NA.output_actions(actions, depth,
|
285
|
+
NA.output_actions(actions, depth, files: files)
|
285
286
|
end
|
286
287
|
end
|
287
288
|
|
@@ -300,7 +301,7 @@ class App
|
|
300
301
|
project = reader.read_line(NA::Color.template('{y}Project name {bw}> {x}'), value: project).strip
|
301
302
|
end
|
302
303
|
|
303
|
-
target = "#{project}.#{
|
304
|
+
target = "#{project}.#{NA.extension}"
|
304
305
|
|
305
306
|
if File.exist?(target)
|
306
307
|
print NA::Color.template("{r}File {bw}#{target}{r} already exists, overwrite it? {br}y{w}/{bg}N{x} ")
|
@@ -339,7 +340,7 @@ class App
|
|
339
340
|
else
|
340
341
|
options[:depth].nil? ? global_options[:depth].to_i : options[:depth].to_i
|
341
342
|
end
|
342
|
-
files = NA.find_files(depth: depth
|
343
|
+
files = NA.find_files(depth: depth)
|
343
344
|
file = if files.count > 1
|
344
345
|
NA.select_file(files)
|
345
346
|
else
|
@@ -354,8 +355,59 @@ class App
|
|
354
355
|
end
|
355
356
|
end
|
356
357
|
|
358
|
+
desc 'Show or install prompt hooks for the current shell'
|
359
|
+
long_desc 'Installing the prompt hook allows you to automatically
|
360
|
+
list next actions when you cd into a directory'
|
361
|
+
command %i[prompt] do |c|
|
362
|
+
c.desc 'Output the prompt hook for the current shell to STDOUT. Pass an argument to specify a shell (zsh, bash, fish)'
|
363
|
+
c.arg_name '[SHELL]'
|
364
|
+
c.command %i[show] do |s|
|
365
|
+
s.action do |global_options, options, args|
|
366
|
+
if args.count.positive?
|
367
|
+
shell = args[0]
|
368
|
+
else
|
369
|
+
shell = File.basename(ENV['SHELL'])
|
370
|
+
end
|
371
|
+
|
372
|
+
case shell
|
373
|
+
when /^f/i
|
374
|
+
NA::Prompt.show_prompt_hook(:fish)
|
375
|
+
when /^z/i
|
376
|
+
NA::Prompt.show_prompt_hook(:zsh)
|
377
|
+
when /^b/i
|
378
|
+
NA::Prompt.show_prompt_hook(:bash)
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
c.desc 'Install the hook for the current shell to the appropriate startup file.'
|
384
|
+
c.arg_name '[SHELL]'
|
385
|
+
c.command %i[install] do |s|
|
386
|
+
s.action do |global_options, options, args|
|
387
|
+
if args.count.positive?
|
388
|
+
shell = args[0]
|
389
|
+
else
|
390
|
+
shell = File.basename(ENV['SHELL'])
|
391
|
+
end
|
392
|
+
|
393
|
+
case shell
|
394
|
+
when /^f/i
|
395
|
+
NA::Prompt.install_prompt_hook(:fish)
|
396
|
+
when /^z/i
|
397
|
+
NA::Prompt.install_prompt_hook(:zsh)
|
398
|
+
when /^b/i
|
399
|
+
NA::Prompt.install_prompt_hook(:bash)
|
400
|
+
end
|
401
|
+
end
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
|
406
|
+
|
357
407
|
pre do |global, command, options, args|
|
358
|
-
NA.verbose = global[:
|
408
|
+
NA.verbose = global[:debug]
|
409
|
+
NA.extension = global[:ext]
|
410
|
+
NA.na_tag = global[:na_tag]
|
359
411
|
true
|
360
412
|
end
|
361
413
|
|
data/lib/na/next_action.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
# Next Action methods
|
4
4
|
module NA
|
5
5
|
class << self
|
6
|
-
attr_accessor :verbose
|
6
|
+
attr_accessor :verbose, :extension, :na_tag
|
7
7
|
|
8
8
|
def create_todo(target, basename)
|
9
9
|
File.open(target, 'w') do |f|
|
@@ -22,11 +22,13 @@ module NA
|
|
22
22
|
ENDCONTENT
|
23
23
|
f.puts(content)
|
24
24
|
end
|
25
|
-
puts NA::Color.template("{y}Created {bw}#{target}{x}")
|
25
|
+
$stderr.puts NA::Color.template("{y}Created {bw}#{target}{x}")
|
26
26
|
end
|
27
27
|
|
28
|
-
def find_files(depth: 1
|
29
|
-
`find . -name "*.#{extension}" -maxdepth #{depth}`.strip.split("\n")
|
28
|
+
def find_files(depth: 1)
|
29
|
+
files = `find . -name "*.#{NA.extension}" -maxdepth #{depth}`.strip.split("\n")
|
30
|
+
files.each { |f| save_working_dir(File.expand_path(f)) }
|
31
|
+
files
|
30
32
|
end
|
31
33
|
|
32
34
|
def select_file(files)
|
@@ -39,7 +41,7 @@ module NA
|
|
39
41
|
elsif TTY::Which.exist?('fzf')
|
40
42
|
res = choose_from(files, prompt: 'Use which file?')
|
41
43
|
unless res
|
42
|
-
puts 'No file selected, cancelled'
|
44
|
+
$stderr.puts 'No file selected, cancelled'
|
43
45
|
Process.exit 1
|
44
46
|
end
|
45
47
|
|
@@ -69,17 +71,17 @@ module NA
|
|
69
71
|
|
70
72
|
File.open(file, 'w') { |f| f.puts content }
|
71
73
|
|
72
|
-
puts NA::Color.template("{by}Task added to {bw}#{file}{x}")
|
74
|
+
$stderr.puts NA::Color.template("{by}Task added to {bw}#{file}{x}")
|
73
75
|
end
|
74
76
|
|
75
|
-
def output_actions(actions, depth,
|
77
|
+
def output_actions(actions, depth, files: nil)
|
76
78
|
template = if files&.count.positive?
|
77
79
|
if files.count == 1
|
78
80
|
'%parent%action'
|
79
81
|
else
|
80
82
|
'%filename%parent%action'
|
81
83
|
end
|
82
|
-
elsif NA.find_files(depth: depth
|
84
|
+
elsif NA.find_files(depth: depth).count > 1
|
83
85
|
if depth > 1
|
84
86
|
'%filename%parent%action'
|
85
87
|
else
|
@@ -89,13 +91,13 @@ module NA
|
|
89
91
|
'%parent%action'
|
90
92
|
end
|
91
93
|
if files && @verbose
|
92
|
-
puts files.map { |f| NA::Color.template("{dw}#{f}{x}") }
|
94
|
+
$stderr.puts files.map { |f| NA::Color.template("{dw}#{f}{x}") }
|
93
95
|
end
|
94
96
|
|
95
97
|
puts actions.map { |action| action.pretty(template: { output: template }) }
|
96
98
|
end
|
97
99
|
|
98
|
-
def parse_actions(depth: 1,
|
100
|
+
def parse_actions(depth: 1, query: nil, tag: nil, search: nil)
|
99
101
|
actions = []
|
100
102
|
required = []
|
101
103
|
optional = []
|
@@ -122,10 +124,10 @@ module NA
|
|
122
124
|
end
|
123
125
|
end
|
124
126
|
|
125
|
-
na_tag = "@#{na_tag.sub(/^@/, '')}"
|
127
|
+
na_tag = "@#{NA.na_tag.sub(/^@/, '')}"
|
126
128
|
|
127
129
|
if query.nil?
|
128
|
-
files = find_files(depth: depth
|
130
|
+
files = find_files(depth: depth)
|
129
131
|
else
|
130
132
|
files = match_working_dir(query)
|
131
133
|
end
|
@@ -151,13 +153,15 @@ module NA
|
|
151
153
|
indent_level = indent
|
152
154
|
end
|
153
155
|
elsif line =~ /^[ \t]*- / && line !~ / @done/
|
156
|
+
next unless line =~ /@#{NA.na_tag}\b/
|
157
|
+
|
154
158
|
unless optional.empty? && required.empty?
|
155
159
|
next unless line.matches(any: optional, all: required)
|
156
160
|
|
157
161
|
end
|
158
162
|
|
159
|
-
action = line.sub(/^[ \t]*- /, '').sub(/
|
160
|
-
new_action = NA::Action.new(file, File.basename(file, ".#{extension}"), parent.dup, action)
|
163
|
+
action = line.sub(/^[ \t]*- /, '').sub(/ @#{NA.na_tag}\b/, '')
|
164
|
+
new_action = NA::Action.new(file, File.basename(file, ".#{NA.extension}"), parent.dup, action)
|
161
165
|
actions.push(new_action)
|
162
166
|
end
|
163
167
|
end
|
@@ -220,7 +224,7 @@ module NA
|
|
220
224
|
dirs.delete_if { |d| !d.matches(any: optional, all: required) }
|
221
225
|
dirs.sort.uniq
|
222
226
|
else
|
223
|
-
puts NA::Color.template('{r}No na database found{x}')
|
227
|
+
$stderr.puts NA::Color.template('{r}No na database found{x}')
|
224
228
|
Process.exit 1
|
225
229
|
end
|
226
230
|
end
|
@@ -269,7 +273,7 @@ module NA
|
|
269
273
|
if 'xdg-open'.available?
|
270
274
|
`xdg-open #{Shellwords.escape(file)}`
|
271
275
|
else
|
272
|
-
puts NA::Color.template('{r}Unable to determine executable for `open`.{x}')
|
276
|
+
$stderr.puts NA::Color.template('{r}Unable to determine executable for `open`.{x}')
|
273
277
|
end
|
274
278
|
end
|
275
279
|
end
|
data/lib/na/prompt.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NA
|
4
|
+
# Prompt Hooks
|
5
|
+
module Prompt
|
6
|
+
class << self
|
7
|
+
def prompt_hook(shell)
|
8
|
+
case shell
|
9
|
+
when :zsh
|
10
|
+
<<~EOHOOK
|
11
|
+
# zsh prompt hook for na
|
12
|
+
chpwd() { na next }
|
13
|
+
EOHOOK
|
14
|
+
when :fish
|
15
|
+
<<~EOHOOK
|
16
|
+
# Fish Prompt Command
|
17
|
+
function __should_na --on-variable PWD
|
18
|
+
test -s (basename $PWD)".#{NA.extension}" && na next
|
19
|
+
end
|
20
|
+
EOHOOK
|
21
|
+
when :bash
|
22
|
+
<<~EOHOOK
|
23
|
+
# Bash PROMPT_COMMAND for na
|
24
|
+
last_command_was_cd() {
|
25
|
+
[[ $(history 1|sed -e "s/^[ ]*[0-9]*[ ]*//") =~ ^((cd|z|j|jump|g|f|pushd|popd|exit)([ ]|$)) ]] && na next
|
26
|
+
}
|
27
|
+
if [[ -z "$PROMPT_COMMAND" ]]; then
|
28
|
+
PROMPT_COMMAND="eval 'last_command_was_cd'"
|
29
|
+
else
|
30
|
+
echo $PROMPT_COMMAND | grep -v -q "last_command_was_cd" && PROMPT_COMMAND="$PROMPT_COMMAND;"'eval "last_command_was_cd"'
|
31
|
+
fi
|
32
|
+
EOHOOK
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def prompt_file(shell)
|
37
|
+
files = {
|
38
|
+
zsh: '~/.zshrc',
|
39
|
+
fish: '~/.config/fish/conf.d/na.fish',
|
40
|
+
bash: '~/.bash_profile'
|
41
|
+
}
|
42
|
+
|
43
|
+
files[shell]
|
44
|
+
end
|
45
|
+
|
46
|
+
def show_prompt_hook(shell)
|
47
|
+
file = prompt_file(shell)
|
48
|
+
|
49
|
+
$stderr.puts NA::Color.template("{bw}# Add this to {y}#{file}{x}")
|
50
|
+
puts prompt_hook(shell)
|
51
|
+
end
|
52
|
+
|
53
|
+
def install_prompt_hook(shell)
|
54
|
+
file = prompt_file(shell)
|
55
|
+
|
56
|
+
File.open(File.expand_path(file), 'a') { |f| f.puts prompt_hook(shell) }
|
57
|
+
$stderr.puts NA::Color.template("{y}Added {bw}#{shell}{xy} prompt hook to {bw}#{file}{x}")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/na/version.rb
CHANGED
data/lib/na.rb
CHANGED
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.0.
|
12
|
+
The current version of `na` is <!--VER-->1.0.6<!--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
|
|
@@ -293,7 +293,6 @@ Fish (in ~/.config/fish/conf.d/*.fish):
|
|
293
293
|
|
294
294
|
```fish
|
295
295
|
function __should_na --on-variable PWD
|
296
|
-
# function __should_na --on-event fish_prompt
|
297
296
|
test -s (basename $PWD)".taskpaper" && na
|
298
297
|
end
|
299
298
|
```
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: na
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brett Terpstra
|
@@ -170,6 +170,7 @@ files:
|
|
170
170
|
- lib/na/action.rb
|
171
171
|
- lib/na/colors.rb
|
172
172
|
- lib/na/next_action.rb
|
173
|
+
- lib/na/prompt.rb
|
173
174
|
- lib/na/string.rb
|
174
175
|
- lib/na/version.rb
|
175
176
|
- na.gemspec
|