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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f9de8bad22cccef320d35bec3e5dd840de73bd58e9288f3a079479135594333
4
- data.tar.gz: 3bb87af83e65f8ceab63188502bc3018302d2755f6cc2dfde34d603bb37d0563
3
+ metadata.gz: 482bb5668dec4d69c1a9fc41340f723589724730fb930ff9f45d5bbaa5bd3dd3
4
+ data.tar.gz: fa3cd141c8cf0a7ad41d52f399e9f400bd35708112d3ce9cab6bf2b7795a96b1
5
5
  SHA512:
6
- metadata.gz: 12aa91ea7c15385478dd0ff8e351c180de3ada85ab818561302b258f058dada8b9fcc5e30ddc43a3c28ef2084df6fd47e53e0085494863984a6e536a6e2e0952
7
- data.tar.gz: 62389ffca74e95eb4e91da17690c1f6d4d78546c38a8aae5b20c246805946ab5ed2041e3aeac0a7c9bd1abbba0a36dc6027d66a3384f3529b739ecffb96d7d4a
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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- na (1.2.78)
4
+ na (1.2.79)
5
5
  chronic (~> 0.10, >= 0.10.2)
6
6
  git (~> 3.0.0)
7
7
  gli (~> 2.21.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.78.
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.78
79
+ 1.2.79
80
80
 
81
81
  GLOBAL OPTIONS
82
82
  -a, --add - Add a next action (deprecated, for backwards compatibility)
@@ -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}
@@ -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
- next if delete
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 add
405
- notify("#{NA.theme[:success]}Task added to #{NA.theme[:filename]}#{target}")
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
- notify("#{NA.theme[:success]}Task updated in #{NA.theme[:filename]}#{target}")
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
@@ -1,3 +1,3 @@
1
1
  module Na
2
- VERSION = '1.2.78'
2
+ VERSION = '1.2.79'
3
3
  end
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.77<!--END VER-->.
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
 
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.78
4
+ version: 1.2.79
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra