na 1.1.9 → 1.1.11
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 +17 -0
 - data/Gemfile.lock +1 -1
 - data/README.md +2 -2
 - data/bin/na +30 -25
 - data/lib/na/next_action.rb +66 -35
 - data/lib/na/string.rb +11 -0
 - data/lib/na/version.rb +1 -1
 - data/src/README.md +2 -2
 - metadata +2 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: b309ba145cf0859f1a9011cf62268261766338d79cb956810fab9c64863c37f2
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 6fc7e065d4d85bf70b9122634414274e6a44d640ffffeeee7409e9102115f11d
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 63ee0b1ac9370533379956e8cd5f6571c8d39731c12c02404b2912d5cb97f49d32c988e4d23c12c50d1b2080412296bc58351680122abd26281580c49d93f722
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: b7500123c7ea092acc42ccba0873942fe871bd201405e3ef2faa66f3d155c3d0ac60b530078d962114a4d0d66bdb8ea427b1452873c14e2b06419cb2675e822e
         
     | 
    
        data/CHANGELOG.md
    CHANGED
    
    | 
         @@ -1,3 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ### 1.1.11
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            2022-10-05 08:56
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            #### IMPROVED
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            - Respect na_tag setting when creating new todo file
         
     | 
| 
      
 8 
     | 
    
         
            +
            - Code cleanup
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            ### 1.1.10
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            2022-10-05 08:19
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            #### FIXED
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            - When adding a project, don't use Ruby #capitalize, which downcases the rest of the project name
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
       1 
18 
     | 
    
         
             
            ### 1.1.9
         
     | 
| 
       2 
19 
     | 
    
         | 
| 
       3 
20 
     | 
    
         
             
            2022-10-03 12: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.1. 
     | 
| 
      
 12 
     | 
    
         
            +
            The current version of `na` is 1.1.11
         
     | 
| 
       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. 
         
     | 
| 
         @@ -37,7 +37,7 @@ You can list next actions in files in the current directory by typing `na`. By d 
     | 
|
| 
       37 
37 
     | 
    
         | 
| 
       38 
38 
     | 
    
         
             
            #### Easy matching
         
     | 
| 
       39 
39 
     | 
    
         | 
| 
       40 
     | 
    
         
            -
            `na` features intelligent project matching. Every time it locates a todo file, it adds the project to the database. Once a project is recorded, you can list its actions by using any portion of the parent directories or file names. If your project is in `~/Sites/dev/markedapp`, you could quickly list its next actions by typing `na dev mark`. It will always look for the shortest match.
         
     | 
| 
      
 40 
     | 
    
         
            +
            `na` features intelligent project matching. Every time it locates a todo file, it adds the project to the database. Once a project is recorded, you can list its actions by using any portion of the parent directories or file names. If your project is in `~/Sites/dev/markedapp`, you could quickly list its next actions by typing `na next dev mark`. It will always look for the shortest match.
         
     | 
| 
       41 
41 
     | 
    
         | 
| 
       42 
42 
     | 
    
         
             
            #### Recursion
         
     | 
| 
       43 
43 
     | 
    
         | 
    
        data/bin/na
    CHANGED
    
    | 
         @@ -1,8 +1,11 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
       2 
4 
     | 
    
         
             
            $LOAD_PATH.unshift File.join(__dir__, '..', 'lib')
         
     | 
| 
       3 
5 
     | 
    
         
             
            require 'gli'
         
     | 
| 
       4 
6 
     | 
    
         
             
            require 'na'
         
     | 
| 
       5 
7 
     | 
    
         | 
| 
      
 8 
     | 
    
         
            +
            # Main application
         
     | 
| 
       6 
9 
     | 
    
         
             
            class App
         
     | 
| 
       7 
10 
     | 
    
         
             
              extend GLI::App
         
     | 
| 
       8 
11 
     | 
    
         | 
| 
         @@ -123,7 +126,7 @@ class App 
     | 
|
| 
       123 
126 
     | 
    
         | 
| 
       124 
127 
     | 
    
         
             
                c.desc 'Add action to specific project'
         
     | 
| 
       125 
128 
     | 
    
         
             
                c.default_value 'Inbox'
         
     | 
| 
       126 
     | 
    
         
            -
                c.flag %[to]
         
     | 
| 
      
 129 
     | 
    
         
            +
                c.flag %i[to]
         
     | 
| 
       127 
130 
     | 
    
         | 
| 
       128 
