na 1.2.79 → 1.2.81
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/.rubocop.yml +8 -2
 - data/.rubocop_todo.yml +33 -538
 - data/CHANGELOG.md +55 -0
 - data/Gemfile +2 -0
 - data/Gemfile.lock +27 -10
 - data/README.md +47 -6
 - data/Rakefile +6 -0
 - data/bin/commands/next.rb +4 -0
 - data/bin/commands/scan.rb +84 -0
 - data/bin/commands/update.rb +1 -1
 - data/bin/na +18 -12
 - data/lib/na/action.rb +181 -83
 - data/lib/na/actions.rb +91 -66
 - data/lib/na/array.rb +11 -7
 - data/lib/na/benchmark.rb +57 -0
 - data/lib/na/colors.rb +113 -92
 - data/lib/na/editor.rb +22 -22
 - data/lib/na/hash.rb +32 -9
 - data/lib/na/help_monkey_patch.rb +9 -1
 - data/lib/na/next_action.rb +327 -248
 - data/lib/na/pager.rb +60 -32
 - data/lib/na/project.rb +14 -1
 - data/lib/na/prompt.rb +25 -3
 - data/lib/na/string.rb +91 -130
 - data/lib/na/theme.rb +47 -39
 - data/lib/na/todo.rb +182 -145
 - data/lib/na/version.rb +3 -1
 - data/lib/na.rb +4 -1
 - data/na.gemspec +4 -2
 - data/scripts/generate-fish-completions.rb +18 -21
 - data/src/_README.md +14 -4
 - data/test_performance.rb +78 -0
 - metadata +55 -24
 
    
        data/CHANGELOG.md
    CHANGED
    
    | 
         @@ -1,3 +1,58 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ### 1.2.81
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            2025-10-25 07:32
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            #### NEW
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            - `na scan` command to scan for untracked todo files (thanks @rhsev)
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            #### IMPROVED
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            - Rubocop cleanup
         
     | 
| 
      
 12 
     | 
    
         
            +
            - YARD documentation
         
     | 
| 
      
 13 
     | 
    
         
            +
            - Test coverage
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            #### FIXED
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            - Reset color/emphasis before closing bracket in parent display
         
     | 
| 
      
 18 
     | 
    
         
            +
            - Subdirectory traversal with `na next -d X` fixed
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            ### 1.2.80
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
            2025-10-23 05:26
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            #### CHANGED
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            - Default behavior: git integration now opt-in with --repo-top flag
         
     | 
| 
      
 27 
     | 
    
         
            +
            - Pager execution: use spawn for better performance than fork+exec
         
     | 
| 
      
 28 
     | 
    
         
            +
            - Color template processing: cache compiled templates and colors hash
         
     | 
| 
      
 29 
     | 
    
         
            +
            - Action processing: batch regex highlighting instead of per-action processing
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            #### NEW
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
            - Add comprehensive benchmarking system with NA_BENCHMARK=1
         
     | 
| 
      
 34 
     | 
    
         
            +
            - Add template caching in Color.template to avoid repeated regex processing
         
     | 
| 
      
 35 
     | 
    
         
            +
            - Add colors hash caching to eliminate repeated hash creation
         
     | 
| 
      
 36 
     | 
    
         
            +
            - Add smart pagination that skips pager for small outputs (<2000 chars, <50 lines)
         
     | 
| 
      
 37 
     | 
    
         
            +
            - Add --repo-top flag to make git integration opt-in instead of default
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
            #### IMPROVED
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
            - Optimize performance
         
     | 
| 
      
 42 
     | 
    
         
            +
            - Theme loading now uses cached NA.theme instead of loading on every Action.pretty call
         
     | 
| 
      
 43 
     | 
    
         
            +
            - Action.pretty method with conditional processing and optimized string operations
         
     | 
| 
      
 44 
     | 
    
         
            +
            - Actions.output with batch regex processing - compile all output first, then apply regexes once
         
     | 
| 
      
 45 
     | 
    
         
            +
            - Pager performance using spawn instead of fork+exec and removing IO.select delays
         
     | 
| 
      
 46 
     | 
    
         
            +
            - Lazy loading of heavy gems (git, chronic, mdless) only when needed
         
     | 
| 
      
 47 
     | 
    
         
            +
            - String operations in Action.pretty with pre-computed template parts
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
            #### FIXED
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
            - Performance variability caused by git system calls running by default
         
     | 
| 
      
 52 
     | 
    
         
            +
            - Pager overhead causing 300-479ms delays on small outputs
         
     | 
| 
      
 53 
     | 
    
         
            +
            - Repeated regex compilation in color template processing
         
     | 
| 
      
 54 
     | 
    
         
            +
            - Theme loading bottleneck in Action.pretty method
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
       1 
56 
     | 
    
         
             
            ### 1.2.79
         
     | 
| 
       2 
57 
     | 
    
         | 
| 
       3 
58 
     | 
    
         
             
            2025-09-29 06:51
         
     | 
    
        data/Gemfile
    CHANGED
    
    
    
        data/Gemfile.lock
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            PATH
         
     | 
| 
       2 
2 
     | 
    
         
             
              remote: .
         
     | 
| 
       3 
3 
     | 
    
         
             
              specs:
         
     | 
