AndrewRadev / vimrunner

Control a vim instance through ruby code
MIT License
238 stars 13 forks source link

Tracking coverage with vimrunner #51

Open blueyed opened 7 years ago

blueyed commented 7 years ago

I am trying to track coverage with vimrunner (via https://github.com/Vimjas/covimerage/), but the problem appears to be that it spawns a gvim instance without waiting for it.

My current attempt is to have a gvim wrapper, which I inject into the $PATH (it would be good to explicitly provide the executable btw):

#!/bin/sh

# echo "$@" >> /tmp/1l
# echo "$1" >> /tmp/1l

if [ "$1" = "--noplugin" ]; then
    echo "Running covimerage run /usr/bin/gvim $*" > /tmp/1l
    exec 1>>/tmp/1l
    exec 2>>/tmp/1l
    echo "running" >> /tmp/1l
    covimerage -vv run --profile-file /tmp/foo.profile --source "$PWD" /usr/bin/gvim -f "$@"
else
    exec /usr/bin/gvim "$@"
fi

I've tried using & and wait here, but this script is already affected by the PTY.spawn.

Any hints?

AndrewRadev commented 7 years ago

I'll have to look into covimerage and how it works, and experiment a bit maybe. For now, I could at least give you some things to try.

For starters:

(it would be good to explicitly provide the executable btw)

It's actually possible. Here's the implementation of the Vimrunner.start_gvim method: https://github.com/AndrewRadev/vimrunner/blob/9cc6e9e3bf3b669319e749fb8d685fa929e7e7fc/lib/vimrunner.rb#L48-L50

Basically, there's a Server, which connects to the Vim instance, and holds pids and such, and a Client, which provides wrappers around common commands. The server's start method returns a Client. You could, theoretically, run your script without PATH manipulations by:

vim = Server.new(executable: "/path/to/my-gvim").start

You could also create an existing Vim instance, and then connect to it, as long as you spawn a Vim with a particular servername. Take a look at the documentation for connect: http://www.rubydoc.info/gems/vimrunner/0.3.4/Vimrunner. Maybe you could spawn your instance, prepare it however you like, and then run Vimrunner with it?

blueyed commented 7 years ago

Thanks!

As for executable, I am using this:

vim = Vimrunner::Server.new(:executable => Dir.getwd + "/bin/gvim").start()

This is for a Vim plugin, which has some spec helpers already (https://github.com/Vimjas/vim-python-pep8-indent/blob/master/spec/spec_helper.rb), and I can use an env var for this then.

Some findings: even when using the "TERM" signal instead of "KILL" to kill the vimrunner server (using Process.kill("TERM", @pid)), it will result in:

Vim: Caught deadly signal HUP
Vim: Finished.

This is the case for both using xvfb-run or without (i.e. gvim being visible). This results in covimerage (which runs rspec) to being killed directly.

I have moved/commented the @r.close and @w.close for this, otherwise the SIGHUP is send before it seems (which makes sense since the pty hung up).

When using Process.wait(@pid) and manually killing the visible gvim, I get the SIGTERM, and covimerage can handle that, i.e. proceed.

covimerage uses Python's subprocess.call.

One easy fix for this is to use remote_expr("VimrunnerEvaluateCommandOutput('quitall!')") (or a simpler version of it) in kill, then wait for the process (possibly with some timeout), falling back to TERM (instead of KILL).

blueyed commented 6 years ago

Using Server.connect is a good method. I've created https://github.com/AndrewRadev/vimrunner/pull/52 nonethess to improve the kill behavior.

blueyed commented 6 years ago

Hmm, the problem seems to be rather that the SIGHUP is not forwarded to Vim by covimerage.

blueyed commented 6 years ago

Using connect requires to overwrite kill though, since it might fail with @r being nil otherwise:

  config.start_vim do
    vim = Vimrunner.connect(ENV['PYTHON_PEP8_INDENT_TEST_VIM_SERVERNAME'])
    def vim.kill
      normal(":quitall!<CR>")
    end