131 
     | 
    
         
             
                c.desc 'Use a tag other than the default next action tag'
         
     | 
| 
       129 
132 
     | 
    
         
             
                c.arg_name 'TAG'
         
     | 
| 
         @@ -136,7 +139,7 @@ class App 
     | 
|
| 
       136 
139 
     | 
    
         
             
                c.arg_name 'PATH'
         
     | 
| 
       137 
140 
     | 
    
         
             
                c.flag %i[f file]
         
     | 
| 
       138 
141 
     | 
    
         | 
| 
       139 
     | 
    
         
            -
                c.action do | 
     | 
| 
      
 142 
     | 
    
         
            +
                c.action do |_global_options, options, args|
         
     | 
| 
       140 
143 
     | 
    
         
             
                  reader = TTY::Reader.new
         
     | 
| 
       141 
144 
     | 
    
         
             
                  action = if args.count.positive?
         
     | 
| 
       142 
145 
     | 
    
         
             
                             args.join(' ').strip
         
     | 
| 
         @@ -168,7 +171,10 @@ class App 
     | 
|
| 
       168 
171 
     | 
    
         | 
| 
       169 
172 
     | 
    
         
             
                  note = if options[:note]
         
     | 
| 
       170 
173 
     | 
    
         
             
                           if TTY::Which.exist?('gum')
         
     | 
| 
       171 
     | 
    
         
            -
                              
     | 
| 
      
 174 
     | 
    
         
            +
                             args = ['--placeholder "Enter a note, CTRL-d to save"']
         
     | 
| 
      
 175 
     | 
    
         
            +
                             args << '--char-limit 0'
         
     | 
| 
      
 176 
     | 
    
         
            +
                             args << '--width $(tput cols)'
         
     | 
| 
      
 177 
     | 
    
         
            +
                             `gum write #{args.join(' ')}`.strip.split("\n")
         
     | 
| 
       172 
178 
     | 
    
         
             
                           else
         
     | 
| 
       173 
179 
     | 
    
         
             
                             puts NA::Color.template('{bm}Enter a note, {bw}CTRL-d{bm} to end editing{bw}')
         
     | 
| 
       174 
180 
     | 
    
         
             
                             reader.read_multiline
         
     | 
| 
         @@ -190,7 +196,7 @@ class App 
     | 
|
| 
       190 
196 
     | 
    
         
             
                    end
         
     | 
| 
       191 
197 
     | 
    
         
             
                  else
         
     | 
| 
       192 
198 
     | 
    
         
             
                    files = NA.find_files(depth: 1)
         
     | 
| 
       193 
     | 
    
         
            -
                    if files.count 
     | 
| 
      
 199 
     | 
    
         
            +
                    if files.count.zero?
         
     | 
| 
       194 
200 
     | 
    
         
             
                      print NA::Color.template('{by}No todo file found, create one? {w}(y/{g}N{w}){x} ')
         
     | 
| 
       195 
201 
     | 
    
         
             
                      res = reader.read_char
         
     | 
| 
       196 
202 
     | 
    
         
             
                      if res =~ /y/i
         
     | 
| 
         @@ -256,10 +262,10 @@ class App 
     | 
|
| 
       256 
262 
     | 
    
         
             
                end
         
     | 
| 
       257 
263 
     | 
    
         
             
              end
         
     | 
| 
       258 
264 
     | 
    
         | 
| 
       259 
     | 
    
         
            -
             
     | 
| 
       260 
265 
     | 
    
         
             
              desc 'Find actions matching a tag'
         
     | 
| 
       261 
266 
     | 
    
         
             
              long_desc 'Finds actions with tags matching the arguments. An action is shown if it
         
     | 
| 
       262 
     | 
    
         
            -
             
     | 
| 
      
 267 
     | 
    
         
            +
                         contains any of the tags listed. Add a + before a tag to make it required.
         
     | 
| 
      
 268 
     | 
    
         
            +
                         You can specify values using TAG=VALUE pairs.'
         
     | 
| 
       263 
269 
     | 
    
         
             
              arg_name 'TAG [VALUE]'
         
     | 
| 
       264 
270 
     | 
    
         
             
              command %i[tagged] do |c|
         
     | 
| 
       265 
271 
     | 
    
         
             
                c.example 'na tagged +maybe', desc: 'Show all actions tagged @maybe'
         
     | 
| 
         @@ -304,7 +310,7 @@ class App 
     | 
|
| 
       304 
