Permalink
Browse files

Big refactor to have only Platform, Server and Client.

  • Loading branch information...
1 parent 812bcac commit 0c958629ad6addc2657711e17008b546ba469d52 @mudge mudge committed May 2, 2012
View
@@ -5,6 +5,6 @@ $: << File.expand_path('../../lib', __FILE__)
require 'irb'
require 'vimrunner'
-$vim = Vimrunner.start_gui_vim
+$vim = Vimrunner.start_gvim
IRB.start
View
@@ -1,16 +1,12 @@
-require 'vimrunner/client'
-require 'vimrunner/server'
+require "vimrunner/server"
+require "vimrunner/platform"
module Vimrunner
- # Starts a new Server with a terminal Vim instance and returns a client,
- # connected to it.
- def self.start_vim
- Client.new(Server.start)
+ def self.start(vim = Platform.vim, &blk)
+ Server.new(vim).start(&blk)
end
- # Starts a new Server with a GUI Vim instance and returns a client, connected
- # to it.
- def self.start_gui_vim
- Client.new(Server.start(:gui => true))
+ def self.start_gvim(&blk)
+ Server.new(Platform.gvim).start(&blk)
end
end
@@ -1,62 +1,74 @@
module Vimrunner
-
- # A Client is simply a proxy to a Vim server. It's initialized with a Server
- # instance and sends commands, keys and signals to it.
class Client
- attr_reader :server, :driver
+ attr_reader :server
def initialize(server)
@server = server
- @driver = server.driver
end
- # Adds a plugin to Vim's runtime. Initially, Vim is started without
- # sourcing any plugins to ensure a clean state. This method can be used to
- # populate the instance's environment.
+ # Public: Adds a plugin to Vim's runtime. Initially, Vim is started
+ # without sourcing any plugins to ensure a clean state. This method can be
+ # used to populate the instance's environment.
#
# dir - The base directory of the plugin, the one that contains
# its autoload, plugin, ftplugin, etc. directories.
- # entry_script - The Vim script that's runtime'd to initialize the plugin.
- # Optional.
+ # entry_script - The Vim script that's runtime'd to initialize the plugin
+ # (optional).
#
# Example:
#
# vim.add_plugin 'rails', 'plugin/rails.vim'
#
+ # Returns nothing.
def add_plugin(dir, entry_script = nil)
command("set runtimepath+=#{dir}")
command("runtime #{entry_script}") if entry_script
end
- # Invokes one of the basic actions the Vim server supports, sending a key
- # sequence. The keys are sent as-is, so it'd probably be better to use the
- # wrapper methods, #normal, #insert and so on.
+ def normal(keys = "")
+ server.remote_send("<C-\\><C-n>#{keys}")
+ end
+
+ # Public: Invokes one of the basic actions the Vim server supports,
+ # sending a key sequence. The keys are sent as-is, so it'd probably be
+ # better to use the wrapper methods, #normal, #insert and so on.
+ #
+ # Returns nothing.
def type(keys)
- invoke_vim '--remote-send', keys
+ server.remote_send(keys)
end
- # Executes the given command in the Vim instance and returns its output,
- # stripping all surrounding whitespace.
- def command(vim_command)
+ # Public: Starts a search in Vim for the given text. The result is that
+ # the cursor is positioned on its first occurrence.
+ #
+ # Returns nothing.
+ def search(text)
normal
+ type "/#{text}<CR>"
+ end
- escaped_command = vim_command.to_s.gsub("'", "''")
- expression = "VimrunnerEvaluateCommandOutput('#{escaped_command}')"
+ # Public: Switches Vim to insert mode and types in the given text.
+ #
+ # Returns nothing.
+ def insert(text)
+ normal "i#{text}"
+ end
- invoke_vim('--remote-expr', expression).tap do |output|
- raise InvalidCommandError if output =~ /^Vim:E\d+:/
- end
+ # Public: Writes the file being edited to disk. Note that you probably
+ # want to set the file's name first by using Runner#edit.
+ def write
+ command :write
end
- # Starts a search in Vim for the given text. The result is that the cursor
- # is positioned on its first occurrence.
- def search(text)
- normal
- type "/#{text}<cr>"
+ # Public: Echo each expression with a space in between.
+ #
+ # Returns the String output.
+ def echo(*expressions)
+ command "echo #{expressions.join(' ')}"
end
- # Sets a setting in Vim. If +value+ is nil, the setting is considered to be
- # a boolean.
+ # Public: Sets a setting in Vim. If +value+ is nil, the setting is
+ # considered to be a boolean.
#
# Examples:
#
@@ -71,34 +83,26 @@ def set(setting, value = nil)
end
end
- # Edits the file +filename+ with Vim.
+ # Public: Edits the file +filename+ with Vim.
#
# Note that this doesn't use the '--remote' Vim flag, it simply types in
- # the command manually. This is necessary to avoid the Vim instance getting
- # focus.
+ # the command manually. This is necessary to avoid the Vim instance
+ # getting focus.
def edit(filename)
command "edit #{filename}"
end
- # Writes the file being edited to disk. Note that you probably want to set
- # the file's name first by using Runner#edit.
- def write
- command :write
- end
-
- # Echo each expression with a space in between.
- def echo(*expressions)
- command "echo #{expressions.join(' ')}"
- end
-
- # Switches Vim to insert mode and types in the given text.
- def insert(text = '')
- normal "i#{text}"
- end
+ # Public: Executes the given command in the Vim instance and returns its
+ # output, stripping all surrounding whitespace.
+ #
+ # Returns the string output.
+ # Raises InvalidCommandError if the command is not recognised by vim.
+ def command(commands)
+ expression = "VimrunnerEvaluateCommandOutput('#{escape(commands)}')"
- # Switches Vim to normal mode and types in the given keys.
- def normal(keys = '')
- type "<c-\\><c-n>#{keys}"
+ server.remote_expr(expression).tap do |output|
+ raise InvalidCommandError if output =~ /^Vim:E\d+:/
+ end
end
# Kills the server it's connected to.
@@ -108,8 +112,8 @@ def kill
private
- def invoke_vim(*args)
- driver.run('--servername', server.name, *args)
+ def escape(string)
+ string.to_s.gsub("'", "''")
end
end
end
@@ -1,48 +0,0 @@
-module Vimrunner
- module Driver
- class Abstract
- attr_reader :executable
-
- def initialize(executable)
- @executable = executable
- end
-
- def spawn(name)
- raise NotImplementedError, "must be defined in a subclass."
- end
-
- def ==(other)
- other.is_a?(Driver::Abstract) && executable == other.executable
- end
-
- def run(*command)
- IO.popen([executable, *command]) { |io| io.read.strip }
- end
-
- # Sends a TERM signal to the given PID. Returns true if the process was
- # found and killed, false otherwise.
- def kill(pid)
- Process.kill('TERM', pid)
- true
- rescue Errno::ESRCH
- false
- end
-
- def suitable?
- version_info = run('--version')
- version_info.include?('+clientserver') and version_info.include?('+xterm_clipboard')
- rescue Errno::ENOENT
- # vim path was not found
- false
- end
-
- private
-
- # The path to a vimrc file containing some required vimscript. The server
- # is started with no settings or a vimrc, apart from this one.
- def vimrc_path
- File.join(File.expand_path('../../../..', __FILE__), 'vim', 'vimrc')
- end
- end
- end
-end
@@ -1,12 +0,0 @@
-require 'vimrunner/driver/abstract'
-
-module Vimrunner
- module Driver
- class Gui < Abstract
- def spawn(name)
- command = "#{executable} -f -u #{vimrc_path} --noplugin --servername #{name}"
- Kernel.spawn(command, [:in, :out, :err] => :close)
- end
- end
- end
-end
@@ -1,16 +0,0 @@
-require 'pty'
-
-require 'vimrunner/driver/abstract'
-
-module Vimrunner
- module Driver
- class Headless < Abstract
- def spawn(name)
- command = "#{executable} -u #{vimrc_path} --noplugin --servername #{name}"
- _r, _w, pid = PTY.spawn(command)
-
- pid
- end
- end
- end
-end
@@ -1,4 +1,5 @@
module Vimrunner
+ class NoSuitableVimError < RuntimeError; end
class InvalidCommandError < RuntimeError; end
class TimeoutError < RuntimeError
@@ -0,0 +1,57 @@
+require "vimrunner/errors"
+
+require "rbconfig"
+
+module Vimrunner
+ module Platform
+ extend self
+
+ def vim
+ vims.find { |vim| suitable?(vim) } or raise NoSuitableVimError
+ end
+
+ def gvim
+ gvims.find { |gvim| suitable?(gvim) } or raise NoSuitableVimError
+ end
+
+ private
+
+ def gvims
+ if mac?
+ %w( mvim gvim )
+ else
+ %w( gvim )
+ end
+ end
+
+ def vims
+ %w( vim ) + gvims
+ end
+
+ def suitable?(vim)
+ features = features(vim)
+
+ if gui?(vim)
+ features.include?("+clientserver")
+ else
+ features.include?("+clientserver") && features.include?("+xterm_clipboard")
+ end
+ end
+
+ def gui?(vim)
+ executable = File.basename(vim)
+
+ executable[0, 1] == "g" || executable[0, 1] == "m"
+ end
+
+ def features(vim)
+ IO.popen([vim, "--version"]) { |io| io.read.strip }
+ rescue Errno::ENOENT
+ ""
+ end
+
+ def mac?
+ RbConfig::CONFIG["host_os"] =~ /darwin/
+ end
+ end
+end
Oops, something went wrong. Retry.

0 comments on commit 0c95862

Please sign in to comment.