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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 03c240ef72b49cbb692ba1f55da9a36036d72bd51bb29549ea87262cceedfd51
4
- data.tar.gz: e61a921f6af384ae5615f54116cb4e4e0c9472ab76d4a347fc50ea5633fc80a3
3
+ metadata.gz: d39a0b804774a7d07c6a1154e536798bdc2f09c20e76aa2ca776cc5111c02534
4
+ data.tar.gz: 66e180d9cf673293e2721d83c8187b06746e352252c7fb1575be33032c088b89
5
5
  SHA512:
6
- metadata.gz: e577876361f3022e29d4c56e06d7c507fe05ac81da752debe476b481f92f671ee85ab25cb06e32a0608baf1b926454ea4e68aa6391e32ee7c5e7e02a5751dd11
7
- data.tar.gz: 660039f2b13e23365ffa88fa8a59266f50941275830175458f867a26bfcbcd3553c8e5dc6ef70da1d1ab5946fc9d7a3361bdf932f8d63eda23c3c692657a5074
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- na (1.1.13)
4
+ na (1.1.15)
5
5
  gli (~> 2.21.0)
6
6
  tty-reader (~> 0.9, >= 0.9.0)
7
7
  tty-screen (~> 0.8, >= 0.8.1)
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.13
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 mark`. It will always look for the shortest match.
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.each do |arg|
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
- NA.output_actions(actions, depth, files: files)
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
- NA.output_actions(actions, depth, files: files)
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: [])
@@ -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
- template = if files&.count.positive?
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
- puts actions.map { |action| action.pretty(template: { output: template }) }
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
- optional, required, negated = parse_search(t, negate)
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
- tabs = prefix[1].gsub(/ /, "\t").scan(/\t/).count
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: '{g}')
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)(@[^ ("']+)(?:(\()(.*?)(\)))?/, "\\1#{tag_color}\\2#{paren_color}\\3#{value_color}\\4#{paren_color}\\5#{last_color}")
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 { |token| token.dir_to_rx }) && matches_all(all.map { |token| token.dir_to_rx })
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
@@ -1,3 +1,3 @@
1
1
  module Na
2
- VERSION = '1.1.13'
2
+ VERSION = '1.1.15'
3
3
  end
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<!--END VER-->.
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 mark`. It will always look for the shortest match.
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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: na
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.13
4
+ version: 1.1.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra