na 1.2.62 → 1.2.64

Sign up to get free protection for your applications and to get access to all the features.
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