na 1.2.80 → 1.2.81

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/pager.rb CHANGED
@@ -7,22 +7,21 @@ module NA
7
7
  module Pager
8
8
  class << self
9
9
  # Boolean determines whether output is paginated
10
+ #
11
+ # @return [Boolean] true if paginated
10
12
  def paginate
11
13
  @paginate ||= false
12
14
  end
13
15
 
14
16
  # Enable/disable pagination
15
17
  #
16
- # @param should_paginate [Boolean] true to paginate
17
- def paginate=(should_paginate)
18
- @paginate = should_paginate
19
- end
18
+ # @return [void]
19
+ attr_writer :paginate
20
20
 
21
- # Page output. If @paginate is false, just dump to
22
- # STDOUT
23
- #
24
- # @param text [String] text to paginate
21
+ # Page output. If @paginate is false, just dump to STDOUT
25
22
  #
23
+ # @param text [String] text to paginate
24
+ # @return [Boolean, nil] true if paged, false if not, nil if no pager
26
25
  def page(text)
27
26
  unless @paginate
28
27
  puts text
@@ -53,31 +52,53 @@ module NA
53
52
  # Wait for pager to complete
54
53
  _, status = Process.waitpid2(pid)
55
54
  status.success?
56
- rescue SystemCallError => e
55
+ rescue SystemCallError
57
56
  # Clean up on error
58
- write_io.close rescue nil
59
- Process.kill('TERM', pid) rescue nil
60
- Process.waitpid(pid) rescue nil
57
+ begin
58
+ write_io.close
59
+ rescue StandardError
60
+ nil
61
+ end
62
+ begin
63
+ Process.kill('TERM', pid)
64
+ rescue StandardError
65
+ nil
66
+ end
67
+ begin
68
+ Process.waitpid(pid)
69
+ rescue StandardError
70
+ nil
71
+ end
61
72
  false
62
73
  end
63
74
  end
64
75
 
65
76
  private
66
77
 
78
+ # Get the git pager command if available
79
+ #
80
+ # @return [String, nil] git pager command
67
81
  def git_pager
68
82
  TTY::Which.exist?('git') ? `#{TTY::Which.which('git')} config --get-all core.pager` : nil
69
83
  end
70
84
 
85
+ # List of possible pager commands
86
+ #
87
+ # @return [Array<String>] pager commands
71
88
  def pagers
72
89
  [
73
- ENV['PAGER'],
90
+ ENV.fetch('PAGER', nil),
74
91
  'less -FXr',
75
- ENV['GIT_PAGER'],
92
+ ENV.fetch('GIT_PAGER', nil),
76
93
  git_pager,
77
94
  'more -r'
78
95
  ].remove_bad
79
96
  end
80
97
 
98
+ # Find the first available executable pager command
99
+ #
100
+ # @param commands [Array<String>] commands to check
101
+ # @return [String, nil] first available command
81
102
  def find_executable(*commands)
82
103
  execs = commands.empty? ? pagers : commands
83
104
  execs
@@ -85,6 +106,9 @@ module NA
85
106
  .find { |cmd| TTY::Which.exist?(cmd.split.first) }
86
107
  end
87
108
 
109
+ # Determine which pager to use
110
+ #
111
+ # @return [String, nil] pager command
88
112
  def which_pager
89
113
  @which_pager ||= find_executable(*pagers)
90
114
  end
data/lib/na/project.rb CHANGED
@@ -4,6 +4,13 @@ module NA
4
4
  class Project < Hash
5
5
  attr_accessor :project, :indent, :line, :last_line
6
6
 
7
+ # Initialize a Project object
8
+ #
9
+ # @param project [String] Project name
10
+ # @param indent [Integer] Indentation level
11
+ # @param line [Integer] Starting line number
12
+ # @param last_line [Integer] Ending line number
13
+ # @return [void]
7
14
  def initialize(project, indent = 0, line = 0, last_line = 0)
