na 1.2.62 → 1.2.64

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: 7593e49883f52039a97b3ab2120d8ff33d4fc96e26668c0ced93925ccbdb50dd
4
- data.tar.gz: a2d81d64424252333b43892e2084b6723f2a86bb49b21bf7e4b2b41910ac276f
3
+ metadata.gz: c2accac212d5f998f830299693f13e3ec27e692b1bc5f460bcd977fb1ce95042
4
+ data.tar.gz: ad75051381180b3d4cc99fe3edb841a591e76ca649eaa051a12752f6066a1ed2
5
5
  SHA512:
6
- metadata.gz: aeb67a3726ca053efe7f453659d40bb87a776f1d52f7bd40d843821ee3569edd8ad5edf3e3e0d5f6d4b3f1ec850f3215f21bee5fda495faf8024771dd4115ca1
7
- data.tar.gz: afa3e3a0cdeaffd7d400f1be9351ef4ed832e0b60311610055a6249d6645e649bb51cf1586b52176620b18665f929ffef8543d110ebc721c9cdbb15fa6fbec8c
6
+ metadata.gz: 96a9f0120855bf9569dd5d35f7701c24196185fa0d82a12e143486687072778cca636369264c45b286e0e4030722cb817258f585f399e50929b3f500bdea47f9
7
+ data.tar.gz: bd58a4c3872fb7ad608f15bdc31fd954f8f7581f168c30e7db3c1e11986df884905a964cfcd263d7807a3f583e22d22e33e0f8c9a46842407a5096d5f17b2271
data/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
+ ### 1.2.64
2
+
3
+ 2024-06-20 12:25
4
+
5
+ #### NEW
6
+
7
+ - `na move ACTION --to PROJECT` command to allow quickly moving actions around
8
+
9
+ ### 1.2.63
10
+
11
+ 2023-12-14 13:56
12
+
13
+ #### FIXED
14
+
15
+ - Frozen string issue in completed
16
+ - Remove debug statement
17
+
1
18
  ### 1.2.62
2
19
 
3
20
  2023-10-05 08:39
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- na (1.2.62)
4
+ na (1.2.64)
5
5
  chronic (~> 0.10, >= 0.10.2)
6
6
  gli (~> 2.21.0)
7
7
  mdless (~> 1.0, >= 1.0.32)
@@ -14,8 +14,8 @@ GEM
14
14
  specs:
15
15
  chronic (0.10.2)
16
16
  gli (2.21.1)
17
- mdless (1.0.35)
18
- minitest (5.16.3)
17
+ mdless (1.0.37)
18
+ minitest (5.20.0)
19
19
  rake (0.9.6)
20
20
  rdoc (4.3.0)
21
21
  tty-cursor (0.7.1)
@@ -25,10 +25,8 @@ GEM
25
25
  wisper (~> 2.0)
26
26
  tty-screen (0.8.1)
27
27
  tty-which (0.5.0)
28
- webrick (1.7.0)
29
28
  wisper (2.0.1)
30
- yard (0.9.28)
31
- webrick (~> 1.7.0)
29
+ yard (0.9.34)
32
30
 
33
31
  PLATFORMS
34
32
  arm64-darwin-20
data/README.md CHANGED
@@ -9,8 +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.62
13
- .
12
+ The current version of `na` is 1.2.64.
14
13
 
15
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.
16
15
 
@@ -77,14 +76,14 @@ SYNOPSIS
77
76
  na [global options] command [command options] [arguments...]
78
77
 
79
78
  VERSION
80
- 1.2.62
79
+ 1.2.64
81
80
 
82
81
  GLOBAL OPTIONS
83
82
  -a, --add - Add a next action (deprecated, for backwards compatibility)
84
83
  --add_at=POSITION - Add all new/moved entries at [s]tart or [e]nd of target project (default: start)
85
84
  --[no-]color - Colorize output (default: enabled)
86
85
  --cwd_as=TYPE - Use current working directory as [p]roject, [t]ag, or [n]one (default: none)
87
- -d, --depth=DEPTH - Recurse to depth (default: 3)
86
+ -d, --depth=DEPTH - Recurse to depth (default: 1)
88
87
  --[no-]debug - Display verbose output
89
88
  --ext=EXT - File extension to consider a todo file (default: taskpaper)
90
89
  -f, --file=PATH - Use a single file as global todo, use initconfig to make permanent (default: none)
@@ -109,6 +108,7 @@ COMMANDS
109
108
  help - Shows a list of commands or help for one command
