na 1.1.13 → 1.1.14

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