na 1.2.78 → 1.2.79
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 +19 -0
- data/Gemfile.lock +1 -1
- data/README.md +2 -2
- data/bin/commands/update.rb +17 -0
- data/lib/na/action.rb +9 -0
- data/lib/na/next_action.rb +59 -4
- 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: 482bb5668dec4d69c1a9fc41340f723589724730fb930ff9f45d5bbaa5bd3dd3
|
4
|
+
data.tar.gz: fa3cd141c8cf0a7ad41d52f399e9f400bd35708112d3ce9cab6bf2b7795a96b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a58d99161596166ce0b0ae34b45a35bcd86239e3606b05ec1431aed999f693475391a2e21ea3a7fdfb80bcf8d88ef2c3bcd3d20daaf34e474b2ab561d5051358
|
7
|
+
data.tar.gz: 02f36b28b78d5fae3144450a34bb910c22a6097dc13512b12e35bbc34d290a2f085500865bba4f2514e55692d9d862ec26854662eb438557e2d8a50473f511e6
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,22 @@
|
|
1
|
+
### 1.2.79
|
2
|
+
|
3
|
+
2025-09-29 06:51
|
4
|
+
|
5
|
+
#### NEW
|
6
|
+
|
7
|
+
- Track affected actions in `update_action` and output per-action summaries
|
8
|
+
|
9
|
+
#### IMPROVED
|
10
|
+
|
11
|
+
- Prompt to select a project when multiple suffix matches are found
|
12
|
+
- Distinguish summaries: Task deleted vs Task updated/added
|
13
|
+
- Display affected actions using `action.to_s_pretty` with colored change descriptions
|
14
|
+
|
15
|
+
#### FIXED
|
16
|
+
|
17
|
+
- Resolve project matching for `na add --to Ideas` by supporting unique suffix matches (e.g. `rnkd:Ideas`)
|
18
|
+
- Validate `na update` requires at least one actionable option; error with No action specified, see `na help update`
|
19
|
+
|
1
20
|
### 1.2.78
|
2
21
|
|
3
22
|
2025-06-02 10:07
|
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.79.
|
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
|
|
@@ -76,7 +76,7 @@ SYNOPSIS
|
|
76
76
|
na [global options] command [command options] [arguments...]
|
77
77
|
|
78
78
|
VERSION
|
79
|
-
1.2.
|
79
|
+
1.2.79
|
80
80
|
|
81
81
|
GLOBAL OPTIONS
|
82
82
|
-a, --add - Add a next action (deprecated, for backwards compatibility)
|
data/bin/commands/update.rb
CHANGED
@@ -189,6 +189,23 @@ class App
|
|
189
189
|
note = stdin_note.empty? ? [] : stdin_note
|
190
190
|
note.concat(line_note) unless line_note.nil? || line_note.empty?
|
191
191
|
|
192
|
+
# Require at least one actionable option to be provided
|
193
|
+
actionable = [
|
194
|
+
options[:note],
|
195
|
+
(options[:priority].to_i if options[:priority]).to_i > 0,
|
196
|
+
!options[:move].to_s.empty?,
|
197
|
+
!(options[:tag].nil? || options[:tag].empty?),
|
198
|
+
!(options[:remove].nil? || options[:remove].empty?),
|
199
|
+
!options[:replace].to_s.empty?,
|
200
|
+
options[:finish],
|
201
|
+
options[:archive],
|
202
|
+
options[:restore],
|
203
|
+
options[:delete],
|
204
|
+
options[:edit]
|
205
|
+
].any?
|
206
|
+
|
207
|
+
NA.notify("#{NA.theme[:error]}No action specified, see `na help update`", exit_code: 1) unless actionable
|
208
|
+
|
192
209
|
target_proj = if options[:move]
|
193
210
|
options[:move]
|
194
211
|
elsif NA.cwd_is == :project
|
data/lib/na/action.rb
CHANGED
@@ -53,6 +53,15 @@ module NA
|
|
53
53
|
"(#{@file}:#{@line}) #{@project}:#{@parent.join('>')} | #{@action}#{note}"
|
54
54
|
end
|
55
55
|
|
56
|
+
def to_s_pretty
|
57
|
+
note = if @note.count.positive?
|
58
|
+
"\n#{@note.join("\n")}"
|
59
|
+
else
|
60
|
+
''
|
61
|
+
end
|
62
|
+
"#{NA.theme[:filename]}#{File.basename(@file)}:#{@line}#{NA.theme[:bracket]}[#{NA.theme[:project]}#{@project}:#{@parent.join(">")}#{NA.theme[:bracket]}]{x} | #{NA.theme[:action]}#{@action}#{NA.theme[:note]}#{note}"
|
63
|
+
end
|
64
|
+
|
56
65
|
def inspect
|
57
66
|
<<~EOINSPECT
|
58
67
|
@file: #{@file}
|
data/lib/na/next_action.rb
CHANGED
@@ -259,6 +259,7 @@ module NA
|
|
259
259
|
tagged: nil)
|
260
260
|
|
261
261
|
projects = find_projects(target)
|
262
|
+
affected_actions = []
|
262
263
|
|
263
264
|
target_proj = nil
|
264
265
|
|
@@ -287,9 +288,22 @@ module NA
|
|
287
288
|
target_proj = if target_proj
|
288
289
|
projects.select { |proj| proj.project =~ /^#{target_proj.project}$/i }.first
|
289
290
|
else
|
291
|
+
# First try exact full-path match
|
290
292
|
projects.select { |proj| proj.project =~ /^#{add.parent.join(':')}$/i }.first
|
291
293
|
end
|
292
294
|
|
295
|
+
# If no exact match, try unique suffix match (e.g., :Ideas at end)
|
296
|
+
if target_proj.nil?
|
297
|
+
leaf = Regexp.escape(add.parent.join(':'))
|
298
|
+
suffix_matches = projects.select { |proj| proj.project =~ /(^|:)#{leaf}$/i }
|
299
|
+
if suffix_matches.count == 1
|
300
|
+
target_proj = suffix_matches.first
|
301
|
+
elsif suffix_matches.count > 1 && $stdout.isatty
|
302
|
+
choice = choose_from(suffix_matches.map(&:project), prompt: 'Select a target project: ', multiple: false)
|
303
|
+
target_proj = projects.select { |proj| proj.project == choice }.first if choice
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
293
307
|
if target_proj.nil?
|
294
308
|
res = NA.yn(NA::Color.template("#{NA.theme[:warning]}Project #{NA.theme[:file]}#{add.project}#{NA.theme[:warning]} doesn't exist, add it"), default: true)
|
295
309
|
|
@@ -336,6 +350,15 @@ module NA
|
|
336
350
|
contents.insert(target_line, "#{indent}\t- #{add.action}#{note}")
|
337
351
|
|
338
352
|
notify(add.pretty)
|
353
|
+
|
354
|
+
# Track affected action and description
|
355
|
+
changes = ["added"]
|
356
|
+
changes << "finished" if finish
|
357
|
+
changes << "priority=#{priority}" if priority.to_i.positive?
|
358
|
+
changes << "tags+#{add_tag.join(',')}" unless add_tag.nil? || add_tag.empty?
|
359
|
+
changes << "tags-#{remove_tag.join(',')}" unless remove_tag.nil? || remove_tag.empty?
|
360
|
+
changes << "note updated" unless note.nil? || note.empty?
|
361
|
+
affected_actions << { action: add, desc: changes.join(', ') }
|
339
362
|
else
|
340
363
|
_, actions = find_actions(target, search, tagged, done: done, all: all, project: project, search_note: search_note)
|
341
364
|
|
@@ -343,7 +366,11 @@ module NA
|
|
343
366
|
|
344
367
|
actions.sort_by(&:line).reverse.each do |action|
|
345
368
|
contents.slice!(action.line, action.note.count + 1)
|
346
|
-
|
369
|
+
if delete
|
370
|
+
# Track deletion before skipping re-insert
|
371
|
+
affected_actions << { action: action, desc: 'deleted' }
|
372
|
+
next
|
373
|
+
end
|
347
374
|
|
348
375
|
projects = shift_index_after(projects, action.line, action.note.count + 1)
|
349
376
|
|
@@ -395,16 +422,44 @@ module NA
|
|
395
422
|
contents.insert(target_line, "#{indent}\t- #{action.action}#{note}")
|
396
423
|
|
397
424
|
notify(action.pretty)
|
425
|
+
|
426
|
+
# Track affected action and description
|
427
|
+
changes = []
|
428
|
+
changes << "finished" if finish
|
429
|
+
changes << "edited" if edit
|
430
|
+
changes << "priority=#{priority}" if priority.to_i.positive?
|
431
|
+
changes << "tags+#{add_tag.join(',')}" unless add_tag.nil? || add_tag.empty?
|
432
|
+
changes << "tags-#{remove_tag.join(',')}" unless remove_tag.nil? || remove_tag.empty?
|
433
|
+
changes << "text replaced" if replace
|
434
|
+
changes << "moved to #{target_proj.project}" if target_proj
|
435
|
+
changes << "note updated" unless note.nil? || note.empty?
|
436
|
+
changes = ["updated"] if changes.empty?
|
437
|
+
affected_actions << { action: action, desc: changes.join(', ') }
|
398
438
|
end
|
399
439
|
end
|
400
440
|
|
401
441
|
backup_file(target)
|
402
442
|
File.open(target, 'w') { |f| f.puts contents.join("\n") }
|
403
443
|
|
404
|
-
if
|
405
|
-
|
444
|
+
if affected_actions.any?
|
445
|
+
if affected_actions.all? { |e| e[:desc] =~ /^deleted/ }
|
446
|
+
notify("#{NA.theme[:success]}Task deleted in #{NA.theme[:filename]}#{target}")
|
447
|
+
elsif add
|
448
|
+
notify("#{NA.theme[:success]}Task added to #{NA.theme[:filename]}#{target}")
|
449
|
+
else
|
450
|
+
notify("#{NA.theme[:success]}Task updated in #{NA.theme[:filename]}#{target}")
|
451
|
+
end
|
452
|
+
|
453
|
+
affected_actions.reverse.each do |entry|
|
454
|
+
action_color = delete ? NA.theme[:error] : NA.theme[:success]
|
455
|
+
notify(" #{entry[:action].to_s_pretty} — #{action_color}#{entry[:desc]}")
|
456
|
+
end
|
406
457
|
else
|
407
|
-
|
458
|
+
if add
|
459
|
+
notify("#{NA.theme[:success]}Task added to #{NA.theme[:filename]}#{target}")
|
460
|
+
else
|
461
|
+
notify("#{NA.theme[:success]}Task updated in #{NA.theme[:filename]}#{target}")
|
462
|
+
end
|
408
463
|
end
|
409
464
|
end
|
410
465
|
|
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.78<!--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
|
|