110
109
  init, create - Create a new todo file in the current directory
111
110
  initconfig - Initialize the config file using current global options
111
+ move - Move an existing action to a different section
112
112
  next, show - Show next actions
113
113
  open - Open a todo file in the default editor
114
114
  projects - Show list of projects for a file
@@ -264,6 +264,48 @@ EXAMPLES
264
264
  na init warpspeed
265
265
  ```
266
266
 
267
+ ##### move
268
+
269
+ Move an action between projects. Argument is a search term, if left blank a prompt will allow you to enter terms. If no `--to` project is specified, a menu will be shown of projects in the target file.
270
+
271
+ Examples:
272
+
273
+ - `na move` (enter a search term, select a file/destination)
274
+ - `na move "Bug description"` (find matching action and show a menu of project destinations)
275
+ - `na move "Bug description" --to Bugs (move matching action to Bugs project)
276
+
277
+ ```
278
+ NAME
279
+ move - Move an existing action to a different section
280
+
281
+ SYNOPSIS
282
+
283
+ na [global options] move [command options] ACTION
284
+
285
+ DESCRIPTION
286
+ Provides an easy way to move an action. If multiple todo files are found in the current directory, a menu will allow you to pick which file to act on.
287
+
288
+ COMMAND OPTIONS
289
+ --all - Act on all matches immediately (no menu)
290
+ --at=POSITION - When moving task, add at [s]tart or [e]nd of target project (default: none)
291
+ -d, --depth=DEPTH - Search for files X directories deep (default: 1)
292
+ -e, --regex - Interpret search pattern as regular expression
293
+ --file=PATH - Specify the file to search for the task (default: none)
294
+ --from=PROJECT[/SUBPROJECT] - Search for actions in a specific project (default: none)
295
+ --in, --todo=TODO_FILE - Use a known todo file, partial matches allowed (default: none)
296
+ -n, --note - Prompt for additional notes. Input will be appended to any existing note. If STDIN input (piped) is detected, it will be used as a note.
297
+ -o, --overwrite - Overwrite note instead of appending
298
+ --[no-]search_notes - Include notes in search (default: enabled)
299
+ --tagged=TAG - Match actions containing tag. Allows value comparisons (may be used more than once, default: none)
300
+ --to=PROJECT - Move action to specific project. If not provided, a menu will be shown (default: none)
301
+ -x, --exact - Match pattern exactly
302
+
303
+ EXAMPLE
304
+
305
+ # Find "A bug in inbox" action and move it to section Bugs
306
+ na move "A bug in inbox" --to Bugs
307
+ ```
308
+
267
309
  ##### next, show
268
310
 
269
311
  Examples:
@@ -573,7 +615,7 @@ COMMAND OPTIONS
573
615
  --search, --find, --grep=QUERY - Filter results using search terms (may be used more than once, default: none)
574
616
  --[no-]search_notes - Include notes in search (default: enabled)
575
617
  --tagged=TAG - Match actions containing tag. Allows value comparisons (may be used more than once, default: none)
576
- --to, --move=PROJECT - Move action to specific project (default: none)
618
+ --to, --move=PROJECT - Add a @done tag and move action to specific project (default: none)
577
619
  -x, --exact - Match pattern exactly
578
620
 
579
621
  EXAMPLES
@@ -20,7 +20,7 @@ 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'
23
+ c.desc 'Add a @done tag and move action to specific project'
24
24
  c.arg_name 'PROJECT'
25
25
  c.flag %i[to move]
26
26
 
@@ -102,7 +102,7 @@ class App
102
102
  title = options[:save].gsub(/[^a-z0-9]/, '_').gsub(/_+/, '_')
103
103
  NA.save_search(title, cmd_string)
104
104
  end
105
- puts cmd_string
105
+
106
106
  exit run(Shellwords.shellsplit(cmd_string))
107
107
  end
108
108
  end
