na 1.2.35 → 1.2.37

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.
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
@@ -1,3 +1,3 @@
1
1
  module Na
2
- VERSION = '1.2.35'
2
+ VERSION = '1.2.37'
3
3
  end
data/lib/na.rb CHANGED
@@ -13,7 +13,10 @@ require 'na/hash'
13
13
  require 'na/colors'
14
14
  require 'na/string'
15
15
  require 'na/array'
16
+ require 'na/todo'
17
+ require 'na/actions'
16
18
  require 'na/project'
17
19
  require 'na/action'
20
+ require 'na/editor'
18
21
  require 'na/next_action'
19
22
  require 'na/prompt'
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.34<!--END VER-->.
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(bundle exec bin/na help)
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(bundle exec bin/na help add)
90
+ @cli(na help add)
91
91
  ```
92
92
 
93
93
  ##### edit
94
94
 
95
95
  ```
96
- @cli(bundle exec bin/na help edit)
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(bundle exec bin/na help find)
106
+ @cli(na help find)
107
107
  ```
108
108
 
109
109
  ##### init, create
110
110
 
111
111
  ```
112
- @cli(bundle exec bin/na help init)
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(bundle exec bin/na help next)
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(bundle exec bin/na help projects)
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(bundle exec bin/na help saved)
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(bundle exec bin/na help show)
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(bundle exec bin/na help todos)
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(bundle exec bin/na help update)
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.35
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-08-30 00:00:00.000000000 Z
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