na 1.2.80 → 1.2.82

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/actions.rb CHANGED
@@ -5,24 +5,19 @@ module NA
5
5
  class Actions < Array
6
6
  def initialize(actions = [])
7
7
  super
8
- concat(actions)
9
8
  end
10
9
 
11
- ##
12
- ## Pretty print a list of actions
13
- ##
14
- ## @param depth [Integer] The depth of the action
15
- ## @param config [Hash] The configuration options
16
- ##
17
- ## @option config [Array] :files The files to include in the output
18
- ## @option config [Array] :regexes The regexes to match against
19
- ## @option config [Boolean] :notes Whether to include notes in the output
20
- ## @option config [Boolean] :nest Whether to nest the output
21
- ## @option config [Boolean] :nest_projects Whether to nest projects in the output
22
- ## @option config [Boolean] :no_files Whether to include files in the output
23
- ##
24
- ## @return [String] The output string
25
- ##
10
+ # Pretty print a list of actions
11
+ #
12
+ # @param depth [Integer] The depth of the action
13
+ # @param config [Hash] The configuration options
14
+ # @option config [Array] :files The files to include in the output
15
+ # @option config [Array] :regexes The regexes to match against
16
+ # @option config [Boolean] :notes Whether to include notes in the output
17
+ # @option config [Boolean] :nest Whether to nest the output
18
+ # @option config [Boolean] :nest_projects Whether to nest projects in the output
19
+ # @option config [Boolean] :no_files Whether to include files in the output
20
+ # @return [String] The output string
26
21
  def output(depth, config = {})
27
22
  NA::Benchmark.measure('Actions.output') do
28
23
  defaults = {
@@ -31,87 +26,94 @@ module NA
31
26
  notes: false,
32
27
  nest: false,
33
28
  nest_projects: false,
34
- no_files: false,
29
+ no_files: false
35
30
  }
36
31
  config = defaults.merge(config)
37
32
 
38
- return if config[:files].nil?
33
+ return if config[:files].nil?
39
34
 
40
- if config[:nest]
41
- template = NA.theme[:templates][:default]
42
- template = NA.theme[:templates][:no_file] if config[:no_files]
35
+ if config[:nest]
36
+ template = NA.theme[:templates][:default]
37
+ template = NA.theme[:templates][:no_file] if config[:no_files]
43
38
 
44
- parent_files = {}
45
- out = []
39
+ parent_files = {}
40
+ out = []
46
41
 
47
- if config[:nest_projects]
48
- each do |action|
49
- parent_files[action.file] ||= []
50
- parent_files[action.file].push(action)
51
- end
42
+ if config[:nest_projects]
43
+ each do |action|
44
+ parent_files[action.file] ||= []
45
+ parent_files[action.file].push(action)
46
+ end
52
47
 
53
- parent_files.each do |file, acts|
54
- projects = NA.project_hierarchy(acts)
55
- out.push("#{file.sub(%r{^./}, "").shorten_path}:")
56
- out.concat(NA.output_children(projects, 0))
57
- end
58
- else
59
- template = NA.theme[:templates][:default]
60
- template = NA.theme[:templates][:no_file] if config[:no_files]
48
+ parent_files.each do |file, acts|
49
+ projects = NA.project_hierarchy(acts)
50
+ out.push("#{file.sub(%r{^./}, '').shorten_path}:")
51
+ out.concat(NA.output_children(projects, 0))
52
+ end
53
+ else
54
+ template = NA.theme[:templates][:default]
55
+ template = NA.theme[:templates][:no_file] if config[:no_files]
61
56
 
62
- each do |action|
63
- parent_files[action.file] ||= []
64
- parent_files[action.file].push(action)
65
- end
57
+ each do |action|
58
+ parent_files[action.file] ||= []
59
+ parent_files[action.file].push(action)
60
+ end
66
61
 