@@ -0,0 +1,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ class App
4
+ extend GLI::App
5
+ desc 'Move an existing action to a different section'
6
+ long_desc 'Provides an easy way to move an action.
7
+
8
+ If multiple todo files are found in the current directory, a menu will
9
+ allow you to pick which file to act on.'
10
+ arg_name 'ACTION'
11
+ command %i[move] do |c|
12
+ c.example 'na move "A bug in inbox" --to Bugs',
13
+ desc: 'Find "A bug in inbox" action and move it to section Bugs'
14
+
15
+ c.desc 'Prompt for additional notes. Input will be appended to any existing note.
16
+ If STDIN input (piped) is detected, it will be used as a note.'
17
+ c.switch %i[n note], negatable: false
18
+
19
+ c.desc 'Overwrite note instead of appending'
20
+ c.switch %i[o overwrite], negatable: false
21
+
22
+ c.desc 'Move action to specific project. If not provided, a menu will be shown'
23
+ c.arg_name 'PROJECT'
24
+ c.flag %i[to]
25
+
26
+ c.desc 'When moving task, add at [s]tart or [e]nd of target project'
27
+ c.arg_name 'POSITION'
28
+ c.flag %i[at], must_match: /^[sbea].*?$/i
29
+
30
+ c.desc 'Search for actions in a specific project'
31
+ c.arg_name 'PROJECT[/SUBPROJECT]'
32
+ c.flag %i[from]
33
+
34
+ c.desc 'Use a known todo file, partial matches allowed'
35
+ c.arg_name 'TODO_FILE'
36
+ c.flag %i[in todo]
37
+
38
+ c.desc 'Specify the file to search for the task'
39
+ c.arg_name 'PATH'
40
+ c.flag %i[file]
41
+
42
+ c.desc 'Search for files X directories deep'
43
+ c.arg_name 'DEPTH'
44
+ c.flag %i[d depth], must_match: /^[1-9]$/, type: :integer, default_value: 1
45
+
46
+ c.desc 'Include notes in search'
47
+ c.switch %i[search_notes], negatable: true, default_value: true
48
+
49
+ c.desc 'Match actions containing tag. Allows value comparisons'
50
+ c.arg_name 'TAG'
51
+ c.flag %i[tagged], multiple: true
52
+
53
+ c.desc 'Act on all matches immediately (no menu)'
54
+ c.switch %i[all], negatable: false
55
+
56
+ c.desc 'Interpret search pattern as regular expression'
57
+ c.switch %i[e regex], negatable: false
58
+
59
+ c.desc 'Match pattern exactly'
60
+ c.switch %i[x exact], negatable: false
61
+
62
+ c.action do |global_options, options, args|
63
+ reader = TTY::Reader.new
64
+
65
+ args.concat(options[:search]) unless options[:search].nil?
66
+
67
+ append = options[:at] ? options[:at] =~ /^[ae]/i : global_options[:add_at] =~ /^[ae]/i
68
+
69
+ options[:done] = true
70
+
71
+ action = if args.count.positive?
72
+ args.join(' ').strip
73
+ else
74
+ NA.request_input(options, prompt: 'Enter a task to search for')
75
+ end
76
+ if action
77
+ tokens = nil
78
+ if options[:exact]
79
+ tokens = action
80
+ elsif options[:regex]
81
+ tokens = Regexp.new(action, Regexp::IGNORECASE)
82
+ else
83
+ tokens = []
84
+ all_req = action !~ /[+!-]/ && !options[:or]
85
+
86
+ action.split(/ /).each do |arg|
87
+ m = arg.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
88
+ tokens.push({
89
+ token: m['tok'],
90
+ required: all_req || (!m['req'].nil? && m['req'] == '+'),
91
+ negate: !m['req'].nil? && m['req'] =~ /[!-]/ ? true : false
92
+ })
93
+ end
94
+ end
95
+ end
96
+
97
+ if (action.nil? || action.empty?) && options[:tagged].empty?
98
+ NA.notify("#{NA.theme[:error]}Empty input, cancelled", exit_code: 1)
99
+ end
100
+
101
+ all_req = options[:tagged].join(' ') !~ /[+!-]/ && !options[:or]
102
+ tags = []
103
+ options[:tagged].join(',').split(/ *, */).each do |arg|
104
+ m = arg.match(/^(?<req>[+!-])?(?<tag>[^ =<>$~\^]+?) *(?:(?<op>[=<>~]{1,2}|[*$\^]=) *(?<val>.*?))?$/)
105
+
106
+ tags.push({
107
+ tag: m['tag'].wildcard_to_rx,
108
+ comp: m['op'],
109
+ value: m['val'],
110
+ required: all_req || (!m['req'].nil? && m['req'] == '+'),
111
+ negate: !m['req'].nil? && m['req'] =~ /[!-]/ ? true : false
112
+ })
113
+ end
114
+
115
+ stdin_note = NA.stdin ? NA.stdin.split("\n") : []
116
+
117
+ line_note = if options[:note] && $stdin.isatty
118
+ puts stdin_note unless stdin_note.nil?
119
+ if TTY::Which.exist?('gum')
120
+ args = ['--placeholder "Enter a note, CTRL-d to save"']
121
+ args << '--char-limit 0'
122
+ args << '--width $(tput cols)'
123
+ gum = TTY::Which.which('gum')
124
+ `#{gum} write #{args.join(' ')}`.strip.split("\n")
125
+ else
126
+ NA.notify("#{NA.theme[:prompt]}Enter a note, {bw}CTRL-d#{NA.theme[:prompt]} to end editing:#{NA.theme[:action]}")
127
+ reader.read_multiline
128
+ end
129
+ end
130
+
131
+ note = stdin_note.empty? ? [] : stdin_note
132
+ note.concat(line_note) unless line_note.nil? || line_note.empty?
133
+
134
+ if options[:file]
135
+ file = File.expand_path(options[:file])
136
+ NA.notify("#{NA.theme[:error]}File not found", exit_code: 1) unless File.exist?(file)
137
+
138
+ targets = [file]
139
+ elsif options[:todo]
140
+ todo = []
141
+ options[:todo].split(/ *, */).each do |a|
142
+ m = a.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
143
+ todo.push({
144
+ token: m['tok'],
145
+ required: all_req || (!m['req'].nil? && m['req'] == '+'),
146
+ negate: !m['req'].nil? && m['req'] =~ /[!-]/ ? true : false
147
+ })
148
+ end
149
+ dirs = NA.match_working_dir(todo)
150
+
151
+ if dirs.count == 1
152
+ targets = [dirs[0]]
153
+ elsif dirs.count.positive?
154
+ targets = NA.select_file(dirs, multiple: true)
155
+ NA.notify("#{NA.theme[:error]}Cancelled", exit_code: 1) unless targets && targets.count.positive?
156
+ else
157
+ NA.notify("#{NA.theme[:error]}Todo not found", exit_code: 1) unless targets && targets.count.positive?
158
+
159
+ end
160
+ else
161
+ files = NA.find_files_matching({
162
+ depth: options[:depth],
163
+ done: options[:done],
164
+ project: options[:from],
165
+ regex: options[:regex],
166
+ require_na: false,
167
+ search: tokens,
168
+ tag: tags
169
+ })
170
+ NA.notify("#{NA.theme[:error]}No todo file found", exit_code: 1) if files.count.zero?
171
+
172
+ targets = files.count > 1 ? NA.select_file(files, multiple: true) : [files[0]]
173
+ NA.notify("#{NA.theme[:error]}Cancelled", exit_code: 1) unless files.count.positive?
174
+ end
175
+
176
+ target_proj = if options[:to]
177
+ options[:to]
178
+ else
179
+ todo = NA::Todo.new(require_na: false, file_path: targets[0])
180
+ projects = todo.projects
181
+ menu = projects.each_with_object([]) { |proj, arr| arr << proj.project }
182
+
183
+ NA.choose_from(menu, prompt: 'Move to: ', multiple: false, sorted: false)
184
+ end
185
+
186
+ NA.notify("#{NA.theme[:error]}No target selected", exit_code: 1) unless target_proj
187
+
188
+ NA.notify("#{NA.theme[:error]}No search terms provided", exit_code: 1) if tokens.nil? && options[:tagged].empty?
189
+
190
+ targets.each do |target|
191
+ NA.update_action(target, tokens,
192
+ all: options[:all],
193
+ append: append,
194
+ move: target_proj,
195
+ note: note,
196
+ overwrite: options[:overwrite],
197
+ project: options[:from],
198
+ search_note: options[:search_notes],
199
+ tagged: tags)
200
+ end
201
+ end
202
+ end
203
+ end
data/bin/commands/next.rb CHANGED
@@ -132,8 +132,6 @@ class App
132
132
  end
