lib/tty/editor.rb in tty-editor-0.1.2 vs lib/tty/editor.rb in tty-editor-0.2.0

- old
+ new

@@ -1,16 +1,19 @@ # encoding: utf-8 require 'tty-prompt' require 'tty-which' require 'tempfile' +require 'fileutils' require 'shellwords' +require_relative 'editor/version' + module TTY # A class responsible for launching an editor # - # @api private + # @api public class Editor # Raised when command cannot be invoked class CommandInvocationError < RuntimeError; end # Raised when editor cannot be found @@ -23,18 +26,35 @@ # @api private def self.exist?(cmd) TTY::Which.exist?(cmd) end + # Check if Windowz + # + # @return [Boolean] + # + # @api public + def self.windows? + ::File::ALT_SEPARATOR == "\\" + end + + # Check editor from environment variables + # + # @return [Array[String]] + # + # @api public + def self.from_env + [ENV['VISUAL'], ENV['EDITOR']].compact + end + # List possible executable for editor command # # @return [Array[String]] # - # @api private + # @api public def self.executables - [ENV['VISUAL'], ENV['EDITOR'], - 'vim', 'vi', 'emacs', 'nano', 'nano-tiny', 'pico', 'mate -w'].compact + ['vim', 'vi', 'emacs', 'nano', 'nano-tiny', 'pico', 'mate -w'] end # Find available command # # @param [Array[String]] commands @@ -42,12 +62,19 @@ # # @return [Array[String]] # # @api public def self.available(*commands) - commands = commands.empty? ? executables : commands - commands.uniq.select(&method(:exist?)) + return commands unless commands.empty? + + if !from_env.all?(&:empty?) + [from_env.find { |e| !e.empty? }] + elsif windows? + ['notepad'] + else + executables.uniq.select(&method(:exist?)) + end end # Open file in system editor # # @example @@ -62,81 +89,86 @@ def self.open(*args) editor = new(*args) yield(editor) if block_given? - editor.run + editor.open end # Initialize an Editor # # @param [String] file + # @param [Hash[Symbol]] options + # @option options [Hash] :command + # the editor command to use, by default auto detects + # @option options [Hash] :env + # environment variables to forward to the editor # # @api public - def initialize(filename = nil, **options) + def initialize(*args, **options) + @filename = args.unshift.first @env = options.fetch(:env) { {} } @command = options[:command] - @filename = filename ? file_or_temp_path(filename) : nil + if @filename + if ::File.exist?(@filename) && !::FileTest.file?(@filename) + raise ArgumentError, "Don't know how to handle `#{@filename}`. " \ + "Please provida a file path or content" + elsif ::File.exist?(@filename) && !options[:content].to_s.empty? + ::File.open(@filename, 'a') { |f| f.write(options[:content]) } + elsif !::File.exist?(@filename) + ::File.write(@filename, options[:content]) + end + elsif options[:content] + @filename = tempfile_path(options[:content]) + end end - # Decide if temp file path needs generating + # Read or update environment vars # - # @return [String] - # the file path - # - # @api private - def file_or_temp_path(filename) - ::FileTest.file?(filename) ? filename : tempfile_path(filename) + # @api public + def env(value = (not_set = true)) + return @env if not_set + @env = value end # Finds command using a configured command(s) or detected shell commands. # # @param [Array[String]] commands + # the optional command to use, by default auto detecting # # @raise [TTY::CommandInvocationError] # # @return [String] # # @api public def command(*commands) - if @command && commands.empty? - @command - else - execs = self.class.available(*commands) - if execs.empty? - raise EditorNotFoundError, - 'Could not find editor to use. Please specify $VISUAL or $EDITOR' - else - exec = if execs.size > 1 - prompt = TTY::Prompt.new - prompt.enum_select('Select an editor?', execs) - else - execs[0] - end - @command = TTY::Which.which(exec) - end + return @command if @command && commands.empty? + + execs = self.class.available(*commands) + if execs.empty? + raise EditorNotFoundError, + 'Could not find editor to use. Please specify $VISUAL or $EDITOR' end + exec = choose_exec_from(execs) + @command = TTY::Which.which(exec.to_s) end - # Check if Windowz - # - # @return [Boolean] - # - # @api public - def windows? - ::File::ALT_SEPARATOR == "\\" + # @api private + def choose_exec_from(execs) + if execs.size > 1 + prompt = TTY::Prompt.new + prompt.enum_select('Select an editor?', execs) + else + execs[0] + end end # Escape file path # # @api private def escape_file - if windows? - @filename.gsub(/\//, '\\') - else - Shellwords.shellescape(@filename) - end + Shellwords.shellescape(@filename) end # Build command path to invoke # # @return [String] @@ -165,11 +197,11 @@ # Inovke editor command in a shell # # @raise [TTY::CommandInvocationError] # # @api private - def run - status = system(*Shellwords.split(command_path)) + def open + status = system(env, *Shellwords.split(command_path)) return status if status fail CommandInvocationError, "`#{command_path}` failed with status: #{$? ? $?.exitstatus : nil}" end end # Editor