na 1.1.13 → 1.1.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -0
- data/Gemfile.lock +1 -1
- data/README.md +7 -3
- data/bin/na +13 -4
- data/lib/na/action.rb +2 -2
- data/lib/na/next_action.rb +11 -7
- data/lib/na/string.rb +55 -23
- data/lib/na/version.rb +1 -1
- data/src/README.md +7 -3
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d39a0b804774a7d07c6a1154e536798bdc2f09c20e76aa2ca776cc5111c02534
|
4
|
+
data.tar.gz: 66e180d9cf673293e2721d83c8187b06746e352252c7fb1575be33032c088b89
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 22e0487072dde7c1bf2f76f412ae20a3018fd038300bdb2aac2557ac77ed1909006c4457debbe31c0c32db57439dff2ec7b07a23f8ebda96ad00748a575a8595
|
7
|
+
data.tar.gz: 0e8175309ff9e1d43be62ec03cdd525e34b38c9ba9608e5edbfe90b97b315a43c397e7a318a624ba3f2fa210acc3f30bbadb47590de8a851fac4b092b133a327
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,32 @@
|
|
1
|
+
### 1.1.15
|
2
|
+
|
3
|
+
2022-10-06 16:12
|
4
|
+
|
5
|
+
#### CHANGED
|
6
|
+
|
7
|
+
- If no + or ! tokens are given in search, default to AND search for tokens
|
8
|
+
|
9
|
+
#### IMPROVED
|
10
|
+
|
11
|
+
- Better handling of color in search highlighting
|
12
|
+
|
13
|
+
#### FIXED
|
14
|
+
|
15
|
+
- --regex search broken
|
16
|
+
|
17
|
+
### 1.1.14
|
18
|
+
|
19
|
+
2022-10-06 12:30
|
20
|
+
|
21
|
+
#### IMPROVED
|
22
|
+
|
23
|
+
- Code cleanup
|
24
|
+
- Highlight search terms in results
|
25
|
+
|
26
|
+
#### FIXED
|
27
|
+
|
28
|
+
- Multiple search terms overriding each other
|
29
|
+
|
1
30
|
### 1.1.13
|
2
31
|
|
3
32
|
2022-10-06 06:28
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
_If you're one of the rare people like me who find this useful, feel free to
|
10
10
|
[buy me some coffee][donate]._
|
11
11
|
|
12
|
-
The current version of `na` is 1.1.
|
12
|
+
The current version of `na` is 1.1.15
|
13
13
|
.
|
14
14
|
|
15
15
|
`na` ("next action") is a command line tool designed to make it easy to see what your next actions are for any project, right from the command line. It works with TaskPaper-formatted files (but any plain text format will do), looking for `@na` tags (or whatever you specify) in todo files in your current folder.
|
@@ -37,7 +37,7 @@ You can list next actions in files in the current directory by typing `na`. By d
|
|
37
37
|
|
38
38
|
#### Easy matching
|
39
39
|
|
40
|
-
`na` features intelligent project matching. Every time it locates a todo file, it adds the project to the database. Once a project is recorded, you can list its actions by using any portion of the parent directories or file names. If your project is in `~/Sites/dev/markedapp`, you could quickly list its next actions by typing `na next dev
|
40
|
+
`na` features intelligent project matching. Every time it locates a todo file, it adds the project to the database. Once a project is recorded, you can list its actions by using any portion of the parent directories or file names. If your project is in `~/Sites/dev/markedapp`, you could quickly list its next actions by typing `na next dev/mark`. Creat paths by separating with / or :, separate multiple queries with spaces. na will always look for the shortest match for a path.
|
41
41
|
|
42
42
|
#### Recursion
|
43
43
|
|
@@ -152,6 +152,8 @@ EXAMPLES
|
|
152
152
|
|
153
153
|
Example: `na find cool feature idea`
|
154
154
|
|
155
|
+
Unless `--exact` is specified, search is tokenized and combined with OR, so `na find cool feature idea` translates to `cool OR feature OR idea`, matching any string that contains any of the words. To make a token required, add a `+` before it (e.g. `cool +feature idea` is `(cool OR idea) AND feature`). Wildcards allowed (`*` and `?`), use `--regex` to interpret the search as a regular expression. Use `-v` to invert the results (display non-matching actions only).
|
156
|
+
|
155
157
|
```
|
156
158
|
NAME
|
157
159
|
find - Find actions matching a search pattern
|
@@ -229,7 +231,9 @@ EXAMPLES
|
|
229
231
|
|
230
232
|
##### tagged
|
231
233
|
|
232
|
-
Example: `na tagged feature +maybe
|
234
|
+
Example: `na tagged feature +maybe`.
|
235
|
+
|
236
|
+
Separate multiple tags with spaces or commas. By default tags are combined with OR, so actions matching any of the tags listed will be displayed. Use `+` to make a tag required and `!` to negate a tag (only display if the action does _not_ contain the tag). Use `-v` to invert the search and display all actions that _don't_ match.
|
233
237
|
|
234
238
|
```
|
235
239
|
NAME
|
data/bin/na
CHANGED
@@ -269,11 +269,13 @@ class App
|
|
269
269
|
tokens = Regexp.new(args.join(' '), Regexp::IGNORECASE)
|
270
270
|
else
|
271
271
|
tokens = []
|
272
|
-
args.
|
272
|
+
all_req = args.join(' ') !~ /[+!\-]/
|
273
|
+
|
274
|
+
args.join(' ').split(/ /).each do |arg|
|
273
275
|
m = arg.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
|
274
276
|
tokens.push({
|
275
277
|
token: m['tok'],
|
276
|
-
required: !m['req'].nil? && m['req'] == '+',
|
278
|
+
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
277
279
|
negate: !m['req'].nil? && m['req'] =~ /[!\-]/
|
278
280
|
})
|
279
281
|
end
|
@@ -285,7 +287,13 @@ class App
|
|
285
287
|
regex: options[:regex],
|
286
288
|
project: options[:project],
|
287
289
|
require_na: false)
|
288
|
-
|
290
|
+
if tokens.is_a?(Array)
|
291
|
+
regexes = tokens.delete_if { |token| token[:negate] }.map { |token| token[:token] }
|
292
|
+
else
|
293
|
+
regexes = [tokens]
|
294
|
+
end
|
295
|
+
|
296
|
+
NA.output_actions(actions, depth, files: files, regexes: regexes)
|
289
297
|
end
|
290
298
|
end
|
291
299
|
|
@@ -336,7 +344,8 @@ class App
|
|
336
344
|
negate: options[:invert],
|
337
345
|
project: options[:project],
|
338
346
|
require_na: false)
|
339
|
-
|
347
|
+
regexes = tags.delete_if { |token| token[:negate] }.map { |token| token[:token] }
|
348
|
+
NA.output_actions(actions, depth, files: files, regexes: regexes)
|
340
349
|
end
|
341
350
|
end
|
342
351
|
|
data/lib/na/action.rb
CHANGED
@@ -27,7 +27,7 @@ module NA
|
|
27
27
|
EOINSPECT
|
28
28
|
end
|
29
29
|
|
30
|
-
def pretty(extension: 'taskpaper', template: {})
|
30
|
+
def pretty(extension: 'taskpaper', template: {}, regexes: [])
|
31
31
|
default_template = {
|
32
32
|
file: '{xbk}',
|
33
33
|
parent: '{c}',
|
@@ -67,7 +67,7 @@ module NA
|
|
67
67
|
NA::Color.template(template[:output].gsub(/%filename/, filename)
|
68
68
|
.gsub(/%project/, project)
|
69
69
|
.gsub(/%parents?/, parents)
|
70
|
-
.gsub(/%action/, action))
|
70
|
+
.gsub(/%action/, action.highlight_search(regexes)))
|
71
71
|
end
|
72
72
|
|
73
73
|
def tags_match?(any: [], all: [], none: [])
|
data/lib/na/next_action.rb
CHANGED
@@ -80,8 +80,10 @@ module NA
|
|
80
80
|
notify("{by}Task added to {bw}#{file}")
|
81
81
|
end
|
82
82
|
|
83
|
-
def output_actions(actions, depth, files: nil)
|
84
|
-
|
83
|
+
def output_actions(actions, depth, files: nil, regexes: [])
|
84
|
+
return if files.nil?
|
85
|
+
|
86
|
+
template = if files.count.positive?
|
85
87
|
if files.count == 1
|
86
88
|
'%parent%action'
|
87
89
|
else
|
@@ -96,11 +98,10 @@ module NA
|
|
96
98
|
else
|
97
99
|
'%parent%action'
|
98
100
|
end
|
99
|
-
if files && @verbose
|
100
|
-
files.map { |f| notify("{dw}#{f}") }
|
101
|
-
end
|
102
101
|
|
103
|
-
|
102
|
+
files.map { |f| notify("{dw}#{f}") } if files && @verbose
|
103
|
+
|
104
|
+
puts(actions.map { |action| action.pretty(template: { output: template }, regexes: regexes) })
|
104
105
|
end
|
105
106
|
|
106
107
|
def parse_actions(depth: 1, query: nil, tag: nil, search: nil, negate: false, regex: false, project: nil, require_na: true)
|
@@ -136,7 +137,10 @@ module NA
|
|
136
137
|
end
|
137
138
|
else
|
138
139
|
search.each do |t|
|
139
|
-
|
140
|
+
opt, req, neg = parse_search(t, negate)
|
141
|
+
optional.concat(opt)
|
142
|
+
required.concat(req)
|
143
|
+
negated.concat(neg)
|
140
144
|
end
|
141
145
|
end
|
142
146
|
end
|
data/lib/na/string.rb
CHANGED
@@ -5,9 +5,7 @@ class ::String
|
|
5
5
|
prefix = match(/(^[ \t]+)/)
|
6
6
|
return 0 if prefix.nil?
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
tabs
|
8
|
+
prefix[1].gsub(/ /, "\t").scan(/\t/).count
|
11
9
|
end
|
12
10
|
|
13
11
|
##
|
@@ -17,25 +15,75 @@ class ::String
|
|
17
15
|
##
|
18
16
|
## @return [String] string with @tags highlighted
|
19
17
|
##
|
20
|
-
def highlight_tags(color: '{m}', value: '{y}', parens: '{m}', last_color: '{
|
18
|
+
def highlight_tags(color: '{m}', value: '{y}', parens: '{m}', last_color: '{xg}')
|
21
19
|
tag_color = NA::Color.template(color)
|
22
20
|
paren_color = NA::Color.template(parens)
|
23
21
|
value_color = NA::Color.template(value)
|
24
|
-
gsub(/(\s|m)(@[^ ("']+)(?:(\()(.*?)(\)))?/,
|
22
|
+
gsub(/(\s|m)(@[^ ("']+)(?:(\()(.*?)(\)))?/,
|
23
|
+
"\\1#{tag_color}\\2#{paren_color}\\3#{value_color}\\4#{paren_color}\\5#{last_color}")
|
24
|
+
end
|
25
|
+
|
26
|
+
def highlight_search(regexes, color: '{y}', last_color: '{xg}')
|
27
|
+
string = dup
|
28
|
+
color = NA::Color.template(color)
|
29
|
+
regexes.each do |rx|
|
30
|
+
next if rx.nil?
|
31
|
+
|
32
|
+
rx = Regexp.new(rx.wildcard_to_rx, Regexp::IGNORECASE) if rx.is_a?(String)
|
33
|
+
|
34
|
+
string.gsub!(rx) do
|
35
|
+
m = Regexp.last_match
|
36
|
+
last = m.pre_match.last_color
|
37
|
+
"#{color}#{m[0]}#{NA::Color.template(last)}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
string
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns the last escape sequence from a string.
|
44
|
+
#
|
45
|
+
# Actually returns all escape codes, with the assumption
|
46
|
+
# that the result of inserting them will generate the
|
47
|
+
# same color as was set at the end of the string.
|
48
|
+
# Because you can send modifiers like dark and bold
|
49
|
+
# separate from color codes, only using the last code
|
50
|
+
# may not render the same style.
|
51
|
+
#
|
52
|
+
# @return [String] All escape codes in string
|
53
|
+
#
|
54
|
+
def last_color
|
55
|
+
scan(/\e\[[\d;]+m/).join('').gsub(/\e\[0m/, '')
|
25
56
|
end
|
26
57
|
|
27
58
|
def dir_to_rx
|
28
|
-
split(%r{[/:]}).join('.*?/.*?')
|
59
|
+
"#{split(%r{[/:]}).join('.*?/.*?')}[^/]+$"
|
29
60
|
end
|
30
61
|
|
31
62
|
def dir_matches(any: [], all: [])
|
32
|
-
matches_any(any.map
|
63
|
+
matches_any(any.map(&:dir_to_rx)) && matches_all(all.map(&:dir_to_rx))
|
33
64
|
end
|
34
65
|
|
35
66
|
def matches(any: [], all: [], none: [])
|
36
67
|
matches_any(any) && matches_all(all) && matches_none(none)
|
37
68
|
end
|
38
69
|
|
70
|
+
def wildcard_to_rx
|
71
|
+
gsub(/\./, '\\.').gsub(/\*/, '[^ ]*?').gsub(/\?/, '.')
|
72
|
+
end
|
73
|
+
|
74
|
+
def cap_first!
|
75
|
+
replace cap_first
|
76
|
+
end
|
77
|
+
|
78
|
+
def cap_first
|
79
|
+
sub(/^([a-z])(.*)$/) do
|
80
|
+
m = Regexp.last_match
|
81
|
+
m[1].upcase << m[2]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
39
87
|
def matches_none(regexes)
|
40
88
|
regexes.each do |rx|
|
41
89
|
return false if match(Regexp.new(rx, Regexp::IGNORECASE))
|
@@ -44,7 +92,6 @@ class ::String
|
|
44
92
|
end
|
45
93
|
|
46
94
|
def matches_any(regexes)
|
47
|
-
string = dup
|
48
95
|
regexes.each do |rx|
|
49
96
|
return true if match(Regexp.new(rx, Regexp::IGNORECASE))
|
50
97
|
end
|
@@ -57,19 +104,4 @@ class ::String
|
|
57
104
|
end
|
58
105
|
true
|
59
106
|
end
|
60
|
-
|
61
|
-
def wildcard_to_rx
|
62
|
-
gsub(/\./, '\\.').gsub(/\*/, '.*?').gsub(/\?/, '.')
|
63
|
-
end
|
64
|
-
|
65
|
-
def cap_first!
|
66
|
-
replace cap_first
|
67
|
-
end
|
68
|
-
|
69
|
-
def cap_first
|
70
|
-
sub(/^([a-z])(.*)$/) do
|
71
|
-
m = Regexp.last_match
|
72
|
-
m[1].upcase << m[2]
|
73
|
-
end
|
74
|
-
end
|
75
107
|
end
|
data/lib/na/version.rb
CHANGED
data/src/README.md
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
_If you're one of the rare people like me who find this useful, feel free to
|
10
10
|
[buy me some coffee][donate]._
|
11
11
|
|
12
|
-
The current version of `na` is <!--VER-->1.1.
|
12
|
+
The current version of `na` is <!--VER-->1.1.14<!--END VER-->.
|
13
13
|
|
14
14
|
`na` ("next action") is a command line tool designed to make it easy to see what your next actions are for any project, right from the command line. It works with TaskPaper-formatted files (but any plain text format will do), looking for `@na` tags (or whatever you specify) in todo files in your current folder.
|
15
15
|
|
@@ -36,7 +36,7 @@ You can list next actions in files in the current directory by typing `na`. By d
|
|
36
36
|
|
37
37
|
#### Easy matching
|
38
38
|
|
39
|
-
`na` features intelligent project matching. Every time it locates a todo file, it adds the project to the database. Once a project is recorded, you can list its actions by using any portion of the parent directories or file names. If your project is in `~/Sites/dev/markedapp`, you could quickly list its next actions by typing `na next dev
|
39
|
+
`na` features intelligent project matching. Every time it locates a todo file, it adds the project to the database. Once a project is recorded, you can list its actions by using any portion of the parent directories or file names. If your project is in `~/Sites/dev/markedapp`, you could quickly list its next actions by typing `na next dev/mark`. Creat paths by separating with / or :, separate multiple queries with spaces. na will always look for the shortest match for a path.
|
40
40
|
|
41
41
|
#### Recursion
|
42
42
|
|
@@ -151,6 +151,8 @@ EXAMPLES
|
|
151
151
|
|
152
152
|
Example: `na find cool feature idea`
|
153
153
|
|
154
|
+
Unless `--exact` is specified, search is tokenized and combined with OR, so `na find cool feature idea` translates to `cool OR feature OR idea`, matching any string that contains any of the words. To make a token required, add a `+` before it (e.g. `cool +feature idea` is `(cool OR idea) AND feature`). Wildcards allowed (`*` and `?`), use `--regex` to interpret the search as a regular expression. Use `-v` to invert the results (display non-matching actions only).
|
155
|
+
|
154
156
|
```
|
155
157
|
NAME
|
156
158
|
find - Find actions matching a search pattern
|
@@ -228,7 +230,9 @@ EXAMPLES
|
|
228
230
|
|
229
231
|
##### tagged
|
230
232
|
|
231
|
-
Example: `na tagged feature +maybe
|
233
|
+
Example: `na tagged feature +maybe`.
|
234
|
+
|
235
|
+
Separate multiple tags with spaces or commas. By default tags are combined with OR, so actions matching any of the tags listed will be displayed. Use `+` to make a tag required and `!` to negate a tag (only display if the action does _not_ contain the tag). Use `-v` to invert the search and display all actions that _don't_ match.
|
232
236
|
|
233
237
|
```
|
234
238
|
NAME
|