8
15
  super()
9
16
  @project = project
@@ -12,17 +19,23 @@ module NA
12
19
  @last_line = last_line
13
20
  end
14
21
 
22
+ # String representation of the project
23
+ #
24
+ # @return [String]
15
25
  def to_s
16
26
  { project: @project, indent: @indent, line: @line, last_line: @last_line }.to_s
17
27
  end
18
28
 
29
+ # Inspect the project object
30
+ #
31
+ # @return [String]
19
32
  def inspect
20
33
  [
21
34
  "@project: #{@project}",
22
35
  "@indent: #{@indent}",
23
36
  "@line: #{@line}",
24
37
  "@last_line: #{@last_line}"
25
- ].join(" ")
38
+ ].join(' ')
26
39
  end
27
40
  end
28
41
  end
data/lib/na/prompt.rb CHANGED
@@ -4,6 +4,10 @@ module NA
4
4
  # Prompt Hooks
5
5
  module Prompt
6
6
  class << self
7
+ # Generate the shell prompt hook script for na
8
+ #
9
+ # @param shell [Symbol] Shell type (:zsh, :fish, :bash)
10
+ # @return [String] Shell script for prompt hook
7
11
  def prompt_hook(shell)
8
12
  case shell
9
13
  when :zsh
@@ -14,7 +18,9 @@ module NA
14
18
  when :tag
15
19
  'na tagged $(basename "$PWD")'
16
20
  else
17
- NA.notify("#{NA.theme[:error]}When using a global file, a prompt hook requires `--cwd_as [tag|project]`", exit_code: 1)
21
+ NA.notify(
22
+ "#{NA.theme[:error]}When using a global file, a prompt hook requires `--cwd_as [tag|project]`", exit_code: 1
23
+ )
18
24
  end
19
25
  else
20
26
  'na next'
@@ -31,7 +37,9 @@ module NA
31
37
  when :tag
32
38
  'na tagged (basename "$PWD")'
33
39
  else
34
- NA.notify("#{NA.theme[:error]}When using a global file, a prompt hook requires `--cwd_as [tag|project]`", exit_code: 1)
40
+ NA.notify(
41
+ "#{NA.theme[:error]}When using a global file, a prompt hook requires `--cwd_as [tag|project]`", exit_code: 1
42
+ )
35
43
  end
36
44
  else
37
45
  'na next'
@@ -50,7 +58,9 @@ module NA
50
58
  when :tag
51
59
  'na tagged $(basename "$PWD")'
52
60
  else
53
- NA.notify("#{NA.theme[:error]}When using a global file, a prompt hook requires `--cwd_as [tag|project]`", exit_code: 1)
61
+ NA.notify(
62
+ "#{NA.theme[:error]}When using a global file, a prompt hook requires `--cwd_as [tag|project]`", exit_code: 1
63
+ )
54
64
  end
55
65
  else
56
66
  'na next'
@@ -70,6 +80,10 @@ module NA
70
80
  end
71
81
  end
72
82
 
83
+ # Get the configuration file path for the given shell
84
+ #
85
+ # @param shell [Symbol] Shell type
86
+ # @return [String] Path to shell config file
73
87
  def prompt_file(shell)
