na 1.2.80 → 1.2.82

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.
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
  gemspec
3
5
  gem 'rake'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- na (1.2.80)
4
+ na (1.2.82)
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.2)
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
- benchmark (0.4.1)
34
- bigdecimal (3.2.3)
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.3)
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.25.5)
50
- ostruct (0.6.1)
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.9.0)
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.3)
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.80.
12
+ The current version of `na` is 1.2.82.
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.80
79
+ 1.2.82
80
80
 
81
81
  GLOBAL OPTIONS
82
82
  -a, --add - Add a next action (deprecated, for backwards compatibility)
@@ -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`.
@@ -438,45 +478,48 @@ To perform a string comparison, you can use `*=` (contains), `^=` (starts with),
438
478
 
439
479
  ```
440
480
  NAME
441
- next - Show next actions
481
+ tagged - Find actions matching a tag
442
482
 
443
483
  SYNOPSIS
444
484
 
445
- na [global options] next [command options] [QUERY]
485
+ na [global options] tagged [command options] TAG[=VALUE]
446
486
 
447
487
  DESCRIPTION
448
- Next actions are actions which contain the next action tag (default @na), do not contain @done, and are not in the Archive project. Arguments will target a todo file from history, whether it's in the current directory or not. Todo file queries can include path components separated by / or :, and may use wildcards (`*` to match any text, `?` to match a single character). Multiple queries allowed (separate arguments or separated by comma).
488
+ Finds actions with tags matching the arguments. An action is shown if it contains all of the tags listed. Add a + before a tag to make it required and others optional. You can specify values using TAG=VALUE pairs. Use <, >, and = for numeric comparisons, and *=, ^=, $=, or =~ (regex) for text comparisons. Date comparisons use natural language (`na tagged "due<=today"`) and are detected automatically.
449
489
 
450
490
  COMMAND OPTIONS
451
- --all - Show next actions from all known todo files (in any directory)
452
- -d, --depth=DEPTH - Recurse to depth (default: none)
491
+ -d, --depth=DEPTH - Recurse to depth (default: 1)
453
492
  --[no-]done - Include @done actions
454
493
  --exact - Search query is exact text match (not tokens)
455
- --file=TODO_FILE - Display matches from specific todo file ([relative] path) (default: none)
456
- --in, --todo=TODO - Display matches from a known todo file anywhere in history (short name) (may be used more than once, default: none)
494
+ --in=TODO_PATH - Show actions from a specific todo file in history. May use wildcards (* and ?) (default: none)
457
495
  --nest - Output actions nested by file
458
496
  --no_file - No filename in output
459
497
  --[no-]notes - Include notes in output
498
+ -o, --or - Combine tags with OR, displaying actions matching ANY of the tags
460
499
  --omnifocus - Output actions nested by file and project
461
- -p, --prio, --priority=PRIORITY - Match actions with priority, allows <>= comparison (may be used more than once, default: none)
462
500
  --proj, --project=PROJECT[/SUBPROJECT] - Show actions from a specific project (default: none)
463
501
  --regex - Search query is regular expression
464
502
  --save=TITLE - Save this search for future use (default: none)
465
503
  --search, --find, --grep=QUERY - Filter results using search terms (may be used more than once, default: none)
466
504
  --[no-]search_notes - Include notes in search (default: enabled)
467
- -t, --tag=TAG - Alternate tag to search for (default: none)
468
- --tagged=TAG - Match actions containing tag. Allows value comparisons (may be used more than once, default: none)
505
+ -v, --invert - Show actions not matching tags
469
506
 
470
507
  EXAMPLES
471
508
 
472
- # display the next actions from any todo files in the current directory
473
- na next
509
+ # Show all actions tagged @maybe
510
+ na tagged maybe
474
511
 
475
- # display the next actions from the current directory, traversing 3 levels deep
476
- na next -d 3
512
+ # Show all actions tagged @feature AND @idea, recurse 3 levels
513
+ na tagged -d 3 "feature, idea"
477
514
 
478
- # display next actions for a project you visited in the past
479
- na next marked
515
+ # Show all actions tagged @feature OR @idea
516
+ na tagged --or "feature, idea"
517
+
518
+ # Show actions with @priority(4) or @priority(5)
519
+ na tagged "priority>=4"
520
+
521
+ # Show actions with a due date coming up in the next 2 days
522
+ na tagged "due<in 2 days"
480
523
  ```
481
524
 
482
525
  ##### todos
@@ -512,6 +555,8 @@ If more than one file is matched, a menu will be presented, multiple selections
512
555
 
513
556
  Any time an update action is carried out, a backup of the file before modification will be made in the same directory with a `.` prepended and `.bak` appended (e.g. `marked.taskpaper` is copied to `.marked.taskpaper.bak`). Only one undo step is available, but if something goes wrong (and this feature is still experimental, so be wary), you can just copy the ".bak" file back to the original.
514
557
 
558
+ > **Note:** When using the `update` command, if you have [fzf](https://github.com/junegunn/fzf) installed, menus for selecting files or actions will support multi-select (tab to mark multiple, return to confirm). If [gum](https://github.com/charmbracelet/gum) is installed, multi-select is also supported (use j/k/x to navigate and mark). If neither is available, a simple prompt is used. This makes it easy to apply updates to multiple actions at once.
559
+
515
560
  ###### Marking a task as complete
516
561
 
517
562
  You can mark an action complete using `--finish`, which will add a dated @done tag to the action. You can also mark it @done and immediately move it to the Archive project using `--archive`.
data/Rakefile CHANGED
@@ -207,3 +207,9 @@ end
207
207
 
208
208
  desc "alias for build"
209
209
  task package: :build
210
+
211
+ desc 'Run tests with coverage'
212
+ task :coverage do
213
+ ENV['COVERAGE'] = 'true'
214
+ Rake::Task[:test].invoke
215
+ end
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