na 1.2.34 → 1.2.37
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +45 -0
- data/Gemfile.lock +1 -1
- data/README.md +80 -3
- data/bin/commands/complete.rb +9 -1
- data/bin/commands/edit.rb +6 -5
- data/bin/commands/find.rb +54 -26
- data/bin/commands/next.rb +22 -18
- data/bin/commands/prompt.rb +2 -0
- data/bin/commands/restore.rb +5 -1
- data/bin/commands/tagged.rb +38 -27
- data/bin/commands/todos.rb +3 -3
- data/bin/commands/undo.rb +22 -0
- data/bin/commands/update.rb +12 -2
- data/lib/na/action.rb +45 -2
- data/lib/na/actions.rb +87 -0
- data/lib/na/editor.rb +123 -0
- data/lib/na/next_action.rb +207 -467
- data/lib/na/todo.rb +183 -0
- data/lib/na/version.rb +1 -1
- data/lib/na.rb +3 -0
- data/src/_README.md +36 -12
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 35e6d784b55e397b8843663130837bcebb9041640a7833d650cedc9b783289e2
|
4
|
+
data.tar.gz: a1ba45d7ba0d77e122667bc5c93629832dc379ee5d2275076182849055c8d72e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1ee63a7b2bfd58496bf2047cd80a16f30bf255ca1edc8b0aa5a84a9abc8e4d1ccdd8082cd8f01fb8db60d5b73c7e2014f4f847369ac0d39274b5929ef8173f07
|
7
|
+
data.tar.gz: d0321cddedf590c96a18cbd1096c7982240cb8c172c9f3491e0569ecfdf8882955898056ff3fd56d9e529d91be2a9ca56f3003bdbf6f1517a9658d08a302ca30
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,48 @@
|
|
1
|
+
### 1.2.37
|
2
|
+
|
3
|
+
2023-09-01 12:42
|
4
|
+
|
5
|
+
#### NEW
|
6
|
+
|
7
|
+
- `na undo` command to undo last change or last change to file specified in arguments
|
8
|
+
|
9
|
+
#### IMPROVED
|
10
|
+
|
11
|
+
- Disable pagination when using --omnifocus
|
12
|
+
- Refactoring codebase
|
13
|
+
- `--in TODO` option for `na complete`
|
14
|
+
|
15
|
+
### 1.2.36
|
16
|
+
|
17
|
+
2023-09-01 12:41
|
18
|
+
|
19
|
+
#### NEW
|
20
|
+
|
21
|
+
- `na undo` command to undo last change or last change to file specified in arguments
|
22
|
+
|
23
|
+
#### IMPROVED
|
24
|
+
|
25
|
+
- Disable pagination when using --omnifocus
|
26
|
+
- Refactoring codebase
|
27
|
+
- `--in TODO` option for `na complete`
|
28
|
+
|
29
|
+
### 1.2.35
|
30
|
+
|
31
|
+
2023-08-30 11:59
|
32
|
+
|
33
|
+
#### IMPROVED
|
34
|
+
|
35
|
+
- If a search string contains @tags and --exact or --regex isn't specified, the @tags will be extracted and passed as a --tagged search.
|
36
|
+
- Tag handling (including values and comparisons) in tags extracted from search strings
|
37
|
+
- `na complete --project PROJ` flag to move to a specific project
|
38
|
+
- `na restore --project PROJ` flag to move restored action to
|
39
|
+
- Exit gracefully if tagged command is run with invalid
|
40
|
+
- Display action affected when using update command
|
41
|
+
|
42
|
+
#### FIXED
|
43
|
+
|
44
|
+
- Escape search for tokens to allow parenthesis and other
|
45
|
+
|
1
46
|
### 1.2.34
|
2
47
|
|
3
48
|
2023-08-30 09:22
|
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.37
|
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.37
|
81
81
|
|
82
82
|
GLOBAL OPTIONS
|
83
83
|
-a, --add - Add a next action (deprecated, for backwards compatibility)
|
@@ -104,7 +104,7 @@ COMMANDS
|
|
104
104
|
complete, finish - Find and mark an action as @done
|
105
105
|
completed, finished - Display completed actions
|
106
106
|
edit - Edit an existing action
|
107
|
-
find, grep
|
107
|
+
find, grep, search - Find actions matching a search pattern
|
108
108
|
help - Shows a list of commands or help for one command
|
109
109
|
init, create - Create a new todo file in the current directory
|
110
110
|
initconfig - Initialize the config file using current global options
|
@@ -116,6 +116,7 @@ COMMANDS
|
|
116
116
|
saved - Execute a saved search
|
117
117
|
tagged - Find actions matching a tag
|
118
118
|
todos - Show list of known todo files
|
119
|
+
undo - Undo the last change
|
119
120
|
update - Update an existing action
|
120
121
|
```
|
121
122
|
|
@@ -512,6 +513,82 @@ EXAMPLES
|
|
512
513
|
na update --archive My cool action
|
513
514
|
```
|
514
515
|
|
516
|
+
##### changelog
|
517
|
+
|
518
|
+
View recent changes with `na changelog` or `na changes`.
|
519
|
+
|
520
|
+
```
|
521
|
+
NAME
|
522
|
+
changes - Display the changelog
|
523
|
+
|
524
|
+
SYNOPSIS
|
525
|
+
|
526
|
+
na [global options] changes
|
527
|
+
```
|
528
|
+
|
529
|
+
##### complete
|
530
|
+
|
531
|
+
Mark an action as complete, shortcut for `na update --finish`.
|
532
|
+
|
533
|
+
```
|
534
|
+
NAME
|
535
|
+
complete - Find and mark an action as @done
|
536
|
+
|
537
|
+
SYNOPSIS
|
538
|
+
|
539
|
+
na [global options] complete [command options] ACTION
|
540
|
+
|
541
|
+
COMMAND OPTIONS
|
542
|
+
-a, --archive - Add a @done tag to action and move to Archive
|
543
|
+
--all - Act on all matches immediately (no menu)
|
544
|
+
-d, --depth=DEPTH - Search for files X directories deep (default: 1)
|
545
|
+
-e, --regex - Interpret search pattern as regular expression
|
546
|
+
--file=PATH - Specify the file to search for the task (default: none)
|
547
|
+
--in, --todo=TODO_FILE - Use a known todo file, partial matches allowed (default: none)
|
548
|
+
-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.
|
549
|
+
-o, --overwrite - Overwrite note instead of appending
|
550
|
+
--tagged=TAG - Match actions containing tag. Allows value comparisons (may be used more than once, default: none)
|
551
|
+
--to, --project, --proj=PROJECT - Move action to specific project (default: none)
|
552
|
+
-x, --exact - Match pattern exactly
|
553
|
+
|
554
|
+
EXAMPLES
|
555
|
+
|
556
|
+
# Find "An existing task" and mark @done
|
557
|
+
na complete "An existing task"
|
558
|
+
|
559
|
+
# Alias for complete
|
560
|
+
na finish "An existing task"
|
561
|
+
```
|
562
|
+
|
563
|
+
##### archive
|
564
|
+
|
565
|
+
Mark an action as complete and move to archive, shortcut for `na update --archive`.
|
566
|
+
|
567
|
+
```
|
568
|
+
NAME
|
569
|
+
archive - Mark an action as @done and archive
|
570
|
+
|
571
|
+
SYNOPSIS
|
572
|
+
|
573
|
+
na [global options] archive [command options] ACTION
|
574
|
+
|
575
|
+
COMMAND OPTIONS
|
576
|
+
--all - Act on all matches immediately (no menu)
|
577
|
+
-d, --depth=DEPTH - Search for files X directories deep (default: 1)
|
578
|
+
--done - Archive all done tasks
|
579
|
+
-e, --regex - Interpret search pattern as regular expression
|
580
|
+
--file=PATH - Specify the file to search for the task (default: none)
|
581
|
+
-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.
|
582
|
+
-o, --overwrite - Overwrite note instead of appending
|
583
|
+
--tagged=TAG - Match actions containing tag. Allows value comparisons (may be used more than once, default: none)
|
584
|
+
-x, --exact - Match pattern exactly
|
585
|
+
|
586
|
+
EXAMPLE
|
587
|
+
|
588
|
+
# Find "An existing task", mark @done if needed, and move to archive
|
589
|
+
na archive "An existing task"
|
590
|
+
```
|
591
|
+
|
515
592
|
### Configuration
|
516
593
|
|
517
594
|
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/complete.rb
CHANGED
@@ -20,10 +20,18 @@ class App
|
|
20
20
|
c.desc 'Add a @done tag to action and move to Archive'
|
21
21
|
c.switch %i[a archive], negatable: false
|
22
22
|
|
23
|
+
c.desc 'Move action to specific project'
|
24
|
+
c.arg_name 'PROJECT'
|
25
|
+
c.flag %i[to project proj]
|
26
|
+
|
23
27
|
c.desc 'Specify the file to search for the task'
|
24
28
|
c.arg_name 'PATH'
|
25
29
|
c.flag %i[file]
|
26
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
|
+
|
27
35
|
c.desc 'Search for files X directories deep'
|
28
36
|
c.arg_name 'DEPTH'
|
29
37
|
c.flag %i[d depth], must_match: /^[1-9]$/, type: :integer, default_value: 1
|
@@ -44,7 +52,7 @@ class App
|
|
44
52
|
c.action do |global, options, args|
|
45
53
|
options[:finish] = true
|
46
54
|
options[:f] = true
|
47
|
-
options[:project] = 'Archive' if options[:archive]
|
55
|
+
options[:project] = 'Archive' if options[:archive] && !options[:project]
|
48
56
|
|
49
57
|
cmd = commands[:update]
|
50
58
|
action = cmd.send(:get_action, nil)
|
data/bin/commands/edit.rb
CHANGED
@@ -140,11 +140,12 @@ class App
|
|
140
140
|
NA.notify('{r}No search terms provided', exit_code: 1) if tokens.nil? && options[:tagged].empty?
|
141
141
|
|
142
142
|
targets.each do |target|
|
143
|
-
NA.update_action(target,
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
143
|
+
NA.update_action(target,
|
144
|
+
tokens,
|
145
|
+
done: options[:done],
|
146
|
+
edit: options[:edit],
|
147
|
+
project: target_proj,
|
148
|
+
tagged: tags)
|
148
149
|
end
|
149
150
|
end
|
150
151
|
end
|
data/bin/commands/find.rb
CHANGED
@@ -7,7 +7,7 @@ class App
|
|
7
7
|
(partial matches allowed). Add a + before a token to make it required, e.g. `na find +feature +maybe`,
|
8
8
|
add a - or ! to ignore matches containing that token.'
|
9
9
|
arg_name 'PATTERN'
|
10
|
-
command %i[find grep] do |c|
|
10
|
+
command %i[find grep search] do |c|
|
11
11
|
c.example 'na find feature idea swift', desc: 'Find all actions containing feature, idea, and swift'
|
12
12
|
c.example 'na find feature idea -swift', desc: 'Find all actions containing feature and idea but NOT swift'
|
13
13
|
c.example 'na find -x feature idea', desc: 'Find all actions containing the exact text "feature idea"'
|
@@ -64,17 +64,33 @@ class App
|
|
64
64
|
NA.save_search(title, "#{NA.command_line.join(' ').sub(/ --save[= ]*\S+/, '').split(' ').map { |t| %("#{t}") }.join(' ')}")
|
65
65
|
end
|
66
66
|
|
67
|
-
|
68
67
|
depth = if global_options[:recurse] && options[:depth].nil? && global_options[:depth] == 1
|
69
68
|
3
|
70
69
|
else
|
71
70
|
options[:depth].nil? ? global_options[:depth].to_i : options[:depth].to_i
|
72
71
|
end
|
73
72
|
|
73
|
+
if options[:exact] || options[:regex]
|
74
|
+
search = args.join(' ')
|
75
|
+
else
|
76
|
+
search = args.join(' ').gsub(/(?<=\A|[ ,])(?<req>[+\-!])?@(?<tag>[^ *=<>$\^,@(]+)(?:\((?<value>.*?)\)| *(?<op>[=<>]{1,2}|[*$\^]=) *(?<val>.*?(?=\Z|[,@])))?/) do |arg|
|
77
|
+
m = Regexp.last_match
|
78
|
+
string = if m['value']
|
79
|
+
"#{m['req']}#{m['tag']}=#{m['value']}"
|
80
|
+
else
|
81
|
+
m[0]
|
82
|
+
end
|
83
|
+
options[:tagged] << string.sub(/@/, '')
|
84
|
+
''
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
search = search.gsub(/ +/, ' ').strip
|
89
|
+
|
74
90
|
all_req = options[:tagged].join(' ') !~ /[+!\-]/ && !options[:or]
|
75
91
|
tags = []
|
76
92
|
options[:tagged].join(',').split(/ *, */).each do |arg|
|
77
|
-
m = arg.match(/^(?<req>[+\-!])?(?<tag>[^ =<>$\^]+?)(?:(?<op>[=<>]{1,2}|[*$\^]=)(?<val>.*?))?$/)
|
93
|
+
m = arg.match(/^(?<req>[+\-!])?(?<tag>[^ =<>$\^]+?) *(?:(?<op>[=<>]{1,2}|[*$\^]=) *(?<val>.*?))?$/)
|
78
94
|
|
79
95
|
tags.push({
|
80
96
|
tag: m['tag'].wildcard_to_rx,
|
@@ -85,54 +101,66 @@ class App
|
|
85
101
|
})
|
86
102
|
end
|
87
103
|
|
104
|
+
search_for_done = false
|
105
|
+
tags.each { |tag| search_for_done = true if tag[:tag] =~ /done/ }
|
106
|
+
options[:done] = true if search_for_done
|
107
|
+
|
88
108
|
tokens = nil
|
89
109
|
if options[:exact]
|
90
|
-
tokens =
|
110
|
+
tokens = search
|
91
111
|
elsif options[:regex]
|
92
|
-
tokens = Regexp.new(
|
112
|
+
tokens = Regexp.new(search, Regexp::IGNORECASE)
|
93
113
|
else
|
94
114
|
tokens = []
|
95
|
-
all_req =
|
115
|
+
all_req = search !~ /[+!-]/ && !options[:or]
|
96
116
|
|
97
|
-
|
117
|
+
search.split(/ /).each do |arg|
|
98
118
|
m = arg.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
|
99
119
|
tokens.push({
|
100
|
-
token: m['tok'],
|
120
|
+
token: Regexp.escape(m['tok']),
|
101
121
|
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
102
|
-
negate: !m['req'].nil? && m['req'] =~ /[
|
122
|
+
negate: !m['req'].nil? && m['req'] =~ /[!-]/
|
103
123
|
})
|
104
124
|
end
|
105
125
|
end
|
106
126
|
|
107
|
-
|
127
|
+
todos = nil
|
108
128
|
if options[:in]
|
109
|
-
|
129
|
+
todos = []
|
110
130
|
options[:in].split(/ *, */).each do |a|
|
111
131
|
m = a.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
132
|
+
todos.push({
|
133
|
+
token: m['tok'],
|
134
|
+
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
135
|
+
negate: !m['req'].nil? && m['req'] =~ /[!-]/
|
136
|
+
})
|
117
137
|
end
|
118
138
|
end
|
119
139
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
140
|
+
todo = NA::Todo.new({
|
141
|
+
depth: depth,
|
142
|
+
done: options[:done],
|
143
|
+
query: todos,
|
144
|
+
search: tokens,
|
145
|
+
tag: tags,
|
146
|
+
negate: options[:invert],
|
147
|
+
regex: options[:regex],
|
148
|
+
project: options[:project],
|
149
|
+
require_na: false
|
150
|
+
})
|
151
|
+
|
129
152
|
regexes = if tokens.is_a?(Array)
|
130
153
|
tokens.delete_if { |token| token[:negate] }.map { |token| token[:token] }
|
131
154
|
else
|
132
155
|
[tokens]
|
133
156
|
end
|
134
157
|
|
135
|
-
|
158
|
+
todo.actions.output(depth,
|
159
|
+
files: todo.files,
|
160
|
+
regexes: regexes,
|
161
|
+
notes: options[:notes],
|
162
|
+
nest: options[:nest],
|
163
|
+
nest_projects: options[:omnifocus])
|
136
164
|
end
|
137
165
|
end
|
138
166
|
end
|
data/bin/commands/next.rb
CHANGED
@@ -52,10 +52,10 @@ class App
|
|
52
52
|
c.switch %i[done]
|
53
53
|
|
54
54
|
c.desc 'Output actions nested by file'
|
55
|
-
c.switch %[nest], negatable: false
|
55
|
+
c.switch %i[nest], negatable: false
|
56
56
|
|
57
57
|
c.desc 'Output actions nested by file and project'
|
58
|
-
c.switch %[omnifocus], negatable: false
|
58
|
+
c.switch %i[omnifocus], negatable: false
|
59
59
|
|
60
60
|
c.action do |global_options, options, args|
|
61
61
|
if global_options[:add]
|
@@ -75,23 +75,23 @@ class App
|
|
75
75
|
options[:depth].nil? ? global_options[:depth].to_i : options[:depth].to_i
|
76
76
|
end
|
77
77
|
|
78
|
-
all_req = options[:tagged].join(' ') !~ /[
|
78
|
+
all_req = options[:tagged].join(' ') !~ /[+!-]/ && !options[:or]
|
79
79
|
tags = []
|
80
80
|
options[:tagged].join(',').split(/ *, */).each do |arg|
|
81
|
-
m = arg.match(/^(?<req>[
|
81
|
+
m = arg.match(/^(?<req>[+!-])?(?<tag>[^ =<>$\^]+?)(?:(?<op>[=<>]{1,2}|[*$\^]=)(?<val>.*?))?$/)
|
82
82
|
|
83
83
|
tags.push({
|
84
84
|
tag: m['tag'].wildcard_to_rx,
|
85
85
|
comp: m['op'],
|
86
86
|
value: m['val'],
|
87
87
|
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
88
|
-
negate: !m['req'].nil? && m['req'] =~ /[
|
88
|
+
negate: !m['req'].nil? && m['req'] =~ /[!-]/
|
89
89
|
})
|
90
90
|
end
|
91
91
|
|
92
92
|
args.concat(options[:in])
|
93
93
|
if args.count.positive?
|
94
|
-
all_req = args.join(' ') !~ /[
|
94
|
+
all_req = args.join(' ') !~ /[+!-]/
|
95
95
|
|
96
96
|
tokens = []
|
97
97
|
args.each do |arg|
|
@@ -100,7 +100,7 @@ class App
|
|
100
100
|
tokens.push({
|
101
101
|
token: m['tok'],
|
102
102
|
required: !m['req'].nil? && m['req'] == '+',
|
103
|
-
negate: !m['req'].nil? && m['req'] =~ /[
|
103
|
+
negate: !m['req'].nil? && m['req'] =~ /[!-]/
|
104
104
|
})
|
105
105
|
end
|
106
106
|
end
|
@@ -114,14 +114,14 @@ class App
|
|
114
114
|
search = Regexp.new(options[:search].join(' '), Regexp::IGNORECASE)
|
115
115
|
else
|
116
116
|
search = []
|
117
|
-
all_req = options[:search].join(' ') !~ /[
|
117
|
+
all_req = options[:search].join(' ') !~ /[+!-]/ && !options[:or]
|
118
118
|
|
119
119
|
options[:search].join(' ').split(/ /).each do |arg|
|
120
120
|
m = arg.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
|
121
121
|
search.push({
|
122
122
|
token: m['tok'],
|
123
123
|
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
124
|
-
negate: !m['req'].nil? && m['req'] =~ /[
|
124
|
+
negate: !m['req'].nil? && m['req'] =~ /[!-]/
|
125
125
|
})
|
126
126
|
end
|
127
127
|
end
|
@@ -133,15 +133,19 @@ class App
|
|
133
133
|
tag = [{ tag: NA.na_tag, value: nil }]
|
134
134
|
tag << { tag: 'done', value: nil, negate: true } unless options[:done]
|
135
135
|
tag.concat(tags)
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
136
|
+
todo = NA::Todo.new({ depth: depth,
|
137
|
+
done: options[:done],
|
138
|
+
query: tokens,
|
139
|
+
tag: tag,
|
140
|
+
search: search,
|
141
|
+
project: options[:project],
|
142
|
+
require_na: require_na })
|
143
|
+
NA::Pager.paginate = false if options[:omnifocus]
|
144
|
+
todo.actions.output(depth,
|
145
|
+
files: todo.files,
|
146
|
+
notes: options[:notes],
|
147
|
+
nest: options[:nest],
|
148
|
+
nest_projects: options[:omnifocus])
|
145
149
|
end
|
146
150
|
end
|
147
151
|
end
|
data/bin/commands/prompt.rb
CHANGED
@@ -9,6 +9,8 @@ class App
|
|
9
9
|
c.desc 'Output the prompt hook for the current shell to STDOUT. Pass an argument to
|
10
10
|
specify a shell (zsh, bash, fish)'
|
11
11
|
c.arg_name 'SHELL', optional: true
|
12
|
+
c.default_command :show
|
13
|
+
|
12
14
|
c.command %i[show] do |s|
|
13
15
|
s.action do |_global_options, _options, args|
|
14
16
|
shell = if args.count.positive?
|
data/bin/commands/restore.rb
CHANGED
@@ -17,6 +17,10 @@ class App
|
|
17
17
|
c.desc 'Overwrite note instead of appending'
|
18
18
|
c.switch %i[o overwrite], negatable: false
|
19
19
|
|
20
|
+
c.desc 'Move action to specific project'
|
21
|
+
c.arg_name 'PROJECT'
|
22
|
+
c.flag %i[to project proj]
|
23
|
+
|
20
24
|
c.desc 'Specify the file to search for the task'
|
21
25
|
c.arg_name 'PATH'
|
22
26
|
c.flag %i[file]
|
@@ -43,7 +47,7 @@ class App
|
|
43
47
|
options[:done] = true
|
44
48
|
options[:finish] = false
|
45
49
|
options[:f] = false
|
46
|
-
|
50
|
+
|
47
51
|
cmd = commands[:update]
|
48
52
|
action = cmd.send(:get_action, nil)
|
49
53
|
action.call(global, options, args)
|
data/bin/commands/tagged.rb
CHANGED
@@ -57,17 +57,18 @@ class App
|
|
57
57
|
c.flag %i[save]
|
58
58
|
|
59
59
|
c.desc 'Output actions nested by file'
|
60
|
-
c.switch %[nest], negatable: false
|
60
|
+
c.switch %i[nest], negatable: false
|
61
61
|
|
62
62
|
c.desc 'Output actions nested by file and project'
|
63
|
-
c.switch %[omnifocus], negatable: false
|
63
|
+
c.switch %i[omnifocus], negatable: false
|
64
64
|
|
65
65
|
c.action do |global_options, options, args|
|
66
66
|
options[:nest] = true if options[:omnifocus]
|
67
67
|
|
68
68
|
if options[:save]
|
69
69
|
title = options[:save].gsub(/[^a-z0-9]/, '_').gsub(/_+/, '_')
|
70
|
-
|
70
|
+
cmd = NA.command_line.join(' ').sub(/ --save[= ]*\S+/, '').split(' ').map { |t| %("#{t}") }.join(' ')
|
71
|
+
NA.save_search(title, cmd)
|
71
72
|
end
|
72
73
|
|
73
74
|
depth = if global_options[:recurse] && options[:depth].nil? && global_options[:depth] == 1
|
@@ -78,22 +79,24 @@ class App
|
|
78
79
|
|
79
80
|
tags = []
|
80
81
|
|
81
|
-
all_req = args.join(' ') !~ /[
|
82
|
+
all_req = args.join(' ') !~ /[+!-]/ && !options[:or]
|
82
83
|
args.join(',').split(/ *, */).each do |arg|
|
83
|
-
m = arg.match(/^(?<req>[+\-!])?(?<tag>[^ =<>$\^]+?)(?:(?<op>[=<>]{1,2}|[*$\^]=)(?<val>.*?))?$/)
|
84
|
+
m = arg.match(/^(?<req>[+\-!])?(?<tag>[^ =<>$\^]+?) *(?:(?<op>[=<>]{1,2}|[*$\^]=) *(?<val>.*?))?$/)
|
85
|
+
next if m.nil?
|
84
86
|
|
85
87
|
tags.push({
|
86
|
-
tag: m['tag'].wildcard_to_rx,
|
88
|
+
tag: m['tag'].sub(/^@/, '').wildcard_to_rx,
|
87
89
|
comp: m['op'],
|
88
90
|
value: m['val'],
|
89
91
|
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
90
|
-
negate: !m['req'].nil? && m['req'] =~ /[
|
92
|
+
negate: !m['req'].nil? && m['req'] =~ /[!-]/
|
91
93
|
})
|
92
94
|
end
|
93
95
|
|
94
96
|
search_for_done = false
|
95
97
|
tags.each { |tag| search_for_done = true if tag[:tag] =~ /done/ }
|
96
|
-
tags.push({ tag: 'done', value: nil, negate: true}) unless search_for_done
|
98
|
+
tags.push({ tag: 'done', value: nil, negate: true }) unless search_for_done || options[:done]
|
99
|
+
options[:done] = true if search_for_done
|
97
100
|
|
98
101
|
tokens = nil
|
99
102
|
if options[:search]
|
@@ -103,47 +106,55 @@ class App
|
|
103
106
|
tokens = Regexp.new(options[:search].join(' '), Regexp::IGNORECASE)
|
104
107
|
else
|
105
108
|
tokens = []
|
106
|
-
all_req = options[:search].join(' ') !~ /[
|
109
|
+
all_req = options[:search].join(' ') !~ /[+!-]/ && !options[:or]
|
107
110
|
|
108
111
|
options[:search].join(' ').split(/ /).each do |arg|
|
109
112
|
m = arg.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
|
110
113
|
tokens.push({
|
111
114
|
token: m['tok'],
|
112
115
|
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
113
|
-
negate: !m['req'].nil? && m['req'] =~ /[
|
116
|
+
negate: !m['req'].nil? && m['req'] =~ /[!-]/
|
114
117
|
})
|
115
118
|
end
|
116
119
|
end
|
117
120
|
end
|
118
121
|
|
119
|
-
|
122
|
+
todos = nil
|
120
123
|
if options[:in]
|
121
|
-
|
124
|
+
todos = []
|
125
|
+
all_req = options[:in] !~ /[+!-]/ && !options[:or]
|
122
126
|
options[:in].split(/ *, */).each do |a|
|
123
127
|
m = a.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
128
|
+
todos.push({
|
129
|
+
token: m['tok'],
|
130
|
+
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
131
|
+
negate: !m['req'].nil? && m['req'] =~ /[!-]/
|
132
|
+
})
|
129
133
|
end
|
130
134
|
end
|
131
135
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
136
|
+
NA.notify('{br}No actions matched search', exit_code: 1) if tags.empty? && tokens.empty?
|
137
|
+
|
138
|
+
todo = NA::Todo.new({ depth: depth,
|
139
|
+
done: options[:done],
|
140
|
+
query: todos,
|
141
|
+
search: tokens,
|
142
|
+
tag: tags,
|
143
|
+
negate: options[:invert],
|
144
|
+
project: options[:project],
|
145
|
+
require_na: false })
|
146
|
+
|
141
147
|
regexes = if tokens.is_a?(Array)
|
142
148
|
tokens.delete_if { |token| token[:negate] }.map { |token| token[:token] }
|
143
149
|
else
|
144
150
|
[tokens]
|
145
151
|
end
|
146
|
-
|
152
|
+
todo.actions.output(depth,
|
153
|
+
files: todo.files,
|
154
|
+
regexes: regexes,
|
155
|
+
notes: options[:notes],
|
156
|
+
nest: options[:nest],
|
157
|
+
nest_projects: options[:omnifocus])
|
147
158
|
end
|
148
159
|
end
|
149
160
|
end
|
data/bin/commands/todos.rb
CHANGED
@@ -10,16 +10,16 @@ class App
|
|
10
10
|
command %i[todos] do |c|
|
11
11
|
c.action do |_global_options, _options, args|
|
12
12
|
if args.count.positive?
|
13
|
-
all_req = args.join(' ') !~ /[
|
13
|
+
all_req = args.join(' ') !~ /[+!-]/
|
14
14
|
|
15
15
|
tokens = [{ token: '*', required: all_req, negate: false }]
|
16
16
|
args.each do |arg|
|
17
17
|
arg.split(/ *, */).each do |a|
|
18
|
-
m = a.match(/^(?<req>[
|
18
|
+
m = a.match(/^(?<req>[+!-])?(?<tok>.*?)$/)
|
19
19
|
tokens.push({
|
20
20
|
token: m['tok'],
|
21
21
|
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
22
|
-
negate: !m['req'].nil? && m['req'] =~ /[
|
22
|
+
negate: !m['req'].nil? && m['req'] =~ /[!-]/
|
23
23
|
})
|
24
24
|
end
|
25
25
|
end
|