310 
     | 
    
         
             
                c.example 'na init', desc: 'Generate a new todo file, prompting for project name'
         
     | 
| 
       305 
311 
     | 
    
         
             
                c.example 'na init warpspeed', desc: 'Generate a new todo for a project called warpspeed'
         
     | 
| 
       306 
312 
     | 
    
         | 
| 
       307 
     | 
    
         
            -
                c.action do | 
     | 
| 
      
 313 
     | 
    
         
            +
                c.action do |_global_options, _options, args|
         
     | 
| 
       308 
314 
     | 
    
         
             
                  reader = TTY::Reader.new
         
     | 
| 
       309 
315 
     | 
    
         
             
                  if args.count.positive?
         
     | 
| 
       310 
316 
     | 
    
         
             
                    project = args.join(' ')
         
     | 
| 
         @@ -346,7 +352,7 @@ class App 
     | 
|
| 
       346 
352 
     | 
    
         
             
                c.arg_name 'EDITOR'
         
     | 
| 
       347 
353 
     | 
    
         
             
                c.flag %i[a app]
         
     | 
| 
       348 
354 
     | 
    
         | 
| 
       349 
     | 
    
         
            -
                c.action do |global_options, options,  
     | 
| 
      
 355 
     | 
    
         
            +
                c.action do |global_options, options, _args|
         
     | 
| 
       350 
356 
     | 
    
         
             
                  depth = if global_options[:recurse] && options[:depth].nil? && global_options[:depth] == 1
         
     | 
| 
       351 
357 
     | 
    
         
             
                            3
         
     | 
| 
       352 
358 
     | 
    
         
             
                          else
         
     | 
| 
         @@ -371,15 +377,16 @@ class App 
     | 
|
| 
       371 
377 
     | 
    
         
             
              long_desc 'Installing the prompt hook allows you to automatically
         
     | 
| 
       372 
378 
     | 
    
         
             
              list next actions when you cd into a directory'
         
     | 
| 
       373 
379 
     | 
    
         
             
              command %i[prompt] do |c|
         
     | 
| 
       374 
     | 
    
         
            -
                c.desc 'Output the prompt hook for the current shell to STDOUT. Pass an argument to 
     | 
| 
      
 380 
     | 
    
         
            +
                c.desc 'Output the prompt hook for the current shell to STDOUT. Pass an argument to
         
     | 
| 
      
 381 
     | 
    
         
            +
                        specify a shell (zsh, bash, fish)'
         
     | 
| 
       375 
382 
     | 
    
         
             
                c.arg_name '[SHELL]'
         
     | 
| 
       376 
383 
     | 
    
         
             
                c.command %i[show] do |s|
         
     | 
| 
       377 
     | 
    
         
            -
                  s.action do | 
     | 
| 
       378 
     | 
    
         
            -
                    if args.count.positive?
         
     | 
| 
       379 
     | 
    
         
            -
             
     | 
| 
       380 
     | 
    
         
            -
             
     | 
| 
       381 
     | 
    
         
            -
             
     | 
| 
       382 
     | 
    
         
            -
             
     | 
| 
      
 384 
     | 
    
         
            +
                  s.action do |_global_options, _options, args|
         
     | 
| 
      
 385 
     | 
    
         
            +
                    shell = if args.count.positive?
         
     | 
| 
      
 386 
     | 
    
         
            +
                              args[0]
         
     | 
| 
      
 387 
     | 
    
         
            +
                            else
         
     | 
| 
      
 388 
     | 
    
         
            +
                              File.basename(ENV['SHELL'])
         
     | 
| 
      
 389 
     | 
    
         
            +
                            end
         
     | 
| 
       383 
390 
     | 
    
         | 
| 
       384 
391 
     | 
    
         
             
                    case shell
         
     | 
| 
       385 
392 
     | 
    
         
             
                    when /^f/i
         
     | 
| 
         @@ -395,12 +402,12 @@ class App 
     | 
|
| 
       395 
402 
     | 
    
         
             
                c.desc 'Install the hook for the current shell to the appropriate startup file.'
         
     | 
| 
       396 
403 
     | 
    
         
             
                c.arg_name '[SHELL]'
         
     | 
| 
       397 
404 
     | 
    
         
             
                c.command %i[install] do |s|
         
     | 
| 
       398 
     | 
    
         
            -
                  s.action do | 
     | 
| 
       399 
     | 
    
         
            -
                    if args.count.positive?
         
     | 
| 
       400 
     | 
    
         
            -
             
     | 