67
- parent_files.each do |file, acts|
68
- out.push("#{file.sub(%r{^\./}, "")}:")
69
- acts.each do |a|
70
- out.push("\t- [#{a.parent.join("/")}] #{a.action}")
71
- out.push("\t\t#{a.note.join("\n\t\t")}") unless a.note.empty?
62
+ parent_files.each do |file, acts|
63
+ out.push("#{file.sub(%r{^\./}, '')}:")
64
+ acts.each do |a|
65
+ out.push("\t- [#{a.parent.join('/')}] #{a.action}")
66
+ out.push("\t\t#{a.note.join("\n\t\t")}") unless a.note.empty?
67
+ end
72
68
  end
73
69
  end
74
- end
75
- NA::Pager.page out.join("\n")
76
- else
77
- # Optimize template selection
78
- template = case
79
- when config[:no_files]
80
- NA.theme[:templates][:no_file]
81
- when config[:files]&.count&.positive?
82
- config[:files].count == 1 ? NA.theme[:templates][:single_file] : NA.theme[:templates][:multi_file]
83
- when depth > 1
84
- NA.theme[:templates][:multi_file]
70
+ NA::Pager.page out.join("\n")
85
71
  else
86
- NA.theme[:templates][:default]
87
- end
88
- template += "%note" if config[:notes]
72
+ # Optimize template selection
73
+ template = if config[:no_files]
74
+ NA.theme[:templates][:no_file]
75
+ elsif config[:files]&.count&.positive?
76
+ config[:files].count == 1 ? NA.theme[:templates][:single_file] : NA.theme[:templates][:multi_file]
77
+ elsif depth > 1
78
+ NA.theme[:templates][:multi_file]
79
+ else
80
+ NA.theme[:templates][:default]
81
+ end
82
+ template += '%note' if config[:notes]
89
83
 
90
- # Skip debug output if not verbose
91
- config[:files]&.each { |f| NA.notify(f, debug: true) } if config[:files] && NA.verbose
84
+ # Show './' for current directory only when listing also includes subdir files
85
+ if template == NA.theme[:templates][:multi_file]
86
+ has_subdir = config[:files]&.any? { |f| File.dirname(f) != '.' } || depth > 1
87
+ NA.show_cwd_indicator = !has_subdir.nil?
88
+ else
89
+ NA.show_cwd_indicator = false
90
+ end
92
91
 
93
- # Optimize output generation - compile all output first, then apply regexes
94
- output = String.new
95
- NA::Benchmark.measure('Generate action strings') do
96
- each_with_index do |action, idx|
97
- # Generate raw output without regex processing
98
- output << action.pretty(template: { templates: { output: template } }, regexes: [], notes: config[:notes])
99
- output << "\n" unless idx == size - 1
92
+ # Skip debug output if not verbose
93
+ config[:files]&.each { |f| NA.notify(f, debug: true) } if config[:files] && NA.verbose
94
+
95
+ # Optimize output generation - compile all output first, then apply regexes
96
+ output = String.new
97
+ NA::Benchmark.measure('Generate action strings') do
98
+ each_with_index do |action, idx|
99
+ # Generate raw output without regex processing
100
+ output << action.pretty(template: { templates: { output: template } }, regexes: [], notes: config[:notes])
101
+ output << "\n" unless idx == size - 1
102
+ end
100
103
  end
101
- end
102
104
 
103
- # Apply regex highlighting to the entire output at once
104
- if config[:regexes].any?
105
- NA::Benchmark.measure('Apply regex highlighting') do
106
- output = output.highlight_search(config[:regexes])
105
+ # Apply regex highlighting to the entire output at once
106
+ if config[:regexes].any?
107
+ NA::Benchmark.measure('Apply regex highlighting') do
108
+ output = output.highlight_search(config[:regexes])
109
+ end
107
110
  end
108
- end
109
111
 
110
- NA::Benchmark.measure('Pager.page call') do
111
- NA::Pager.page(output)
112
+ NA::Benchmark.measure('Pager.page call') do
113
+ NA::Pager.page(output)
114
+ end
112
115
  end
113
116
  end
114
- end
115
117
  end
116
118
  end
117
119
  end