133
133
  end
134
134
 
135
- pp options[:tagged]
136
-
137
135
  all_req = options[:tagged].join(' ') !~ /(?<=[, ])[+!-]/ && !options[:or]
138
136
  tags = []
139
137
  options[:tagged].join(',').split(/ *, */).each do |arg|
@@ -178,7 +178,8 @@ class App
178
178
  args = ['--placeholder "Enter a note, CTRL-d to save"']
179
179
  args << '--char-limit 0'
180
180
  args << '--width $(tput cols)'
181
- `gum write #{args.join(' ')}`.strip.split("\n")
181
+ gum = TTY::Which.which('gum')
182
+ `#{gum} write #{args.join(' ')}`.strip.split("\n")
182
183
  else
183
184
  NA.notify("#{NA.theme[:prompt]}Enter a note, {bw}CTRL-d#{NA.theme[:prompt]} to end editing:#{NA.theme[:action]}")
184
185
  reader.read_multiline
data/lib/na/action.rb CHANGED
@@ -39,8 +39,7 @@ module NA
39
39
 
40
40
  string = "#{string.strip} @done(#{Time.now.strftime('%Y-%m-%d %H:%M')})" if finish && string !~ /(?<=\A| )@done/
41
41
 
42
- @action = string
43
- @action.expand_date_tags
42
+ @action = string.expand_date_tags
44
43
  @note = note unless note.empty?