74
88
  files = {
75
89
  zsh: '~/.zshrc',
@@ -80,6 +94,10 @@ module NA
80
94
  files[shell]
81
95
  end
82
96
 
97
+ # Display the prompt hook script and notify user of config file
98
+ #
99
+ # @param shell [Symbol] Shell type
100
+ # @return [void]
83
101
  def show_prompt_hook(shell)
84
102
  file = prompt_file(shell)
85
103
 
@@ -87,6 +105,10 @@ module NA
87
105
  puts prompt_hook(shell)
88
106
  end
89
107
 
108
+ # Install the prompt hook script into the shell config file
109
+ #
110
+ # @param shell [Symbol] Shell type
111
+ # @return [void]
90
112
  def install_prompt_hook(shell)
91
113
  file = prompt_file(shell)
92
114
 
data/lib/na/string.rb CHANGED
@@ -6,30 +6,20 @@ REGEX_TIME = /^#{REGEX_CLOCK}$/i.freeze
6
6
 
7
7
  # String helpers
8
8
  class ::String
9
- ##
10
- ## Insert a comment character at the start of every line
11
- ##
12
- ## @param char [String] The character to insert (default #)
13
- ##
14
- def comment(char = "#")
15
- split(/\n/).map { |l| "# #{l}" }.join("\n")
9
+ # Insert a comment character at the start of every line
10
+ # @param char [String] The character to insert (default #)
11
+ def comment(_char = '#')
12
+ split("\n").map { |l| "# #{l}" }.join("\n")
16
13
  end
17
14
 
18
- ##
19
- ## Tests if object is nil or empty
20
- ##
21
- ## @return [Boolean] true if object is defined and
22
- ## has content
23
- ##
15
+ # Tests if object is nil or empty
16
+ # @return [Boolean] true if object is defined and has content
24
17
  def good?
25
18
  !strip.empty?
26
19
  end
27
20
 
28
- ##
29
- ## Test if line should be ignored
30
- ##
31
- ## @return [Boolean] line is empty or comment
32
- ##
21
+ # Test if line should be ignored
22
+ # @return [Boolean] line is empty or comment
33
23
  def ignore?
34
24
  line = self
35
25
  line =~ /^#/ || line.strip.empty?
@@ -50,19 +40,16 @@ class ::String
50
40
  end
51
41
 
52
42
  # IO.read(file).force_encoding('ASCII-8BIT').encode('UTF-8', invalid: :replace, undef: :replace, replace: '?')
53
- IO.read(file).force_encoding('utf-8')
43
+ File.read(file).force_encoding('utf-8')
54
44
  end
55
45
 
56
- ##
57
- ## Determine indentation level of line
58
- ##
59
- ## @return [Number] number of indents detected
60
- ##
46
+ # Determine indentation level of line
47
+ # @return [Number] number of indents detected
61
48
  def indent_level
62
49
  prefix = match(/(^[ \t]+)/)
63
50
  return 0 if prefix.nil?
64
51
 
65
- prefix[1].gsub(/ /, "\t").scan(/\t/).count
52
+ prefix[1].gsub(' ', "\t").scan("\t").count
66
53
  end
67
54
 
68
55
  def action?
@@ -94,31 +81,22 @@ class ::String
94
81
  self =~ /@#{NA.na_tag}\b/
95
82
  end
96
83
 
97
- ##
98
- ## Colorize the dirname and filename of a path
99
- ##
100
- ## @return Colorized string
101
- ##
84
+ # Colorize the dirname and filename of a path
85
+ # @return [String] Colorized string
102
86
  def highlight_filename
103
87
  dir = File.dirname(self).shorten_path.trunc_middle(TTY::Screen.columns / 3)
104
88
  file = NA.include_ext ? File.basename(self) : File.basename(self, ".#{NA.extension}")
105
89
  "#{NA.theme[:dirname]}#{dir}/#{NA.theme[:filename]}#{file}{x}"
106
90
  end
107
91
 
108
- ##
109
- ## Colorize @tags with ANSI escapes
110
- ##
111
- ## @param color [String] color (see #Color)
112
- ## @param value [String] The value color
113
- ## template
114
- ## @param parens [String] The parens color
115
- ## template
116
- ## @param last_color [String] Color to restore after
117
- ## tag highlight
118
- ##
119
- ## @return [String] string with @tags highlighted
120
- ##
121
- def highlight_tags(color: NA.theme[:tags], value: NA.theme[:value], parens: NA.theme[:value_parens], last_color: NA.theme[:action])
92
+ # Colorize @tags with ANSI escapes
93
+ # @param color [String] color (see #Color)
94
+ # @param value [String] The value color template
95
+ # @param parens [String] The parens color template
96
+ # @param last_color [String] Color to restore after tag highlight
97
+ # @return [String] string with @tags highlighted
98
+ def highlight_tags(color: NA.theme[:tags], value: NA.theme[:value], parens: NA.theme[:value_parens],
99
+ last_color: NA.theme[:action])
122
100
  tag_color = NA::Color.template(color)
123
101
  paren_color = NA::Color.template(parens)
124
102
  value_color = NA::Color.template(value)
@@ -132,21 +110,16 @@ class ::String
132
110
  end
133
111
  end
134
112
 
135
- ##
136
- ## Highlight search results
137
- ##
138
- ## @param regexes [Array] The regexes for the
139
- ## search
140
- ## @param color [String] The highlight color
141
- ## template
142
- ## @param last_color [String] Color to restore after
143
- ## highlight
144
- ##
113
+ # Highlight search results
114
+ # @param regexes [Array] The regexes for the search
115
+ # @param color [String] The highlight color template
116
+ # @param last_color [String] Color to restore after highlight
145
117
  def highlight_search(regexes, color: NA.theme[:search_highlight], last_color: NA.theme[:action])
146
118
  string = dup
147
119
  color = NA::Color.template(color.dup)
148
120
  regexes.each do |rx|
149
121
  next if rx.nil?
122
+
150
123
  rx = Regexp.new(rx, Regexp::IGNORECASE) if rx.is_a?(String)
151
124
 
152
125
  string.gsub!(rx) do
@@ -158,16 +131,23 @@ class ::String
158
131
  string
159
132
  end
160
133
 
134
+ # Truncate the string in the middle, replacing the removed section with '[...]'.
135
+ # @param max [Integer] Maximum allowed length of the string
136
+ # @return [String] Truncated string with middle replaced if necessary
161
137
  def trunc_middle(max)
162
138
  return self unless length > max
163
139
 
164
140
  half = (max / 2).floor - 3
165
- chars = split('')
141
+ chars = chars
166
142
  pre = chars.slice(0, half)
167
143
  post = chars.reverse.slice(0, half).reverse
168
- "#{pre.join('')}[...]#{post.join('')}"
144
+ "#{pre.join}[...]#{post.join}"
169
145
  end
170
146
 
147
+ # Wrap the string to a given width, indenting each line and preserving tag formatting.
148
+ # @param width [Integer] The maximum line width
149
+ # @param indent [Integer] Number of spaces to indent each line
150
+ # @return [String] Wrapped string
171
151
  def wrap(width, indent)
172
152
  return "\n#{self}" if width <= 80
173
153
 
@@ -188,40 +168,33 @@ class ::String
188
168
  end
189
169
  end
190
170
  output << line.join(' ')
191
- output.join("\n" + ' ' * (indent + 2)).gsub(/†/, ' ')
171
+ output.join("\n#{' ' * (indent + 2)}").gsub(/†/, ' ')
192
172
  end
193
173
 
194
174
  # Returns the last escape sequence from a string.
195
- #
196
- # @note Actually returns all escape codes, with the
197
- # assumption that the result of inserting them
198
- # will generate the same color as was set at
199
- # the end of the string. Because you can send
200
- # modifiers like dark and bold separate from
201
- # color codes, only using the last code may
202
- # not render the same style.
203
- #
204
- # @return [String] All escape codes in string
205
- #
175
+ # @note Actually returns all escape codes, with the assumption that the result of inserting them will generate the same color as was set at end of the string. Because you can send modifiers like dark and bold separate from color codes, only using the last code may not render the same style.
176
+ # @return [String] All escape codes in string
206
177
  def last_color
207
- scan(/\e\[[\d;]+m/).join('').gsub(/\e\[0m/, '')
178
+ scan(/\e\[[\d;]+m/).join.gsub("\e[0m", '')
208
179
  end
209
180
 
210
- ##
211
- ## Convert a directory path to a regular expression
212
- ##
213
- ## @note Splits at / or :, adds variable distance
214
- ## between characters, joins segments with
215
- ## slashes and requires that last segment
216
- ## match last segment of target path
217
- ##
218
- ## @param distance The distance allowed between characters
219
- ## @param require_last Require match to be last element in path
220
- ##
181
+ # Convert a directory path to a regular expression
182
+ # @note Splits at / or :, adds variable distance between characters, joins segments with slashes and requires that last segment match last segment of target path
183
+ # @param distance [Integer] The distance allowed between characters
184
+ # @param require_last [Boolean] Require match to be last element in path
221
185
  def dir_to_rx(distance: 1, require_last: true)
222
- "#{split(%r{[/:]}).map { |comp| comp.split('').join(".{0,#{distance}}").gsub(/\*/, '[^ ]*?') }.join('.*?/.*?')}#{require_last ? '[^/]*?$' : ''}"
186
+ "#{split(%r{[/:]}).map do |comp|
187
+ comp.chars.join(".{0,#{distance}}").gsub('*', '[^ ]*?')
188
+ end.join('.*?/.*?')}#{require_last ? '[^/]*?$' : ''}"
223
189
  end
224
190
 
191
+ # Check if the string matches directory patterns using any, all, and none criteria.
192
+ # @param any [Array] Patterns where any match is sufficient
193
+ # @param all [Array] Patterns where all must match
194
+ # @param none [Array] Patterns where none must match
195
+ # @param require_last [Boolean] Require last segment match
196
+ # @param distance [Integer] Allowed character distance in regex
197
+ # @return [Boolean] True if matches criteria
225
198
  def dir_matches(any: [], all: [], none: [], require_last: true, distance: 1)
226
199
  any_rx = any.map { |q| q.dir_to_rx(distance: distance, require_last: require_last) }
227
200
  all_rx = all.map { |q| q.dir_to_rx(distance: distance, require_last: require_last) }
@@ -229,29 +202,29 @@ class ::String
229
202
  matches_any(any_rx) && matches_all(all_rx) && matches_none(none_rx)
230
203
  end
231
204
 
205
+ # Check if the string matches any, all, and none regex patterns.
206
+ # @param any [Array] Patterns where any match is sufficient
207
+ # @param all [Array] Patterns where all must match
208
+ # @param none [Array] Patterns where none must match
209
+ # @return [Boolean] True if matches criteria
232
210
  def matches(any: [], all: [], none: [])
233
211
  matches_any(any) && matches_all(all) && matches_none(none)
234
212
  end
235
213
 
236
- ##
237
- ## Convert wildcard characters to regular expressions
238
- ##
239
- ## @return [String] Regex string
240
- ##
214
+ # Convert wildcard characters to regular expressions
215
+ # @return [String] Regex string
241
216
  def wildcard_to_rx
242
- gsub(/\./, '\\.').gsub(/\?/, '.').gsub(/\*/, '[^ ]*?')
217
+ gsub('.', '\\.').gsub('?', '.').gsub('*', '[^ ]*?')
243
218
  end
244
219
 
220
+ # Capitalize the first character of the string in place.
221
+ # @return [String] The modified string
245
222
  def cap_first!
246
223
  replace cap_first
247
224
  end
248
225
 
249
- ##
250
- ## Capitalize first character, leaving other
251
- ## capitalization in place
252
- ##
253
- ## @return [String] capitalized string
254
- ##
226
+ # Capitalize first character, leaving other capitalization in place
227
+ # @return [String] capitalized string
255
228
  def cap_first
256
229
  sub(/^([a-z])(.*)$/) do
257
230
  m = Regexp.last_match
@@ -259,24 +232,14 @@ class ::String
259
232
  end
260
233
  end
261
234
 
262
- ##
263
- ## Replace home directory with tilde
264
- ##
265
- ## @return [String] shortened path
266
- ##
235
+ # Replace home directory with tilde
236
+ # @return [String] shortened path
267
237
  def shorten_path
268
- sub(/^#{ENV['HOME']}/, '~')
238
+ sub(/^#{Dir.home}/, '~')
269
239
  end
270
240
 
271
- ##
272
- ## Convert (chronify) natural language dates
273
- ## within configured date tags (tags whose value is
274
- ## expected to be a date). Modifies string in place.
275
- ##
276
- ## @param additional_tags [Array] An array of
277
- ## additional tags to
278
- ## consider date_tags
279
- ##
241
+ # Convert (chronify) natural language dates within configured date tags (tags whose value is expected to be a date). Modifies string in place.
242
+ # @param additional_tags [Array] An array of additional tags to consider date_tags
280
243
  def expand_date_tags(additional_tags = nil)
281
244
  iso_rx = /\d{4}-\d\d-\d\d \d\d:\d\d/
282
245
 
@@ -312,27 +275,14 @@ class ::String
312
275
  end
313
276
  end
314
277
 
315
- ##
316
- ## Converts input string into a Time object when input
317
- ## takes on the following formats:
318
- ## - interval format e.g. '1d2h30m', '45m'
319
- ## etc.
320
- ## - a semantic phrase e.g. 'yesterday
321
- ## 5:30pm'
322
- ## - a strftime e.g. '2016-03-15 15:32:04
323
- ## PDT'
324
- ##
325
- ## @param options Additional options
326
- ##
327
- ## @option options :future [Boolean] assume future date
328
- ## (default: false)
329
- ##
330
- ## @option options :guess [Symbol] :begin or :end to
331
- ## assume beginning or end of
332
- ## arbitrary time range
333
- ##
334
- ## @return [DateTime] result
335
- ##
278
+ # Converts input string into a Time object when input takes on the following formats:
279
+ # - interval format e.g. '1d2h30m', '45m' etc.
280
+ # - a semantic phrase e.g. 'yesterday 5:30pm'
281
+ # - a strftime e.g. '2016-03-15 15:32:04 PDT'
282
+ # @param options [Hash] Additional options
283
+ # @option options :future [Boolean] assume future date (default: false)
284
+ # @option options :guess [Symbol] :begin or :end to assume beginning or end of arbitrary time range
285
+ # @return [DateTime] result
336
286
  def chronify(**options)
337
287
  now = Time.now
338
288
  raise StandardError, "Invalid time expression #{inspect}" if to_s.strip == ''
@@ -353,7 +303,7 @@ class ::String
353
303
  else
354
304
  date_string = dup
355
305
  date_string = 'today' if date_string.match(REGEX_DAY) && now.strftime('%a') =~ /^#{Regexp.last_match(1)}/i
356
- date_string = "#{options[:context].to_s} #{date_string}" if date_string =~ REGEX_TIME && options[:context]
306
+ date_string = "#{options[:context]} #{date_string}" if date_string =~ REGEX_TIME && options[:context]
357
307
 
358
308
  require 'chronic' unless defined?(Chronic)
359
309
  res = Chronic.parse(date_string, {
@@ -368,8 +318,12 @@ class ::String
368
318
  res
369
319
  end
370
320
 
321
+ # Private helper methods for pattern matching
371
322
  private
372
323
 
324
+ # Returns true if none of the regexes match the string.
325
+ # @param regexes [Array] Array of regex patterns
326
+ # @return [Boolean] True if none match
373
327
  def matches_none(regexes)
374
328
  regexes.each do |rx|
375
329
  return false if match(Regexp.new(rx, Regexp::IGNORECASE))
@@ -377,6 +331,9 @@ class ::String
377
331
  true
378
332
  end
379
333
 
334
+ # Returns true if any of the regexes match the string.
335
+ # @param regexes [Array] Array of regex patterns
336
+ # @return [Boolean] True if any match
380
337
  def matches_any(regexes)
381
338
  regexes.each do |rx|
382
339
  return true if match(Regexp.new(rx, Regexp::IGNORECASE))
@@ -384,6 +341,9 @@ class ::String
384
341
  false
385
342
  end
386
343
 
344
+ # Returns true if all of the regexes match the string.
345
+ # @param regexes [Array] Array of regex patterns
346
+ # @return [Boolean] True if all match
387
347
  def matches_all(regexes)
388
348
  regexes.each do |rx|
389
349
  return false unless match(Regexp.new(rx, Regexp::IGNORECASE))
data/lib/na/theme.rb CHANGED
@@ -3,6 +3,8 @@
3
3
  module NA
4
4
  module Theme
5
5
  class << self
6
+ # Returns a help string describing available color placeholders for themes.
7
+ # @return [String] Help text for theme placeholders
6
8
  def template_help
7
9
  <<~EOHELP
8
10
  Use {X} placeholders to apply colors. Available colors are:
@@ -22,43 +24,47 @@ module NA
22
24
  EOHELP
23
25
  end
24
26
 
27
+ # Loads the theme configuration, merging defaults with any custom theme file and the provided template.
28
+ # Writes the help text and theme YAML to the theme file.
29
+ # @param template [Hash] Additional theme settings to merge
30
+ # @return [Hash] The merged theme configuration
25
31
  def load_theme(template: {})
26
32
  NA::Benchmark.measure('Theme.load_theme') do
27
33
  # Default colorization, can be overridden with full or partial template variable
28
34
  default_template = {
29
- parent: '{c}',
30
- bracket: '{dc}',
31
- parent_divider: '{xw}/',
32
- action: '{bg}',
33
- project: '{xbk}',
34
- tags: '{m}',
35
- value_parens: '{m}',
36
- values: '{c}',
37
- search_highlight: '{y}',
38
- note: '{dw}',
39
- dirname: '{xdw}',
40
- filename: '{xb}{#eccc87}',
41
- prompt: '{m}',
42
- success: '{bg}',
43
- error: '{b}{#b61d2a}',
44
- warning: '{by}',
45
- debug: '{dw}',
46
- templates: {
47
- output: '%filename%parents| %action',
48
- default: '%parent%action',
49
- single_file: '%parent%action',
50
- multi_file: '%filename%parent%action',
51
- no_file: '%parent%action'
35
+ parent: '{c}',
36
+ bracket: '{dc}',
37
+ parent_divider: '{xw}/',
38
+ action: '{bg}',
39
+ project: '{xbk}',
40
+ tags: '{m}',
41
+ value_parens: '{m}',
42
+ values: '{c}',
43
+ search_highlight: '{y}',
44
+ note: '{dw}',
45
+ dirname: '{xdw}',
46
+ filename: '{xb}{#eccc87}',
47
+ prompt: '{m}',
48
+ success: '{bg}',
49
+ error: '{b}{#b61d2a}',
50
+ warning: '{by}',
51
+ debug: '{dw}',
52
+ templates: {
53
+ output: '%filename%parents| %action',
54
+ default: '%parent%action',
55
+ single_file: '%parent%action',
56
+ multi_file: '%filename%parent%action',
57
+ no_file: '%parent%action'
58
+ }
52
59
  }
53
- }
54
60
 
55
- # Load custom theme
56
- theme_file = NA.database_path(file: 'theme.yaml')
57
- theme = if File.exist?(theme_file)
58
- YAML.load(IO.read(theme_file)) || {}
59
- else
60
- {}
61
- end
61
+ # Load custom theme
62
+ theme_file = NA.database_path(file: 'theme.yaml')
63
+ theme = if File.exist?(theme_file)
64
+ YAML.load(File.read(theme_file)) || {}
65
+ else
66
+ {}
67
+ end
62
68
  theme = default_template.deep_merge(theme)
63
69
 
64
70
  File.open(theme_file, 'w') do |f|