| 
       4 
     | 
    
         
            -
                na (1.2. 
     | 
| 
      
 4 
     | 
    
         
            +
                na (1.2.81)
         
     | 
| 
       5 
5 
     | 
    
         
             
                  chronic (~> 0.10, >= 0.10.2)
         
     | 
| 
       6 
6 
     | 
    
         
             
                  git (~> 3.0.0)
         
     | 
| 
       7 
7 
     | 
    
         
             
                  gli (~> 2.21.0)
         
     | 
| 
         @@ -14,14 +14,14 @@ PATH 
     | 
|
| 
       14 
14 
     | 
    
         
             
            GEM
         
     | 
| 
       15 
15 
     | 
    
         
             
              remote: https://rubygems.org/
         
     | 
| 
       16 
16 
     | 
    
         
             
              specs:
         
     | 
| 
       17 
     | 
    
         
            -
                activesupport (8.0 
     | 
| 
      
 17 
     | 
    
         
            +
                activesupport (8.1.0)
         
     | 
| 
       18 
18 
     | 
    
         
             
                  base64
         
     | 
| 
       19 
     | 
    
         
            -
                  benchmark (>= 0.3)
         
     | 
| 
       20 
19 
     | 
    
         
             
                  bigdecimal
         
     | 
| 
       21 
20 
     | 
    
         
             
                  concurrent-ruby (~> 1.0, >= 1.3.1)
         
     | 
| 
       22 
21 
     | 
    
         
             
                  connection_pool (>= 2.2.5)
         
     | 
| 
       23 
22 
     | 
    
         
             
                  drb
         
     | 
| 
       24 
23 
     | 
    
         
             
                  i18n (>= 1.6, < 2)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  json
         
     | 
| 
       25 
25 
     | 
    
         
             
                  logger (>= 1.4.2)
         
     | 
| 
       26 
26 
     | 
    
         
             
                  minitest (>= 5.1)
         
     | 
| 
       27 
27 
     | 
    
         
             
                  securerandom (>= 0.3)
         
     | 
| 
         @@ -30,11 +30,12 @@ GEM 
     | 
|
| 
       30 
30 
     | 
    
         
             
                addressable (2.8.7)
         
     | 
| 
       31 
31 
     | 
    
         
             
                  public_suffix (>= 2.0.2, < 7.0)
         
     | 
| 
       32 
32 
     | 
    
         
             
                base64 (0.3.0)
         
     | 
| 
       33 
     | 
    
         
            -
                 
     | 
| 
       34 
     | 
    
         
            -
                 
     | 
| 
      
 33 
     | 
    
         
            +
                bigdecimal (3.3.1)
         
     | 
| 
      
 34 
     | 
    
         
            +
                bump (0.6.1)
         
     | 
| 
       35 
35 
     | 
    
         
             
                chronic (0.10.2)
         
     | 
| 
       36 
36 
     | 
    
         
             
                concurrent-ruby (1.3.5)
         
     | 
| 
       37 
     | 
    
         
            -
                connection_pool (2.5. 
     | 
| 
      
 37 
     | 
    
         
            +
                connection_pool (2.5.4)
         
     | 
| 
      
 38 
     | 
    
         
            +
                diff-lcs (1.6.2)
         
     | 
| 
       38 
39 
     | 
    
         
             
                drb (2.2.3)
         
     | 
| 
       39 
40 
     | 
    
         
             
                git (3.0.2)
         
     | 
| 
       40 
41 
     | 
    
         
             
                  activesupport (>= 5.0)
         
     | 
| 
         @@ -44,15 +45,29 @@ GEM 
     | 
|
| 
       44 
45 
     | 
    
         
             
                gli (2.21.5)
         
     | 
| 
       45 
46 
     | 
    
         
             
                i18n (1.14.7)
         
     | 
| 
       46 
47 
     | 
    
         
             
                  concurrent-ruby (~> 1.0)
         
     | 
| 
      
 48 
     | 
    
         
            +
                json (2.15.2)
         
     | 
| 
       47 
49 
     | 
    
         
             
                logger (1.7.0)
         
     | 
| 
       48 
50 
     | 
    
         
             
                mdless (1.0.37)
         
     | 
| 
       49 
     | 
    
         
            -
                minitest (5. 
     | 
| 
       50 
     | 
    
         
            -
                ostruct (0.6. 
     | 
| 
      
 51 
     | 
    
         
            +
                minitest (5.26.0)
         
     | 
| 
      
 52 
     | 
    
         
            +
                ostruct (0.6.3)
         
     | 
| 
       51 
53 
     | 
    
         
             
                process_executer (1.3.0)
         
     | 
| 
       52 
54 
     | 
    
         
             
                public_suffix (6.0.2)
         
     | 
| 
       53 
55 
     | 
    
         
             
                rake (13.3.0)
         
     | 
| 
       54 
     | 
    
         
            -
                rchardet (1. 
     | 
| 
      
 56 
     | 
    
         
            +
                rchardet (1.10.0)
         
     | 
| 
       55 
57 
     | 
    
         
             
                rdoc (4.3.0)
         
     | 
| 
      
 58 
     | 
    
         
            +
                rspec (3.13.0)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  rspec-core (~> 3.13.0)
         
     | 
| 
      
 60 
     | 
    
         
            +
                  rspec-expectations (~> 3.13.0)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  rspec-mocks (~> 3.13.0)
         
     | 
| 
      
 62 
     | 
    
         
            +
                rspec-core (3.13.3)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  rspec-support (~> 3.13.0)
         
     | 
| 
      
 64 
     | 
    
         
            +
                rspec-expectations (3.13.5)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  diff-lcs (>= 1.2.0, < 2.0)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  rspec-support (~> 3.13.0)
         
     | 
| 
      
 67 
     | 
    
         
            +
                rspec-mocks (3.13.4)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  diff-lcs (>= 1.2.0, < 2.0)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  rspec-support (~> 3.13.0)
         
     | 
| 
      
 70 
     | 
    
         
            +
                rspec-support (3.13.6)
         
     | 
| 
       56 
71 
     | 
    
         
             
                securerandom (0.4.1)
         
     | 
| 
       57 
72 
     | 
    
         
             
                tty-cursor (0.7.1)
         
     | 
| 
       58 
73 
     | 
    
         
             
                tty-reader (0.9.0)
         
     | 
| 
         @@ -65,7 +80,7 @@ GEM 
     | 
|
| 
       65 
80 
     | 
    
         
             
                tty-which (0.5.0)
         
     | 
| 
       66 
81 
     | 
    
         
             
                tzinfo (2.0.6)
         
     | 
| 
       67 
82 
     | 
    
         
             
                  concurrent-ruby (~> 1.0)
         
     | 
| 
       68 
     | 
    
         
            -
                uri (1.0. 
     | 
| 
      
 83 
     | 
    
         
            +
                uri (1.0.4)
         
     | 
| 
       69 
84 
     | 
    
         
             
                wisper (2.0.1)
         
     | 
| 
       70 
85 
     | 
    
         | 
| 
       71 
86 
     | 
    
         
             
            PLATFORMS
         
     | 
| 
         @@ -82,10 +97,12 @@ PLATFORMS 
     | 
|
| 
       82 
97 
     | 
    
         
             
              x86_64-linux-musl
         
     | 
| 
       83 
98 
     | 
    
         | 
| 
       84 
99 
     | 
    
         
             
            DEPENDENCIES
         
     | 
| 
      
 100 
     | 
    
         
            +
              bump (~> 0.6.0)
         
     | 
| 
       85 
101 
     | 
    
         
             
              minitest (~> 5.14)
         
     | 
| 
       86 
102 
     | 
    
         
             
              na!
         
     | 
| 
       87 
103 
     | 
    
         
             
              rake
         
     | 
| 
       88 
104 
     | 
    
         
             
              rdoc (~> 4.3)
         
     | 
| 
      
 105 
     | 
    
         
            +
              rspec (~> 3.0)
         
     | 
| 
       89 
106 
     | 
    
         
             
              tty-spinner (~> 0.9, >= 0.9.0)
         
     | 
| 
       90 
107 
     | 
    
         | 
| 
       91 
108 
     | 
    
         
             
            BUNDLED WITH
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -9,9 +9,9 @@ 
     | 
|
| 
       9 
9 
     | 
    
         
             
            _If you're one of the rare people like me who find this useful, feel free to
         
     | 
| 
       10 
10 
     | 
    
         
             
            [buy me some coffee][donate]._
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
     | 
    
         
            -
            The current version of `na` is 1.2. 
     | 
| 
      
 12 
     | 
    
         
            +
            The current version of `na` is 1.2.81.
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
       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. 
     | 
| 
      
 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 
     | 
    
         | 
| 
       16 
16 
     | 
    
         
             
            Used with Taskpaper files, it can add new action items quickly from the command line, automatically tagging them as next actions. It can also mark actions as completed, delete them, archive them, and move them between projects.
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
         @@ -48,7 +48,7 @@ You can list next actions in files in the current directory by typing `na`. By d 
     | 
|
| 
       48 
48 
     | 
    
         | 
| 
       49 
49 
     | 
    
         
             
            #### Adding todos
         
     | 
| 
       50 
50 
     | 
    
         | 
| 
       51 
     | 
    
         
            -
            You can also quickly add todo items from the command line with the `add` subcommand. The script will look for a file in the current directory with a `.taskpaper` extension (configurable). 
     | 
| 
      
 51 
     | 
    
         
            +
            You can also quickly add todo items from the command line with the `add` subcommand. The script will look for a file in the current directory with a `.taskpaper` extension (configurable).
         
     | 
| 
       52 
52 
     | 
    
         | 
| 
       53 
53 
     | 
    
         
             
            If found, it will try to locate an `Inbox:` project, or create one if it doesn't exist. Any arguments after `add` will be combined to create a new task in TaskPaper format. They will automatically be assigned as next actions (tagged `@na`) and will show up when `na` lists the tasks for the project.
         
     | 
| 
       54 
54 
     | 
    
         | 
| 
         @@ -76,7 +76,7 @@ SYNOPSIS 
     | 
|
| 
       76 
76 
     | 
    
         
             
                na [global options] command [command options] [arguments...]
         
     | 
| 
       77 
77 
     | 
    
         | 
| 
       78 
78 
     | 
    
         
             
            VERSION
         
     | 
| 
       79 
     | 
    
         
            -
                1.2. 
     | 
| 
      
 79 
     | 
    
         
            +
                1.2.81
         
     | 
| 
       80 
80 
     | 
    
         | 
| 
       81 
81 
     | 
    
         
             
            GLOBAL OPTIONS
         
     | 
| 
       82 
82 
     | 
    
         
             
                -a, --add               - Add a next action (deprecated, for backwards compatibility)
         
     | 
| 
         @@ -93,7 +93,7 @@ GLOBAL OPTIONS 
     | 
|
| 
       93 
93 
     | 
    
         
             
                -p, --priority=PRIORITY - Set a priority 0-5 (deprecated, for backwards compatibility) (default: none)
         
     | 
| 
       94 
94 
     | 
    
         
             
                --[no-]pager            - Enable pagination (default: enabled)
         
     | 
| 
       95 
95 
     | 
    
         
             
                -r, --[no-]recurse      - Recurse 3 directories deep (deprecated, for backwards compatability)
         
     | 
| 
       96 
     | 
    
         
            -
                --[no-]repo 
     | 
| 
      
 96 
     | 
    
         
            +
                --[no-]repo-top         - Use a taskpaper file named after the git repository (enables git integration)
         
     | 
| 
       97 
97 
     | 
    
         
             
                -t, --na_tag=TAG        - Tag to consider a next action (default: na)
         
     | 
| 
       98 
98 
     | 
    
         
             
                --template=arg          - Provide a template for new/blank todo files, use initconfig to make permanent (default: none)
         
     | 
| 
       99 
99 
     | 
    
         
             
                --version               - Display the program version
         
     | 
| 
         @@ -116,6 +116,7 @@ COMMANDS 
     | 
|
| 
       116 
116 
     | 
    
         
             
                prompt              - Show or install prompt hooks for the current shell
         
     | 
| 
       117 
117 
     | 
    
         
             
                restore, unfinish   - Find and remove @done tag from an action
         
     | 
| 
       118 
118 
     | 
    
         
             
                saved               - Execute a saved search
         
     | 
| 
      
 119 
     | 
    
         
            +
                scan                - Scan a directory tree for todo files and cache them
         
     | 
| 
       119 
120 
     | 
    
         
             
                tag                 - Add tags to matching action(s)
         
     | 
| 
       120 
121 
     | 
    
         
             
                tagged              - Find actions matching a tag
         
     | 
| 
       121 
122 
     | 
    
         
             
                todos               - Show list of known todo files
         
     | 
| 
         @@ -133,7 +134,7 @@ If you run the `add` command with no arguments, you'll be asked for input on the 
     | 
|
| 
       133 
134 
     | 
    
         | 
| 
       134 
135 
     | 
    
         
             
            ###### Adding notes
         
     | 
| 
       135 
136 
     | 
    
         | 
| 
       136 
     | 
    
         
            -
            Use the `--note` switch to add a note. If STDIN (piped) input is present when this switch is used, it will be included in the note. A prompt will be displayed for adding additional notes, which will be appended to any STDIN note passed. Press CTRL-d to end editing and save the note. 
     | 
| 
      
 137 
     | 
    
         
            +
            Use the `--note` switch to add a note. If STDIN (piped) input is present when this switch is used, it will be included in the note. A prompt will be displayed for adding additional notes, which will be appended to any STDIN note passed. Press CTRL-d to end editing and save the note.
         
     | 
| 
       137 
138 
     | 
    
         | 
| 
       138 
139 
     | 
    
         
             
            Notes are not displayed by the `next/tagged/find` commands unless `--notes` is specified.
         
     | 
| 
       139 
140 
     | 
    
         | 
| 
         @@ -335,6 +336,7 @@ COMMAND OPTIONS 
     | 
|
| 
       335 
336 
     | 
    
         
             
                --[no-]done                            - Include @done actions
         
     | 
| 
       336 
337 
     | 
    
         
             
                --exact                                - Search query is exact text match (not tokens)
         
     | 
| 
       337 
338 
     | 
    
         
             
                --file=TODO_FILE                       - Display matches from specific todo file ([relative] path) (default: none)
         
     | 
| 
      
 339 
     | 
    
         
            +
                --hidden                               - Include hidden directories while traversing
         
     | 
| 
       338 
340 
     | 
    
         
             
                --in, --todo=TODO                      - Display matches from a known todo file anywhere in history (short name) (may be used more than once, default: none)
         
     | 
| 
       339 
341 
     | 
    
         
             
                --nest                                 - Output actions nested by file
         
     | 
| 
       340 
342 
     | 
    
         
             
                --no_file                              - No filename in output
         
     | 
| 
         @@ -426,6 +428,44 @@ EXAMPLES 
     | 
|
| 
       426 
428 
     | 
    
         
             
                na saved
         
     | 
| 
       427 
429 
     | 
    
         
             
            ```
         
     | 
| 
       428 
430 
     | 
    
         | 
| 
      
 431 
     | 
    
         
            +
            ##### scan
         
     | 
| 
      
 432 
     | 
    
         
            +
             
     | 
| 
      
 433 
     | 
    
         
            +
            Scan a directory tree for todo files and cache them in tdlist.txt. Avoids duplicates and can optionally prune non-existent entries.
         
     | 
| 
      
 434 
     | 
    
         
            +
             
     | 
| 
      
 435 
     | 
    
         
            +
            Scan reports how many files were added and, if --prune is used, how many were pruned. With --dry-run, it lists the full file paths that would be added and/or pruned.
         
     | 
| 
      
 436 
     | 
    
         
            +
             
     | 
| 
      
 437 
     | 
    
         
            +
            ```
         
     | 
| 
      
 438 
     | 
    
         
            +
            NAME
         
     | 
| 
      
 439 
     | 
    
         
            +
                scan - Scan a directory tree for todo files and cache them
         
     | 
| 
      
 440 
     | 
    
         
            +
             
     | 
| 
      
 441 
     | 
    
         
            +
            SYNOPSIS
         
     | 
| 
      
 442 
     | 
    
         
            +
             
     | 
| 
      
 443 
     | 
    
         
            +
                na [global options] scan [command options] [PATH]
         
     | 
| 
      
 444 
     | 
    
         
            +
             
     | 
| 
      
 445 
     | 
    
         
            +
            DESCRIPTION
         
     | 
| 
      
 446 
     | 
    
         
            +
                Searches PATH (default: current directory) for files matching the current NA.extension and adds their absolute paths to the tdlist.txt cache. Avoids duplicates. Optionally prunes non-existent entries from the cache. 
         
     | 
| 
      
 447 
     | 
    
         
            +
             
     | 
| 
      
 448 
     | 
    
         
            +
            COMMAND OPTIONS
         
     | 
| 
      
 449 
     | 
    
         
            +
                -d, --depth=DEPTH - Recurse to depth (1..N or i/inf for infinite) (default: 5)
         
     | 
| 
      
 450 
     | 
    
         
            +
                --hidden          - Include hidden directories and files while scanning
         
     | 
| 
      
 451 
     | 
    
         
            +
                -n, --dry-run     - Show what would be added/pruned, but do not write tdlist.txt
         
     | 
| 
      
 452 
     | 
    
         
            +
                -p, --prune       - Prune removed files from cache after scan
         
     | 
| 
      
 453 
     | 
    
         
            +
             
     | 
| 
      
 454 
     | 
    
         
            +
            EXAMPLES
         
     | 
| 
      
 455 
     | 
    
         
            +
             
     | 
| 
      
 456 
     | 
    
         
            +
                # Scan current directory up to default depth (5)
         
     | 
| 
      
 457 
     | 
    
         
            +
                na scan
         
     | 
| 
      
 458 
     | 
    
         
            +
             
     | 
| 
      
 459 
     | 
    
         
            +
                # Scan a specific path up to depth 3
         
     | 
| 
      
 460 
     | 
    
         
            +
                na scan -d 3 ~/Projects
         
     | 
| 
      
 461 
     | 
    
         
            +
             
     | 
| 
      
 462 
     | 
    
         
            +
                # Scan current directory recursively with no depth limit
         
     | 
| 
      
 463 
     | 
    
         
            +
                na scan -d inf
         
     | 
| 
      
 464 
     | 
    
         
            +
             
     | 
| 
      
 465 
     | 
    
         
            +
                # Prune non-existent entries from the cache (in addition to scanning)
         
     | 
| 
      
 466 
     | 
    
         
            +
                na scan --prune
         
     | 
| 
      
 467 
     | 
    
         
            +
            ```
         
     | 
| 
      
 468 
     | 
    
         
            +
             
     | 
| 
       429 
469 
     | 
    
         
             
            ##### tagged
         
     | 
| 
       430 
470 
     | 
    
         | 
| 
       431 
471 
     | 
    
         
             
            Example: `na tagged feature +maybe`.
         
     | 
| 
         @@ -453,6 +493,7 @@ COMMAND OPTIONS 
     | 
|
| 
       453 
493 
     | 
    
         
             
                --[no-]done                            - Include @done actions
         
     | 
| 
       454 
494 
     | 
    
         
             
                --exact                                - Search query is exact text match (not tokens)
         
     | 
| 
       455 
495 
     | 
    
         
             
                --file=TODO_FILE                       - Display matches from specific todo file ([relative] path) (default: none)
         
     | 
| 
      
 496 
     | 
    
         
            +
                --hidden                               - Include hidden directories while traversing
         
     | 
| 
       456 
497 
     | 
    
         
             
                --in, --todo=TODO                      - Display matches from a known todo file anywhere in history (short name) (may be used more than once, default: none)
         
     | 
| 
       457 
498 
     | 
    
         
             
                --nest                                 - Output actions nested by file
         
     | 
| 
       458 
499 
     | 
    
         
             
                --no_file                              - No filename in output
         
     | 
    
        data/Rakefile
    CHANGED
    
    
    
        data/bin/commands/next.rb
    CHANGED
    
    | 
         @@ -19,6 +19,9 @@ class App 
     | 
|
| 
       19 
19 
     | 
    
         
             
                c.arg_name "DEPTH"
         
     | 
| 
       20 
20 
     | 
    
         
             
                c.flag %i[d depth], type: :integer, must_match: /^[1-9]$/
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
      
 22 
     | 
    
         
            +
                c.desc "Include hidden directories while traversing"
         
     | 
| 
      
 23 
     | 
    
         
            +
                c.switch %i[hidden], negatable: false, default_value: false
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
       22 
25 
     | 
    
         
             
                c.desc "Show next actions from all known todo files (in any directory)"
         
     | 
| 
       23 
26 
     | 
    
         
             
                c.switch %i[all], negatable: false, default_value: false
         
     | 
| 
       24 
27 
     | 
    
         | 
| 
         @@ -217,6 +220,7 @@ class App 
     | 
|
| 
       217 
220 
     | 
    
         
             
                  file_path = options[:file] ? File.expand_path(options[:file]) : nil
         
     | 
| 
       218 
221 
     | 
    
         | 
| 
       219 
222 
     | 
    
         
             
                  todo = NA::Todo.new({ depth: depth,
         
     | 
| 
      
 223 
     | 
    
         
            +
                                        hidden: options[:hidden],
         
     | 
| 
       220 
224 
     | 
    
         
             
                                        done: options[:done],
         
     | 
| 
       221 
225 
     | 
    
         
             
                                        file_path: file_path,
         
     | 
| 
       222 
226 
     | 
    
         
             
                                        project: options[:project],
         
     | 
| 
         @@ -0,0 +1,84 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class App
         
     | 
| 
      
 4 
     | 
    
         
            +
              extend GLI::App
         
     | 
| 
      
 5 
     | 
    
         
            +
              desc 'Scan a directory tree for todo files and cache them'
         
     | 
| 
      
 6 
     | 
    
         
            +
              long_desc 'Searches PATH (default: current directory) for files matching the current NA.extension
         
     | 
| 
      
 7 
     | 
    
         
            +
            and adds their absolute paths to the tdlist.txt cache. Avoids duplicates. Optionally prunes
         
     | 
| 
      
 8 
     | 
    
         
            +
            non-existent entries from the cache.'
         
     | 
| 
      
 9 
     | 
    
         
            +
              arg_name 'PATH', optional: true
         
     | 
| 
      
 10 
     | 
    
         
            +
              command %i[scan] do |c|
         
     | 
| 
      
 11 
     | 
    
         
            +
                c.example 'na scan', desc: 'Scan current directory up to default depth (5)'
         
     | 
| 
      
 12 
     | 
    
         
            +
                c.example 'na scan -d 3 ~/Projects', desc: 'Scan a specific path up to depth 3'
         
     | 
| 
      
 13 
     | 
    
         
            +
                c.example 'na scan -d inf', desc: 'Scan current directory recursively with no depth limit'
         
     | 
| 
      
 14 
     | 
    
         
            +
                c.example 'na scan --prune', desc: 'Prune non-existent entries from the cache (in addition to scanning)'
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                c.desc 'Recurse to depth (1..N or i/inf for infinite)'
         
     | 
| 
      
 17 
     | 
    
         
            +
                c.arg_name 'DEPTH'
         
     | 
| 
      
 18 
     | 
    
         
            +
                c.default_value '5'
         
     | 
| 
      
 19 
     | 
    
         
            +
                c.flag %i[d depth], must_match: /^(\d+|i\w*)$/i
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                c.desc 'Prune removed files from cache after scan'
         
     | 
| 
      
 22 
     | 
    
         
            +
                c.switch %i[p prune], negatable: false, default_value: false
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                c.desc 'Include hidden directories and files while scanning'
         
     | 
| 
      
 25 
     | 
    
         
            +
                c.switch %i[hidden], negatable: false, default_value: false
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                c.desc 'Show what would be added/pruned, but do not write tdlist.txt'
         
     | 
| 
      
 28 
     | 
    
         
            +
                c.switch %i[n dry-run], negatable: false, default_value: false
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                c.action do |_global_options, options, args|
         
     | 
| 
      
 31 
     | 
    
         
            +
                  base = args.first || Dir.pwd
         
     | 
| 
      
 32 
     | 
    
         
            +
                  ext = NA.extension
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  # Parse depth: numeric or starts-with-i for infinite
         
     | 
| 
      
 35 
     | 
    
         
            +
                  depth_arg = (options[:depth] || '5').to_s
         
     | 
| 
      
 36 
     | 
    
         
            +
                  infinite = depth_arg =~ /^i/i ? true : false
         
     | 
| 
      
 37 
     | 
    
         
            +
                  depth = infinite ? nil : depth_arg.to_i
         
     | 
| 
      
 38 
     | 
    
         
            +
                  depth = 5 if depth.nil? && !infinite
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  # Prepare existing cache
         
     | 
| 
      
 41 
     | 
    
         
            +
                  db = NA.database_path
         
     | 
| 
      
 42 
     | 
    
         
            +
                  existing = if File.exist?(db)
         
     | 
| 
      
 43 
     | 
    
         
            +
                               File.read(db).split(/\n/).map(&:strip)
         
     | 
| 
      
 44 
     | 
    
         
            +
                             else
         
     | 
| 
      
 45 
     | 
    
         
            +
                               []
         
     | 
| 
      
 46 
     | 
    
         
            +
                             end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  found = []
         
     | 
| 
      
 49 
     | 
    
         
            +
                  Dir.chdir(base) do
         
     | 
| 
      
 50 
     | 
    
         
            +
                    patterns = if infinite
         
     | 
| 
      
 51 
     | 
    
         
            +
                                 ["*.#{ext}", "**/*.#{ext}"]
         
     | 
| 
      
 52 
     | 
    
         
            +
                               else
         
     | 
| 
      
 53 
     | 
    
         
            +
                                 (1..[depth, 1].max).map { |d| (d > 1 ? ('*/' * (d - 1)) : '') + "*.#{ext}" }
         
     | 
| 
      
 54 
     | 
    
         
            +
                               end
         
     | 
| 
      
 55 
     | 
    
         
            +
                    pattern = patterns.length == 1 ? patterns.first : "{#{patterns.join(',')}}"
         
     | 
| 
      
 56 
     | 
    
         
            +
                    files = Dir.glob(pattern, File::FNM_DOTMATCH)
         
     | 
| 
      
 57 
     | 
    
         
            +
                    # Exclude hidden dirs/files (any segment starting with '.') unless --hidden
         
     | 
| 
      
 58 
     | 
    
         
            +
                    files.reject! { |f| f.split('/').any? { |seg| seg.start_with?('.') && seg !~ /^\.\.?$/ } } unless options[:hidden]
         
     | 
| 
      
 59 
     | 
    
         
            +
                    found = files.map { |f| File.expand_path(f) }
         
     | 
| 
      
 60 
     | 
    
         
            +
                  end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  merged = (existing + found).map(&:strip).uniq.sort
         
     | 
| 
      
 63 
     | 
    
         
            +
                  merged.select! { |f| File.exist?(f) } if options[:prune]
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  added_files = (merged - existing)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  pruned_files = options[:prune] ? (existing - merged) : []
         
     | 
| 
      
 67 
     | 
    
         
            +
                  added = added_files.count
         
     | 
| 
      
 68 
     | 
    
         
            +
                  pruned = pruned_files.count
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                  if options[:dry_run]
         
     | 
| 
      
 71 
     | 
    
         
            +
                    msg = "#{NA.theme[:success]}Dry run: would add #{added} file#{added == 1 ? '' : 's'}"
         
     | 
| 
      
 72 
     | 
    
         
            +
                    msg << ", prune #{pruned} file#{pruned == 1 ? '' : 's'}" if options[:prune]
         
     | 
| 
      
 73 
     | 
    
         
            +
                    NA.notify(msg)
         
     | 
| 
      
 74 
     | 
    
         
            +
                    NA.notify("{bw}Would add:{x}\n#{added_files.join("\n")}") if added_files.any?
         
     | 
| 
      
 75 
     | 
    
         
            +
                    NA.notify("{bw}Would prune:{x}\n#{pruned_files.join("\n")}") if options[:prune] && pruned_files.any?
         
     | 
| 
      
 76 
     | 
    
         
            +
                  else
         
     | 
| 
      
 77 
     | 
    
         
            +
                    File.open(db, 'w') { |f| f.puts merged.join("\n") }
         
     | 
| 
      
 78 
     | 
    
         
            +
                    msg = "#{NA.theme[:success]}Scan complete: #{NA.theme[:filename]}#{added}{x}#{NA.theme[:success]} added"
         
     | 
| 
      
 79 
     | 
    
         
            +
                    msg << ", #{NA.theme[:filename]}#{pruned}{x}#{NA.theme[:success]} pruned" if options[:prune]
         
     | 
| 
      
 80 
     | 
    
         
            +
                    NA.notify(msg)
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
              end
         
     | 
| 
      
 84 
     | 
    
         
            +
            end
         
     | 
    
        data/bin/commands/update.rb
    CHANGED
    
    | 
         @@ -192,7 +192,7 @@ class App 
     | 
|
| 
       192 
192 
     | 
    
         
             
                  # Require at least one actionable option to be provided
         
     | 
| 
       193 
193 
     | 
    
         
             
                  actionable = [
         
     | 
| 
       194 
194 
     | 
    
         
             
                    options[:note],
         
     | 
| 
       195 
     | 
    
         
            -
                    (options[:priority].to_i if options[:priority]).to_i 
     | 
| 
      
 195 
     | 
    
         
            +
                    (options[:priority].to_i if options[:priority]).to_i.positive?,
         
     | 
| 
       196 
196 
     | 
    
         
             
                    !options[:move].to_s.empty?,
         
     | 
| 
       197 
197 
     | 
    
         
             
                    !(options[:tag].nil? || options[:tag].empty?),
         
     | 
| 
       198 
198 
     | 
    
         
             
                    !(options[:remove].nil? || options[:remove].empty?),
         
     | 
    
        data/bin/na
    CHANGED
    
    | 
         @@ -5,12 +5,16 @@ $LOAD_PATH.unshift File.join(__dir__, '..', 'lib') 
     | 
|
| 
       5 
5 
     | 
    
         
             
            require 'gli'
         
     | 
| 
       6 
6 
     | 
    
         
             
            require 'na/help_monkey_patch'
         
     | 
| 
       7 
7 
     | 
    
         
             
            require 'na'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'na/benchmark'
         
     | 
| 
       8 
9 
     | 
    
         
             
            require 'fcntl'
         
     | 
| 
       9 
10 
     | 
    
         
             
            require 'tempfile'
         
     | 
| 
       10 
11 
     | 
    
         | 
| 
      
 12 
     | 
    
         
            +
            NA::Benchmark.init
         
     | 
| 
      
 13 
     | 
    
         
            +
            NA::Benchmark.measure('Gem loading') { nil } # Measures time up to this point
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
       11 
15 
     | 
    
         
             
            # Search for XDG compliant config first. Default to ~/.na.rc for compatibility
         
     | 
| 
       12 
16 
     | 
    
         
             
            def self.find_config_file
         
     | 
| 
       13 
     | 
    
         
            -
              home =  
     | 
| 
      
 17 
     | 
    
         
            +
              home = Dir.home
         
     | 
| 
       14 
18 
     | 
    
         
             
              xdg_config_home = ENV['XDG_CONFIG_HOME'] || File.join(home, '.config')
         
     | 
| 
       15 
19 
     | 
    
         | 
| 
       16 
20 
     | 
    
         
             
              rc_paths = [
         
     | 
| 
         @@ -26,7 +30,6 @@ def self.find_config_file 
     | 
|
| 
       26 
30 
     | 
    
         
             
              existing_path || File.join(xdg_config_home, 'na', 'na.rc')
         
     | 
| 
       27 
31 
     | 
    
         
             
            end
         
     | 
| 
       28 
32 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
33 
     | 
    
         
             
            # Main application
         
     | 
| 
       31 
34 
     | 
    
         
             
            class App
         
     | 
| 
       32 
35 
     | 
    
         
             
              extend GLI::App
         
     | 
| 
         @@ -75,12 +78,12 @@ class App 
     | 
|
| 
       75 
78 
     | 
    
         
             
              arg_name 'PATH'
         
     | 
| 
       76 
79 
     | 
    
         
             
              flag %i[f file]
         
     | 
| 
       77 
80 
     | 
    
         | 
| 
       78 
     | 
    
         
            -
              desc 'Use a taskpaper file named after the git repository'
         
     | 
| 
       79 
     | 
    
         
            -
              arg_name ' 
     | 
| 
       80 
     | 
    
         
            -
              switch %i[repo],  
     | 
| 
      
 81 
     | 
    
         
            +
              desc 'Use a taskpaper file named after the git repository (enables git integration)'
         
     | 
| 
      
 82 
     | 
    
         
            +
              arg_name 'REPO_TOP'
         
     | 
| 
      
 83 
     | 
    
         
            +
              switch %i[repo-top], default_value: false
         
     | 
| 
       81 
84 
     | 
    
         | 
| 
       82 
85 
     | 
    
         
             
              desc 'Provide a template for new/blank todo files, use initconfig to make permanent'
         
     | 
| 
       83 
     | 
    
         
            -
              flag % 
     | 
| 
      
 86 
     | 
    
         
            +
              flag %(template)
         
     | 
| 
       84 
87 
     | 
    
         | 
| 
       85 
88 
     | 
    
         
             
              desc 'Use current working directory as [p]roject, [t]ag, or [n]one'
         
     | 
| 
       86 
89 
     | 
    
         
             
              arg_name 'TYPE'
         
     | 
| 
         @@ -117,7 +120,7 @@ class App 
     | 
|
| 
       117 
120 
     | 
    
         
             
                NA.include_ext = global[:include_ext]
         
     | 
| 
       118 
121 
     | 
    
         
             
                NA.na_tag = global[:na_tag]
         
     | 
| 
       119 
122 
     | 
    
         
             
                NA.global_file = global[:file]
         
     | 
| 
       120 
     | 
    
         
            -
                NA.cwd = File.basename(ENV 
     | 
| 
      
 123 
     | 
    
         
            +
                NA.cwd = File.basename(ENV.fetch('PWD', nil))
         
     | 
| 
       121 
124 
     | 
    
         
             
                NA.cwd_is = if global[:cwd_as] =~ /^n/
         
     | 
| 
       122 
125 
     | 
    
         
             
                              :none
         
     | 
| 
       123 
126 
     | 
    
         
             
                            else
         
     | 
| 
         @@ -125,8 +128,8 @@ class App 
     | 
|
| 
       125 
128 
     | 
    
         
             
                            end
         
     | 
| 
       126 
129 
     | 
    
         | 
| 
       127 
130 
     | 
    
         
             
                # start of git repo addition ==================================
         
     | 
| 
       128 
     | 
    
         
            -
                #  
     | 
| 
       129 
     | 
    
         
            -
                if global[: 
     | 
| 
      
 131 
     | 
    
         
            +
                # Use git repo if --repo-top flag is specified
         
     | 
| 
      
 132 
     | 
    
         
            +
                if global[:repo_top]
         
     | 
| 
       130 
133 
     | 
    
         
             
                  begin
         
     | 
| 
       131 
134 
     | 
    
         
             
                    require 'git'
         
     | 
| 
       132 
135 
     | 
    
         | 
| 
         @@ -142,7 +145,8 @@ class App 
     | 
|
| 
       142 
145 
     | 
    
         
             
                      NA.global_file = taskpaper_file
         
     | 
| 
       143 
146 
     | 
    
         
             
                      # Add this block to create the file if it doesn't exist
         
     | 
| 
       144 
147 
     | 
    
         
             
                      unless File.exist?(taskpaper_file)
         
     | 
| 
       145 
     | 
    
         
            -
                        res = NA.yn(NA::Color.template("#{NA.theme[:warning]}Repository file not found, create #{taskpaper_file}"), 
     | 
| 
      
 148 
     | 
    
         
            +
                        res = NA.yn(NA::Color.template("#{NA.theme[:warning]}Repository file not found, create #{taskpaper_file}"),
         
     | 
| 
      
 149 
     | 
    
         
            +
                                    default: true)
         
     | 
| 
       146 
150 
     | 
    
         
             
                        if res
         
     | 
| 
       147 
151 
     | 
    
         
             
                          NA.create_todo(taskpaper_file, repo_name, template: global[:template])
         
     | 
| 
       148 
152 
     | 
    
         
             
                        else
         
     | 
| 
         @@ -194,7 +198,7 @@ class App 
     | 
|
| 
       194 
198 
     | 
    
         
             
            end
         
     | 
| 
       195 
199 
     | 
    
         | 
| 
       196 
200 
     | 
    
         
             
            NA.stdin = $stdin.read.strip if $stdin.stat.size.positive? || $stdin.fcntl(Fcntl::F_GETFL, 0).zero?
         
     | 
| 
       197 
     | 
    
         
            -
            NA.stdin = nil unless NA.stdin 
     | 
| 
      
 201 
     | 
    
         
            +
            NA.stdin = nil unless NA.stdin&.length&.positive?
         
     | 
| 
       198 
202 
     | 
    
         | 
| 
       199 
203 
     | 
    
         
             
            NA.globals = []
         
     | 
| 
       200 
204 
     | 
    
         
             
            NA.command_line = []
         
     | 
| 
         @@ -209,4 +213,6 @@ ARGV.each do |arg| 
     | 
|
| 
       209 
213 
     | 
    
         
             
            end
         
     | 
| 
       210 
214 
     | 
    
         
             
            NA.command = NA.command_line[0]
         
     | 
| 
       211 
215 
     | 
    
         | 
| 
       212 
     | 
    
         
            -
             
     | 
| 
      
 216 
     | 
    
         
            +
            exit_code = App.run(ARGV)
         
     | 
| 
      
 217 
     | 
    
         
            +
            NA::Benchmark.report
         
     | 
| 
      
 218 
     | 
    
         
            +
            exit exit_code
         
     |