na 1.0.4 → 1.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/Gemfile.lock +1 -1
- data/README.md +1 -2
- data/bin/na +63 -18
- data/lib/na/next_action.rb +17 -17
- 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: ac0a37d801443c68aaee6eee3b6c4a31461a61d4221c7a073beb0f176d7d7424
|
4
|
+
data.tar.gz: d04d6bd01a3104f6858e9a797af728486b80a8482b6644a09940a6272ae2ec4b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ec40b0dd9ff9f154cc22e5d1cb2df700fae82e9c8118110d72b0ea3aeed46a0bd7543955e8b491f99816a9c5dea8ede5866534c362abbb771a3fefbe8d346d9
|
7
|
+
data.tar.gz: c66d44910edfe4200655b6775665ead7836b47dd7b8b20385da29ee21ce6ba38d5fef0f99b2da009385d9962204cf491d3ee928b2c255bd5d2ce278d8a4c15fa
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
### 1.0.6
|
2
|
+
|
3
|
+
2022-09-28 04:22
|
4
|
+
|
5
|
+
#### NEW
|
6
|
+
|
7
|
+
- `na prompt [show|install]` command to help with adding prompt hooks to your shell
|
8
|
+
|
9
|
+
### 1.0.5
|
10
|
+
|
11
|
+
2022-09-28 01:53
|
12
|
+
|
13
|
+
#### FIXED
|
14
|
+
|
15
|
+
- A note containing a colon would be recognized as a project line
|
16
|
+
|
1
17
|
### 1.0.4
|
2
18
|
|
3
19
|
2022-09-28 01:18
|
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.5.
|
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'
|
@@ -94,11 +94,9 @@ class App
|
|
94
94
|
tag = options[:tag] == global_options[: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
|
|
@@ -148,7 +146,7 @@ class App
|
|
148
146
|
action = "#{action.gsub(/@priority\(\d+\)/, '')} @priority(#{options[:priority]})"
|
149
147
|
end
|
150
148
|
|
151
|
-
na_tag =
|
149
|
+
na_tag = NA.na_tag
|
152
150
|
na_tag = options[:tag] unless options[:tag].nil?
|
153
151
|
|
154
152
|
action = "#{action.gsub(/@#{na_tag}/, '')} @#{na_tag}"
|
@@ -167,7 +165,7 @@ class App
|
|
167
165
|
print NA::Color.template('{by}Specified file not found, create it? {w}(y/{g}N{w}){x} ')
|
168
166
|
res = reader.read_char
|
169
167
|
if res =~ /y/i
|
170
|
-
basename = File.basename(target, ".#{
|
168
|
+
basename = File.basename(target, ".#{NA.extension}")
|
171
169
|
NA.create_todo(target, basename)
|
172
170
|
else
|
173
171
|
puts NA::Color.template('{r}Cancelled{x}')
|
@@ -175,15 +173,15 @@ class App
|
|
175
173
|
end
|
176
174
|
end
|
177
175
|
else
|
178
|
-
files = NA.find_files(depth: 1
|
176
|
+
files = NA.find_files(depth: 1)
|
179
177
|
if files.count == 0
|
180
178
|
print NA::Color.template('{by}No todo file found, create one? {w}(y/{g}N{w}){x} ')
|
181
179
|
res = reader.read_char
|
182
180
|
if res =~ /y/i
|
183
181
|
basename = File.expand_path('.').split('/').last
|
184
|
-
target = "#{basename}.#{
|
182
|
+
target = "#{basename}.#{NA.extension}"
|
185
183
|
NA.create_todo(target, basename)
|
186
|
-
files = NA.find_files(depth: 1
|
184
|
+
files = NA.find_files(depth: 1)
|
187
185
|
end
|
188
186
|
end
|
189
187
|
target = files.count > 1 ? NA.select_file(files) : files[0]
|
@@ -236,10 +234,8 @@ class App
|
|
236
234
|
end
|
237
235
|
|
238
236
|
files, actions = NA.parse_actions(depth: depth,
|
239
|
-
extension: global_options[:ext],
|
240
|
-
na_tag: global_options[:na_tag],
|
241
237
|
search: tokens)
|
242
|
-
NA.output_actions(actions, depth,
|
238
|
+
NA.output_actions(actions, depth, files: files)
|
243
239
|
end
|
244
240
|
end
|
245
241
|
|
@@ -278,10 +274,8 @@ class App
|
|
278
274
|
end
|
279
275
|
|
280
276
|
files, actions = NA.parse_actions(depth: depth,
|
281
|
-
extension: global_options[:ext],
|
282
|
-
na_tag: global_options[:na_tag],
|
283
277
|
tag: tags)
|
284
|
-
NA.output_actions(actions, depth,
|
278
|
+
NA.output_actions(actions, depth, files: files)
|
285
279
|
end
|
286
280
|
end
|
287
281
|
|
@@ -300,7 +294,7 @@ class App
|
|
300
294
|
project = reader.read_line(NA::Color.template('{y}Project name {bw}> {x}'), value: project).strip
|
301
295
|
end
|
302
296
|
|
303
|
-
target = "#{project}.#{
|
297
|
+
target = "#{project}.#{NA.extension}"
|
304
298
|
|
305
299
|
if File.exist?(target)
|
306
300
|
print NA::Color.template("{r}File {bw}#{target}{r} already exists, overwrite it? {br}y{w}/{bg}N{x} ")
|
@@ -339,7 +333,7 @@ class App
|
|
339
333
|
else
|
340
334
|
options[:depth].nil? ? global_options[:depth].to_i : options[:depth].to_i
|
341
335
|
end
|
342
|
-
files = NA.find_files(depth: depth
|
336
|
+
files = NA.find_files(depth: depth)
|
343
337
|
file = if files.count > 1
|
344
338
|
NA.select_file(files)
|
345
339
|
else
|
@@ -354,8 +348,59 @@ class App
|
|
354
348
|
end
|
355
349
|
end
|
356
350
|
|
351
|
+
desc 'Show or install prompt hooks for the current shell'
|
352
|
+
long_desc 'Installing the prompt hook allows you to automatically
|
353
|
+
list next actions when you cd into a directory'
|
354
|
+
command %i[prompt] do |c|
|
355
|
+
c.desc 'Output the prompt hook for the current shell to STDOUT. Pass an argument to specify a shell (zsh, bash, fish)'
|
356
|
+
c.arg_name '[SHELL]'
|
357
|
+
c.command %i[show] do |s|
|
358
|
+
s.action do |global_options, options, args|
|
359
|
+
if args.count.positive?
|
360
|
+
shell = args[0]
|
361
|
+
else
|
362
|
+
shell = File.basename(ENV['SHELL'])
|
363
|
+
end
|
364
|
+
|
365
|
+
case shell
|
366
|
+
when /^f/i
|
367
|
+
NA::Prompt.show_prompt_hook(:fish)
|
368
|
+
when /^z/i
|
369
|
+
NA::Prompt.show_prompt_hook(:zsh)
|
370
|
+
when /^b/i
|
371
|
+
NA::Prompt.show_prompt_hook(:bash)
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
c.desc 'Install the hook for the current shell to the appropriate startup file.'
|
377
|
+
c.arg_name '[SHELL]'
|
378
|
+
c.command %i[install] do |s|
|
379
|
+
s.action do |global_options, options, args|
|
380
|
+
if args.count.positive?
|
381
|
+
shell = args[0]
|
382
|
+
else
|
383
|
+
shell = File.basename(ENV['SHELL'])
|
384
|
+
end
|
385
|
+
|
386
|
+
case shell
|
387
|
+
when /^f/i
|
388
|
+
NA::Prompt.install_prompt_hook(:fish)
|
389
|
+
when /^z/i
|
390
|
+
NA::Prompt.install_prompt_hook(:zsh)
|
391
|
+
when /^b/i
|
392
|
+
NA::Prompt.install_prompt_hook(:bash)
|
393
|
+
end
|
394
|
+
end
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
|
399
|
+
|
357
400
|
pre do |global, command, options, args|
|
358
|
-
NA.verbose = global[:
|
401
|
+
NA.verbose = global[:debug]
|
402
|
+
NA.extension = global[:ext]
|
403
|
+
NA.na_tag = global[:na_tag]
|
359
404
|
true
|
360
405
|
end
|
361
406
|
|
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,11 @@ 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
|
+
`find . -name "*.#{NA.extension}" -maxdepth #{depth}`.strip.split("\n")
|
30
30
|
end
|
31
31
|
|
32
32
|
def select_file(files)
|
@@ -39,7 +39,7 @@ module NA
|
|
39
39
|
elsif TTY::Which.exist?('fzf')
|
40
40
|
res = choose_from(files, prompt: 'Use which file?')
|
41
41
|
unless res
|
42
|
-
puts 'No file selected, cancelled'
|
42
|
+
$stderr.puts 'No file selected, cancelled'
|
43
43
|
Process.exit 1
|
44
44
|
end
|
45
45
|
|
@@ -69,17 +69,17 @@ module NA
|
|
69
69
|
|
70
70
|
File.open(file, 'w') { |f| f.puts content }
|
71
71
|
|
72
|
-
puts NA::Color.template("{by}Task added to {bw}#{file}{x}")
|
72
|
+
$stderr.puts NA::Color.template("{by}Task added to {bw}#{file}{x}")
|
73
73
|
end
|
74
74
|
|
75
|
-
def output_actions(actions, depth,
|
75
|
+
def output_actions(actions, depth, files: nil)
|
76
76
|
template = if files&.count.positive?
|
77
77
|
if files.count == 1
|
78
78
|
'%parent%action'
|
79
79
|
else
|
80
80
|
'%filename%parent%action'
|
81
81
|
end
|
82
|
-
elsif NA.find_files(depth: depth
|
82
|
+
elsif NA.find_files(depth: depth).count > 1
|
83
83
|
if depth > 1
|
84
84
|
'%filename%parent%action'
|
85
85
|
else
|
@@ -89,13 +89,13 @@ module NA
|
|
89
89
|
'%parent%action'
|
90
90
|
end
|
91
91
|
if files && @verbose
|
92
|
-
puts files.map { |f| NA::Color.template("{dw}#{f}{x}") }
|
92
|
+
$stderr.puts files.map { |f| NA::Color.template("{dw}#{f}{x}") }
|
93
93
|
end
|
94
94
|
|
95
95
|
puts actions.map { |action| action.pretty(template: { output: template }) }
|
96
96
|
end
|
97
97
|
|
98
|
-
def parse_actions(depth: 1,
|
98
|
+
def parse_actions(depth: 1, query: nil, tag: nil, search: nil)
|
99
99
|
actions = []
|
100
100
|
required = []
|
101
101
|
optional = []
|
@@ -122,10 +122,10 @@ module NA
|
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
125
|
-
na_tag = "@#{na_tag.sub(/^@/, '')}"
|
125
|
+
na_tag = "@#{NA.na_tag.sub(/^@/, '')}"
|
126
126
|
|
127
127
|
if query.nil?
|
128
|
-
files = find_files(depth: depth
|
128
|
+
files = find_files(depth: depth)
|
129
129
|
else
|
130
130
|
files = match_working_dir(query)
|
131
131
|
end
|
@@ -137,7 +137,7 @@ module NA
|
|
137
137
|
parent = []
|
138
138
|
content.split("\n").each do |line|
|
139
139
|
new_action = nil
|
140
|
-
if line =~ /([ \t]*)([^\-]+.*?)
|
140
|
+
if line =~ /([ \t]*)([^\-]+.*?): *(@\S+ *)*$/
|
141
141
|
proj = Regexp.last_match(2)
|
142
142
|
indent = line.indent_level
|
143
143
|
|
@@ -156,8 +156,8 @@ module NA
|
|
156
156
|
|
157
157
|
end
|
158
158
|
|
159
|
-
action = line.sub(/^[ \t]*- /, '').sub(/ #{na_tag}/, '')
|
160
|
-
new_action = NA::Action.new(file, File.basename(file, ".#{extension}"), parent.dup, action)
|
159
|
+
action = line.sub(/^[ \t]*- /, '').sub(/ #{NA.na_tag}/, '')
|
160
|
+
new_action = NA::Action.new(file, File.basename(file, ".#{NA.extension}"), parent.dup, action)
|
161
161
|
actions.push(new_action)
|
162
162
|
end
|
163
163
|
end
|
@@ -220,7 +220,7 @@ module NA
|
|
220
220
|
dirs.delete_if { |d| !d.matches(any: optional, all: required) }
|
221
221
|
dirs.sort.uniq
|
222
222
|
else
|
223
|
-
puts NA::Color.template('{r}No na database found{x}')
|
223
|
+
$stderr.puts NA::Color.template('{r}No na database found{x}')
|
224
224
|
Process.exit 1
|
225
225
|
end
|
226
226
|
end
|
@@ -269,7 +269,7 @@ module NA
|
|
269
269
|
if 'xdg-open'.available?
|
270
270
|
`xdg-open #{Shellwords.escape(file)}`
|
271
271
|
else
|
272
|
-
puts NA::Color.template('{r}Unable to determine executable for `open`.{x}')
|
272
|
+
$stderr.puts NA::Color.template('{r}Unable to determine executable for `open`.{x}')
|
273
273
|
end
|
274
274
|
end
|
275
275
|
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 }
|
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
|
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
|
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.5<!--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.6
|
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
|