na 1.2.35 → 1.2.38

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: 1f8982f5720115576a78ab96a430d1d83f501bb1b477b2cff1a694648a186afc
4
- data.tar.gz: 86dd520a3265473471b6d09fc05136dd07b53ded24ab2c82936074fa50595b67
3
+ metadata.gz: 13c74e296d8e9d6e252949394c5471a27b1c7d3619026383fc75590dcb5d6046
4
+ data.tar.gz: c67deb62ee0ad5c2b3cf35b5ca39cebe2f6780e675cb48fbaec260068111a33a
5
5
  SHA512:
6
- metadata.gz: 7ea9bb861c82251c1ec52925d6527f0e4efa1eef0175d268b8a8bb307fafcc407dc888e5e5cd6d588e5e4a500a96ae64765106f23d9c4acda6e0667c71247d62
7
- data.tar.gz: e5f603160851411f66dd50ae47a65369aaa1e51352cf2eb6313674d95d64db8914d3a870f816dcc4303fbd5b4e675f213020fa6a7fd93805af4692f04eb99aed
6
+ metadata.gz: 4fd8a183c2fcadf9d128bab65267b841bdd253db40071cb87c3fa0dbfd1be0517d667ba64f21b28f0a24adfbc08cbefe79c3638ac63736698de34a21c81d0658
7
+ data.tar.gz: 8cb24b17379576cf4f86f709a277c2e075fb41c905d67750f09500471f5948f0d3cd2e0d66d9f29a073172e6808c8d4f2b2dd0afe3b6b223ff04ec493ccd8289
data/CHANGELOG.md CHANGED
@@ -1,3 +1,53 @@
1
+ ### 1.2.38
2
+
3
+ 2023-09-03 11:25
4
+
5
+ #### NEW
6
+
7
+ - Open the todos database in an editor with `na todos --edit`
8
+ - A theme file is written to ~/.local/share/na/theme.yaml where you can modify the colors used for all displays
9
+ - Allow tag=~PATTERN comparison for regex matching
10
+
11
+ #### IMPROVED
12
+
13
+ - Better error message for `na next` when no todo is matched
14
+ - If STDOUT isn't a TTY, don't enable pagination, regardless of global setting
15
+ - Allow --find or --grep as synonyms for --search
16
+
17
+ #### FIXED
18
+
19
+ - Date tags containing hyphens triggered OR searches because they were initially interpreted as negative tag searches
20
+ - Templating irregularities
21
+ - Error thrown when running without $EDITOR variable defined in environment
22
+
23
+ ### 1.2.37
24
+
25
+ 2023-09-01 12:42
26
+
27
+ #### NEW
28
+
29
+ - `na undo` command to undo last change or last change to file specified in arguments
30
+
31
+ #### IMPROVED
32
+
33
+ - Disable pagination when using --omnifocus
34
+ - Refactoring codebase
35
+ - `--in TODO` option for `na complete`
36
+
37
+ ### 1.2.36
38
+
39
+ 2023-09-01 12:41
40
+
41
+ #### NEW
42
+
43
+ - `na undo` command to undo last change or last change to file specified in arguments
44
+
45
+ #### IMPROVED
46
+
47
+ - Disable pagination when using --omnifocus
48
+ - Refactoring codebase
49
+ - `--in TODO` option for `na complete`
50
+
1
51
  ### 1.2.35
2
52
 
3
53
  2023-08-30 11:59
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- na (1.2.35)
4
+ na (1.2.38)
5
5
  chronic (~> 0.10, >= 0.10.2)
6
6
  gli (~> 2.21.0)
7
7
  mdless (~> 1.0, >= 1.0.32)
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.35
12
+ The current version of `na` is 1.2.38
13
13
  .
14
14
 
15
15
  `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.
@@ -77,7 +77,7 @@ SYNOPSIS
77
77
  na [global options] command [command options] [arguments...]
78
78
 
79
79
  VERSION
80
- 1.2.35
80
+ 1.2.38
81
81
 
82
82
  GLOBAL OPTIONS
83
83
  -a, --add - Add a next action (deprecated, for backwards compatibility)
@@ -114,8 +114,10 @@ COMMANDS
114
114
  prompt - Show or install prompt hooks for the current shell
115
115
  restore, unfinish - Find and remove @done tag from an action
116
116
  saved - Execute a saved search
117
+ tag - Add tags to matching action(s)
117
118
  tagged - Find actions matching a tag
118
119
  todos - Show list of known todo files
120
+ undo - Undo the last change
119
121
  update - Update an existing action
120
122
  ```
