na 1.0.5 → 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92a40acdde96bfe4a27a093edf4e0f909b23b1c300d6be4f742323ac4e9233be
4
- data.tar.gz: bfddb6edfe9cddf7a631819bd980708fd816d2853b3146f348c2095b1ca7aee2
3
+ metadata.gz: 9aab87ece3f35afbe5280d6c1b777c9d8dece4916f796eedb3dfebdbbeb5032e
4
+ data.tar.gz: 46b7eef3d84ede3a69f9497e4d0bb4fcc772fd159fbffe23f9749f3172bc2cdf
5
5
  SHA512:
6
- metadata.gz: 77fd24c44ea1b7dba5fb2feb8d36e625972b7662c3032d96ffb7af28843cc08ad16f911fb58778b7cfc831b329859effb04134168517eb596f1da4e9d62cc001
7
- data.tar.gz: 212c87e2f59706bd6ed9b5e4cec2ecbd629e9b344a7538f653d8b278dd0f9e62aeb2ceada2d2ed8ef12421fc8c54396ec6e2462b77fe28f90d90946a6aed3967
6
+ metadata.gz: 05bda9033431ce005ad32fb9cd1c711642504972ffa73131d1c989b90dd4b50089b53d9e6746df4555d87e9b65d8b3c2c3707023dd8a8287f8596f4583a727f5
7
+ data.tar.gz: d474663a84ca7ef0287f05c3c2ed6fa63b0fb3d6482337b33343bbfa71a7a7d1c4fe542f91d9c75797c48a4f073079b85a96ef6704d2056b193b7f891596cbf9
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ### 1.0.7
2
+
3
+ 2022-09-28 04:38
4
+
5
+ ### 1.0.6
6
+
7
+ 2022-09-28 04:22
8
+
9
+ #### NEW
10
+
11
+ - `na prompt [show|install]` command to help with adding prompt hooks to your shell
12
+
1
13
  ### 1.0.5
2
14
 
3
15
  2022-09-28 01:53
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- na (1.0.4)
4
+ na (1.0.6)
5
5
  gli (~> 2.21.0)
6
6
  tty-reader (~> 0.9, >= 0.9.0)
7
7
  tty-screen (~> 0.8, >= 0.8.1)
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.4.
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[verbose]
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] == global_options[:na_tag] ? nil : 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, global_options[:ext], files: files)
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 = global_options[:na_tag]
152
- na_tag = options[:tag] unless options[:tag].nil?
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(/@#{na_tag}/, '')} @#{na_tag}"
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, ".#{global_options[:ext]}")
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, extension: global_options[:ext])
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}.#{global_options[:ext]}"
190
+ target = "#{basename}.#{NA.extension}"
185
191
  NA.create_todo(target, basename)
186
- files = NA.find_files(depth: 1, extension: global_options[:ext])
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, global_options[:ext], files: files)
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, global_options[:ext], files: files)
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}.#{global_options[:ext]}"
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, extension: global_options[:ext])
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[:verbose]
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
 
@@ -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, extension: 'taskpaper')
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, extension, files: nil)
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, extension: extension).count > 1
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, extension: 'taskpaper', na_tag: 'na', query: nil, tag: nil, search: nil)
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, extension: extension)
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(/ #{na_tag}/, '')
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
@@ -1,3 +1,3 @@
1
1
  module Na
2
- VERSION = '1.0.5'
2
+ VERSION = '1.0.7'
3
3
  end
data/lib/na.rb CHANGED
@@ -11,3 +11,4 @@ require 'na/colors.rb'
11
11
  require 'na/string.rb'
12
12
  require 'na/action.rb'
13
13
  require 'na/next_action.rb'
14
+ require 'na/prompt.rb'
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.4<!--END VER-->.
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.5
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