na 1.2.35 → 1.2.38
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +50 -0
- data/Gemfile.lock +1 -1
- data/README.md +156 -6
- data/bin/commands/add.rb +11 -13
- data/bin/commands/complete.rb +4 -0
- data/bin/commands/edit.rb +21 -24
- data/bin/commands/find.rb +36 -23
- data/bin/commands/init.rb +1 -1
- data/bin/commands/next.rb +70 -37
- data/bin/commands/projects.rb +1 -1
- data/bin/commands/prompt.rb +2 -0
- data/bin/commands/saved.rb +3 -4
- data/bin/commands/tagged.rb +37 -30
- data/bin/commands/todos.rb +24 -14
- data/bin/commands/undo.rb +22 -0
- data/bin/commands/update.rb +28 -21
- data/bin/na +2 -1
- data/lib/na/action.rb +39 -22
- data/lib/na/actions.rb +87 -0
- data/lib/na/colors.rb +23 -1
- data/lib/na/editor.rb +125 -0
- data/lib/na/hash.rb +31 -0
- data/lib/na/next_action.rb +237 -498
- data/lib/na/pager.rb +1 -1
- data/lib/na/prompt.rb +6 -6
- data/lib/na/string.rb +23 -3
- data/lib/na/theme.rb +71 -0
- data/lib/na/todo.rb +183 -0
- data/lib/na/version.rb +1 -1
- data/lib/na.rb +4 -0
- data/src/_README.md +45 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 13c74e296d8e9d6e252949394c5471a27b1c7d3619026383fc75590dcb5d6046
|
4
|
+
data.tar.gz: c67deb62ee0ad5c2b3cf35b5ca39cebe2f6780e675cb48fbaec260068111a33a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4fd8a183c2fcadf9d128bab65267b841bdd253db40071cb87c3fa0dbfd1be0517d667ba64f21b28f0a24adfbc08cbefe79c3638ac63736698de34a21c81d0658
|
7
|
+
data.tar.gz: 8cb24b17379576cf4f86f709a277c2e075fb41c905d67750f09500471f5948f0d3cd2e0d66d9f29a073172e6808c8d4f2b2dd0afe3b6b223ff04ec493ccd8289
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,53 @@
|
|
1
|
+
### 1.2.38
|
2
|
+
|
3
|
+
2023-09-03 11:25
|
4
|
+
|
5
|
+
#### NEW
|
6
|
+
|
7
|
+
- Open the todos database in an editor with `na todos --edit`
|
8
|
+
- A theme file is written to ~/.local/share/na/theme.yaml where you can modify the colors used for all displays
|
9
|
+
- Allow tag=~PATTERN comparison for regex matching
|
10
|
+
|
11
|
+
#### IMPROVED
|
12
|
+
|
13
|
+
- Better error message for `na next` when no todo is matched
|
14
|
+
- If STDOUT isn't a TTY, don't enable pagination, regardless of global setting
|
15
|
+
- Allow --find or --grep as synonyms for --search
|
16
|
+
|
17
|
+
#### FIXED
|
18
|
+
|
19
|
+
- Date tags containing hyphens triggered OR searches because they were initially interpreted as negative tag searches
|
20
|
+
- Templating irregularities
|
21
|
+
- Error thrown when running without $EDITOR variable defined in environment
|
22
|
+
|
23
|
+
### 1.2.37
|
24
|
+
|
25
|
+
2023-09-01 12:42
|
26
|
+
|
27
|
+
#### NEW
|
28
|
+
|
29
|
+
- `na undo` command to undo last change or last change to file specified in arguments
|
30
|
+
|
31
|
+
#### IMPROVED
|
32
|
+
|
33
|
+
- Disable pagination when using --omnifocus
|
34
|
+
- Refactoring codebase
|
35
|
+
- `--in TODO` option for `na complete`
|
36
|
+
|
37
|
+
### 1.2.36
|
38
|
+
|
39
|
+
2023-09-01 12:41
|
40
|
+
|
41
|
+
#### NEW
|
42
|
+
|
43
|
+
- `na undo` command to undo last change or last change to file specified in arguments
|
44
|
+
|
45
|
+
#### IMPROVED
|
46
|
+
|
47
|
+
- Disable pagination when using --omnifocus
|
48
|
+
- Refactoring codebase
|
49
|
+
- `--in TODO` option for `na complete`
|
50
|
+
|
1
51
|
### 1.2.35
|
2
52
|
|
3
53
|
2023-08-30 11:59
|
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.2.
|
12
|
+
The current version of `na` is 1.2.38
|
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.
|
@@ -77,7 +77,7 @@ SYNOPSIS
|
|
77
77
|
na [global options] command [command options] [arguments...]
|
78
78
|
|
79
79
|
VERSION
|
80
|
-
1.2.
|
80
|
+
1.2.38
|
81
81
|
|
82
82
|
GLOBAL OPTIONS
|
83
83
|
-a, --add - Add a next action (deprecated, for backwards compatibility)
|
@@ -114,8 +114,10 @@ COMMANDS
|
|
114
114
|
prompt - Show or install prompt hooks for the current shell
|
115
115
|
restore, unfinish - Find and remove @done tag from an action
|
116
116
|
saved - Execute a saved search
|
117
|
+
tag - Add tags to matching action(s)
|
117
118
|
tagged - Find actions matching a tag
|
118
119
|
todos - Show list of known todo files
|
120
|
+
undo - Undo the last change
|
119
121
|
update - Update an existing action
|
120
122
|
```
|
121
123
|
|
@@ -290,7 +292,7 @@ COMMAND OPTIONS
|
|
290
292
|
--omnifocus - Output actions nested by file and project
|
291
293
|
--proj, --project=PROJECT[/SUBPROJECT] - Show actions from a specific project (default: none)
|
292
294
|
--regex - Search query is regular expression
|
293
|
-
--search=QUERY
|
295
|
+
--search, --find, --grep=QUERY - Filter results using search terms (may be used more than once, default: none)
|
294
296
|
-t, --tag=TAG - Alternate tag to search for (default: none)
|
295
297
|
--tagged=TAG - Match actions containing tag. Allows value comparisons (may be used more than once, default: none)
|
296
298
|
|
@@ -401,7 +403,7 @@ COMMAND OPTIONS
|
|
401
403
|
--omnifocus - Output actions nested by file and project
|
402
404
|
--proj, --project=PROJECT[/SUBPROJECT] - Show actions from a specific project (default: none)
|
403
405
|
--regex - Search query is regular expression
|
404
|
-
--search=QUERY
|
406
|
+
--search, --find, --grep=QUERY - Filter results using search terms (may be used more than once, default: none)
|
405
407
|
-t, --tag=TAG - Alternate tag to search for (default: none)
|
406
408
|
--tagged=TAG - Match actions containing tag. Allows value comparisons (may be used more than once, default: none)
|
407
409
|
|
@@ -427,10 +429,13 @@ NAME
|
|
427
429
|
|
428
430
|
SYNOPSIS
|
429
431
|
|
430
|
-
na [global options] todos [QUERY]
|
432
|
+
na [global options] todos [command options] [QUERY]
|
431
433
|
|
432
434
|
DESCRIPTION
|
433
|
-
Arguments will be interpreted as a query against which the list of todos will be fuzzy matched. Separate directories with /, :, or a space, e.g. `na todos code/marked`
|
435
|
+
Arguments will be interpreted as a query against which the list of todos will be fuzzy matched. Separate directories with /, :, or a space, e.g. `na todos code/marked`
|
436
|
+
|
437
|
+
COMMAND OPTIONS
|
438
|
+
-e, --[no-]edit - Open the todo database in an editor for manual modification
|
434
439
|
```
|
435
440
|
|
436
441
|
##### update
|
@@ -512,6 +517,151 @@ EXAMPLES
|
|
512
517
|
na update --archive My cool action
|
513
518
|
```
|
514
519
|
|
520
|
+
##### changelog
|
521
|
+
|
522
|
+
View recent changes with `na changelog` or `na changes`.
|
523
|
+
|
524
|
+
```
|
525
|
+
NAME
|
526
|
+
changes - Display the changelog
|
527
|
+
|
528
|
+
SYNOPSIS
|
529
|
+
|
530
|
+
na [global options] changes
|
531
|
+
```
|
532
|
+
|
533
|
+
##### complete
|
534
|
+
|
535
|
+
Mark an action as complete, shortcut for `na update --finish`.
|
536
|
+
|
537
|
+
```
|
538
|
+
NAME
|
539
|
+
complete - Find and mark an action as @done
|
540
|
+
|
541
|
+
SYNOPSIS
|
542
|
+
|
543
|
+
na [global options] complete [command options] ACTION
|
544
|
+
|
545
|
+
COMMAND OPTIONS
|
546
|
+
-a, --archive - Add a @done tag to action and move to Archive
|
547
|
+
--all - Act on all matches immediately (no menu)
|
548
|
+
-d, --depth=DEPTH - Search for files X directories deep (default: 1)
|
549
|
+
-e, --regex - Interpret search pattern as regular expression
|
550
|
+
--file=PATH - Specify the file to search for the task (default: none)
|
551
|
+
--in, --todo=TODO_FILE - Use a known todo file, partial matches allowed (default: none)
|
552
|
+
-n, --note - Prompt for additional notes. Input will be appended to any existing note. If STDIN input (piped) is detected, it will be used as a note.
|
553
|
+
-o, --overwrite - Overwrite note instead of appending
|
554
|
+
--tagged=TAG - Match actions containing tag. Allows value comparisons (may be used more than once, default: none)
|
555
|
+
--to, --project, --proj=PROJECT - Move action to specific project (default: none)
|
556
|
+
-x, --exact - Match pattern exactly
|
557
|
+
|
558
|
+
EXAMPLES
|
559
|
+
|
560
|
+
# Find "An existing task" and mark @done
|
561
|
+
na complete "An existing task"
|
562
|
+
|
563
|
+
# Alias for complete
|
564
|
+
na finish "An existing task"
|
565
|
+
```
|
566
|
+
|
567
|
+
##### archive
|
568
|
+
|
569
|
+
Mark an action as complete and move to archive, shortcut for `na update --archive`.
|
570
|
+
|
571
|
+
```
|
572
|
+
NAME
|
573
|
+
archive - Mark an action as @done and archive
|
574
|
+
|
575
|
+
SYNOPSIS
|
576
|
+
|
577
|
+
na [global options] archive [command options] ACTION
|
578
|
+
|
579
|
+
COMMAND OPTIONS
|
580
|
+
--all - Act on all matches immediately (no menu)
|
581
|
+
-d, --depth=DEPTH - Search for files X directories deep (default: 1)
|
582
|
+
--done - Archive all done tasks
|
583
|
+
-e, --regex - Interpret search pattern as regular expression
|
584
|
+
--file=PATH - Specify the file to search for the task (default: none)
|
585
|
+
-n, --note - Prompt for additional notes. Input will be appended to any existing note. If STDIN input (piped) is detected, it will be used as a note.
|
586
|
+
-o, --overwrite - Overwrite note instead of appending
|
587
|
+
--tagged=TAG - Match actions containing tag. Allows value comparisons (may be used more than once, default: none)
|
588
|
+
-x, --exact - Match pattern exactly
|
589
|
+
|
590
|
+
EXAMPLE
|
591
|
+
|
592
|
+
# Find "An existing task", mark @done if needed, and move to archive
|
593
|
+
na archive "An existing task"
|
594
|
+
```
|
595
|
+
|
596
|
+
##### tag
|
597
|
+
|
598
|
+
Add, remove, or modify tags.
|
599
|
+
|
600
|
+
Use `na tag TAGNAME --[search|tagged] SEARCH_STRING` to add a tag to matching action (use `--all` to apply to all matching actions). If you use `!TAGNAME` it will remove that tag (regardless of value). To change the value of an existing tag (or add it if it doesn't exist), use `~TAGNAME(NEW VALUE)`.
|
601
|
+
|
602
|
+
```
|
603
|
+
NAME
|
604
|
+
tag - Add tags to matching action(s)
|
605
|
+
|
606
|
+
SYNOPSIS
|
607
|
+
|
608
|
+
na [global options] tag [command options] TAG
|
609
|
+
|
610
|
+
DESCRIPTION
|
611
|
+
Provides an easy way to tag existing actions. Use !tag to remove a tag, use ~tag(new value) to change a tag or add a value. If multiple todo files are found in the current directory, a menu will allow you to pick which file to act on, or use --all to apply to all matches.
|
612
|
+
|
613
|
+
COMMAND OPTIONS
|
614
|
+
--all - Act on all matches immediately (no menu)
|
615
|
+
-d, --depth=DEPTH - Search for files X directories deep (default: 1)
|
616
|
+
--[no-]done - Include @done actions
|
617
|
+
-e, --regex - Interpret search pattern as regular expression
|
618
|
+
--file=PATH - Specify the file to search for the task (default: none)
|
619
|
+
--in, --todo=TODO_FILE - Use a known todo file, partial matches allowed (default: none)
|
620
|
+
--search, --find, --grep=QUERY - Filter results using search terms (may be used more than once, default: none)
|
621
|
+
--tagged=TAG - Match actions containing tag. Allows value comparisons (may be used more than once, default: none)
|
622
|
+
-x, --exact - Match pattern exactly
|
623
|
+
|
624
|
+
EXAMPLES
|
625
|
+
|
626
|
+
# Find "An existing task" action and add @project(warpspeed) to it
|
627
|
+
na tag "project(warpspeed)" --search "An existing task"
|
628
|
+
|
629
|
+
# Find all actions tagged @project2 and remove @project1 from them
|
630
|
+
na tag "!project1" --tagged project2 --all
|
631
|
+
|
632
|
+
# Remove @project2 from all actions
|
633
|
+
na tag "!project2" --all
|
634
|
+
|
635
|
+
# Find "An existing task" and change (or add) its @project tag value to "dirt nap"
|
636
|
+
na tag "~project(dirt nap)" --search "An existing task"
|
637
|
+
```
|
638
|
+
|
639
|
+
##### undo
|
640
|
+
|
641
|
+
Undoes the last file change resulting from an add or update command. If no argument is given, it undoes whatever the last change in history was. If an argument is provided, it's used to match against the change history, finding a specific file to restore from backup.
|
642
|
+
|
643
|
+
Only the most recent change can be undone.
|
644
|
+
|
645
|
+
```
|
646
|
+
NAME
|
647
|
+
undo - Undo the last change
|
648
|
+
|
649
|
+
SYNOPSIS
|
650
|
+
|
651
|
+
na [global options] undo [FILE]...
|
652
|
+
|
653
|
+
DESCRIPTION
|
654
|
+
Run without argument to undo most recent change
|
655
|
+
|
656
|
+
EXAMPLES
|
657
|
+
|
658
|
+
# Undo the last change
|
659
|
+
na undo
|
660
|
+
|
661
|
+
# Undo the last change to a file matching "myproject"
|
662
|
+
na undo myproject
|
663
|
+
```
|
664
|
+
|
515
665
|
### Configuration
|
516
666
|
|
517
667
|
Global options such as todo extension and default next action tag can be stored permanently by using the `na initconfig` command. Run na with the global options you'd like to set, and add `initconfig` at the end of the command. A file will be written to `~/.na.rc`. You can edit this manually, or just update it using the `initconfig --force` command to overwrite it with new settings.
|
data/bin/commands/add.rb
CHANGED
@@ -62,25 +62,23 @@ class App
|
|
62
62
|
if NA.global_file
|
63
63
|
target = File.expand_path(NA.global_file)
|
64
64
|
unless File.exist?(target)
|
65
|
-
res = NA.yn(NA::Color.template(
|
65
|
+
res = NA.yn(NA::Color.template("#{NA.theme[:warning]}Specified file not found, create it"), default: true)
|
66
66
|
if res
|
67
67
|
basename = File.basename(target, ".#{NA.extension}")
|
68
68
|
NA.create_todo(target, basename, template: global_options[:template])
|
69
69
|
else
|
70
|
-
|
71
|
-
Process.exit 1
|
70
|
+
NA.notify("#{NA.theme[:error]}Cancelled", exit_code: 1)
|
72
71
|
end
|
73
72
|
end
|
74
73
|
elsif options[:file]
|
75
74
|
target = File.expand_path(options[:file])
|
76
75
|
unless File.exist?(target)
|
77
|
-
res = NA.yn(NA::Color.template(
|
76
|
+
res = NA.yn(NA::Color.template("#{NA.theme[:warning]}Specified file not found, create it"), default: true)
|
78
77
|
if res
|
79
78
|
basename = File.basename(target, ".#{NA.extension}")
|
80
79
|
NA.create_todo(target, basename, template: global_options[:template])
|
81
80
|
else
|
82
|
-
|
83
|
-
Process.exit 1
|
81
|
+
NA.notify("#{NA.theme[:error]}Cancelled", exit_code: 1)
|
84
82
|
end
|
85
83
|
end
|
86
84
|
elsif options[:todo]
|
@@ -102,8 +100,8 @@ class App
|
|
102
100
|
target = File.expand_path(todo)
|
103
101
|
unless File.exist?(target)
|
104
102
|
|
105
|
-
res = NA.yn(NA::Color.template("{
|
106
|
-
NA.notify(
|
103
|
+
res = NA.yn(NA::Color.template("#{NA.theme[:warning]}Specified file not found, create #{todo}"), default: true)
|
104
|
+
NA.notify("#{NA.theme[:error]}Cancelled{x}", exit_code: 1) unless res
|
107
105
|
|
108
106
|
basename = File.basename(target, ".#{NA.extension}")
|
109
107
|
NA.create_todo(target, basename, template: global_options[:template])
|
@@ -113,7 +111,7 @@ class App
|
|
113
111
|
else
|
114
112
|
files = NA.find_files(depth: options[:depth])
|
115
113
|
if files.count.zero?
|
116
|
-
res = NA.yn(NA::Color.template(
|
114
|
+
res = NA.yn(NA::Color.template("#{NA.theme[:warning]}No todo file found, create one"), default: true)
|
117
115
|
if res
|
118
116
|
basename = File.expand_path('.').split('/').last
|
119
117
|
target = "#{basename}.#{NA.extension}"
|
@@ -122,7 +120,7 @@ class App
|
|
122
120
|
end
|
123
121
|
end
|
124
122
|
target = files.count > 1 ? NA.select_file(files) : files[0]
|
125
|
-
NA.notify(
|
123
|
+
NA.notify("#{NA.theme[:error]}Cancelled{x}", exit_code: 1) unless files.count.positive? && File.exist?(target)
|
126
124
|
|
127
125
|
end
|
128
126
|
|
@@ -131,8 +129,8 @@ class App
|
|
131
129
|
elsif $stdin.isatty && TTY::Which.exist?('gum')
|
132
130
|
`gum input --placeholder "Enter a task" --char-limit=500 --width=#{TTY::Screen.columns}`.strip
|
133
131
|
elsif $stdin.isatty
|
134
|
-
|
135
|
-
reader.read_line(NA::Color.template(
|
132
|
+
NA.notify("#{NA.theme[:prompt]}Enter task:")
|
133
|
+
reader.read_line(NA::Color.template("#{NA.theme[:warning]}> #{NA.theme[:action]}")).strip
|
136
134
|
end
|
137
135
|
|
138
136
|
if action.nil? || action.empty?
|
@@ -171,7 +169,7 @@ class App
|
|
171
169
|
args << '--width $(tput cols)'
|
172
170
|
`gum write #{args.join(' ')}`.strip.split("\n")
|
173
171
|
else
|
174
|
-
|
172
|
+
NA.notify("#{NA.theme[:prompt]}Enter a note, {bw}CTRL-d#{NA.theme[:prompt]} to end editing#{NA.theme[:action]}")
|
175
173
|
reader.read_multiline
|
176
174
|
end
|
177
175
|
end
|
data/bin/commands/complete.rb
CHANGED
@@ -28,6 +28,10 @@ class App
|
|
28
28
|
c.arg_name 'PATH'
|
29
29
|
c.flag %i[file]
|
30
30
|
|
31
|
+
c.desc 'Use a known todo file, partial matches allowed'
|
32
|
+
c.arg_name 'TODO_FILE'
|
33
|
+
c.flag %i[in todo]
|
34
|
+
|
31
35
|
c.desc 'Search for files X directories deep'
|
32
36
|
c.arg_name 'DEPTH'
|
33
37
|
c.flag %i[d depth], must_match: /^[1-9]$/, type: :integer, default_value: 1
|
data/bin/commands/edit.rb
CHANGED
@@ -51,11 +51,11 @@ class App
|
|
51
51
|
]
|
52
52
|
`gum input #{opts.join(' ')}`.strip
|
53
53
|
elsif $stdin.isatty && options[:tagged].empty?
|
54
|
-
|
55
|
-
reader.read_line(NA::Color.template(
|
54
|
+
NA.notify("#{NA.theme[:prompt]}Enter search string:")
|
55
|
+
reader.read_line(NA::Color.template("#{NA.theme[:warning]}> #{NA.theme[:action]}")).strip
|
56
56
|
end
|
57
57
|
|
58
|
-
NA.notify(
|
58
|
+
NA.notify("#{NA.theme[:error]}Empty input", exit_code: 1) if (action.nil? || action.empty?) && options[:tagged].empty?
|
59
59
|
|
60
60
|
if action
|
61
61
|
tokens = nil
|
@@ -79,32 +79,28 @@ class App
|
|
79
79
|
end
|
80
80
|
|
81
81
|
if (action.nil? || action.empty?) && options[:tagged].empty?
|
82
|
-
NA.notify(
|
82
|
+
NA.notify("#{NA.theme[:error]}Empty input, cancelled", exit_code: 1)
|
83
83
|
end
|
84
84
|
|
85
|
-
all_req = options[:tagged].join(' ') !~ /[
|
85
|
+
all_req = options[:tagged].join(' ') !~ /[+!-]/ && !options[:or]
|
86
86
|
tags = []
|
87
87
|
options[:tagged].join(',').split(/ *, */).each do |arg|
|
88
|
-
m = arg.match(/^(?<req>[+\-!])?(?<tag>[^
|
88
|
+
m = arg.match(/^(?<req>[+\-!])?(?<tag>[^ =<>*$\^~]+?)(?:(?<op>[=<>~]{1,2}|[*$\^]=)(?<val>.*?))?$/)
|
89
89
|
|
90
90
|
tags.push({
|
91
91
|
tag: m['tag'].wildcard_to_rx,
|
92
92
|
comp: m['op'],
|
93
93
|
value: m['val'],
|
94
94
|
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
95
|
-
negate: !m['req'].nil? && m['req'] =~ /[
|
95
|
+
negate: !m['req'].nil? && m['req'] =~ /[!-]/
|
96
96
|
})
|
97
97
|
end
|
98
98
|
|
99
|
-
target_proj =
|
100
|
-
NA.cwd
|
101
|
-
else
|
102
|
-
nil
|
103
|
-
end
|
99
|
+
target_proj = NA.cwd_is == :project ? NA.cwd : nil
|
104
100
|
|
105
101
|
if options[:file]
|
106
102
|
file = File.expand_path(options[:file])
|
107
|
-
NA.notify(
|
103
|
+
NA.notify("#{NA.theme[:error]}File not found", exit_code: 1) unless File.exist?(file)
|
108
104
|
|
109
105
|
targets = [file]
|
110
106
|
elsif options[:todo]
|
@@ -114,7 +110,7 @@ class App
|
|
114
110
|
todo.push({
|
115
111
|
token: m['tok'],
|
116
112
|
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
117
|
-
negate: !m['req'].nil? && m['req'] =~ /[
|
113
|
+
negate: !m['req'].nil? && m['req'] =~ /[!-]/
|
118
114
|
})
|
119
115
|
end
|
120
116
|
dirs = NA.match_working_dir(todo)
|
@@ -123,28 +119,29 @@ class App
|
|
123
119
|
targets = [dirs[0]]
|
124
120
|
elsif dirs.count.positive?
|
125
121
|
targets = NA.select_file(dirs, multiple: true)
|
126
|
-
NA.notify(
|
122
|
+
NA.notify("#{NA.theme[:error]}Cancelled", exit_code: 1) unless targets && targets.count.positive?
|
127
123
|
else
|
128
|
-
NA.notify(
|
124
|
+
NA.notify("#{NA.theme[:error]}Todo not found", exit_code: 1) unless targets && targets.count.positive?
|
129
125
|
|
130
126
|
end
|
131
127
|
else
|
132
128
|
files = NA.find_files(depth: options[:depth])
|
133
|
-
NA.notify(
|
129
|
+
NA.notify("#{NA.theme[:error]}No todo file found", exit_code: 1) if files.count.zero?
|
134
130
|
|
135
131
|
targets = files.count > 1 ? NA.select_file(files, multiple: true) : [files[0]]
|
136
|
-
NA.notify(
|
132
|
+
NA.notify("#{NA.theme[:error]}Cancelled", exit_code: 1) unless files.count.positive?
|
137
133
|
|
138
134
|
end
|
139
135
|
|
140
|
-
NA.notify(
|
136
|
+
NA.notify("#{NA.theme[:error]}No search terms provided", exit_code: 1) if tokens.nil? && options[:tagged].empty?
|
141
137
|
|
142
138
|
targets.each do |target|
|
143
|
-
NA.update_action(target,
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
139
|
+
NA.update_action(target,
|
140
|
+
tokens,
|
141
|
+
done: options[:done],
|
142
|
+
edit: options[:edit],
|
143
|
+
project: target_proj,
|
144
|
+
tagged: tags)
|
148
145
|
end
|
149
146
|
end
|
150
147
|
end
|
data/bin/commands/find.rb
CHANGED
@@ -73,7 +73,12 @@ class App
|
|
73
73
|
if options[:exact] || options[:regex]
|
74
74
|
search = args.join(' ')
|
75
75
|
else
|
76
|
-
|
76
|
+
rx = [
|
77
|
+
'(?<=\A|[ ,])(?<req>[+!-])?@(?<tag>[^ *=<>$*\^,@(]+)',
|
78
|
+
'(?:\((?<value>.*?)\)| *(?<op>[=<>~]{1,2}|[*$\^]=) *',
|
79
|
+
'(?<val>.*?(?=\Z|[,@])))?'
|
80
|
+
].join('')
|
81
|
+
search = args.join(' ').gsub(Regexp.new(rx)) do
|
77
82
|
m = Regexp.last_match
|
78
83
|
string = if m['value']
|
79
84
|
"#{m['req']}#{m['tag']}=#{m['value']}"
|
@@ -87,17 +92,17 @@ class App
|
|
87
92
|
|
88
93
|
search = search.gsub(/ +/, ' ').strip
|
89
94
|
|
90
|
-
all_req = options[:tagged].join(' ') !~ /[
|
95
|
+
all_req = options[:tagged].join(' ') !~ /[+!-]/ && !options[:or]
|
91
96
|
tags = []
|
92
97
|
options[:tagged].join(',').split(/ *, */).each do |arg|
|
93
|
-
m = arg.match(/^(?<req>[
|
98
|
+
m = arg.match(/^(?<req>[+!-])?(?<tag>[^ =<>$*~\^]+?) *(?:(?<op>[=<>~]{1,2}|[*$\^]=) *(?<val>.*?))?$/)
|
94
99
|
|
95
100
|
tags.push({
|
96
101
|
tag: m['tag'].wildcard_to_rx,
|
97
102
|
comp: m['op'],
|
98
103
|
value: m['val'],
|
99
104
|
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
100
|
-
negate: !m['req'].nil? && m['req'] =~ /[
|
105
|
+
negate: !m['req'].nil? && m['req'] =~ /[!-]/ ? true : false
|
101
106
|
})
|
102
107
|
end
|
103
108
|
|
@@ -112,47 +117,55 @@ class App
|
|
112
117
|
tokens = Regexp.new(search, Regexp::IGNORECASE)
|
113
118
|
else
|
114
119
|
tokens = []
|
115
|
-
all_req = search !~ /[
|
120
|
+
all_req = search !~ /(?<=[, ])[+!-]/ && !options[:or]
|
116
121
|
|
117
122
|
search.split(/ /).each do |arg|
|
118
123
|
m = arg.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
|
119
124
|
tokens.push({
|
120
125
|
token: Regexp.escape(m['tok']),
|
121
126
|
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
122
|
-
negate: !m['req'].nil? && m['req'] =~ /[
|
127
|
+
negate: !m['req'].nil? && m['req'] =~ /[!-]/ ? true : false
|
123
128
|
})
|
124
129
|
end
|
125
130
|
end
|
126
131
|
|
127
|
-
|
132
|
+
todos = nil
|
128
133
|
if options[:in]
|
129
|
-
|
134
|
+
todos = []
|
130
135
|
options[:in].split(/ *, */).each do |a|
|
131
136
|
m = a.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
+
todos.push({
|
138
|
+
token: m['tok'],
|
139
|
+
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
140
|
+
negate: !m['req'].nil? && m['req'] =~ /[!-]/
|
141
|
+
})
|
137
142
|
end
|
138
143
|
end
|
139
144
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
145
|
+
todo = NA::Todo.new({
|
146
|
+
depth: depth,
|
147
|
+
done: options[:done],
|
148
|
+
query: todos,
|
149
|
+
search: tokens,
|
150
|
+
tag: tags,
|
151
|
+
negate: options[:invert],
|
152
|
+
regex: options[:regex],
|
153
|
+
project: options[:project],
|
154
|
+
require_na: false
|
155
|
+
})
|
156
|
+
|
149
157
|
regexes = if tokens.is_a?(Array)
|
150
158
|
tokens.delete_if { |token| token[:negate] }.map { |token| token[:token] }
|
151
159
|
else
|
152
160
|
[tokens]
|
153
161
|
end
|
154
162
|
|
155
|
-
|
163
|
+
todo.actions.output(depth,
|
164
|
+
files: todo.files,
|
165
|
+
regexes: regexes,
|
166
|
+
notes: options[:notes],
|
167
|
+
nest: options[:nest],
|
168
|
+
nest_projects: options[:omnifocus])
|
156
169
|
end
|
157
170
|
end
|
158
171
|
end
|
data/bin/commands/init.rb
CHANGED
@@ -14,7 +14,7 @@ class App
|
|
14
14
|
project = args.join(' ')
|
15
15
|
elsif
|
16
16
|
project = File.expand_path('.').split('/').last
|
17
|
-
project = reader.read_line(NA::Color.template(
|
17
|
+
project = reader.read_line(NA::Color.template("#{NA.theme[:prompt]}Project name #{NA.theme[:filename]}> "), value: project).strip if $stdin.isatty
|
18
18
|
end
|
19
19
|
|
20
20
|
target = "#{project}.#{NA.extension}"
|