45
44
  end
46
45
 
data/lib/na/editor.rb CHANGED
@@ -105,7 +105,7 @@ module NA
105
105
  title = input_lines[0]&.strip
106
106
  NA.notify("#{NA.theme[:error]}No content in first line", exit_code: 1) if title.nil? || title.strip.empty?
107
107
 
108
- title.expand_date_tags
108
+ title = title.expand_date_tags
109
109
 
110
110
  note = if input_lines.length > 1
111
111
  input_lines[1..-1]
@@ -425,7 +425,7 @@ module NA
425
425
  end
426
426
 
427
427
  def project_hierarchy(actions)
428
- parents = { actions: []}
428
+ parents = { actions: [] }
429
429
  actions.each do |a|
430
430
  parent = a.parent
431
431
  current_parent = parents
@@ -958,7 +958,7 @@ module NA
958
958
  end
959
959
 
960
960
  return false if res&.strip&.size&.zero?
961
- pp NA::Color.uncolor(NA::Color.template(res))
961
+ # pp NA::Color.uncolor(NA::Color.template(res))
962
962
  multiple ? NA::Color.uncolor(NA::Color.template(res)).split(/\n/) : NA::Color.uncolor(NA::Color.template(res))
963
963
  end
964
964
 
data/lib/na/string.rb CHANGED
@@ -294,7 +294,7 @@ class ::String
294
294
 
295
295
  done_rx = /(?<=^| )@(?<tag>#{watch_tags.join('|')})\((?<date>.*?)\)/i
296
296
 
297
- gsub!(done_rx) do
297
+ dup.gsub(done_rx) do
298
298
  m = Regexp.last_match
299
299
  t = m['tag']
300
300
  d = m['date']
data/lib/na/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Na
2
- VERSION = '1.2.62'
2
+ VERSION = '1.2.64'
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.61<!--END VER-->.
12
+ The current version of `na` is <!--VER-->1.2.63<!--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
 
@@ -112,6 +112,20 @@ Unless `--exact` is specified, search is tokenized and combined with AND, so `na
112
112
  @cli(bundle exec bin/na help init)
113
113
  ```
114
114
 
115
+ ##### move
116
+
117
+ Move an action between projects. Argument is a search term, if left blank a prompt will allow you to enter terms. If no `--to` project is specified, a menu will be shown of projects in the target file.
118
+
119
+ Examples:
120
+
121
+ - `na move` (enter a search term, select a file/destination)
122
+ - `na move "Bug description"` (find matching action and show a menu of project destinations)
123
+ - `na move "Bug description" --to Bugs (move matching action to Bugs project)
124
+
125
+ ```
126
+ @cli(bundle exec bin/na help move)
127
+ ```
128
+
115
129
  ##### next, show
116
130
 
117
131
  Examples:
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.62
4
+ version: 1.2.64
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-10-05 00:00:00.000000000 Z
11
+ date: 2024-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -215,6 +215,7 @@ files:
215
215
  - bin/commands/edit.rb
216
216
  - bin/commands/find.rb
217
217
  - bin/commands/init.rb
218
+ - bin/commands/move.rb
218
219
  - bin/commands/next.rb
219
220
  - bin/commands/open.rb
220
221
  - bin/commands/projects.rb
@@ -275,7 +276,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
275
276
  - !ruby/object:Gem::Version
276
277
  version: '0'
277
278
  requirements: []
278
- rubygems_version: 3.4.0.dev
279
+ rubygems_version: 3.2.15
279
280
  signing_key:
280
281
  specification_version: 4
281
282
  summary: A command line tool for adding and listing project todos