Class: TTY::Editor

Inherits:
Object
  • Object
show all
Defined in:
lib/tty/editor.rb,
lib/tty/editor/version.rb

Overview

A class responsible for launching an editor

Defined Under Namespace

Classes: CommandInvocationError, EditorNotFoundError

Constant Summary collapse

Error =
Class.new(StandardError)
InvalidArgumentError =

Raised when user provides unnexpected or incorrect argument

Class.new(Error)
EXECUTABLES =

List possible command line text editors

Returns:

  • (Array<String>)
[
  "atom", "code", "emacs", "gedit", "jed", "kate",
  "mate -w", "mg", "nano -w", "notepad", "pico",
  "qe", "subl -n -w", "vi", "vim"
].freeze
VERSION =
"0.7.0"

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(command: nil, raise_on_failure: false, hide_menu: false, prompt: "Select an editor?", env: {}, enable_color: nil, input: $stdin, output: $stdout, menu_interrupt: :error, &block) ⇒ Editor

Initialize an Editor

Examples:

TTY::Editor.new(command: "vim")

Parameters:

  • command (String) (defaults to: nil)

    the editor command to use, by default auto detects

  • env (Hash) (defaults to: {})

    environment variables to forward to the editor

  • input (IO) (defaults to: $stdin)

    the standard input

  • output (IO) (defaults to: $stdout)

    the standard output

  • raise_on_failure (Boolean) (defaults to: false)

    whether or not raise on command failure, false by default

  • hide_menu (Boolean) (defaults to: false)

    whether or not to hide commands menu, false by default

  • enable_color (Boolean) (defaults to: nil)

    disable or force prompt coloring, defaults to nil

  • menu_interrupt (Symbol) (defaults to: :error)

    how to handle Ctrl+C key interrupt out of :error, :signal, :exit, :noop



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/tty/editor.rb', line 162

def initialize(command: nil, raise_on_failure: false, hide_menu: false,
               prompt: "Select an editor?", env: {}, enable_color: nil,
               input: $stdin, output: $stdout, menu_interrupt: :error,
               &block)
  @env = env
  @command = nil
  @input = input
  @output = output
  @raise_on_failure = raise_on_failure
  @enable_color = enable_color
  @hide_menu = hide_menu
  @prompt = prompt
  @menu_interrupt = menu_interrupt

  block.(self) if block

  command(*Array(command))
end

Class Method Details

.available(*commands) ⇒ Array<String>

Find available text editors

Parameters:

  • commands (Array<String>)

    the commands to use intstead of defaults

Returns:

  • (Array<String>)

    the existing editor commands



86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/tty/editor.rb', line 86

def self.available(*commands)
  if commands.any?
    execs = search_executables(commands.map(&:to_s))
    return execs unless execs.empty?
  end

  if from_env.any?
    execs = search_executables(from_env)
    return execs unless execs.empty?
  end

  search_executables(EXECUTABLES)
end

.exist?(command) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Check if editor command exists

Examples:

exist?("vim") # => true
exist?("/usr/local/bin/vim") # => true
exist?("C:\\Program Files\\Vim\\vim.exe") # => true

Parameters:

  • command (String)

    the command to check for the existence

Returns:

  • (Boolean)


54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/tty/editor.rb', line 54

def self.exist?(command)
  path = Pathname(command)
  exts = [""].concat(ENV.fetch("PATHEXT", "").split(::File::PATH_SEPARATOR))

  if path.absolute?
    return exts.any? { |ext| ::File.exist?("#{command}#{ext}") }
  end

  ENV.fetch("PATH", "").split(::File::PATH_SEPARATOR).any? do |dir|
    file = ::File.join(dir, command)
    exts.any? { |ext| ::File.exist?("#{file}#{ext}") }
  end
end

.from_envArray<String>

Check editor from environment variables

Returns:

  • (Array<String>)


73
74
75
# File 'lib/tty/editor.rb', line 73

def self.from_env
  [ENV["VISUAL"], ENV["EDITOR"]].compact
end

.open(*files, text: nil, **options, &block) ⇒ Object

Open file in system editor

Examples:

TTY::Editor.open("/path/to/filename")
TTY::Editor.open("file1", "file2", "file3")
TTY::Editor.open(text: "Some text")

Parameters:

  • files (Array<String>)

    the files to open in an editor

  • command (String)

    the editor command to use, by default auto detects

  • text (String) (defaults to: nil)

    the text to edit in an editor

  • env (Hash)

    environment variables to forward to the editor

Returns:

  • (Object)


134
135
136
137
# File 'lib/tty/editor.rb', line 134

def self.open(*files, text: nil, **options, &block)
  editor = new(**options, &block)
  editor.open(*files, text: text)
end

Instance Method Details

#command(*commands) ⇒ String

Finds command using a configured command(s) or detected shell commands

Examples:

editor.command("vim")

Parameters:

  • commands (Array<String>)

    the optional command to use, by default auto detecting

Returns:

  • (String)

Raises:



211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/tty/editor.rb', line 211

def command(*commands)
  return @command if @command && commands.empty?

  execs = self.class.available(*commands)
  if execs.empty?
    raise EditorNotFoundError,
          "could not find a text editor to use. Please specify $VISUAL or "\
          "$EDITOR or install one of the following editors: " \
          "#{EXECUTABLES.map { |ed| ed.split.first }.join(", ")}."
  end
  @command = choose_exec_from(execs)
end

#env(value = (not_set = true)) ⇒ Hash

Read or update environment vars

Examples:

editor.env({"FOO" => "bar"})

Parameters:

  • value (Hash{String => String}) (defaults to: (not_set = true))

    the environment variables to use

Returns:

  • (Hash)


192
193
194
195
196
# File 'lib/tty/editor.rb', line 192

def env(value = (not_set = true))
  return @env if not_set

  @env = value
end

#open(*files, text: nil) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Run editor command in a shell

Parameters:

  • files (Array<String>)

    the files to open in an editor

  • text (String) (defaults to: nil)

    the text to edit in an editor

Returns:

  • (Boolean)

    whether editor command suceeded or not

Raises:



237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/tty/editor.rb', line 237

def open(*files, text: nil)
  validate_arguments(files, text)
  text_written = false

  filepaths = files.reduce([]) do |paths, filename|
    if !::File.exist?(filename)
      ::File.write(filename, text || "")
      text_written = true
    end
    paths + [filename]
  end

  if !text.nil? && !text_written
    tempfile = create_tempfile(text)
    filepaths << tempfile.path
  end

  run(filepaths)
ensure
  tempfile.unlink if tempfile
end