Module: NA::Editor
- Included in:
- NA
- Defined in:
- lib/na/editor.rb
Overview
Provides editor selection and argument helpers for launching text editors.
Class Method Summary collapse
-
.args_for_editor(editor) ⇒ String
Returns the editor command with appropriate arguments for file opening.
-
.default_editor(prefer_git_editor: true) ⇒ String?
Returns the default editor command, checking environment variables and available editors.
-
.editor_with_args ⇒ String
Returns the default editor command with its arguments.
-
.fork_editor(input = '', message: :default) ⇒ String
Create a process for an editor and wait for the file handle to return.
-
.format_input(input) ⇒ Array
Takes a multi-line string and formats it as an entry.
-
.format_multi_action_input(actions) ⇒ String
Format multiple actions for multi-edit.
-
.parse_multi_action_output(content) ⇒ Hash
Parse multi-action editor output.
Class Method Details
.args_for_editor(editor) ⇒ String
Returns the editor command with appropriate arguments for file opening.
45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/na/editor.rb', line 45 def args_for_editor(editor) return editor if editor =~ /-\S/ args = case editor when /^(subl|code|mate)$/ ['-w'] when /^(vim|mvim)$/ ['-f'] else [] end "#{editor} #{args.join(' ')}" end |
.default_editor(prefer_git_editor: true) ⇒ String?
Returns the default editor command, checking environment variables and available editors.
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/na/editor.rb', line 12 def default_editor(prefer_git_editor: true) editor ||= if prefer_git_editor ENV['NA_EDITOR'] || ENV['GIT_EDITOR'] || ENV.fetch('EDITOR', nil) else ENV['NA_EDITOR'] || ENV['EDITOR'] || ENV.fetch('GIT_EDITOR', nil) end return editor if editor&.good? && TTY::Which.exist?(editor) NA.notify('No EDITOR environment variable, testing available editors', debug: true) editors = %w[vim vi code subl mate mvim nano emacs] editors.each do |ed| try = TTY::Which.which(ed) if try NA.notify("Using editor #{try}", debug: true) return try end end NA.notify("#{NA.theme[:error]}No editor found", exit_code: 5) nil end |
.editor_with_args ⇒ String
Returns the default editor command with its arguments.
38 39 40 |
# File 'lib/na/editor.rb', line 38 def editor_with_args args_for_editor(default_editor) end |
.fork_editor(input = '', message: :default) ⇒ String
Create a process for an editor and wait for the file handle to return
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/na/editor.rb', line 63 def fork_editor(input = '', message: :default) # raise NonInteractive, 'Non-interactive terminal' unless $stdout.isatty || ENV['DOING_EDITOR_TEST'] NA.notify("#{NA.theme[:error]}No EDITOR variable defined in environment", exit_code: 5) if default_editor.nil? tmpfile = Tempfile.new(['na_temp', '.na']) File.open(tmpfile.path, 'w+') do |f| f.puts input unless .nil? f.puts == :default ? '# First line is the action, lines after are added as a note' : end end pid = Process.fork { system("#{editor_with_args} #{tmpfile.path}") } trap('INT') do begin Process.kill(9, pid) rescue StandardError Errno::ESRCH end tmpfile.unlink tmpfile.close! exit 0 end Process.wait(pid) begin if $CHILD_STATUS.exitstatus.zero? input = File.read(tmpfile.path) else exit_now! 'Cancelled' end ensure tmpfile.close tmpfile.unlink end # Don't strip comments if this looks like multi-action format (has # ------ markers) if input.include?('# ------ ') input else input.split("\n").delete_if(&:ignore?).join("\n") end end |
.format_input(input) ⇒ Array
Takes a multi-line string and formats it as an entry
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/na/editor.rb', line 115 def format_input(input) NA.notify("#{NA.theme[:error]}No content in entry", exit_code: 1) if input.nil? || input.strip.empty? input_lines = input.split(/[\n\r]+/).delete_if(&:ignore?) title = input_lines[0]&.strip NA.notify("#{NA.theme[:error]}No content in first line", exit_code: 1) if title.nil? || title.strip.empty? title = title. note = if input_lines.length > 1 input_lines[1..] else [] end unless note.empty? note.map!(&:strip) note.delete_if { |l| l =~ /^\s*$/ || l =~ /^#/ } end [title, note] end |
.format_multi_action_input(actions) ⇒ String
Format multiple actions for multi-edit
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/na/editor.rb', line 141 def format_multi_action_input(actions) header = <<~EOF # Instructions: # - Edit the action text (the lines WITHOUT # comment markers) # - DO NOT remove or edit the lines starting with "# ------" # - Add notes on new lines after the action # - Blank lines are ignored # EOF # Use + to create a mutable string content = +header actions.each do |action| # Use file_path to get the path and file_line to get the line number content << "# ------ #{action.file_path}:#{action.file_line}\n" content << "#{action.action}\n" content << "#{action.note.join("\n")}\n" if action.note.any? content << "\n" # Blank line separator end content end |
.parse_multi_action_output(content) ⇒ Hash
Parse multi-action editor output
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/na/editor.rb', line 169 def parse_multi_action_output(content) results = {} current_file = nil current_action = nil current_note = [] content.lines.each do |line| stripped = line.strip # Check for file marker: # ------ path:line match = stripped.match(/^# ------ (.+?):(\d+)$/) if match # Save previous action if exists results[current_file] = [current_action, current_note] if current_file && current_action # Start new action current_file = "#{match[1]}:#{match[2]}" current_action = nil current_note = [] next end # Skip other comment lines next if stripped.start_with?('#') # Skip blank lines next if stripped.empty? # Store as action or note based on what we've seen so far if current_action.nil? current_action = stripped else # Subsequent lines are notes current_note << stripped end end # Save last action results[current_file] = [current_action, current_note] if current_file && current_action results end |