na 1.2.40 → 1.2.43
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/Gemfile.lock +3 -3
- data/README.md +2 -2
- data/bin/commands/tag.rb +167 -0
- data/lib/na/action.rb +2 -2
- data/lib/na/version.rb +1 -1
- data/src/_README.md +1 -1
- data/test2.txt +7 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04412e8d8032341b954bd7cf3cd576262ca9598ba426e186bf5115183d664ce2
|
4
|
+
data.tar.gz: de6eee0c665411beaf485cd139bb8254cea08f610549bc2c94af2d89e463ab23
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74c57d212cbf93a6b855f81a7abb10c862febb576d39ce4389521b8c2d70a88bbd12532899eee92c814c8d12664cc4a2bb62978792d1b5f8851be465edc1bb86
|
7
|
+
data.tar.gz: e1ccd2d08d24c22aebb1d7542304f6262e8b05b75b1f567d9d6c6c234e2afe37cc306f01a97d374f73fe33cce9ab1cd1dc206b27a5be6dafd51f0e9f67657042
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
na (1.2.
|
4
|
+
na (1.2.43)
|
5
5
|
chronic (~> 0.10, >= 0.10.2)
|
6
6
|
gli (~> 2.21.0)
|
7
7
|
mdless (~> 1.0, >= 1.0.32)
|
@@ -13,8 +13,8 @@ GEM
|
|
13
13
|
remote: https://rubygems.org/
|
14
14
|
specs:
|
15
15
|
chronic (0.10.2)
|
16
|
-
gli (2.21.
|
17
|
-
mdless (1.0.
|
16
|
+
gli (2.21.1)
|
17
|
+
mdless (1.0.35)
|
18
18
|
minitest (5.16.3)
|
19
19
|
rake (0.9.6)
|
20
20
|
rdoc (4.3.0)
|
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.2.
|
12
|
+
The current version of `na` is 1.2.43
|
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.
|
@@ -77,7 +77,7 @@ SYNOPSIS
|
|
77
77
|
na [global options] command [command options] [arguments...]
|
78
78
|
|
79
79
|
VERSION
|
80
|
-
1.2.
|
80
|
+
1.2.43
|
81
81
|
|
82
82
|
GLOBAL OPTIONS
|
83
83
|
-a, --add - Add a next action (deprecated, for backwards compatibility)
|
data/bin/commands/tag.rb
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class App
|
4
|
+
extend GLI::App
|
5
|
+
desc 'Add tags to matching action(s)'
|
6
|
+
long_desc 'Provides an easy way to tag existing actions.
|
7
|
+
|
8
|
+
Use !tag to remove a tag, use ~tag(new value) to change a tag or add a value.
|
9
|
+
|
10
|
+
If multiple todo files are found in the current directory, a menu will
|
11
|
+
allow you to pick which file to act on, or use --all to apply to all matches.'
|
12
|
+
arg_name 'TAG', mutliple: true
|
13
|
+
command %i[tag] do |c|
|
14
|
+
c.example 'na tag "project(warpspeed)" --search "An existing task"',
|
15
|
+
desc: 'Find "An existing task" action and add @project(warpspeed) to it'
|
16
|
+
c.example 'na tag "!project1" --tagged project2 --all',
|
17
|
+
desc: 'Find all actions tagged @project2 and remove @project1 from them'
|
18
|
+
c.example 'na tag "!project2" --all',
|
19
|
+
desc: 'Remove @project2 from all actions'
|
20
|
+
c.example 'na tag "~project(dirt nap)" --search "An existing task"',
|
21
|
+
desc: 'Find "An existing task" and change (or add) its @project tag value to "dirt nap"'
|
22
|
+
|
23
|
+
c.desc 'Use a known todo file, partial matches allowed'
|
24
|
+
c.arg_name 'TODO_FILE'
|
25
|
+
c.flag %i[in todo]
|
26
|
+
|
27
|
+
c.desc 'Include @done actions'
|
28
|
+
c.switch %i[done]
|
29
|
+
|
30
|
+
c.desc 'Specify the file to search for the task'
|
31
|
+
c.arg_name 'PATH'
|
32
|
+
c.flag %i[file]
|
33
|
+
|
34
|
+
c.desc 'Search for files X directories deep'
|
35
|
+
c.arg_name 'DEPTH'
|
36
|
+
c.flag %i[d depth], must_match: /^[1-9]$/, type: :integer, default_value: 1
|
37
|
+
|
38
|
+
c.desc 'Match actions containing tag. Allows value comparisons'
|
39
|
+
c.arg_name 'TAG'
|
40
|
+
c.flag %i[tagged], multiple: true
|
41
|
+
|
42
|
+
c.desc 'Act on all matches immediately (no menu)'
|
43
|
+
c.switch %i[all], negatable: false
|
44
|
+
|
45
|
+
c.desc 'Filter results using search terms'
|
46
|
+
c.arg_name 'QUERY'
|
47
|
+
c.flag %i[search find grep], multiple: true
|
48
|
+
|
49
|
+
c.desc 'Interpret search pattern as regular expression'
|
50
|
+
c.switch %i[e regex], negatable: false
|
51
|
+
|
52
|
+
c.desc 'Match pattern exactly'
|
53
|
+
c.switch %i[x exact], negatable: false
|
54
|
+
|
55
|
+
c.action do |global_options, options, args|
|
56
|
+
tags = args.join(',').split(/ *, */)
|
57
|
+
options[:remove] = []
|
58
|
+
options[:tag] = []
|
59
|
+
tags.each do |tag|
|
60
|
+
if tag =~ /^[!-]/
|
61
|
+
options[:remove] << tag.sub(/^[!-]/, '').sub(/^@/, '')
|
62
|
+
elsif tag =~ /^~/
|
63
|
+
options[:remove] << tag.sub(/^~/, '').sub(/\(.*?\)$/, '').sub(/^@/, '')
|
64
|
+
options[:tag] << tag.sub(/^~/, '').sub(/^@/, '')
|
65
|
+
else
|
66
|
+
options[:tag] << tag.sub(/^@/, '')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
if options[:search]
|
71
|
+
tokens = nil
|
72
|
+
if options[:exact]
|
73
|
+
tokens = options[:search]
|
74
|
+
elsif options[:regex]
|
75
|
+
tokens = Regexp.new(options[:search], Regexp::IGNORECASE)
|
76
|
+
else
|
77
|
+
action = options[:search].join(' ')
|
78
|
+
tokens = []
|
79
|
+
all_req = action !~ /[+!-]/ && !options[:or]
|
80
|
+
|
81
|
+
action.split(/ /).each do |arg|
|
82
|
+
m = arg.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
|
83
|
+
tokens.push({
|
84
|
+
token: m['tok'],
|
85
|
+
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
86
|
+
negate: !m['req'].nil? && m['req'] =~ /[!-]/ ? true : false
|
87
|
+
})
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
if (tokens.nil? || tokens.empty?) && options[:tagged].empty?
|
93
|
+
NA.notify("#{NA.theme[:error]}Empty input, cancelled", exit_code: 1)
|
94
|
+
end
|
95
|
+
|
96
|
+
all_req = options[:tagged].join(' ') !~ /[+!-]/ && !options[:or]
|
97
|
+
tags = []
|
98
|
+
options[:tagged].join(',').split(/ *, */).each do |arg|
|
99
|
+
m = arg.match(/^(?<req>[+!-])?(?<tag>[^ =<>$~\^]+?) *(?:(?<op>[=<>~]{1,2}|[*$\^]=) *(?<val>.*?))?$/)
|
100
|
+
|
101
|
+
tags.push({
|
102
|
+
tag: m['tag'].wildcard_to_rx,
|
103
|
+
comp: m['op'],
|
104
|
+
value: m['val'],
|
105
|
+
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
106
|
+
negate: !m['req'].nil? && m['req'] =~ /[!-]/ ? true : false
|
107
|
+
})
|
108
|
+
end
|
109
|
+
|
110
|
+
add_tags = options[:tag] ? options[:tag].join(',').split(/ *, */).map { |t| t.sub(/^@/, '').wildcard_to_rx } : []
|
111
|
+
remove_tags = options[:remove] ? options[:remove].join(',').split(/ *, */).map { |t| t.sub(/^@/, '').wildcard_to_rx } : []
|
112
|
+
|
113
|
+
if options[:file]
|
114
|
+
file = File.expand_path(options[:file])
|
115
|
+
NA.notify("#{NA.theme[:error]}File not found", exit_code: 1) unless File.exist?(file)
|
116
|
+
|
117
|
+
targets = [file]
|
118
|
+
elsif options[:todo]
|
119
|
+
todo = []
|
120
|
+
options[:todo].split(/ *, */).each do |a|
|
121
|
+
m = a.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
|
122
|
+
todo.push({
|
123
|
+
token: m['tok'],
|
124
|
+
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
125
|
+
negate: !m['req'].nil? && m['req'] =~ /[!-]/ ? true : false
|
126
|
+
})
|
127
|
+
end
|
128
|
+
dirs = NA.match_working_dir(todo)
|
129
|
+
|
130
|
+
if dirs.count == 1
|
131
|
+
targets = [dirs[0]]
|
132
|
+
elsif dirs.count.positive?
|
133
|
+
targets = NA.select_file(dirs, multiple: true)
|
134
|
+
NA.notify("#{NA.theme[:error]}Cancelled", exit_code: 1) unless targets && targets.count.positive?
|
135
|
+
else
|
136
|
+
NA.notify("#{NA.theme[:error]}Todo not found", exit_code: 1) unless targets && targets.count.positive?
|
137
|
+
|
138
|
+
end
|
139
|
+
else
|
140
|
+
files = NA.find_files_matching({
|
141
|
+
depth: options[:depth],
|
142
|
+
done: options[:done],
|
143
|
+
regex: options[:regex],
|
144
|
+
require_na: false,
|
145
|
+
search: tokens,
|
146
|
+
tag: tags
|
147
|
+
})
|
148
|
+
NA.notify("#{NA.theme[:error]}No todo file found", exit_code: 1) if files.count.zero?
|
149
|
+
|
150
|
+
targets = files.count > 1 ? NA.select_file(files, multiple: true) : [files[0]]
|
151
|
+
NA.notify("#{NA.theme[:error]}Cancelled", exit_code: 1) unless files.count.positive?
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
NA.notify("#{NA.theme[:error]}No search terms provided", exit_code: 1) if tokens.nil? && options[:tagged].empty?
|
156
|
+
|
157
|
+
targets.each do |target|
|
158
|
+
NA.update_action(target, tokens,
|
159
|
+
add_tag: add_tags,
|
160
|
+
all: options[:all],
|
161
|
+
done: options[:done],
|
162
|
+
remove_tag: remove_tags,
|
163
|
+
tagged: tags)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
data/lib/na/action.rb
CHANGED
@@ -110,13 +110,13 @@ module NA
|
|
110
110
|
|
111
111
|
if detect_width
|
112
112
|
width = TTY::Screen.columns
|
113
|
-
prefix = NA::Color.uncolor(pretty(template: { output: template[:templates][:output].sub(/%action/, '') }, detect_width: false))
|
113
|
+
prefix = NA::Color.uncolor(pretty(template: { templates: { output: template[:templates][:output].sub(/%action/, '') } }, detect_width: false))
|
114
114
|
indent = prefix.length
|
115
115
|
action = action.wrap(width, indent)
|
116
116
|
end
|
117
117
|
|
118
118
|
# Replace variables in template string and output colorized
|
119
|
-
NA::Color.template(template[:output].gsub(/%filename/, filename)
|
119
|
+
NA::Color.template(template[:templates][:output].gsub(/%filename/, filename)
|
120
120
|
.gsub(/%project/, project)
|
121
121
|
.gsub(/%parents?/, parents)
|
122
122
|
.gsub(/%action/, action.highlight_search(regexes))
|
data/lib/na/version.rb
CHANGED
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.2.
|
12
|
+
The current version of `na` is <!--VER-->1.2.41<!--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
|
|
data/test2.txt
ADDED
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.2.
|
4
|
+
version: 1.2.43
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brett Terpstra
|
@@ -220,6 +220,7 @@ files:
|
|
220
220
|
- bin/commands/prompt.rb
|
221
221
|
- bin/commands/restore.rb
|
222
222
|
- bin/commands/saved.rb
|
223
|
+
- bin/commands/tag.rb
|
223
224
|
- bin/commands/tagged.rb
|
224
225
|
- bin/commands/todos.rb
|
225
226
|
- bin/commands/undo.rb
|
@@ -245,6 +246,7 @@ files:
|
|
245
246
|
- na.rdoc
|
246
247
|
- scripts/fixreadme.rb
|
247
248
|
- src/_README.md
|
249
|
+
- test2.txt
|
248
250
|
homepage: https://brettterpstra.com/projects/na/
|
249
251
|
licenses:
|
250
252
|
- MIT
|
@@ -271,7 +273,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
271
273
|
- !ruby/object:Gem::Version
|
272
274
|
version: '0'
|
273
275
|
requirements: []
|
274
|
-
rubygems_version: 3.
|
276
|
+
rubygems_version: 3.4.0.dev
|
275
277
|
signing_key:
|
276
278
|
specification_version: 4
|
277
279
|
summary: A command line tool for adding and listing project todos
|