na 1.1.13 → 1.1.15

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.
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