121
123
 
@@ -290,7 +292,7 @@ COMMAND OPTIONS
290
292
  --omnifocus - Output actions nested by file and project
291
293
  --proj, --project=PROJECT[/SUBPROJECT] - Show actions from a specific project (default: none)
292
294
  --regex - Search query is regular expression
293
- --search=QUERY - Filter results using search terms (may be used more than once, default: none)
295
+ --search, --find, --grep=QUERY - Filter results using search terms (may be used more than once, default: none)
294
296
  -t, --tag=TAG - Alternate tag to search for (default: none)
295
297
  --tagged=TAG - Match actions containing tag. Allows value comparisons (may be used more than once, default: none)
296
298
 
@@ -401,7 +403,7 @@ COMMAND OPTIONS
401
403
  --omnifocus - Output actions nested by file and project
402
404
  --proj, --project=PROJECT[/SUBPROJECT] - Show actions from a specific project (default: none)
403
405
  --regex - Search query is regular expression
404
- --search=QUERY - Filter results using search terms (may be used more than once, default: none)
406
+ --search, --find, --grep=QUERY - Filter results using search terms (may be used more than once, default: none)
405
407
  -t, --tag=TAG - Alternate tag to search for (default: none)
406
408
  --tagged=TAG - Match actions containing tag. Allows value comparisons (may be used more than once, default: none)
407
409
 
@@ -427,10 +429,13 @@ NAME
427
429
 
428
430
  SYNOPSIS
429
431
 
430
- na [global options] todos [QUERY]
432
+ na [global options] todos [command options] [QUERY]
431
433
 
432
434
  DESCRIPTION
433
- Arguments will be interpreted as a query against which the list of todos will be fuzzy matched. Separate directories with /, :, or a space, e.g. `na todos code/marked`
435
+ Arguments will be interpreted as a query against which the list of todos will be fuzzy matched. Separate directories with /, :, or a space, e.g. `na todos code/marked`
436
+
437
+ COMMAND OPTIONS
438
+ -e, --[no-]edit - Open the todo database in an editor for manual modification
434
439
  ```
435
440
 
436
441
  ##### update
@@ -512,6 +517,151 @@ EXAMPLES
512
517
  na update --archive My cool action
513
518
  ```
514
519
 
