Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/vimrunner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,6 @@ def self.start_gvim(&blk)
#
# Returns a Client for the named server.
def self.connect(name)
Server.new(:name => name).connect
Server.new(:name => name).connect(:spawn => true)
end
end
23 changes: 21 additions & 2 deletions lib/vimrunner/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,19 @@ def add_plugin(dir, entry_script = nil)
command("runtime #{entry_script}") if entry_script
end

# Public: source a script in Vim server
#
# script - The Vim script to be sourced
#
# Examples
#
# vim.source '/path/to/plugin/rails.vim'
#
# Returns nothing.
def source(script)
feedkeys(":\\<C-u>source #{filename_escape(script)}\\<CR>")
end

# Public: Appends a directory to Vim's runtimepath
#
# dir - The directory added to the path
Expand Down Expand Up @@ -144,7 +157,7 @@ def set(setting, value = nil)
#
# Returns the Client instance.
def edit(filename)
command "edit #{filename}"
command "edit #{filename_escape(filename)}"
self
end

Expand All @@ -154,7 +167,7 @@ def edit(filename)
#
# Returns the Client instance.
def edit!(filename)
command "edit! #{filename}"
command "edit! #{filename_escape(filename)}"
self
end

Expand All @@ -174,6 +187,12 @@ def kill
server.kill
end

def filename_escape(name)
name.gsub(/([^A-Za-z0-9_\-.,:\/@\n])/, "\\\\\\1")
end



private

def escape(string)
Expand Down
41 changes: 25 additions & 16 deletions lib/vimrunner/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ module Vimrunner
# to use a Server directly to invoke --remote commands on its Vim instance.
class Server
VIMRC = File.expand_path("../../../vim/vimrc", __FILE__)
VIMRUNNER_RC = File.expand_path("../../../vim/vimrunner_rc", __FILE__)

attr_reader :name, :executable
attr_reader :name, :executable, :vimrc

# Public: Initialize a Server
#
Expand All @@ -30,6 +31,8 @@ class Server
def initialize(options = {})
@executable = options.fetch(:executable) { Platform.vim }
@name = options.fetch(:name) { "VIMRUNNER#{rand}" }
@vimrc = options.fetch(:vimrc) { VIMRC }
@foreground = options.fetch(:foreground, true)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to make the foreground an option? To be honest, I just kept it around, since I needed it before for gvim spawning, but I don't think it's even necessary now. On my linux, both with and without -f, it works the same way.

@mudge, could you experiment with removing -f on your mac? I may make a separate issue for this.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issue with removing -f, this works fine:

$ mvim --servername FOO
$ mvim --servername FOO --remote-send ihello

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I do not optional remove -f, the spawn vim server would quit after my script quit. The purpose is to send some command for vim to do it for me. I do not want to spawn the vim server each time. For example, I use Vim to detect and fix file encoding, dir diff, batch rename files, etc.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, that makes a lot of sense. I'm okay with leaving the foreground optional then. I'll make a separate issue for this, though, because I want to see if I can get consistently similar behaviour for the headless version as well. Maybe a different method may make sense, like detach.

end

# Public: Start a Server. This spawns a background process.
Expand All @@ -46,32 +49,34 @@ def initialize(options = {})
# Returns a new Client instance initialized with this Server.
# Yields a new Client instance initialized with this Server.
def start
@r, @w, @pid = spawn
if block_given?
spawn do |r, w, pid|
begin
@result = yield(connect)
ensure
r.close
w.close
Process.kill(9, pid) rescue Errno::ESRCH
end
begin
@result = yield(connect)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should be @r and @w. Though, I'd rather remove this change instead, since I'd prefer connect not to spawn a new instance.

ensure
@r.close
@w.close
Process.kill(9, @pid) rescue Errno::ESRCH
end

@result
else
@r, @w, @pid = spawn

connect
end
end

# Public: Connects to the running server by name, blocking if need be.
#
# Returns a new Client instance initialized with this Server.
def connect
def connect(options = {})
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather not have connect spawn a new instance. It should be possible, even now, to do something like this:

# if you want to spawn a new server if it's not already there:
server = Server.new(:name => 'FOO')
if not server.connected?
  server.start
end

# if you want to wait until someone spawns the server:
server = Server.new(:name => 'FOO')
server.connect

Do you have a use case that this doesn't cover?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have add the (:spawn => true) option to connect.

# if you want to spawn a new server if it's not already there:
client = Server.new(:name => 'FOO').connect(:spawn => true)

# if you want to wait until someone spawns the server:
client = Server.new(:name => 'FOO').connect

if !connected? && options[:spawn]
@r, @w, @pid = spawn
end
wait_until_started

new_client
client = new_client
client.source(VIMRUNNER_RC)

return client
end

# Public: Checks if the server is connected to a running Vim instance.
Expand Down Expand Up @@ -129,12 +134,16 @@ def remote_send(keys)

private

def foreground_option
@foreground ? '-f' : ''
end

def execute(command)
IO.popen(command) { |io| io.read.strip }
end

def spawn(&blk)
PTY.spawn(executable, "-f", "--servername", name, "-u", VIMRC, &blk)
def spawn
PTY.spawn("#{executable} #{foreground_option} --servername #{name} -u #{vimrc}")
end

def wait_until_started
Expand Down
32 changes: 1 addition & 31 deletions vim/vimrc
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,4 @@ set noswapfile nobackup
set runtimepath-=~/.vim
set runtimepath-=~/.vim/after

function! VimrunnerEvaluateCommandOutput(command)
let output = ''

try
redir => output
silent exe a:command
redir END

let output = s:StripSilencedErrors(output)
catch
let output = v:exception
endtry

return output
endfunction

" Remove errors from the output that have been silenced by :silent!. These are
" visible in the captured output since all messages are captured by :redir.
function! s:StripSilencedErrors(output)
let processed_output = []

for line in reverse(split(a:output, "\n"))
if line =~ '^E\d\+:'
break
endif

call add(processed_output, line)
endfor

return join(reverse(processed_output), "\n")
endfunction
execute "source " . expand('<sfile>:p:h') . "/vimrunner_rc"
33 changes: 33 additions & 0 deletions vim/vimrunner_rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
function! VimrunnerEvaluateCommandOutput(command)
let output = ''

try
redir => output
silent exe a:command
redir END

let output = s:StripSilencedErrors(output)
catch
let output = v:exception
endtry

return output
endfunction

" Remove errors from the output that have been silenced by :silent!. These are
" visible in the captured output since all messages are captured by :redir.
function! s:StripSilencedErrors(output)
let processed_output = []

for line in reverse(split(a:output, "\n"))
if line =~ '^E\d\+:'
break
endif

call add(processed_output, line)
endfor

return join(reverse(processed_output), "\n")
endfunction

" vim: set ft=vim