I played around a bit more and got to a similar stage that I think
everybody else is getting to using --remote commands to progressively
update buffers.

Here's my current script. This script is a little less sophisticated
than Marc's in that it doesn't keep track of the background process'
pid but I think that'd be easy to rip from his script. ;) I had to use
Ruby because I'm not very experienced with vimscript. (That might be
obvious given my vimscript below.)

You can see that I go through several options for trying to refresh
gvim's quickfix buffer using --remote commands, none of which seem to
work right (update it without crashing vim and without disrupting the
editing of other buffers).

Anyway it is here as a template if somebody has any good ideas to make
it work "right". I'll post any future versions of it that I write to
this thread, too.

" Function for compilation in background with progressively updated quickfix
" buffer.
" vim:ts=2:sw=2:et:sts

nmap <C-F12> :call QuickFixRefresh()<CR>
imap <C-F12> <ESC>:call QuickFixRefresh()<CR>a
vmap <C-F12> <ESC>:call QuickFixRefresh()<CR>v

" Runs a command in the background with progressive output in the quickfix
" window. Requires gvim (relies on vim server).
function! QuickFix(...)
 if a:0 > 1
   let i=1
   let command=[]
   while i<=a:0
     let command += [a:{i}]
     let i += 1
   endwhile
 else
   let command = a:1
 endif
ruby << EORUBY

 module Shell
   # Escape string so that it interpreted right by sh/bash.
   # Like Regexp.escape but for shell scripts.
   def self.escape(string)
     if string !~ %r{[ "\\]}i
       string
     else
       '"' + string.gsub(%r{(["\\])}i, '\\\\\1') + '"'
     end
   end

   # Turn a set of commands such as those from ARGV into a string
   # that can be passed to IO.popen or `` or similar without messing
   # up due to spaces in filenames etc.
   def self.command(args)
     args.map{|x| escape(x) }.join(' ')
   end
 end

 module VIM

   # Like evaluate but returns a Ruby array from a VIM array value.
   def self.evaluate_array(str)
     evaluate(str).split(/\n/m)
   end

   module Quickfix
     def self.path()
       "/tmp/vim.quickfix"
     end

     def self.truncate()
       File.open(path, "w")
     end

     def self.append(line)
       File.open(path, "a") do |f|
         f.print line
       end
     end

     def self.reload()
       VIM.command("cgetfile #{path}")
     end
   end
 end

 command = Shell.command(VIM.evaluate_array("l:command"))
 VIM::Quickfix.truncate
 VIM.command("copen")

 fork do
   IO.popen(command) do |io|
     io.each_line do |line|
       # Append the line to the file.
       VIM::Quickfix.append(line)

       # Refresh the quickfix buffer in Vim from the file.
       # No nice way to do this! :(
       # Here are the alternatives I've played with:

       # Using VIM.command("cfile ..") here causes errors like:
       #   Xlib: unexpected async reply
       # because we are in a sub-process and vim gets confused. (?)

       #VIM::Quickfix.reload

       # Use --remote-send, to emulate typing the refresh command myself.
       # This makes the window flicker, takes you out of insert mode, and
       # generally makes continuing to use gvim impossible while the
       # compilation progresses. But it doesn't crash vim...

       #system("gvim", "--remote-send",
       #  "<ESC>:cgetfile #{VIM::Quickfix.path}<CR>")

       # A variant on that theme. Pre-defined keybinding that works in all
       # modes. Lots of flickering, same as above.

       #system("gvim", "--remote-send", "<C-F12>")

       # Another variation, try using silent!
       #`gvim --remote-send '<ESC>:silent! exec "silent! cgetfile
#{VIM::Quickfix.path}"<CR>'`
       #break if $? != 0

       # Idea: user --remote-expr to call a function we define. An expression
       # with a side-effect.
       # This works really really nicely - it doesn't disrupt editing - but
       # sometimes causes a segment violation which crashes gvim :(

       #output = `gvim --remote-expr 'QuickFixRefresh()'`.strip
       # output should be '0'
     end
   end
 end
EORUBY
endfunction

function! QuickFixRefresh()
 exe "cgetfile /tmp/vim.quickfix"
endfunction



--
Greg McIntyre

Reply via email to