na 1.1.13 → 1.1.14

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: 2324b729bcc5e20eab3e063427fa5c6480274ea844fe72117e7f25c7e9801764
4
+ data.tar.gz: 68d00ee26f320e14afd0e6a72a072b2cf30c82beaaf7818962b90e7fa0884914
5
5
  SHA512:
6
- metadata.gz: e577876361f3022e29d4c56e06d7c507fe05ac81da752debe476b481f92f671ee85ab25cb06e32a0608baf1b926454ea4e68aa6391e32ee7c5e7e02a5751dd11
7
- data.tar.gz: 660039f2b13e23365ffa88fa8a59266f50941275830175458f867a26bfcbcd3553c8e5dc6ef70da1d1ab5946fc9d7a3361bdf932f8d63eda23c3c692657a5074
6
+ metadata.gz: b6b7fd0066ba41b9fa184ab3231cb8d7b68e68526bc380f21f2b12048de1c4a4eae24d2da8e47abe95c2389536e90ee32fa35ebdf786570745b8153c72d65e4a
7
+ data.tar.gz: 320264ba4f636f8a68804f7767bd09a4c2105adf684b603514d933003f06f72e2cebb978476a659c2a7ee716fbdaadf7f9fd507c3985ec2dc870162da2751414
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ### 1.1.14
2
+
3
+ 2022-10-06 12:30
4
+
5
+ #### IMPROVED
6
+
7
+ - Code cleanup
8
+ - Highlight search terms in results
9
+
10
+ #### FIXED
11
+
12
+ - Multiple search terms overriding each other
13
+
1
14
  ### 1.1.13
2
15
 
3
16
  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.14)
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.14
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,7 +269,7 @@ class App
269
269
  tokens = Regexp.new(args.join(' '), Regexp::IGNORECASE)
270
270
  else
271
271
  tokens = []
272
- args.each do |arg|
272
+ args.join(' ').split(/ /).each do |arg|
273
273
  m = arg.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
274
274
  tokens.push({
275
275
  token: m['tok'],
@@ -285,7 +285,8 @@ class App
285
285
  regex: options[:regex],
286
286
  project: options[:project],
287
287
  require_na: false)
288
- NA.output_actions(actions, depth, files: files)
288
+ regexes = tokens.delete_if { |token| token[:negate] }.map { |token| token[:token] }
289
+ NA.output_actions(actions, depth, files: files, regexes: regexes)
289
290
  end
290
291
  end
291
292
 
@@ -336,7 +337,8 @@ class App
336
337
  negate: options[:invert],
337
338
  project: options[:project],
338
339
  require_na: false)
339
- NA.output_actions(actions, depth, files: files)
340
+ regexes = tags.delete_if { |token| token[:negate] }.map { |token| token[:token] }
341
+ NA.output_actions(actions, depth, files: files, regexes: regexes)
340
342
  end
341
343
  end
342
344
 
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
  ##
@@ -21,21 +19,65 @@ class ::String
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}')
27
+ string = dup
28
+ color = NA::Color.template(color)
29
+ regexes.each do |rx|
30
+ next if rx.nil?
31
+
32
+ string.gsub!(/(#{rx.wildcard_to_rx})/i, "#{color}\\1#{NA::Color.template('{xg}')}")
33
+ end
34
+ string
35
+ end
36
+
37
+ # Returns the last escape sequence from a string.
38
+ #
39
+ # Actually returns all escape codes, with the assumption
40
+ # that the result of inserting them will generate the
41
+ # same color as was set at the end of the string.
42
+ # Because you can send modifiers like dark and bold
43
+ # separate from color codes, only using the last code
44
+ # may not render the same style.
45
+ #
46
+ # @return [String] All escape codes in string
47
+ #
48
+ def last_color
49
+ scan(/\e\[[\d;]+m/).join('').gsub(/\e\[0m/, '')
25
50
  end
26
51
 
27
52
  def dir_to_rx
28
- split(%r{[/:]}).join('.*?/.*?') + '[^/]+$'
53
+ "#{split(%r{[/:]}).join('.*?/.*?')}[^/]+$"
29
54
  end
30
55
 
31
56
  def dir_matches(any: [], all: [])
32
- matches_any(any.map { |token| token.dir_to_rx }) && matches_all(all.map { |token| token.dir_to_rx })
57
+ matches_any(any.map(&:dir_to_rx)) && matches_all(all.map(&:dir_to_rx))
33
58
  end
34
59
 
35
60
  def matches(any: [], all: [], none: [])
36
61
  matches_any(any) && matches_all(all) && matches_none(none)
37
62
  end
38
63
 
64
+ def wildcard_to_rx
65
+ gsub(/\./, '\\.').gsub(/\*/, '.*?').gsub(/\?/, '.')
66
+ end
67
+
68
+ def cap_first!
69
+ replace cap_first
70
+ end
71
+
72
+ def cap_first
73
+ sub(/^([a-z])(.*)$/) do
74
+ m = Regexp.last_match
75
+ m[1].upcase << m[2]
76
+ end
77
+ end
78
+
79
+ private
80
+
39
81
  def matches_none(regexes)
40
82
  regexes.each do |rx|
41
83
  return false if match(Regexp.new(rx, Regexp::IGNORECASE))
@@ -44,7 +86,6 @@ class ::String
44
86
  end
45
87
 
46
88
  def matches_any(regexes)
47
- string = dup
48
89
  regexes.each do |rx|
49
90
  return true if match(Regexp.new(rx, Regexp::IGNORECASE))
50
91
  end
@@ -57,19 +98,4 @@ class ::String
57
98
  end
58
99
  true
59
100
  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
101
  end
data/lib/na/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Na
2
- VERSION = '1.1.13'
2
+ VERSION = '1.1.14'
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.13<!--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.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra