na 1.2.35 → 1.2.37
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +28 -0
- data/Gemfile.lock +1 -1
- data/README.md +79 -2
- data/bin/commands/complete.rb +4 -0
- data/bin/commands/edit.rb +6 -5
- data/bin/commands/find.rb +27 -19
- data/bin/commands/next.rb +22 -18
- data/bin/commands/prompt.rb +2 -0
- data/bin/commands/tagged.rb +32 -25
- data/bin/commands/todos.rb +3 -3
- data/bin/commands/undo.rb +22 -0
- data/bin/commands/update.rb +12 -2
- data/lib/na/action.rb +27 -1
- data/lib/na/actions.rb +87 -0
- data/lib/na/editor.rb +123 -0
- data/lib/na/next_action.rb +203 -471
- data/lib/na/todo.rb +183 -0
- data/lib/na/version.rb +1 -1
- data/lib/na.rb +3 -0
- data/src/_README.md +36 -12
- metadata +6 -2
data/lib/na/todo.rb
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NA
|
4
|
+
class Todo
|
5
|
+
attr_accessor :actions, :projects, :files
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@files, @actions, @projects = parse(options)
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
## Read a todo file and create a list of actions
|
13
|
+
##
|
14
|
+
## @param options The options
|
15
|
+
##
|
16
|
+
## @option depth [Number] The directory depth to
|
17
|
+
## search for files
|
18
|
+
## @option done [Boolean] include @done actions
|
19
|
+
## @option query [Hash] The todo file query
|
20
|
+
## @option tag [Array] Tags to search for
|
21
|
+
## @option search [String] A search string
|
22
|
+
## @option negate [Boolean] Invert results
|
23
|
+
## @option regex [Boolean] Interpret as regular
|
24
|
+
## expression
|
25
|
+
## @option project [String] The project
|
26
|
+
## @option require_na [Boolean] Require @na tag
|
27
|
+
## @option file_path [String] file path to parse
|
28
|
+
##
|
29
|
+
def parse(options)
|
30
|
+
defaults = {
|
31
|
+
depth: 1,
|
32
|
+
done: false,
|
33
|
+
file_path: nil,
|
34
|
+
negate: false,
|
35
|
+
project: nil,
|
36
|
+
query: nil,
|
37
|
+
regex: false,
|
38
|
+
require_na: true,
|
39
|
+
search: nil,
|
40
|
+
tag: nil
|
41
|
+
}
|
42
|
+
|
43
|
+
settings = defaults.merge(options)
|
44
|
+
|
45
|
+
actions = NA::Actions.new
|
46
|
+
required = []
|
47
|
+
optional = []
|
48
|
+
negated = []
|
49
|
+
required_tag = []
|
50
|
+
optional_tag = []
|
51
|
+
negated_tag = []
|
52
|
+
projects = []
|
53
|
+
|
54
|
+
NA.notify("{dw}Tags: #{settings[:tag]}", debug:true)
|
55
|
+
NA.notify("{dw}Search: #{settings[:search]}", debug:true)
|
56
|
+
|
57
|
+
settings[:tag]&.each do |t|
|
58
|
+
unless t[:tag].nil?
|
59
|
+
if settings[:negate]
|
60
|
+
optional_tag.push(t) if t[:negate]
|
61
|
+
required_tag.push(t) if t[:required] && t[:negate]
|
62
|
+
negated_tag.push(t) unless t[:negate]
|
63
|
+
else
|
64
|
+
optional_tag.push(t) unless t[:negate]
|
65
|
+
required_tag.push(t) if t[:required] && !t[:negate]
|
66
|
+
negated_tag.push(t) if t[:negate]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
unless settings[:search].nil? || settings[:search].empty?
|
72
|
+
if settings[:regex] || settings[:search].is_a?(String)
|
73
|
+
if settings[:negate]
|
74
|
+
negated.push(settings[:search])
|
75
|
+
else
|
76
|
+
optional.push(settings[:search])
|
77
|
+
required.push(settings[:search])
|
78
|
+
end
|
79
|
+
else
|
80
|
+
settings[:search].each do |t|
|
81
|
+
opt, req, neg = parse_search(t, settings[:negate])
|
82
|
+
optional.concat(opt)
|
83
|
+
required.concat(req)
|
84
|
+
negated.concat(neg)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
files = if !settings[:file_path].nil?
|
90
|
+
[settings[:file_path]]
|
91
|
+
elsif settings[:query].nil?
|
92
|
+
NA.find_files(depth: settings[:depth])
|
93
|
+
else
|
94
|
+
NA.match_working_dir(settings[:query])
|
95
|
+
end
|
96
|
+
|
97
|
+
files.each do |file|
|
98
|
+
NA.save_working_dir(File.expand_path(file))
|
99
|
+
content = file.read_file
|
100
|
+
indent_level = 0
|
101
|
+
parent = []
|
102
|
+
in_action = false
|
103
|
+
content.split(/\n/).each.with_index do |line, idx|
|
104
|
+
if line.project?
|
105
|
+
in_action = false
|
106
|
+
proj = line.project
|
107
|
+
indent = line.indent_level
|
108
|
+
|
109
|
+
if indent.zero? # top level project
|
110
|
+
parent = [proj]
|
111
|
+
elsif indent <= indent_level # if indent level is same or less, split parent before indent level and append
|
112
|
+
parent.slice!(indent, parent.count - indent)
|
113
|
+
parent.push(proj)
|
114
|
+
else # if indent level is greater, append project to parent
|
115
|
+
parent.push(proj)
|
116
|
+
end
|
117
|
+
|
118
|
+
projects.push(NA::Project.new(parent.join(':'), indent, idx, idx))
|
119
|
+
|
120
|
+
indent_level = indent
|
121
|
+
elsif line.blank?
|
122
|
+
in_action = false
|
123
|
+
elsif line.action?
|
124
|
+
in_action = false
|
125
|
+
|
126
|
+
action = line.action
|
127
|
+
new_action = NA::Action.new(file, File.basename(file, ".#{NA.extension}"), parent.dup, action, idx)
|
128
|
+
|
129
|
+
projects[-1].last_line = idx if projects.count.positive?
|
130
|
+
|
131
|
+
next if line.done? && !settings[:done]
|
132
|
+
|
133
|
+
next if settings[:require_na] && !line.na?
|
134
|
+
|
135
|
+
has_search = !optional.empty? || !required.empty? || !negated.empty?
|
136
|
+
|
137
|
+
next if has_search && !new_action.search_match?(any: optional,
|
138
|
+
all: required,
|
139
|
+
none: negated)
|
140
|
+
|
141
|
+
if settings[:project]
|
142
|
+
rx = settings[:project].split(%r{[/:]}).join('.*?/')
|
143
|
+
next unless parent.join('/') =~ Regexp.new("#{rx}.*?", Regexp::IGNORECASE)
|
144
|
+
end
|
145
|
+
|
146
|
+
has_tag = !optional_tag.empty? || !required_tag.empty? || !negated_tag.empty?
|
147
|
+
next if has_tag && !new_action.tags_match?(any: optional_tag,
|
148
|
+
all: required_tag,
|
149
|
+
none: negated_tag)
|
150
|
+
|
151
|
+
actions.push(new_action)
|
152
|
+
in_action = true
|
153
|
+
elsif in_action
|
154
|
+
actions[-1].note.push(line.strip) if actions.count.positive?
|
155
|
+
projects[-1].last_line = idx if projects.count.positive?
|
156
|
+
end
|
157
|
+
end
|
158
|
+
projects = projects.dup
|
159
|
+
end
|
160
|
+
|
161
|
+
[files, actions, projects]
|
162
|
+
end
|
163
|
+
|
164
|
+
def parse_search(tag, negate)
|
165
|
+
required = []
|
166
|
+
optional = []
|
167
|
+
negated = []
|
168
|
+
new_rx = tag[:token].to_s.wildcard_to_rx
|
169
|
+
|
170
|
+
if negate
|
171
|
+
optional.push(new_rx) if tag[:negate]
|
172
|
+
required.push(new_rx) if tag[:required] && tag[:negate]
|
173
|
+
negated.push(new_rx) unless tag[:negate]
|
174
|
+
else
|
175
|
+
optional.push(new_rx) unless tag[:negate]
|
176
|
+
required.push(new_rx) if tag[:required] && !tag[:negate]
|
177
|
+
negated.push(new_rx) if tag[:negate]
|
178
|
+
end
|
179
|
+
|
180
|
+
[optional, required, negated]
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
data/lib/na/version.rb
CHANGED
data/lib/na.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.35<!--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
|
|
@@ -69,7 +69,7 @@ You can mark todos as complete, delete them, add and remove tags, change priorit
|
|
69
69
|
### Usage
|
70
70
|
|
71
71
|
```
|
72
|
-
@cli(
|
72
|
+
@cli(na help)
|
73
73
|
```
|
74
74
|
|
75
75
|
#### Commands
|
@@ -87,13 +87,13 @@ Use the `--note` switch to add a note. If STDIN (piped) input is present when th
|
|
87
87
|
Notes are not displayed by the `next/tagged/find` commands unless `--notes` is specified.
|
88
88
|
|
89
89
|
```
|
90
|
-
@cli(
|
90
|
+
@cli(na help add)
|
91
91
|
```
|
92
92
|
|
93
93
|
##### edit
|
94
94
|
|
95
95
|
```
|
96
|
-
@cli(
|
96
|
+
@cli(na help edit)
|
97
97
|
```
|
98
98
|
|
99
99
|
##### find
|
@@ -103,13 +103,13 @@ Example: `na find cool feature idea`
|
|
103
103
|
Unless `--exact` is specified, search is tokenized and combined with AND, so `na find cool feature idea` translates to `cool AND feature AND idea`, matching any string that contains all of the words. To make a token required and others optional, 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).
|
104
104
|
|
105
105
|
```
|
106
|
-
@cli(
|
106
|
+
@cli(na help find)
|
107
107
|
```
|
108
108
|
|
109
109
|
##### init, create
|
110
110
|
|
111
111
|
```
|
112
|
-
@cli(
|
112
|
+
@cli(na help init)
|
113
113
|
```
|
114
114
|
|
115
115
|
##### next, show
|
@@ -123,7 +123,7 @@ Examples:
|
|
123
123
|
To see all next actions across all known todos, use `na next "*"`. You can combine multiple arguments to see actions across multiple todos, e.g. `na next marked nvultra`.
|
124
124
|
|
125
125
|
```
|
126
|
-
@cli(
|
126
|
+
@cli(na help next)
|
127
127
|
```
|
128
128
|
|
129
129
|
##### projects
|
@@ -131,7 +131,7 @@ To see all next actions across all known todos, use `na next "*"`. You can combi
|
|
131
131
|
List all projects in a file. If arguments are provided, they're used to match a todo file from history, otherwise the todo file(s) in the current directory will be used.
|
132
132
|
|
133
133
|
```
|
134
|
-
@cli(
|
134
|
+
@cli(na help projects)
|
135
135
|
```
|
136
136
|
|
137
137
|
##### saved
|
@@ -146,7 +146,7 @@ Run `na saved` without an argument to list your saved searches.
|
|
146
146
|
<!--JEKYLL{:.tip}-->
|
147
147
|
|
148
148
|
```
|
149
|
-
@cli(
|
149
|
+
@cli(na help saved)
|
150
150
|
```
|
151
151
|
|
152
152
|
##### tagged
|
@@ -160,7 +160,7 @@ You can also perform value comparisons on tags. A value in a TaskPaper tag is ad
|
|
160
160
|
To perform a string comparison, you can use `*=` (contains), `^=` (starts with), `$=` (ends with), or `=` (matches). E.g. `na tagged "note*=video"`.
|
161
161
|
|
162
162
|
```
|
163
|
-
@cli(
|
163
|
+
@cli(na help show)
|
164
164
|
```
|
165
165
|
|
166
166
|
##### todos
|
@@ -168,7 +168,7 @@ To perform a string comparison, you can use `*=` (contains), `^=` (starts with),
|
|
168
168
|
List all known todo files from history.
|
169
169
|
|
170
170
|
```
|
171
|
-
@cli(
|
171
|
+
@cli(na help todos)
|
172
172
|
```
|
173
173
|
|
174
174
|
##### update
|
@@ -206,7 +206,31 @@ Notes are not displayed by the `next/tagged/find` commands unless `--notes` is s
|
|
206
206
|
See the help output for a list of all available actions.
|
207
207
|
|
208
208
|
```
|
209
|
-
@cli(
|
209
|
+
@cli(na help update)
|
210
|
+
```
|
211
|
+
|
212
|
+
##### changelog
|
213
|
+
|
214
|
+
View recent changes with `na changelog` or `na changes`.
|
215
|
+
|
216
|
+
```
|
217
|
+
@cli(na help changelog)
|
218
|
+
```
|
219
|
+
|
220
|
+
##### complete
|
221
|
+
|
222
|
+
Mark an action as complete, shortcut for `na update --finish`.
|
223
|
+
|
224
|
+
```
|
225
|
+
@cli(na help complete)
|
226
|
+
```
|
227
|
+
|
228
|
+
##### archive
|
229
|
+
|
230
|
+
Mark an action as complete and move to archive, shortcut for `na update --archive`.
|
231
|
+
|
232
|
+
```
|
233
|
+
@cli(na help archive)
|
210
234
|
```
|
211
235
|
|
212
236
|
### Configuration
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
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.37
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brett Terpstra
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-09-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -222,12 +222,15 @@ files:
|
|
222
222
|
- bin/commands/saved.rb
|
223
223
|
- bin/commands/tagged.rb
|
224
224
|
- bin/commands/todos.rb
|
225
|
+
- bin/commands/undo.rb
|
225
226
|
- bin/commands/update.rb
|
226
227
|
- bin/na
|
227
228
|
- lib/na.rb
|
228
229
|
- lib/na/action.rb
|
230
|
+
- lib/na/actions.rb
|
229
231
|
- lib/na/array.rb
|
230
232
|
- lib/na/colors.rb
|
233
|
+
- lib/na/editor.rb
|
231
234
|
- lib/na/hash.rb
|
232
235
|
- lib/na/help_monkey_patch.rb
|
233
236
|
- lib/na/next_action.rb
|
@@ -235,6 +238,7 @@ files:
|
|
235
238
|
- lib/na/project.rb
|
236
239
|
- lib/na/prompt.rb
|
237
240
|
- lib/na/string.rb
|
241
|
+
- lib/na/todo.rb
|
238
242
|
- lib/na/version.rb
|
239
243
|
- na.gemspec
|
240
244
|
- na.rdoc
|