520
+ ##### changelog
521
+
522
+ View recent changes with `na changelog` or `na changes`.
523
+
524
+ ```
525
+ NAME
526
+ changes - Display the changelog
527
+
528
+ SYNOPSIS
529
+
530
+ na [global options] changes
531
+ ```
532
+
533
+ ##### complete
534
+
535
+ Mark an action as complete, shortcut for `na update --finish`.
536
+
537
+ ```
538
+ NAME
539
+ complete - Find and mark an action as @done
540
+
541
+ SYNOPSIS
542
+
543
+ na [global options] complete [command options] ACTION
544
+
545
+ COMMAND OPTIONS
546
+ -a, --archive - Add a @done tag to action and move to Archive
547
+ --all - Act on all matches immediately (no menu)
548
+ -d, --depth=DEPTH - Search for files X directories deep (default: 1)
549
+ -e, --regex - Interpret search pattern as regular expression
550
+ --file=PATH - Specify the file to search for the task (default: none)
551
+ --in, --todo=TODO_FILE - Use a known todo file, partial matches allowed (default: none)
552
+ -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.
553
+ -o, --overwrite - Overwrite note instead of appending
554
+ --tagged=TAG - Match actions containing tag. Allows value comparisons (may be used more than once, default: none)
555
+ --to, --project, --proj=PROJECT - Move action to specific project (default: none)
556
+ -x, --exact - Match pattern exactly
557
+
558
+ EXAMPLES
559
+
560
+ # Find "An existing task" and mark @done
561
+ na complete "An existing task"
562
+
563
+ # Alias for complete
564
+ na finish "An existing task"
565
+ ```
566
+
567
+ ##### archive
568
+
569
+ Mark an action as complete and move to archive, shortcut for `na update --archive`.
570
+
571
+ ```
572
+ NAME
573
+ archive - Mark an action as @done and archive
574
+
575
+ SYNOPSIS
576
+
577
+ na [global options] archive [command options] ACTION
578
+
579
+ COMMAND OPTIONS
580
+ --all - Act on all matches immediately (no menu)
581
+ -d, --depth=DEPTH - Search for files X directories deep (default: 1)
582
+ --done - Archive all done tasks
583
+ -e, --regex - Interpret search pattern as regular expression
584
+ --file=PATH - Specify the file to search for the task (default: none)
585
+ -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.
586
+ -o, --overwrite - Overwrite note instead of appending
587
+ --tagged=TAG - Match actions containing tag. Allows value comparisons (may be used more than once, default: none)
588
+ -x, --exact - Match pattern exactly
589
+
590
+ EXAMPLE
591
+
592
+ # Find "An existing task", mark @done if needed, and move to archive
593
+ na archive "An existing task"
594
+ ```
595
+
596
+ ##### tag
597
+
598
+ Add, remove, or modify tags.
599
+
600
+ Use `na tag TAGNAME --[search|tagged] SEARCH_STRING` to add a tag to matching action (use `--all` to apply to all matching actions). If you use `!TAGNAME` it will remove that tag (regardless of value). To change the value of an existing tag (or add it if it doesn't exist), use `~TAGNAME(NEW VALUE)`.
601
+
602
+ ```
603
+ NAME
604
+ tag - Add tags to matching action(s)
605
+
606
+ SYNOPSIS
607
+
608
+ na [global options] tag [command options] TAG
609
+
610
+ DESCRIPTION
611
+ Provides an easy way to tag existing actions. Use !tag to remove a tag, use ~tag(new value) to change a tag or add a value. If multiple todo files are found in the current directory, a menu will allow you to pick which file to act on, or use --all to apply to all matches.
612
+
613
+ COMMAND OPTIONS
614
+ --all - Act on all matches immediately (no menu)
615
+ -d, --depth=DEPTH - Search for files X directories deep (default: 1)
616
+ --[no-]done - Include @done actions
617
+ -e, --regex - Interpret search pattern as regular expression
618
+ --file=PATH - Specify the file to search for the task (default: none)
619
+ --in, --todo=TODO_FILE - Use a known todo file, partial matches allowed (default: none)
620
+ --search, --find, --grep=QUERY - Filter results using search terms (may be used more than once, default: none)
621
+ --tagged=TAG - Match actions containing tag. Allows value comparisons (may be used more than once, default: none)
622
+ -x, --exact - Match pattern exactly
623
+
624
+ EXAMPLES
625
+
626
+ # Find "An existing task" action and add @project(warpspeed) to it
627
+ na tag "project(warpspeed)" --search "An existing task"
628
+
629
+ # Find all actions tagged @project2 and remove @project1 from them
630
+ na tag "!project1" --tagged project2 --all
631
+
632
+ # Remove @project2 from all actions
633
+ na tag "!project2" --all
634
+
635
+ # Find "An existing task" and change (or add) its @project tag value to "dirt nap"
636
+ na tag "~project(dirt nap)" --search "An existing task"
637
+ ```
638
+
639
+ ##### undo
640
+
641
+ Undoes the last file change resulting from an add or update command. If no argument is given, it undoes whatever the last change in history was. If an argument is provided, it's used to match against the change history, finding a specific file to restore from backup.
642
+
643
+ Only the most recent change can be undone.
644
+
645
+ ```
646
+ NAME
647
+ undo - Undo the last change
648
+
649
+ SYNOPSIS
650
+
651
+ na [global options] undo [FILE]...
652
+
653
+ DESCRIPTION
654
+ Run without argument to undo most recent change
655
+
656
+ EXAMPLES
657
+
658
+ # Undo the last change
659
+ na undo
660
+
661
+ # Undo the last change to a file matching "myproject"
662
+ na undo myproject
663
+ ```
664
+
515
665
  ### Configuration
516
666
 
517
667
  Global options such as todo extension and default next action tag can be stored permanently by using the `na initconfig` command. Run na with the global options you'd like to set, and add `initconfig` at the end of the command. A file will be written to `~/.na.rc`. You can edit this manually, or just update it using the `initconfig --force` command to overwrite it with new settings.
data/bin/commands/add.rb CHANGED
@@ -62,25 +62,23 @@ class App
62
62
  if NA.global_file
63
63
  target = File.expand_path(NA.global_file)
64
64
  unless File.exist?(target)
65
- res = NA.yn(NA::Color.template('{by}Specified file not found, create it'), default: true)
65
+ res = NA.yn(NA::Color.template("#{NA.theme[:warning]}Specified file not found, create it"), default: true)
66
66
  if res
67
67
  basename = File.basename(target, ".#{NA.extension}")
68
68
  NA.create_todo(target, basename, template: global_options[:template])
69
69
  else
70
- puts NA::Color.template('{r}Cancelled{x}')
71
- Process.exit 1
70
+ NA.notify("#{NA.theme[:error]}Cancelled", exit_code: 1)
72
71
  end
73
72
  end
74
73
  elsif options[:file]
75
74
  target = File.expand_path(options[:file])
76
75
  unless File.exist?(target)
77
- res = NA.yn(NA::Color.template('{by}Specified file not found, create it'), default: true)
76
+ res = NA.yn(NA::Color.template("#{NA.theme[:warning]}Specified file not found, create it"), default: true)
78
77
  if res
79
78
  basename = File.basename(target, ".#{NA.extension}")
80
79
  NA.create_todo(target, basename, template: global_options[:template])
81
80
  else
82
- puts NA::Color.template('{r}Cancelled{x}')
83
- Process.exit 1
81
+ NA.notify("#{NA.theme[:error]}Cancelled", exit_code: 1)
84
82
  end
85
83
  end
86
84
  elsif options[:todo]
@@ -102,8 +100,8 @@ class App
102
100
  target = File.expand_path(todo)
103
101
  unless File.exist?(target)
104
102
 
105
- res = NA.yn(NA::Color.template("{by}Specified file not found, create #{todo}"), default: true)
106
- NA.notify('{r}Cancelled{x}', exit_code: 1) unless res
103
+ res = NA.yn(NA::Color.template("#{NA.theme[:warning]}Specified file not found, create #{todo}"), default: true)
104
+ NA.notify("#{NA.theme[:error]}Cancelled{x}", exit_code: 1) unless res
107
105
 
108
106
  basename = File.basename(target, ".#{NA.extension}")
109
107
  NA.create_todo(target, basename, template: global_options[:template])
@@ -113,7 +111,7 @@ class App
113
111
  else
114
112
  files = NA.find_files(depth: options[:depth])
115
113
  if files.count.zero?
116
- res = NA.yn(NA::Color.template('{by}No todo file found, create one'), default: true)
114
+ res = NA.yn(NA::Color.template("#{NA.theme[:warning]}No todo file found, create one"), default: true)
117
115
  if res
118
116
  basename = File.expand_path('.').split('/').last
119
117
  target = "#{basename}.#{NA.extension}"
@@ -122,7 +120,7 @@ class App
122
120
  end
123
121
  end
124
122
  target = files.count > 1 ? NA.select_file(files) : files[0]
125
- NA.notify('{r}Cancelled{x}', exit_code: 1) unless files.count.positive? && File.exist?(target)
123
+ NA.notify("#{NA.theme[:error]}Cancelled{x}", exit_code: 1) unless files.count.positive? && File.exist?(target)
126
124
 
127
125
  end
128
126
 
@@ -131,8 +129,8 @@ class App
131
129
  elsif $stdin.isatty && TTY::Which.exist?('gum')
132
130
  `gum input --placeholder "Enter a task" --char-limit=500 --width=#{TTY::Screen.columns}`.strip
133
131
  elsif $stdin.isatty
134
- puts NA::Color.template('{bm}Enter task:{x}')
135
- reader.read_line(NA::Color.template('{by}> {bw}')).strip
132
+ NA.notify("#{NA.theme[:prompt]}Enter task:")
133
+ reader.read_line(NA::Color.template("#{NA.theme[:warning]}> #{NA.theme[:action]}")).strip
136
134
  end
137
135
 
138
136
  if action.nil? || action.empty?
@@ -171,7 +169,7 @@ class App
171
169
  args << '--width $(tput cols)'
172
170
  `gum write #{args.join(' ')}`.strip.split("\n")
173
171
  else
174
- puts NA::Color.template('{bm}Enter a note, {bw}CTRL-d{bm} to end editing{bw}')
172
+ NA.notify("#{NA.theme[:prompt]}Enter a note, {bw}CTRL-d#{NA.theme[:prompt]} to end editing#{NA.theme[:action]}")
175
173
  reader.read_multiline
176
174
  end
177
175
  end
@@ -28,6 +28,10 @@ class App
28
28
  c.arg_name 'PATH'
29
29
  c.flag %i[file]
30
30
 
31
+ c.desc 'Use a known todo file, partial matches allowed'
32
+ c.arg_name 'TODO_FILE'
33
+ c.flag %i[in todo]
34
+
31
35
  c.desc 'Search for files X directories deep'
32
36
  c.arg_name 'DEPTH'
33
37
  c.flag %i[d depth], must_match: /^[1-9]$/, type: :integer, default_value: 1
data/bin/commands/edit.rb CHANGED
@@ -51,11 +51,11 @@ class App
51
51
  ]
