na 1.2.29 → 1.2.30

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.
@@ -1,146 +1,149 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- desc 'Find actions matching a tag'
4
- long_desc 'Finds actions with tags matching the arguments. An action is shown if it
5
- contains all of the tags listed. Add a + before a tag to make it required
6
- and others optional. You can specify values using TAG=VALUE pairs.
7
- Use <, >, and = for numeric comparisons, and *=, ^=, and $= for text comparisons.
8
- Date comparisons use natural language (`na tagged "due<=today"`) and
9
- are detected automatically.'
10
- arg_name 'TAG[=VALUE]'
11
- command %i[tagged] do |c|
12
- c.example 'na tagged maybe', desc: 'Show all actions tagged @maybe'
13
- c.example 'na tagged -d 3 "feature, idea"', desc: 'Show all actions tagged @feature AND @idea, recurse 3 levels'
14
- c.example 'na tagged --or "feature, idea"', desc: 'Show all actions tagged @feature OR @idea'
15
- c.example 'na tagged "priority>=4"', desc: 'Show actions with @priority(4) or @priority(5)'
16
- c.example 'na tagged "due<in 2 days"', desc: 'Show actions with a due date coming up in the next 2 days'
17
-
18
- c.desc 'Recurse to depth'
19
- c.arg_name 'DEPTH'
20
- c.default_value 1
21
- c.flag %i[d depth], type: :integer, must_match: /^\d+$/
22
-
23
- c.desc 'Show actions from a specific todo file in history. May use wildcards (* and ?)'
24
- c.arg_name 'TODO_PATH'
25
- c.flag %i[in]
26
-
27
- c.desc 'Include notes in output'
28
- c.switch %i[notes], negatable: true, default_value: false
29
-
30
- c.desc 'Combine tags with OR, displaying actions matching ANY of the tags'
31
- c.switch %i[o or], negatable: false
32
-
33
- c.desc 'Show actions from a specific project'
34
- c.arg_name 'PROJECT[/SUBPROJECT]'
35
- c.flag %i[proj project]
36
-
37
- c.desc 'Filter results using search terms'
38
- c.arg_name 'QUERY'
39
- c.flag %i[search], multiple: true
40
-
41
- c.desc 'Search query is regular expression'
42
- c.switch %i[regex], negatable: false
43
-
44
- c.desc 'Search query is exact text match (not tokens)'
45
- c.switch %i[exact], negatable: false
46
-
47
- c.desc 'Include @done actions'
48
- c.switch %i[done]
49
-
50
- c.desc 'Show actions not matching tags'
51
- c.switch %i[v invert], negatable: false
52
-
53
- c.desc 'Save this search for future use'
54
- c.arg_name 'TITLE'
55
- c.flag %i[save]
56
-
57
- c.desc 'Output actions nested by file'
58
- c.switch %[nest], negatable: false
59
-
60
- c.desc 'Output actions nested by file and project'
61
- c.switch %[omnifocus], negatable: false
62
-
63
- c.action do |global_options, options, args|
64
- options[:nest] = true if options[:omnifocus]
65
-
66
- if options[:save]
67
- title = options[:save].gsub(/[^a-z0-9]/, '_').gsub(/_+/, '_')
68
- NA.save_search(title, "#{NA.command_line.join(' ').sub(/ --save[= ]*\S+/, '').split(' ').map { |t| %("#{t}") }.join(' ')}")
69
- end
3
+ class App
4
+ extend GLI::App
5
+ desc 'Find actions matching a tag'
6
+ long_desc 'Finds actions with tags matching the arguments. An action is shown if it
7
+ contains all of the tags listed. Add a + before a tag to make it required
8
+ and others optional. You can specify values using TAG=VALUE pairs.
9
+ Use <, >, and = for numeric comparisons, and *=, ^=, and $= for text comparisons.
10
+ Date comparisons use natural language (`na tagged "due<=today"`) and
11
+ are detected automatically.'
12
+ arg_name 'TAG[=VALUE]'
13
+ command %i[tagged] do |c|
14
+ c.example 'na tagged maybe', desc: 'Show all actions tagged @maybe'
15
+ c.example 'na tagged -d 3 "feature, idea"', desc: 'Show all actions tagged @feature AND @idea, recurse 3 levels'
16
+ c.example 'na tagged --or "feature, idea"', desc: 'Show all actions tagged @feature OR @idea'
17
+ c.example 'na tagged "priority>=4"', desc: 'Show actions with @priority(4) or @priority(5)'
18
+ c.example 'na tagged "due<in 2 days"', desc: 'Show actions with a due date coming up in the next 2 days'
19
+
20
+ c.desc 'Recurse to depth'
21
+ c.arg_name 'DEPTH'
22
+ c.default_value 1
23
+ c.flag %i[d depth], type: :integer, must_match: /^\d+$/
24
+
25
+ c.desc 'Show actions from a specific todo file in history. May use wildcards (* and ?)'
26
+ c.arg_name 'TODO_PATH'
27
+ c.flag %i[in]
28
+
29
+ c.desc 'Include notes in output'
30
+ c.switch %i[notes], negatable: true, default_value: false
31
+
32
+ c.desc 'Combine tags with OR, displaying actions matching ANY of the tags'
33
+ c.switch %i[o or], negatable: false
34
+
35
+ c.desc 'Show actions from a specific project'
36
+ c.arg_name 'PROJECT[/SUBPROJECT]'
37
+ c.flag %i[proj project]
38
+
39
+ c.desc 'Filter results using search terms'
40
+ c.arg_name 'QUERY'
41
+ c.flag %i[search], multiple: true
42
+
43
+ c.desc 'Search query is regular expression'
44
+ c.switch %i[regex], negatable: false
45
+
46
+ c.desc 'Search query is exact text match (not tokens)'
47
+ c.switch %i[exact], negatable: false
48
+
49
+ c.desc 'Include @done actions'
50
+ c.switch %i[done]
51
+
52
+ c.desc 'Show actions not matching tags'
53
+ c.switch %i[v invert], negatable: false
54
+
55
+ c.desc 'Save this search for future use'
56
+ c.arg_name 'TITLE'
57
+ c.flag %i[save]
58
+
59
+ c.desc 'Output actions nested by file'
60
+ c.switch %[nest], negatable: false
61
+
62
+ c.desc 'Output actions nested by file and project'
63
+ c.switch %[omnifocus], negatable: false
64
+
65
+ c.action do |global_options, options, args|
66
+ options[:nest] = true if options[:omnifocus]
67
+
68
+ if options[:save]
69
+ title = options[:save].gsub(/[^a-z0-9]/, '_').gsub(/_+/, '_')
70
+ NA.save_search(title, "#{NA.command_line.join(' ').sub(/ --save[= ]*\S+/, '').split(' ').map { |t| %("#{t}") }.join(' ')}")
71
+ end
70
72
 
71
- depth = if global_options[:recurse] && options[:depth].nil? && global_options[:depth] == 1
72
- 3
73
- else
74
- options[:depth].nil? ? global_options[:depth].to_i : options[:depth].to_i
75
- end
76
-
77
- tags = []
78
-
79
- all_req = args.join(' ') !~ /[+!\-]/ && !options[:or]
80
- args.join(',').split(/ *, */).each do |arg|
81
- m = arg.match(/^(?<req>[+\-!])?(?<tag>[^ =<>$\^]+?)(?:(?<op>[=<>]{1,2}|[*$\^]=)(?<val>.*?))?$/)
82
-
83
- tags.push({
84
- tag: m['tag'].wildcard_to_rx,
85
- comp: m['op'],
86
- value: m['val'],
87
- required: all_req || (!m['req'].nil? && m['req'] == '+'),
88
- negate: !m['req'].nil? && m['req'] =~ /[!\-]/
89
- })
90
- end
73
+ depth = if global_options[:recurse] && options[:depth].nil? && global_options[:depth] == 1
74
+ 3
75
+ else
76
+ options[:depth].nil? ? global_options[:depth].to_i : options[:depth].to_i
77
+ end
91
78
 
92
- search_for_done = false
93
- tags.each { |tag| search_for_done = true if tag[:tag] =~ /done/ }
94
- tags.push({ tag: 'done', value: nil, negate: true}) unless search_for_done
95
-
96
- tokens = nil
97
- if options[:search]
98
- if options[:exact]
99
- tokens = options[:search].join(' ')
100
- elsif options[:regex]
101
- tokens = Regexp.new(options[:search].join(' '), Regexp::IGNORECASE)
102
- else
103
- tokens = []
104
- all_req = options[:search].join(' ') !~ /[+!\-]/ && !options[:or]
105
-
106
- options[:search].join(' ').split(/ /).each do |arg|
107
- m = arg.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
108
- tokens.push({
109
- token: m['tok'],
110
- required: all_req || (!m['req'].nil? && m['req'] == '+'),
111
- negate: !m['req'].nil? && m['req'] =~ /[!\-]/
112
- })
113
- end
114
- end
115
- end
79
+ tags = []
116
80
 
117
- todo = nil
118
- if options[:in]
119
- todo = []
120
- options[:in].split(/ *, */).each do |a|
121
- m = a.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
122
- todo.push({
123
- token: m['tok'],
81
+ all_req = args.join(' ') !~ /[+!\-]/ && !options[:or]
82
+ args.join(',').split(/ *, */).each do |arg|
83
+ m = arg.match(/^(?<req>[+\-!])?(?<tag>[^ =<>$\^]+?)(?:(?<op>[=<>]{1,2}|[*$\^]=)(?<val>.*?))?$/)
84
+
85
+ tags.push({
86
+ tag: m['tag'].wildcard_to_rx,
87
+ comp: m['op'],
88
+ value: m['val'],
124
89
  required: all_req || (!m['req'].nil? && m['req'] == '+'),
125
90
  negate: !m['req'].nil? && m['req'] =~ /[!\-]/
126
91
  })
127
92
  end
128
- end
129
93
 
130
- files, actions, = NA.parse_actions(depth: depth,
131
- done: options[:done],
132
- query: todo,
133
- search: tokens,
134
- tag: tags,
135
- negate: options[:invert],
136
- project: options[:project],
137
- require_na: false)
138
- # regexes = tags.delete_if { |token| token[:negate] }.map { |token| token[:token] }
139
- regexes = if tokens.is_a?(Array)
140
- tokens.delete_if { |token| token[:negate] }.map { |token| token[:token] }
141
- else
142
- [tokens]
143
- end
144
- NA.output_actions(actions, depth, files: files, regexes: regexes, notes: options[:notes], nest: options[:nest], nest_projects: options[:omnifocus])
94
+ search_for_done = false
95
+ tags.each { |tag| search_for_done = true if tag[:tag] =~ /done/ }
96
+ tags.push({ tag: 'done', value: nil, negate: true}) unless search_for_done
97
+
98
+ tokens = nil
99
+ if options[:search]
100
+ if options[:exact]
101
+ tokens = options[:search].join(' ')
102
+ elsif options[:regex]
103
+ tokens = Regexp.new(options[:search].join(' '), Regexp::IGNORECASE)
104
+ else
105
+ tokens = []
106
+ all_req = options[:search].join(' ') !~ /[+!\-]/ && !options[:or]
107
+
108
+ options[:search].join(' ').split(/ /).each do |arg|
109
+ m = arg.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
110
+ tokens.push({
111
+ token: m['tok'],
112
+ required: all_req || (!m['req'].nil? && m['req'] == '+'),
113
+ negate: !m['req'].nil? && m['req'] =~ /[!\-]/
114
+ })
115
+ end
116
+ end
117
+ end
118
+
119
+ todo = nil
120
+ if options[:in]
121
+ todo = []
122
+ options[:in].split(/ *, */).each do |a|
123
+ m = a.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
124
+ todo.push({
125
+ token: m['tok'],
126
+ required: all_req || (!m['req'].nil? && m['req'] == '+'),
127
+ negate: !m['req'].nil? && m['req'] =~ /[!\-]/
128
+ })
129
+ end
130
+ end
131
+
132
+ files, actions, = NA.parse_actions(depth: depth,
133
+ done: options[:done],
134
+ query: todo,
135
+ search: tokens,
136
+ tag: tags,
137
+ negate: options[:invert],
138
+ project: options[:project],
139
+ require_na: false)
140
+ # regexes = tags.delete_if { |token| token[:negate] }.map { |token| token[:token] }
141
+ regexes = if tokens.is_a?(Array)
142
+ tokens.delete_if { |token| token[:negate] }.map { |token| token[:token] }
143
+ else
144
+ [tokens]
145
+ end
146
+ NA.output_actions(actions, depth, files: files, regexes: regexes, notes: options[:notes], nest: options[:nest], nest_projects: options[:omnifocus])
147
+ end
145
148
  end
146
149
  end
@@ -1,28 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- desc 'Show list of known todo files'
4
- long_desc 'Arguments will be interpreted as a query against which the
5
- list of todos will be fuzzy matched. Separate directories with
6
- /, :, or a space, e.g. `na todos code/marked`'
7
- arg_name 'QUERY', optional: true
8
- command %i[todos] do |c|
9
- c.action do |_global_options, _options, args|
10
- if args.count.positive?
11
- all_req = args.join(' ') !~ /[+!\-]/
3
+ class App
4
+ extend GLI::App
5
+ desc 'Show list of known todo files'
6
+ long_desc 'Arguments will be interpreted as a query against which the
7
+ list of todos will be fuzzy matched. Separate directories with
8
+ /, :, or a space, e.g. `na todos code/marked`'
9
+ arg_name 'QUERY', optional: true
10
+ command %i[todos] do |c|
11
+ c.action do |_global_options, _options, args|
12
+ if args.count.positive?
13
+ all_req = args.join(' ') !~ /[+!\-]/
12
14
 
13
- tokens = [{ token: '*', required: all_req, negate: false }]
14
- args.each do |arg|
15
- arg.split(/ *, */).each do |a|
16
- m = a.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
17
- tokens.push({
18
- token: m['tok'],
19
- required: all_req || (!m['req'].nil? && m['req'] == '+'),
20
- negate: !m['req'].nil? && m['req'] =~ /[!\-]/
21
- })
15
+ tokens = [{ token: '*', required: all_req, negate: false }]
16
+ args.each do |arg|
17
+ arg.split(/ *, */).each do |a|
18
+ m = a.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
19
+ tokens.push({
20
+ token: m['tok'],
21
+ required: all_req || (!m['req'].nil? && m['req'] == '+'),
22
+ negate: !m['req'].nil? && m['req'] =~ /[!\-]/
23
+ })
24
+ end
22
25
  end
23
26
  end
24
- end
25
27
 
26
- NA.list_todos(query: tokens)
28
+ NA.list_todos(query: tokens)
29
+ end
27
30
  end
28
31
  end