data/lib/na/array.rb CHANGED
@@ -1,21 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class ::Array
4
- ##
5
- ## Like Array#compact -- removes nil items, but also
6
- ## removes empty strings, zero or negative numbers and FalseClass items
7
- ##
8
- ## @return [Array] Array without "bad" elements
9
- ##
4
+ # Like Array#compact -- removes nil items, but also
5
+ # removes empty strings, zero or negative numbers and FalseClass items
6
+ #
7
+ # @return [Array] Array without "bad" elements
10
8
  def remove_bad
11
9
  compact.map { |x| x.is_a?(String) ? x.strip : x }.select(&:good?)
12
10
  end
13
11
 
12
+ # Wrap each string in the array to the given width and indent, with color
13
+ #
14
+ # @param width [Integer] Maximum line width
15
+ # @param indent [Integer] Indentation spaces
16
+ # @param color [String] Color code to apply
17
+ # @return [Array, String] Wrapped and colorized lines
14
18
  def wrap(width, indent, color)
15
19
  return map { |l| "#{color} #{l.wrap(width, 2)}" } if width < 60
16
20
 
17
21
  map! do |l|
18
- "#{color}#{' ' * indent }• #{l.wrap(width, indent)}{x}"
22
+ "#{color}#{' ' * indent}• #{l.wrap(width, indent)}{x}"
19
23
  end
20
24
  "\n#{join("\n")}"
21
25
  end
data/lib/na/benchmark.rb CHANGED
@@ -5,12 +5,19 @@ module NA
5
5
  class << self
6
6
  attr_accessor :enabled, :timings
7
7
 
8
+ # Initialize benchmarking state
9
+ #
10
+ # @return [void]
8
11
  def init
9
- @enabled = ENV['NA_BENCHMARK'] == '1' || ENV['NA_BENCHMARK'] == 'true'
12
+ @enabled = %w[1 true].include?(ENV.fetch('NA_BENCHMARK', nil))
10
13
  @timings = []
11
14
  @start_time = Time.now
12
15
  end
13
16
 
17
+ # Measure the execution time of a block
18
+ #
19
+ # @param label [String] Label for the measurement
20
+ # @return [Object] Result of the block
14
21
  def measure(label)
15
22
  return yield unless @enabled
16
23
 
@@ -21,24 +28,29 @@ module NA
21
28
  result
22
29
  end
23
30
 
31
+ # Output a performance report to STDERR
32
+ #
33
+ # @return [void]
24
34
  def report
25
35
  return unless @enabled
26
36
 
27
37
  total = @timings.sum { |t| t[:duration] }
28
- $stderr.puts "\n#{NA::Color.template('{y}=== NA Performance Report ===')}"
29
- $stderr.puts NA::Color.template("{dw}Total: {bw}#{total.round(2)}ms{x}")
30
- $stderr.puts NA::Color.template("{dw}GC Count: {bw}#{GC.count}{x}") if defined?(GC)
31
- $stderr.puts NA::Color.template("{dw}Memory: {bw}#{(GC.stat[:heap_live_slots] * 40 / 1024.0).round(1)}KB{x}") if defined?(GC)
32
- $stderr.puts ""
38
+ warn "\n#{NA::Color.template('{y}=== NA Performance Report ===')}"
39
+ warn NA::Color.template("{dw}Total: {bw}#{total.round(2)}ms{x}")
40
+ warn NA::Color.template("{dw}GC Count: {bw}#{GC.count}{x}") if defined?(GC)
41
+ if defined?(GC)
42
+ warn NA::Color.template("{dw}Memory: {bw}#{(GC.stat[:heap_live_slots] * 40 / 1024.0).round(1)}KB{x}")
43
+ end
44
+ warn ''
33
45
 
34
46
  @timings.each do |timing|
35
- pct = total > 0 ? ((timing[:duration] / total) * 100).round(1) : 0
47
+ pct = total.positive? ? ((timing[:duration] / total) * 100).round(1) : 0
36
48
  bar = '█' * [(pct / 2).round, 50].min