52
52
  `gum input #{opts.join(' ')}`.strip
53
53
  elsif $stdin.isatty && options[:tagged].empty?
54
- puts NA::Color.template('{bm}Enter search string:{x}')
55
- reader.read_line(NA::Color.template('{by}> {bw}')).strip
54
+ NA.notify("#{NA.theme[:prompt]}Enter search string:")
55
+ reader.read_line(NA::Color.template("#{NA.theme[:warning]}> #{NA.theme[:action]}")).strip
56
56
  end
57
57
 
58
- NA.notify('{br}Empty input{x}', exit_code: 1) unless action
58
+ NA.notify("#{NA.theme[:error]}Empty input", exit_code: 1) if (action.nil? || action.empty?) && options[:tagged].empty?
59
59
 
60
60
  if action
61
61
  tokens = nil
@@ -79,32 +79,28 @@ class App
79
79
  end
80
80
 
81
81
  if (action.nil? || action.empty?) && options[:tagged].empty?
82
- NA.notify('{br}Empty input, cancelled{x}', exit_code: 1)
82
+ NA.notify("#{NA.theme[:error]}Empty input, cancelled", exit_code: 1)
83
83
  end
84
84
 
85
- all_req = options[:tagged].join(' ') !~ /[+!\-]/ && !options[:or]
85
+ all_req = options[:tagged].join(' ') !~ /[+!-]/ && !options[:or]
86
86
  tags = []
