na 1.2.34 → 1.2.35
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 +4 -4
- data/CHANGELOG.md +17 -0
- data/Gemfile.lock +1 -1
- data/README.md +3 -3
- data/bin/commands/complete.rb +5 -1
- data/bin/commands/find.rb +28 -8
- data/bin/commands/restore.rb +5 -1
- data/bin/commands/tagged.rb +7 -3
- data/lib/na/action.rb +18 -1
- data/lib/na/next_action.rb +10 -2
- data/lib/na/version.rb +1 -1
- data/src/_README.md +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1f8982f5720115576a78ab96a430d1d83f501bb1b477b2cff1a694648a186afc
|
|
4
|
+
data.tar.gz: 86dd520a3265473471b6d09fc05136dd07b53ded24ab2c82936074fa50595b67
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7ea9bb861c82251c1ec52925d6527f0e4efa1eef0175d268b8a8bb307fafcc407dc888e5e5cd6d588e5e4a500a96ae64765106f23d9c4acda6e0667c71247d62
|
|
7
|
+
data.tar.gz: e5f603160851411f66dd50ae47a65369aaa1e51352cf2eb6313674d95d64db8914d3a870f816dcc4303fbd5b4e675f213020fa6a7fd93805af4692f04eb99aed
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
### 1.2.35
|
|
2
|
+
|
|
3
|
+
2023-08-30 11:59
|
|
4
|
+
|
|
5
|
+
#### IMPROVED
|
|
6
|
+
|
|
7
|
+
- If a search string contains @tags and --exact or --regex isn't specified, the @tags will be extracted and passed as a --tagged search.
|
|
8
|
+
- Tag handling (including values and comparisons) in tags extracted from search strings
|
|
9
|
+
- `na complete --project PROJ` flag to move to a specific project
|
|
10
|
+
- `na restore --project PROJ` flag to move restored action to
|
|
11
|
+
- Exit gracefully if tagged command is run with invalid
|
|
12
|
+
- Display action affected when using update command
|
|
13
|
+
|
|
14
|
+
#### FIXED
|
|
15
|
+
|
|
16
|
+
- Escape search for tokens to allow parenthesis and other
|
|
17
|
+
|
|
1
18
|
### 1.2.34
|
|
2
19
|
|
|
3
20
|
2023-08-30 09:22
|
data/Gemfile.lock
CHANGED
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.35
|
|
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.35
|
|
81
81
|
|
|
82
82
|
GLOBAL OPTIONS
|
|
83
83
|
-a, --add - Add a next action (deprecated, for backwards compatibility)
|
|
@@ -104,7 +104,7 @@ COMMANDS
|
|
|
104
104
|
complete, finish - Find and mark an action as @done
|
|
105
105
|
completed, finished - Display completed actions
|
|
106
106
|
edit - Edit an existing action
|
|
107
|
-
find, grep
|
|
107
|
+
find, grep, search - Find actions matching a search pattern
|
|
108
108
|
help - Shows a list of commands or help for one command
|
|
109
109
|
init, create - Create a new todo file in the current directory
|
|
110
110
|
initconfig - Initialize the config file using current global options
|
data/bin/commands/complete.rb
CHANGED
|
@@ -20,6 +20,10 @@ class App
|
|
|
20
20
|
c.desc 'Add a @done tag to action and move to Archive'
|
|
21
21
|
c.switch %i[a archive], negatable: false
|
|
22
22
|
|
|
23
|
+
c.desc 'Move action to specific project'
|
|
24
|
+
c.arg_name 'PROJECT'
|
|
25
|
+
c.flag %i[to project proj]
|
|
26
|
+
|
|
23
27
|
c.desc 'Specify the file to search for the task'
|
|
24
28
|
c.arg_name 'PATH'
|
|
25
29
|
c.flag %i[file]
|
|
@@ -44,7 +48,7 @@ class App
|
|
|
44
48
|
c.action do |global, options, args|
|
|
45
49
|
options[:finish] = true
|
|
46
50
|
options[:f] = true
|
|
47
|
-
options[:project] = 'Archive' if options[:archive]
|
|
51
|
+
options[:project] = 'Archive' if options[:archive] && !options[:project]
|
|
48
52
|
|
|
49
53
|
cmd = commands[:update]
|
|
50
54
|
action = cmd.send(:get_action, nil)
|
data/bin/commands/find.rb
CHANGED
|
@@ -7,7 +7,7 @@ class App
|
|
|
7
7
|
(partial matches allowed). Add a + before a token to make it required, e.g. `na find +feature +maybe`,
|
|
8
8
|
add a - or ! to ignore matches containing that token.'
|
|
9
9
|
arg_name 'PATTERN'
|
|
10
|
-
command %i[find grep] do |c|
|
|
10
|
+
command %i[find grep search] do |c|
|
|
11
11
|
c.example 'na find feature idea swift', desc: 'Find all actions containing feature, idea, and swift'
|
|
12
12
|
c.example 'na find feature idea -swift', desc: 'Find all actions containing feature and idea but NOT swift'
|
|
13
13
|
c.example 'na find -x feature idea', desc: 'Find all actions containing the exact text "feature idea"'
|
|
@@ -64,17 +64,33 @@ class App
|
|
|
64
64
|
NA.save_search(title, "#{NA.command_line.join(' ').sub(/ --save[= ]*\S+/, '').split(' ').map { |t| %("#{t}") }.join(' ')}")
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
-
|
|
68
67
|
depth = if global_options[:recurse] && options[:depth].nil? && global_options[:depth] == 1
|
|
69
68
|
3
|
|
70
69
|
else
|
|
71
70
|
options[:depth].nil? ? global_options[:depth].to_i : options[:depth].to_i
|
|
72
71
|
end
|
|
73
72
|
|
|
73
|
+
if options[:exact] || options[:regex]
|
|
74
|
+
search = args.join(' ')
|
|
75
|
+
else
|
|
76
|
+
search = args.join(' ').gsub(/(?<=\A|[ ,])(?<req>[+\-!])?@(?<tag>[^ *=<>$\^,@(]+)(?:\((?<value>.*?)\)| *(?<op>[=<>]{1,2}|[*$\^]=) *(?<val>.*?(?=\Z|[,@])))?/) do |arg|
|
|
77
|
+
m = Regexp.last_match
|
|
78
|
+
string = if m['value']
|
|
79
|
+
"#{m['req']}#{m['tag']}=#{m['value']}"
|
|
80
|
+
else
|
|
81
|
+
m[0]
|
|
82
|
+
end
|
|
83
|
+
options[:tagged] << string.sub(/@/, '')
|
|
84
|
+
''
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
search = search.gsub(/ +/, ' ').strip
|
|
89
|
+
|
|
74
90
|
all_req = options[:tagged].join(' ') !~ /[+!\-]/ && !options[:or]
|
|
75
91
|
tags = []
|
|
76
92
|
options[:tagged].join(',').split(/ *, */).each do |arg|
|
|
77
|
-
m = arg.match(/^(?<req>[+\-!])?(?<tag>[^ =<>$\^]+?)(?:(?<op>[=<>]{1,2}|[*$\^]=)(?<val>.*?))?$/)
|
|
93
|
+
m = arg.match(/^(?<req>[+\-!])?(?<tag>[^ =<>$\^]+?) *(?:(?<op>[=<>]{1,2}|[*$\^]=) *(?<val>.*?))?$/)
|
|
78
94
|
|
|
79
95
|
tags.push({
|
|
80
96
|
tag: m['tag'].wildcard_to_rx,
|
|
@@ -85,19 +101,23 @@ class App
|
|
|
85
101
|
})
|
|
86
102
|
end
|
|
87
103
|
|
|
104
|
+
search_for_done = false
|
|
105
|
+
tags.each { |tag| search_for_done = true if tag[:tag] =~ /done/ }
|
|
106
|
+
options[:done] = true if search_for_done
|
|
107
|
+
|
|
88
108
|
tokens = nil
|
|
89
109
|
if options[:exact]
|
|
90
|
-
tokens =
|
|
110
|
+
tokens = search
|
|
91
111
|
elsif options[:regex]
|
|
92
|
-
tokens = Regexp.new(
|
|
112
|
+
tokens = Regexp.new(search, Regexp::IGNORECASE)
|
|
93
113
|
else
|
|
94
114
|
tokens = []
|
|
95
|
-
all_req =
|
|
115
|
+
all_req = search !~ /[+!\-]/ && !options[:or]
|
|
96
116
|
|
|
97
|
-
|
|
117
|
+
search.split(/ /).each do |arg|
|
|
98
118
|
m = arg.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
|
|
99
119
|
tokens.push({
|
|
100
|
-
token: m['tok'],
|
|
120
|
+
token: Regexp.escape(m['tok']),
|
|
101
121
|
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
|
102
122
|
negate: !m['req'].nil? && m['req'] =~ /[!\-]/
|
|
103
123
|
})
|
data/bin/commands/restore.rb
CHANGED
|
@@ -17,6 +17,10 @@ class App
|
|
|
17
17
|
c.desc 'Overwrite note instead of appending'
|
|
18
18
|
c.switch %i[o overwrite], negatable: false
|
|
19
19
|
|
|
20
|
+
c.desc 'Move action to specific project'
|
|
21
|
+
c.arg_name 'PROJECT'
|
|
22
|
+
c.flag %i[to project proj]
|
|
23
|
+
|
|
20
24
|
c.desc 'Specify the file to search for the task'
|
|
21
25
|
c.arg_name 'PATH'
|
|
22
26
|
c.flag %i[file]
|
|
@@ -43,7 +47,7 @@ class App
|
|
|
43
47
|
options[:done] = true
|
|
44
48
|
options[:finish] = false
|
|
45
49
|
options[:f] = false
|
|
46
|
-
|
|
50
|
+
|
|
47
51
|
cmd = commands[:update]
|
|
48
52
|
action = cmd.send(:get_action, nil)
|
|
49
53
|
action.call(global, options, args)
|
data/bin/commands/tagged.rb
CHANGED
|
@@ -80,10 +80,11 @@ class App
|
|
|
80
80
|
|
|
81
81
|
all_req = args.join(' ') !~ /[+!\-]/ && !options[:or]
|
|
82
82
|
args.join(',').split(/ *, */).each do |arg|
|
|
83
|
-
m = arg.match(/^(?<req>[+\-!])?(?<tag>[^ =<>$\^]+?)(?:(?<op>[=<>]{1,2}|[*$\^]=)(?<val>.*?))?$/)
|
|
83
|
+
m = arg.match(/^(?<req>[+\-!])?(?<tag>[^ =<>$\^]+?) *(?:(?<op>[=<>]{1,2}|[*$\^]=) *(?<val>.*?))?$/)
|
|
84
|
+
next if m.nil?
|
|
84
85
|
|
|
85
86
|
tags.push({
|
|
86
|
-
tag: m['tag'].wildcard_to_rx,
|
|
87
|
+
tag: m['tag'].sub(/^@/, '').wildcard_to_rx,
|
|
87
88
|
comp: m['op'],
|
|
88
89
|
value: m['val'],
|
|
89
90
|
required: all_req || (!m['req'].nil? && m['req'] == '+'),
|
|
@@ -93,7 +94,8 @@ class App
|
|
|
93
94
|
|
|
94
95
|
search_for_done = false
|
|
95
96
|
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
|
+
tags.push({ tag: 'done', value: nil, negate: true}) unless search_for_done || options[:done]
|
|
98
|
+
options[:done] = true if search_for_done
|
|
97
99
|
|
|
98
100
|
tokens = nil
|
|
99
101
|
if options[:search]
|
|
@@ -129,6 +131,8 @@ class App
|
|
|
129
131
|
end
|
|
130
132
|
end
|
|
131
133
|
|
|
134
|
+
NA.notify('{br}No actions matched search', exit_code: 1) if tags.empty? && tokens.empty?
|
|
135
|
+
|
|
132
136
|
files, actions, = NA.parse_actions(depth: depth,
|
|
133
137
|
done: options[:done],
|
|
134
138
|
query: todo,
|
data/lib/na/action.rb
CHANGED
|
@@ -37,7 +37,18 @@ module NA
|
|
|
37
37
|
EOINSPECT
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
##
|
|
41
|
+
## Pretty print an action
|
|
42
|
+
##
|
|
43
|
+
## @param extension [String] The file extension
|
|
44
|
+
## @param template [Hash] The template to use for
|
|
45
|
+
## colorization
|
|
46
|
+
## @param regexes [Array] The regexes to
|
|
47
|
+
## highlight (searches)
|
|
48
|
+
## @param notes [Boolean] Include notes
|
|
49
|
+
##
|
|
40
50
|
def pretty(extension: 'taskpaper', template: {}, regexes: [], notes: false)
|
|
51
|
+
# Default colorization, can be overridden with full or partial template variable
|
|
41
52
|
default_template = {
|
|
42
53
|
file: '{xbk}',
|
|
43
54
|
parent: '{c}',
|
|
@@ -51,32 +62,38 @@ module NA
|
|
|
51
62
|
note: '{dw}'
|
|
52
63
|
}
|
|
53
64
|
template = default_template.merge(template)
|
|
54
|
-
|
|
65
|
+
# Create the hierarchical parent string
|
|
55
66
|
parents = @parent.map do |par|
|
|
56
67
|
NA::Color.template("#{template[:parent]}#{par}")
|
|
57
68
|
end.join(NA::Color.template(template[:parent_divider]))
|
|
58
69
|
parents = "{dc}[{x}#{parents}{dc}]{x} "
|
|
59
70
|
|
|
71
|
+
# Create the project string
|
|
60
72
|
project = NA::Color.template("#{template[:project]}#{@project}{x} ")
|
|
61
73
|
|
|
74
|
+
# Create the source filename string, substituting ~ for HOME and removing extension
|
|
62
75
|
file = @file.sub(%r{^\./}, '').sub(/#{ENV['HOME']}/, '~')
|
|
63
76
|
file = file.sub(/\.#{extension}$/, '')
|
|
77
|
+
# colorize the basename
|
|
64
78
|
file = file.sub(/#{File.basename(@file, ".#{extension}")}$/, "{dw}#{File.basename(@file, ".#{extension}")}{x}")
|
|
65
79
|
file_tpl = "#{template[:file]}#{file} {x}"
|
|
66
80
|
filename = NA::Color.template(file_tpl)
|
|
67
81
|
|
|
82
|
+
# Add notes if needed
|
|
68
83
|
note = if notes && @note.count.positive?
|
|
69
84
|
NA::Color.template("\n#{@note.map { |l| " #{template[:note]}• #{l}{x}" }.join("\n")}")
|
|
70
85
|
else
|
|
71
86
|
''
|
|
72
87
|
end
|
|
73
88
|
|
|
89
|
+
# colorize the action and highlight tags
|
|
74
90
|
action = NA::Color.template("#{template[:action]}#{@action.sub(/ @#{NA.na_tag}\b/, '')}{x}")
|
|
75
91
|
action = action.highlight_tags(color: template[:tags],
|
|
76
92
|
parens: template[:value_parens],
|
|
77
93
|
value: template[:values],
|
|
78
94
|
last_color: template[:action])
|
|
79
95
|
|
|
96
|
+
# Replace variables in template string and output colorized
|
|
80
97
|
NA::Color.template(template[:output].gsub(/%filename/, filename)
|
|
81
98
|
.gsub(/%project/, project)
|
|
82
99
|
.gsub(/%parents?/, parents)
|
data/lib/na/next_action.rb
CHANGED
|
@@ -420,7 +420,7 @@ module NA
|
|
|
420
420
|
projects.select { |proj| proj.project =~ /^#{action.parent.join(':')}$/ }.first
|
|
421
421
|
end
|
|
422
422
|
|
|
423
|
-
NA.notify("{r}Error parsing project #{
|
|
423
|
+
NA.notify("{r}Error parsing project #{target}", exit_code: 1) if target_proj.nil?
|
|
424
424
|
|
|
425
425
|
indent = "\t" * target_proj.indent
|
|
426
426
|
note = note.split("\n") unless note.is_a?(Array)
|
|
@@ -450,6 +450,8 @@ module NA
|
|
|
450
450
|
end
|
|
451
451
|
|
|
452
452
|
contents.insert(target_line, "#{indent}\t- #{action.action}#{note}")
|
|
453
|
+
|
|
454
|
+
notify(action.pretty)
|
|
453
455
|
else
|
|
454
456
|
_, actions = find_actions(target, search, tagged, done: done, all: all)
|
|
455
457
|
|
|
@@ -502,7 +504,10 @@ module NA
|
|
|
502
504
|
target_line = target_proj.line + 1
|
|
503
505
|
end
|
|
504
506
|
|
|
507
|
+
|
|
505
508
|
contents.insert(target_line, "#{indent}\t- #{action.action}#{note}")
|
|
509
|
+
|
|
510
|
+
notify(action.pretty)
|
|
506
511
|
end
|
|
507
512
|
end
|
|
508
513
|
|
|
@@ -692,6 +697,9 @@ module NA
|
|
|
692
697
|
negated_tag = []
|
|
693
698
|
projects = []
|
|
694
699
|
|
|
700
|
+
notify("{dw}Tags: #{tag}", debug:true)
|
|
701
|
+
notify("{dw}Search: #{search}", debug:true)
|
|
702
|
+
|
|
695
703
|
tag&.each do |t|
|
|
696
704
|
unless t[:tag].nil?
|
|
697
705
|
if negate
|
|
@@ -706,7 +714,7 @@ module NA
|
|
|
706
714
|
end
|
|
707
715
|
end
|
|
708
716
|
|
|
709
|
-
unless search.nil?
|
|
717
|
+
unless search.nil? || search.empty?
|
|
710
718
|
if regex || search.is_a?(String)
|
|
711
719
|
if negate
|
|
712
720
|
negated.push(search)
|
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.34<!--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
|
|