37
- $stderr.puts NA::Color.template(
49
+ warn NA::Color.template(
38
50
  "{dw}[{y}#{bar.ljust(25)}{dw}] {bw}#{timing[:duration].to_s.rjust(7)}ms {dw}(#{pct.to_s.rjust(5)}%) {x}#{timing[:label]}"
39
51
  )
40
52
  end
41
- $stderr.puts NA::Color.template("{y}#{'=' * 50}{x}\n")
53
+ warn NA::Color.template("{y}#{'=' * 50}{x}\n")
42
54
  end
43
55
  end
44
56
  end
data/lib/na/colors.rb CHANGED
@@ -5,7 +5,7 @@ module NA
5
5
  # Terminal output color functions.
6
6
  module Color
7
7
  # Regexp to match excape sequences
8
- ESCAPE_REGEX = /(?<=\[)(?:(?:(?:[349]|10)[0-9]|[0-9])?;?)+(?=m)/
8
+ ESCAPE_REGEX = /(?<=\[)(?:(?:(?:[349]|10)[0-9]|[0-9])?;?)+(?=m)/.freeze
9
9
 
10
10
  # All available color names. Available as methods and string extensions.
11
11
  #
@@ -99,35 +99,33 @@ module NA
99
99
 
100
100
  # Template coloring
101
101
  class ::String
102
- ##
103
- ## Extract the longest valid %color name from a string.
104
- ##
105
- ## Allows %colors to bleed into other text and still
106
- ## be recognized, e.g. %greensomething still finds
107
- ## %green.
108
- ##
109
- ## @return [String] a valid color name
110
- ##
102
+ # Extract the longest valid %color name from a string.
103
+ #
104
+ # Allows %colors to bleed into other text and still
105
+ # be recognized, e.g. %greensomething still finds
106
+ # %green.
107
+ #
108
+ # @return [String] a valid color name
111
109
  def validate_color
112
110
  valid_color = nil
113
111
  compiled = ''
114
- normalize_color.split('').each do |char|
112
+ normalize_color.chars.each do |char|
115
113
  compiled += char
116
- valid_color = compiled if Color.attributes.include?(compiled.to_sym) || compiled =~ /^([fb]g?)?#([a-f0-9]{6})$/i
114
+ if Color.attributes.include?(compiled.to_sym) || compiled =~ /^([fb]g?)?#([a-f0-9]{6})$/i
115
+ valid_color = compiled
116
+ end
117
117
  end
118
118
 
119
119
  valid_color
120
120
  end
121
121
 
122
- ##
123
- ## Normalize a color name, removing underscores,
124
- ## replacing "bright" with "bold", and converting
125
- ## bgbold to boldbg
126
- ##
127
- ## @return [String] Normalized color name
128
- ##
122
+ # Normalize a color name, removing underscores,
123
+ # replacing "bright" with "bold", and converting
124
+ # bgbold to boldbg
125
+ #
126
+ # @return [String] Normalized color name
129
127
  def normalize_color
130
- gsub(/_/, '').sub(/bright/i, 'bold').sub(/bgbold/, 'boldbg')
128
+ gsub('_', '').sub(/bright/i, 'bold').sub('bgbold', 'boldbg')
131
129
  end
132
130
 
133
131
  # Get the calculated ANSI color at the end of the
@@ -159,20 +157,20 @@ module NA
159
157
  rgbb = c
160
158
  end
161
159
  else
162
- c.split(/;/).each do |i|
160
+ c.split(';').each do |i|
163
161
  x = i.to_i
164
162
  if x <= 9
165
163
  em << x
166
- elsif x >= 30 && x <= 39
164
+ elsif x.between?(30, 39)
167
165
  rgbf = nil
168
166
  fg = x
169
- elsif x >= 40 && x <= 49
167
+ elsif x.between?(40, 49)
170
168
  rgbb = nil
171
169
  bg = x
172
- elsif x >= 90 && x <= 97
170
+ elsif x.between?(90, 97)
173
171
  rgbf = nil
174
172
  fg = x
175
- elsif x >= 100 && x <= 107
173
+ elsif x.between?(100, 107)
176
174
  rgbb = nil
177
175
  bg = x
178
176
  end
@@ -208,48 +206,48 @@ module NA
208
206
  # Pre-computed colors hash (expensive to create, so we cache it)
209
207
  def colors_hash
210
208
  @colors_hash ||= { w: white, k: black, g: green, l: blue,
211
- y: yellow, c: cyan, m: magenta, r: red,
212
- W: bgwhite, K: bgblack, G: bggreen, L: bgblue,
213
- Y: bgyellow, C: bgcyan, M: bgmagenta, R: bgred,
214
- d: dark, b: bold, u: underline, i: italic, x: reset }
209
+ y: yellow, c: cyan, m: magenta, r: red,
210
+ W: bgwhite, K: bgblack, G: bggreen, L: bgblue,
211
+ Y: bgyellow, C: bgcyan, M: bgmagenta, R: bgred,
212
+ d: dark, b: bold, u: underline, i: italic, x: reset }
215
213
  end
216
214
 
217
- ##
218
- ## Enables colored output
219
- ##
220
- ## @example Turn color on or off based on TTY
221
- ## NA::Color.coloring = STDOUT.isatty
215
+ #
216
+ # Enables colored output
217
+ #
218
+ # @example Turn color on or off based on TTY
219
+ # NA::Color.coloring = STDOUT.isatty
222
220
  def coloring
223
221
  @coloring ||= true
224
222
  end
225
223
 
226
- ##
227
- ## Convert a template string to a colored string.
228
- ## Colors are specified with single letters inside
229
- ## curly braces. Uppercase changes background color.
230
- ##
231
- ## w: white, k: black, g: green, l: blue, y: yellow,
232
- ## c: cyan, m: magenta, r: red, b: bold, u: underline,
233
- ## i: italic, x: reset (remove background, color,
234
- ## emphasis)
235
- ##
236
- ## Also accepts {#RGB} and {#RRGGBB} strings. Put a b
237
- ## before the hash to make it a background color
238
- ##
239
- ## @example Convert a templated string
240
- ## Color.template('{Rwb}Warning:{x} {w}you look a
241
- ## little {g}ill{x}')
242
- ##
243
- ## @example Convert using RGB colors
244
- ## Color.template('{#f0a}This is an RGB color')
245
- ##
246
- ## @param input [String, Array] The template
247
- ## string. If this is an array, the
248
- ## elements will be joined with a
249
- ## space.
250
- ##
251
- ## @return [String] Colorized string
252
- ##
224
+ #
225
+ # Convert a template string to a colored string.
226
+ # Colors are specified with single letters inside
227
+ # curly braces. Uppercase changes background color.
228
+ #
229
+ # w: white, k: black, g: green, l: blue, y: yellow,
230
+ # c: cyan, m: magenta, r: red, b: bold, u: underline,
231
+ # i: italic, x: reset (remove background, color,
232
+ # emphasis)
233
+ #
234
+ # Also accepts {#RGB} and {#RRGGBB} strings. Put a b
235
+ # before the hash to make it a background color
236
+ #
237
+ # @example Convert a templated string
238
+ # Color.template('{Rwb}Warning:{x} {w}you look a
239
+ # little {g}ill{x}')
240
+ #
241
+ # @example Convert using RGB colors
242
+ # Color.template('{#f0a}This is an RGB color')
243
+ #
244
+ # @param input [String, Array] The template
245
+ # string. If this is an array, the
246
+ # elements will be joined with a
247
+ # space.
248
+ #
249
+ # @return [String] Colorized string
250
+ #
253
251
  def template(input)
254
252
  input = input.join(' ') if input.is_a? Array
255
253
  return input.gsub(/(?<!\\)\{#?(\w+)\}/i, '') unless NA::Color.coloring?
@@ -265,9 +263,9 @@ module NA
265
263
  end
266
264
 
267
265
  # Convert to format string
268
- fmt = processed_input.gsub(/%/, '%%')
266
+ fmt = processed_input.gsub('%', '%%')
269
267
  fmt = fmt.gsub(/(?<!\\)\{(\w+)\}/i) do
270
- Regexp.last_match(1).split('').map { |c| "%<#{c}>s" }.join('')
268
+ Regexp.last_match(1).chars.map { |c| "%<#{c}>s" }.join
271
269
  end
272
270
 
273
271
  # Use pre-computed colors hash
@@ -283,18 +281,18 @@ module NA
283
281
  new_method = <<-EOSCRIPT
284
282
  # Color string as #{c}
285
283
  def #{c}(string = nil)
286
- result = ''
287
- result << "\e[#{v}m" if NA::Color.coloring?
284
+ result = ''.dup
285
+ result << "\e[#{v}m".dup if NA::Color.coloring?
288
286
  if block_given?
289
287
  result << yield
290
288
  elsif string.respond_to?(:to_str)
291
- result << string.to_str
289
+ result << string.to_str.dup
292
290
  elsif respond_to?(:to_str)
293
- result << to_str
291
+ result << to_str.dup
294
292
  else
295
293
  return result #only switch on
296
294
  end
297
- result << "\e[0m" if NA::Color.coloring?
295
+ result << "\e[0m".dup if NA::Color.coloring?
298
296
  result
299
297
  end
300
298
  EOSCRIPT
@@ -306,19 +304,19 @@ module NA
306
304
  # Accept brightwhite in addition to boldwhite
307
305
  new_method = <<-EOSCRIPT
308
306
  # color string as #{c}
309
- def #{c.to_s.sub(/bold/, 'bright')}(string = nil)
310
- result = ''
311
- result << "\e[#{v}m" if NA::Color.coloring?
307
+ def #{c.to_s.sub('bold', 'bright')}(string = nil)
308
+ result = ''.dup
309
+ result << "\e[#{v}m".dup if NA::Color.coloring?
312
310
  if block_given?
313
311
  result << yield
314
312
  elsif string.respond_to?(:to_str)
315
- result << string.to_str
313
+ result << string.to_str.dup
316
314
  elsif respond_to?(:to_str)
317
- result << to_str
315
+ result << to_str.dup
318
316
  else
319
317
  return result #only switch on
320
318
  end
321
- result << "\e[0m" if NA::Color.coloring?
319
+ result << "\e[0m".dup if NA::Color.coloring?
322
320
  result
323
321
  end
324
322
  EOSCRIPT
@@ -326,13 +324,13 @@ module NA
326
324
  module_eval(new_method)
327
325
  end
328
326
 
329
- ##
330
- ## Generate escape codes for hex colors
331
- ##
332
- ## @param hex [String] The hexadecimal color code
333
- ##
334
- ## @return [String] ANSI escape string
335
- ##
327
+ #
328
+ # Generate escape codes for hex colors
329
+ #
330
+ # @param hex [String] The hexadecimal color code
331
+ #
332
+ # @return [String] ANSI escape string
333
+ #
336
334
  def rgb(hex)
337
335
  is_bg = hex.match(/^bg?#/) ? true : false
338
336
  hex_string = hex.sub(/^([fb]g?)?#/, '')
@@ -345,13 +343,12 @@ module NA
345
343
  t << parts[e]
346
344
  t << parts[e]
347
345
  end
348
- hex_string = t.join('')
346
+ hex_string = t.join
349
347
  end
350
348
 
351
349
  parts = hex_string.match(/(?<r>..)(?<g>..)(?<b>..)/)
352
- t = []
353
- %w[r g b].each do |e|
354
- t << parts[e].hex
350
+ t = %w[r g b].map do |e|
351
+ parts[e].hex
355
352
  end
356
353
 
357
354
  "\e[#{is_bg ? '48' : '38'};2;#{t.join(';')}m"
@@ -359,7 +356,7 @@ module NA
359
356
 
360
357
  # Regular expression that is used to scan for ANSI-sequences while
361
358
  # uncoloring strings.
362
- COLORED_REGEXP = /\e\[(?:(?:(?:[349]|10)[0-9]|[0-9])?;?)+m/
359
+ COLORED_REGEXP = /\e\[(?:(?:(?:[349]|10)[0-9]|[0-9])?;?)+m/.freeze
363
360
 
364
361
  # Returns an uncolored version of the string, that is all
365
362
  # ANSI-sequences are stripped from the string.
@@ -379,6 +376,7 @@ module NA
379
376
  def attributes
380
377
  ATTRIBUTE_NAMES
381
378
  end
379
+
382
380
  extend self
383
381
  end
384
382
  end
data/lib/na/editor.rb CHANGED
@@ -1,16 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'English'
4
+
1
5
  module NA
2
6
  module Editor
3
7
  class << self
4
8
  def default_editor(prefer_git_editor: true)
5
- if prefer_git_editor
6
- editor ||= ENV['NA_EDITOR'] || ENV['GIT_EDITOR'] || ENV['EDITOR']
7
- else
8
- editor ||= ENV['NA_EDITOR'] || ENV['EDITOR'] || ENV['GIT_EDITOR']
9
- end
9
+ editor ||= if prefer_git_editor
10
+ ENV['NA_EDITOR'] || ENV['GIT_EDITOR'] || ENV.fetch('EDITOR', nil)
11
+ else
12
+ ENV['NA_EDITOR'] || ENV['EDITOR'] || ENV.fetch('GIT_EDITOR', nil)
13
+ end
10
14
 
11
15
  return editor if editor&.good? && TTY::Which.exist?(editor)
12
16
 
13
- NA.notify("No EDITOR environment variable, testing available editors", debug: true)
17
+ NA.notify('No EDITOR environment variable, testing available editors', debug: true)
14
18
  editors = %w[vim vi code subl mate mvim nano emacs]
15
19
  editors.each do |ed|
16
20
  try = TTY::Which.which(ed)
@@ -43,11 +47,10 @@ module NA
43
47
  "#{editor} #{args.join(' ')}"
44
48
  end
45
49
 
46
- ##
47
- ## Create a process for an editor and wait for the file handle to return
48
- ##
49
- ## @param input [String] Text input for editor
50
- ##
50
+ # Create a process for an editor and wait for the file handle to return
51
+ #
52
+ # @param input [String] Text input for editor
53
+ # @return [String] Edited text
51
54
  def fork_editor(input = '', message: :default)
52
55
  # raise NonInteractive, 'Non-interactive terminal' unless $stdout.isatty || ENV['DOING_EDITOR_TEST']
53
56
 
@@ -78,8 +81,8 @@ module NA
78
81
  Process.wait(pid)
79
82
 
80
83
  begin
81
- if $?.exitstatus == 0
82
- input = IO.read(tmpfile.path)
84
+ if $CHILD_STATUS.exitstatus.zero?
85
+ input = File.read(tmpfile.path)
83
86
  else
84
87
  exit_now! 'Cancelled'
85
88
  end
@@ -88,16 +91,13 @@ module NA
88
91
  tmpfile.unlink
89
92
  end
90
93
 
91
- input.split(/\n/).delete_if(&:ignore?).join("\n")
94
+ input.split("\n").delete_if(&:ignore?).join("\n")
92
95
  end
93
96
 
94
- ##
95
- ## Takes a multi-line string and formats it as an entry
96
- ##
97
- ## @param input [String] The string to parse
98
- ##
99
- ## @return [Array] [[String]title, [Note]note]
100
- ##
97
+ # Takes a multi-line string and formats it as an entry
98
+ #
99
+ # @param input [String] The string to parse
100
+ # @return [Array] [[String]title, [Note]note]
101
101
  def format_input(input)
102
102
  NA.notify("#{NA.theme[:error]}No content in entry", exit_code: 1) if input.nil? || input.strip.empty?
103
103
 
@@ -108,7 +108,7 @@ module NA
108
108
  title = title.expand_date_tags
109
109
 
110
110
  note = if input_lines.length > 1
111
- input_lines[1..-1]
111
+ input_lines[1..]
112
112
  else
113
113
  []
114
114
  end