87
87
  options[:tagged].join(',').split(/ *, */).each do |arg|
88
- m = arg.match(/^(?<req>[+\-!])?(?<tag>[^ =<>$\^]+?)(?:(?<op>[=<>]{1,2}|[*$\^]=)(?<val>.*?))?$/)
88
+ m = arg.match(/^(?<req>[+\-!])?(?<tag>[^ =<>*$\^~]+?)(?:(?<op>[=<>~]{1,2}|[*$\^]=)(?<val>.*?))?$/)
89
89
 
90
90
  tags.push({
91
91
  tag: m['tag'].wildcard_to_rx,
92
92
  comp: m['op'],
93
93
  value: m['val'],
94
94
  required: all_req || (!m['req'].nil? && m['req'] == '+'),
95
- negate: !m['req'].nil? && m['req'] =~ /[!\-]/
95
+ negate: !m['req'].nil? && m['req'] =~ /[!-]/
96
96
  })
97
97
  end
98
98
 
99
- target_proj = if NA.cwd_is == :project
100
- NA.cwd
101
- else
102
- nil
103
- end
99
+ target_proj = NA.cwd_is == :project ? NA.cwd : nil
104
100
 
105
101
  if options[:file]
106
102
  file = File.expand_path(options[:file])
107
- NA.notify('{r}File not found', exit_code: 1) unless File.exist?(file)
103
+ NA.notify("#{NA.theme[:error]}File not found", exit_code: 1) unless File.exist?(file)
108
104
 
109
105
  targets = [file]
110
106
  elsif options[:todo]