| 
       401 
     | 
    
         
            -
             
     | 
| 
       402 
     | 
    
         
            -
             
     | 
| 
       403 
     | 
    
         
            -
             
     | 
| 
      
 405 
     | 
    
         
            +
                  s.action do |_global_options, _options, args|
         
     | 
| 
      
 406 
     | 
    
         
            +
                    shell = if args.count.positive?
         
     | 
| 
      
 407 
     | 
    
         
            +
                              args[0]
         
     | 
| 
      
 408 
     | 
    
         
            +
                            else
         
     | 
| 
      
 409 
     | 
    
         
            +
                              File.basename(ENV['SHELL'])
         
     | 
| 
      
 410 
     | 
    
         
            +
                            end
         
     | 
| 
       404 
411 
     | 
    
         | 
| 
       405 
412 
     | 
    
         
             
                    case shell
         
     | 
| 
       406 
413 
     | 
    
         
             
                    when /^f/i
         
     | 
| 
         @@ -414,7 +421,7 @@ class App 
     | 
|
| 
       414 
421 
     | 
    
         
             
                end
         
     | 
| 
       415 
422 
     | 
    
         
             
              end
         
     | 
| 
       416 
423 
     | 
    
         | 
| 
       417 
     | 
    
         
            -
              pre do |global,  
     | 
| 
      
 424 
     | 
    
         
            +
              pre do |global, _command, _options, _args|
         
     | 
| 
       418 
425 
     | 
    
         
             
                NA.verbose = global[:debug]
         
     | 
| 
       419 
426 
     | 
    
         
             
                NA.extension = global[:ext]
         
     | 
| 
       420 
427 
     | 
    
         
             
                NA.na_tag = global[:na_tag]
         
     | 
| 
         @@ -432,9 +439,7 @@ class App 
     | 
|
| 
       432 
439 
     | 
    
         
             
                case exception
         
     | 
| 
       433 
440 
     | 
    
         
             
                when GLI::UnknownCommand
         
     | 
| 
       434 
441 
     | 
    
         
             
                  cmd = ['add']
         
     | 
| 
       435 
     | 
    
         
            -
                  if ARGV.count.positive?
         
     | 
| 
       436 
     | 
    
         
            -
                    cmd.concat(ARGV.unshift($first_arg))
         
     | 
| 
       437 
     | 
    
         
            -
                  end
         
     | 
| 
      
 442 
     | 
    
         
            +
                  cmd.concat(ARGV.unshift($first_arg)) if ARGV.count.positive?
         
     | 
| 
       438 
443 
     | 
    
         | 
| 
       439 
444 
     | 
    
         
             
                  exit run(cmd)
         
     | 
| 
       440 
445 
     | 
    
         
             
                when SystemExit
         
     | 
    
        data/lib/na/next_action.rb
    CHANGED
    
    | 
         @@ -5,10 +5,17 @@ module NA 
     | 
|
| 
       5 
5 
     | 
    
         
             
              class << self
         
     | 
| 
       6 
6 
     | 
    
         
             
                attr_accessor :verbose, :extension, :na_tag
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
      
 8 
     | 
    
         
            +
                def notify(msg, exit_code: false)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  $stderr.puts NA::Color.template("{x}#{msg}{x}")
         
     | 
| 
      
 10 
     | 
    
         
            +
                  if exit_code && exit_code.is_a?(Number)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    Process.exit exit_code
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
       8 
15 
     | 
    
         
             
                def create_todo(target, basename)
         
     | 
| 
       9 
16 
     | 
    
         
             
                  File.open(target, 'w') do |f|
         
     | 
| 
       10 
17 
     | 
    
         
             
                    content = <<~ENDCONTENT
         
     | 
| 
       11 
     | 
    
         
            -
                      Inbox: 
     | 
| 
      
 18 
     | 
    
         
            +
                      Inbox:
         
     | 
| 
       12 
19 
     | 
    
         
             
                      #{basename}:
         
     | 
| 
       13 
20 
     | 
    
         
             
                      \tFeature Requests:
         
     | 
| 
       14 
21 
     | 
    
         
             
                      \tIdeas:
         
     | 
| 
         @@ -18,11 +25,11 @@ module NA 
     | 
|
| 
       18 
25 
     | 
    
         
             
                      \tTop Priority @search(@priority = 5 and not @done)
         
     | 
| 
       19 
26 
     | 
    
         
             
                      \tHigh Priority @search(@priority > 3 and not @done)
         
     | 
