na 1.2.29 → 1.2.31

Sign up to get free protection for your applications and to get access to all the features.
@@ -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