@@ -114,7 +110,7 @@ class App
114
110
  todo.push({
115
111
  token: m['tok'],
116
112
  required: all_req || (!m['req'].nil? && m['req'] == '+'),
117
- negate: !m['req'].nil? && m['req'] =~ /[!\-]/
113
+ negate: !m['req'].nil? && m['req'] =~ /[!-]/
118
114
  })
119
115
  end
120
116
  dirs = NA.match_working_dir(todo)
@@ -123,28 +119,29 @@ class App
123
119
  targets = [dirs[0]]
124
120
  elsif dirs.count.positive?
125
121
  targets = NA.select_file(dirs, multiple: true)
126
- NA.notify('{r}Cancelled', exit_code: 1) unless targets && targets.count.positive?
122
+ NA.notify("#{NA.theme[:error]}Cancelled", exit_code: 1) unless targets && targets.count.positive?
127
123
  else
128
- NA.notify('{r}Todo not found', exit_code: 1) unless targets && targets.count.positive?
124
+ NA.notify("#{NA.theme[:error]}Todo not found", exit_code: 1) unless targets && targets.count.positive?
129
125
 
130
126
  end
131
127
  else
132
128
  files = NA.find_files(depth: options[:depth])
133
- NA.notify('{r}No todo file found', exit_code: 1) if files.count.zero?
129
+ NA.notify("#{NA.theme[:error]}No todo file found", exit_code: 1) if files.count.zero?
134
130
 
135
131
  targets = files.count > 1 ? NA.select_file(files, multiple: true) : [files[0]]
136
- NA.notify('{r}Cancelled{x}', exit_code: 1) unless files.count.positive?
132
+ NA.notify("#{NA.theme[:error]}Cancelled", exit_code: 1) unless files.count.positive?
137
133
 
138
134
  end
139
135
 
140
- NA.notify('{r}No search terms provided', exit_code: 1) if tokens.nil? && options[:tagged].empty?
136
+ NA.notify("#{NA.theme[:error]}No search terms provided", exit_code: 1) if tokens.nil? && options[:tagged].empty?
141
137
 
142
138
  targets.each do |target|
143
- NA.update_action(target, tokens,
144
- done: options[:done],
145
- edit: options[:edit],
146
- project: target_proj,
147
- tagged: tags)
139
+ NA.update_action(target,
140
+ tokens,
141
+ done: options[:done],
142
+ edit: options[:edit],
143
+ project: target_proj,
144
+ tagged: tags)
148
145
  end
149
146
  end
150
147
  end
data/bin/commands/find.rb CHANGED
@@ -73,7 +73,12 @@ class App
73
73
  if options[:exact] || options[:regex]
74
74
  search = args.join(' ')
75
75
  else