| 
       20 
27 
     | 
    
         
             
                      \tMaybe @search(@maybe)
         
     | 
| 
       21 
     | 
    
         
            -
                      \tNext @search( 
     | 
| 
      
 28 
     | 
    
         
            +
                      \tNext @search(@#{NA.na_tag} and not @done and not project = \"Archive\")
         
     | 
| 
       22 
29 
     | 
    
         
             
                    ENDCONTENT
         
     | 
| 
       23 
30 
     | 
    
         
             
                    f.puts(content)
         
     | 
| 
       24 
31 
     | 
    
         
             
                  end
         
     | 
| 
       25 
     | 
    
         
            -
                   
     | 
| 
      
 32 
     | 
    
         
            +
                  notify("{y}Created {bw}#{target}")
         
     | 
| 
       26 
33 
     | 
    
         
             
                end
         
     | 
| 
       27 
34 
     | 
    
         | 
| 
       28 
35 
     | 
    
         
             
                def find_files(depth: 1)
         
     | 
| 
         @@ -41,8 +48,7 @@ module NA 
     | 
|
| 
       41 
48 
     | 
    
         
             
                  elsif TTY::Which.exist?('fzf')
         
     | 
| 
       42 
49 
     | 
    
         
             
                    res = choose_from(files, prompt: 'Use which file?')
         
     | 
| 
       43 
50 
     | 
    
         
             
                    unless res
         
     | 
| 
       44 
     | 
    
         
            -
                       
     | 
| 
       45 
     | 
    
         
            -
                      Process.exit 1
         
     | 
| 
      
 51 
     | 
    
         
            +
                      notify('{r}No file selected, cancelled', exit_code: 1)
         
     | 
| 
       46 
52 
     | 
    
         
             
                    end
         
     | 
| 
       47 
53 
     | 
    
         | 
| 
       48 
54 
     | 
    
         
             
                    res.strip
         
     | 
| 
         @@ -60,18 +66,18 @@ module NA 
     | 
|
| 
       60 
66 
     | 
    
         
             
                def add_action(file, project, action, note = nil)
         
     | 
| 
       61 
67 
     | 
    
         
             
                  content = IO.read(file)
         
     | 
| 
       62 
68 
     | 
    
         
             
                  unless content =~ /^[ \t]*#{project}:/i
         
     | 
| 
       63 
     | 
    
         
            -
                    content = "#{project. 
     | 
| 
      
 69 
     | 
    
         
            +
                    content = "#{project.cap_first}:\n#{content}"
         
     | 
| 
       64 
70 
     | 
    
         
             
                  end
         
     | 
| 
       65 
71 
     | 
    
         | 
| 
       66 
72 
     | 
    
         
             
                  content.sub!(/^([ \t]*)#{project}:(.*?)$/i) do
         
     | 
| 
       67 
73 
     | 
    
         
             
                    m = Regexp.last_match
         
     | 
| 
       68 
74 
     | 
    
         
             
                    note = note.nil? ? '' : "\n#{m[1]}\t\t#{note.join('').strip}"
         
     | 
| 
       69 
     | 
    
         
            -
                    "#{m[1]}#{project. 
     | 
| 
      
 75 
     | 
    
         
            +
                    "#{m[1]}#{project.cap_first}:#{m[2]}\n#{m[1]}\t- #{action}#{note}"
         
     | 
| 
       70 
76 
     | 
    
         
             
                  end
         
     | 
| 
       71 
77 
     | 
    
         | 
| 
       72 
78 
     | 
    
         
             
                  File.open(file, 'w') { |f| f.puts content }
         
     | 
| 
       73 
79 
     | 
    
         | 
| 
       74 
     | 
    
         
            -
                   
     | 
| 
      
 80 
     | 
    
         
            +
                  notify("{by}Task added to {bw}#{file}")
         
     | 
| 
       75 
81 
     | 
    
         
             
                end
         
     | 
| 
       76 
82 
     | 
    
         | 
| 
       77 
83 
     | 
    
         
             
                def output_actions(actions, depth, files: nil)
         
     | 
| 
         @@ -91,7 +97,7 @@ module NA 
     | 
|
| 
       91 
97 
     | 
    
         
             
                               '%parent%action'
         
     | 
| 
       92 
98 
     | 
    
         
             
                             end
         
     | 
| 
       93 
99 
     | 
    
         
             
                  if files && @verbose
         
     | 
| 
       94 
     | 
    
         
            -
                     
     | 
| 
      
 100 
     | 
    
         
            +
                    files.map { |f| notify("{dw}#{f}") }
         
     | 
| 
       95 
101 
     | 
    
         
             
                  end
         
     | 
| 
       96 
102 
     | 
    
         | 
| 
       97 
103 
     | 
    
         
             
                  puts actions.map { |action| action.pretty(template: { output: template }) }
         
     | 
| 
         @@ -188,11 +194,7 @@ module NA 
     | 
|
| 
       188 
194 
     | 
    
         
             
                def choose_from(options, prompt: 'Make a selection: ', multiple: false, sorted: true, fzf_args: [])
         
     | 
| 
       189 
195 
     | 
    
         
             
                  return nil unless $stdout.isatty
         
     | 
| 
       190 
196 
     | 
    
         | 
| 
       191 
     | 
    
         
            -
                   
     | 
| 
       192 
     | 
    
         
            -
                  default_args = []
         
     | 
| 
       193 
     | 
    
         
            -
                  default_args << %(--prompt="#{prompt}")
         
     | 
| 
       194 
     | 
    
         
            -
                  default_args << "--height=#{options.count + 2}"
         
     | 
| 
       195 
     | 
    
         
            -
                  default_args << '--info=inline'
         
     | 
| 
      
 197 
     | 
    
         
            +
                  default_args = [%(--prompt="#{prompt}"), "--height=#{options.count + 2}", '--info=inline']
         
     | 
| 
       196 
198 
     | 
    
         
             
                  default_args << '--multi' if multiple
         
     | 
| 
       197 
199 
     | 
    
         
             
                  header = "esc: cancel,#{multiple ? ' tab: multi-select, ctrl-a: select all,' : ''} return: confirm"
         
     | 
| 
       198 
200 
     | 
    
         
             
                  default_args << %(--header="#{header}")
         
     | 
| 
         @@ -205,33 +207,50 @@ module NA 
     | 
|
| 
       205 
207 
     | 
    
         
             
                  res
         
     | 
| 
       206 
208 
     | 
    
         
             
                end
         
     | 
| 
       207 
209 
     | 
    
         | 
| 
      
 210 
     | 
    
         
            +
                ##
         
     | 
| 
      
 211 
     | 
    
         
            +
                ## Get path to database of known todo files
         
     | 
| 
      
 212 
     | 
    
         
            +
                ##
         
     | 
| 
      
 213 
     | 
    
         
            +
                ## @return     [String] File path
         
     | 
| 
      
 214 
     | 
    
         
            +
                ##
         
     | 
| 
       208 
215 
     | 
    
         
             
                def database_path
         
     | 
| 
       209 
216 
     | 
    
         
             
                  db_dir = File.expand_path('~/.local/share/na')
         
     | 
| 
      
 217 
     | 
    
         
            +
                  # Create directory if needed
         
     | 
| 
       210 
218 
     | 
    
         
             
                  FileUtils.mkdir_p(db_dir) unless File.directory?(db_dir)
         
     | 
| 
       211 
219 
     | 
    
         
             
                  db_file = 'tdlist.txt'
         
     | 
| 
       212 
220 
     | 
    
         
             
                  File.join(db_dir, db_file)
         
     | 
| 
       213 
221 
     | 
    
         
             
                end
         
     | 
| 
       214 
222 
     | 
    
         | 
| 
       215 
     | 
    
         
            -
                 
     | 
| 
      
 223 
     | 
    
         
            +
                ##
         
     | 
| 
      
 224 
     | 
    
         
            +
                ## Find a matching path using semi-fuzzy matching.
         
     | 
| 
      
 225 
     | 
    
         
            +
                ## Search tokens can include ! and + to negate or make
         
     | 
| 
      
 226 
     | 
    
         
            +
                ## required.
         
     | 
| 
      
 227 
     | 
    
         
            +
                ##
         
     | 
| 
      
 228 
     | 
    
         
            +
                ## @param      search    [Array] search tokens to match
         
     | 
| 
      
 229 
     | 
    
         
            +
                ## @param      distance  [Integer] allowed distance
         
     | 
| 
      
 230 
     | 
    
         
            +
                ##                       between characters
         
     | 
| 
      
 231 
     | 
    
         
            +
                ##
         
     | 
| 
      
 232 
     | 
    
         
            +
                def match_working_dir(search, distance: 1)
         
     | 
| 
       216 
233 
     | 
    
         
             
                  optional = []
         
     | 
| 
       217 
234 
     | 
    
         
             
                  required = []
         
     | 
| 
       218 
235 
     | 
    
         | 
| 
       219 
236 
     | 
    
         
             
                  search&.each do |t|
         
     | 
| 
       220 
     | 
    
         
            -
                     
     | 
| 
      
 237 
     | 
    
         
            +
                    # Make "search" into "s.{0,1}e.{0,1}a.{0,1}r.{0,1}c.{0,1}h"
         
     | 
| 
      
 238 
     | 
    
         
            +
                    new_rx = t[:token].to_s.split('').join(".{0,#{distance}}")
         
     | 
| 
       221 
239 
     | 
    
         | 
| 
       222 
240 
     | 
    
         
             
                    optional.push(new_rx)
         
     | 
| 
       223 
241 
     | 
    
         
             
                    required.push(new_rx) if t[:required]
         
     | 
| 
       224 
242 
     | 
    
         
             
                  end
         
     | 
| 
       225 
243 
     | 
    
         | 
| 
      
 244 
     | 
    
         
            +
                  match_dir(optional, required)
         
     | 
| 
      
 245 
     | 
    
         
            +
                end
         
     | 
| 
      
 246 
     | 
    
         
            +
             
     | 
| 
      
 247 
     | 
    
         
            +
                def match_dir(optional, required)
         
     | 
| 
       226 
248 
     | 
    
         
             
                  file = database_path
         
     | 
| 
       227 
     | 
    
         
            -
                   
     | 
| 
       228 
     | 
    
         
            -
             
     | 
| 
       229 
     | 
    
         
            -
             
     | 
| 
       230 
     | 
    
         
            -
             
     | 
| 
       231 
     | 
    
         
            -
                   
     | 
| 
       232 
     | 
    
         
            -
                    $stderr.puts NA::Color.template('{r}No na database found{x}')
         
     | 
| 
       233 
     | 
    
         
            -
                    Process.exit 1
         
     | 
| 
       234 
     | 
    
         
            -
                  end
         
     | 
| 
      
 249 
     | 
    
         
            +
                  notify('{r}No na database found', exit_code: 1) unless File.exist?(file)
         
     | 
| 
      
 250 
     | 
    
         
            +
             
     | 
| 
      
 251 
     | 
    
         
            +
                  dirs = IO.read(file).split("\n")
         
     | 
| 
      
 252 
     | 
    
         
            +
                  dirs.delete_if { |d| !d.matches(any: optional, all: required) }
         
     | 
| 
      
 253 
     | 
    
         
            +
                  dirs.sort.uniq
         
     | 
| 
       235 
254 
     | 
    
         
             
                end
         
     | 
| 
       236 
255 
     | 
    
         | 
| 
       237 
256 
     | 
    
         
             
                def save_working_dir(todo_file)
         
     | 
| 
         @@ -258,6 +277,26 @@ module NA 
     | 
|
| 
       258 
277 
     | 
    
         
             
                  os_open(file, app: app) if file && File.exist?(file)
         
     | 
| 
       259 
278 
     | 
    
         
             
                end
         
     | 
| 
       260 
279 
     | 
    
         | 
| 
      
 280 
     | 
    
         
            +
                def darwin_open(file, app: nil)
         
     | 
| 
      
 281 
     | 
    
         
            +
                  if app
         
     | 
| 
      
 282 
     | 
    
         
            +
                    `open -a "#{app}" #{Shellwords.escape(file)}`
         
     | 
| 
      
 283 
     | 
    
         
            +
                  else
         
     | 
| 
      
 284 
     | 
    
         
            +
                    `open #{Shellwords.escape(file)}`
         
     | 
| 
      
 285 
     | 
    
         
            +
                  end
         
     | 
| 
      
 286 
     | 
    
         
            +
                end
         
     | 
| 
      
 287 
     | 
    
         
            +
             
     | 
| 
      
 288 
     | 
    
         
            +
                def win_open(file)
         
     | 
| 
      
 289 
     | 
    
         
            +
                  `start #{Shellwords.escape(file)}`
         
     | 
| 
      
 290 
     | 
    
         
            +
                end
         
     | 
| 
      
 291 
     | 
    
         
            +
             
     | 
| 
      
 292 
     | 
    
         
            +
                def linux_open(file)
         
     | 
| 
      
 293 
     | 
    
         
            +
                  if TTY::Which.exist?('xdg-open')
         
     | 
| 
      
 294 
     | 
    
         
            +
                    `xdg-open #{Shellwords.escape(file)}`
         
     | 
| 
      
 295 
     | 
    
         
            +
                  else
         
     | 
| 
      
 296 
     | 
    
         
            +
                    notify('{r}Unable to determine executable for `xdg-open`.')
         
     | 
| 
      
 297 
     | 
    
         
            +
                  end
         
     | 
| 
      
 298 
     | 
    
         
            +
                end
         
     | 
| 
      
 299 
     | 
    
         
            +
             
     | 
| 
       261 
300 
     | 
    
         
             
                ##
         
     | 
| 
       262 
301 
     | 
    
         
             
                ## Platform-agnostic open command
         
     | 
| 
       263 
302 
     | 
    
         
             
                ##
         
     | 
| 
         @@ -267,19 +306,11 @@ module NA 
     | 
|
| 
       267 
306 
     | 
    
         
             
                  os = RbConfig::CONFIG['target_os']
         
     | 
| 
       268 
307 
     | 
    
         
             
                  case os
         
     | 
| 
       269 
308 
     | 
    
         
             
                  when /darwin.*/i
         
     | 
| 
       270 
     | 
    
         
            -
                     
     | 
| 
       271 
     | 
    
         
            -
                      `open -a "#{app}" #{Shellwords.escape(file)}`
         
     | 
| 
       272 
     | 
    
         
            -
                    else
         
     | 
| 
       273 
     | 
    
         
            -
                      `open #{Shellwords.escape(file)}`
         
     | 
| 
       274 
     | 
    
         
            -
                    end
         
     | 
| 
      
 309 
     | 
    
         
            +
                    darwin_open(file, app: app)
         
     | 
| 
       275 
310 
     | 
    
         
             
                  when /mingw|mswin/i
         
     | 
| 
       276 
     | 
    
         
            -
                     
     | 
| 
      
 311 
     | 
    
         
            +
                    win_open(file)
         
     | 
| 
       277 
312 
     | 
    
         
             
                  else
         
     | 
| 
       278 
     | 
    
         
            -
                     
     | 
| 
       279 
     | 
    
         
            -
                      `xdg-open #{Shellwords.escape(file)}`
         
     | 
| 
       280 
     | 
    
         
            -
                    else
         
     | 
| 
       281 
     | 
    
         
            -
                      $stderr.puts NA::Color.template('{r}Unable to determine executable for `open`.{x}')
         
     | 
| 
       282 
     | 
    
         
            -
                    end
         
     | 
| 
      
 313 
     | 
    
         
            +
                    linux_open(file)
         
     | 
| 
       283 
314 
     | 
    
         
             
                  end
         
     | 
| 
       284 
315 
     | 
    
         
             
                end
         
     | 
| 
       285 
316 
     | 
    
         
             
              end
         
     | 
    
        data/lib/na/string.rb
    CHANGED
    
    
    
        data/lib/na/version.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.1. 
     | 
| 
      
 12 
     | 
    
         
            +
            The current version of `na` is <!--VER-->1.1.10<!--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 
     | 
    
         | 
| 
         @@ -36,7 +36,7 @@ You can list next actions in files in the current directory by typing `na`. By d 
     | 
|
| 
       36 
36 
     | 
    
         | 
| 
       37 
37 
     | 
    
         
             
            #### Easy matching
         
     | 
| 
       38 
38 
     | 
    
         | 
| 
       39 
     | 
    
         
            -
            `na` features intelligent project matching. Every time it locates a todo file, it adds the project to the database. Once a project is recorded, you can list its actions by using any portion of the parent directories or file names. If your project is in `~/Sites/dev/markedapp`, you could quickly list its next actions by typing `na dev mark`. It will always look for the shortest match.
         
     | 
| 
      
 39 
     | 
    
         
            +
            `na` features intelligent project matching. Every time it locates a todo file, it adds the project to the database. Once a project is recorded, you can list its actions by using any portion of the parent directories or file names. If your project is in `~/Sites/dev/markedapp`, you could quickly list its next actions by typing `na next dev mark`. It will always look for the shortest match.
         
     | 
| 
       40 
40 
     | 
    
         | 
| 
       41 
41 
     | 
    
         
             
            #### Recursion
         
     | 
| 
       42 
42 
     | 
    
         | 
    
        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.1. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 1.1.11
         
     | 
| 
       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-05 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: rake
         
     |