76
- search = args.join(' ').gsub(/(?<=\A|[ ,])(?<req>[+\-!])?@(?<tag>[^ *=<>$\^,@(]+)(?:\((?<value>.*?)\)| *(?<op>[=<>]{1,2}|[*$\^]=) *(?<val>.*?(?=\Z|[,@])))?/) do |arg|
76
+ rx = [
77
+ '(?<=\A|[ ,])(?<req>[+!-])?@(?<tag>[^ *=<>$*\^,@(]+)',
78
+ '(?:\((?<value>.*?)\)| *(?<op>[=<>~]{1,2}|[*$\^]=) *',
79
+ '(?<val>.*?(?=\Z|[,@])))?'
80
+ ].join('')
81
+ search = args.join(' ').gsub(Regexp.new(rx)) do
77
82
  m = Regexp.last_match
78
83
  string = if m['value']
79
84
  "#{m['req']}#{m['tag']}=#{m['value']}"
@@ -87,17 +92,17 @@ class App
87
92
 
88
93
  search = search.gsub(/ +/, ' ').strip
89
94
 
90
- all_req = options[:tagged].join(' ') !~ /[+!\-]/ && !options[:or]
95
+ all_req = options[:tagged].join(' ') !~ /[+!-]/ && !options[:or]
91
96
  tags = []
92
97
  options[:tagged].join(',').split(/ *, */).each do |arg|
93
- m = arg.match(/^(?<req>[+\-!])?(?<tag>[^ =<>$\^]+?) *(?:(?<op>[=<>]{1,2}|[*$\^]=) *(?<val>.*?))?$/)
98
+ m = arg.match(/^(?<req>[+!-])?(?<tag>[^ =<>$*~\^]+?) *(?:(?<op>[=<>~]{1,2}|[*$\^]=) *(?<val>.*?))?$/)
94
99
 
95
100
  tags.push({
96
101
  tag: m['tag'].wildcard_to_rx,
97
102
  comp: m['op'],
98
103
  value: m['val'],
99
104
  required: all_req || (!m['req'].nil? && m['req'] == '+'),
100
- negate: !m['req'].nil? && m['req'] =~ /[!\-]/
105
+ negate: !m['req'].nil? && m['req'] =~ /[!-]/ ? true : false
101
106
  })
102
107
  end
103
108
 
@@ -112,47 +117,55 @@ class App
112
117
  tokens = Regexp.new(search, Regexp::IGNORECASE)
113
118
  else
114
119
  tokens = []
115
- all_req = search !~ /[+!\-]/ && !options[:or]
120
+ all_req = search !~ /(?<=[, ])[+!-]/ && !options[:or]
116
121
 
117
122
  search.split(/ /).each do |arg|
118
123
  m = arg.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
119
124
  tokens.push({
120
125
  token: Regexp.escape(m['tok']),
121
126
  required: all_req || (!m['req'].nil? && m['req'] == '+'),
122
- negate: !m['req'].nil? && m['req'] =~ /[!\-]/
127
+ negate: !m['req'].nil? && m['req'] =~ /[!-]/ ? true : false
123
128
  })
124
129
  end
125
130
  end
126
131
 
127
- todo = nil
132
+ todos = nil
128
133
  if options[:in]
129
- todo = []
134
+ todos = []
130
135
  options[:in].split(/ *, */).each do |a|
131
136
  m = a.match(/^(?<req>[+\-!])?(?<tok>.*?)$/)
132
- todo.push({
133
- token: m['tok'],
134
- required: all_req || (!m['req'].nil? && m['req'] == '+'),
135
- negate: !m['req'].nil? && m['req'] =~ /[!\-]/
136
- })
137
+ todos.push({
138
+ token: m['tok'],
139
+ required: all_req || (!m['req'].nil? && m['req'] == '+'),
140
+ negate: !m['req'].nil? && m['req'] =~ /[!-]/
141
+ })
137
142
  end
138
143
  end
139
144
 
140
- files, actions, = NA.parse_actions(depth: depth,
141
- done: options[:done],
142
- query: todo,
143
- search: tokens,
144
- tag: tags,
145
- negate: options[:invert],
146
- regex: options[:regex],
147
- project: options[:project],
148
- require_na: false)
145
+ todo = NA::Todo.new({
146
+ depth: depth,
147
+ done: options[:done],
148
+ query: todos,
149
+ search: tokens,
150
+ tag: tags,
151
+ negate: options[:invert],
152
+ regex: options[:regex],
153
+ project: options[:project],
154
+ require_na: false
155
+ })
156
+
149
157
  regexes = if tokens.is_a?(Array)
150
158
  tokens.delete_if { |token| token[:negate] }.map { |token| token[:token] }
151
159
  else
152
160
  [tokens]
153
161
  end
154
162
 
155
- NA.output_actions(actions, depth, files: files, regexes: regexes, notes: options[:notes], nest: options[:nest], nest_projects: options[:omnifocus])
163
+ todo.actions.output(depth,
164
+ files: todo.files,
165
+ regexes: regexes,
166
+ notes: options[:notes],
167
+ nest: options[:nest],
168
+ nest_projects: options[:omnifocus])
156
169
  end
157
170
  end
158
171
  end
data/bin/commands/init.rb CHANGED
@@ -14,7 +14,7 @@ class App
14
14
  project = args.join(' ')
15
15
  elsif
16
16
  project = File.expand_path('.').split('/').last
17
- project = reader.read_line(NA::Color.template('{y}Project name {bw}> {x}'), value: project).strip if $stdin.isatty
17
+ project = reader.read_line(NA::Color.template("#{NA.theme[:prompt]}Project name #{NA.theme[:filename]}> "), value: project).strip if $stdin.isatty
18
18
  end
19
19
 
20
20
  target = "#{project}.#{NA.extension}"