I'm currently doing something like this:
redir => m
silent w ! ruby
redir END
new
put=m
It executes the contents of the current buffer as Ruby code and puts the output in a new buffer.
But if the Ruby code I run is something like
puts "start"
sleep 10
puts "end"
then I will see no output for 10 seconds, then both "start" and "end" all at once.
Is there instead some way to "stream" the output to a buffer, line by line as it appears? So that I would see "start", then 10 seconds later I would see "end"? Similar t开发者_C百科o what happens if I just do
w ! ruby
and look at the output under the command line.
Vim does not really expose primitives for this kind of I/O, but you can do it from one of the embedded language interfaces.
Here's a sketch using Python and subprocess (Ruby would look similar; see if_ruby):
python << EOF
import vim
import subprocess
def output_lines_to_buffer(cmd):
"""
Append the given shell command's output linewise to the current buffer.
"""
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
for line in iter(p.stdout.readline, ''):
vim.current.buffer.append(line)
vim.command('redraw')
EOF
To use:
:python output_lines_to_buffer('my command')
This will simply append each line of output to the end of the current buffer, as my command
emits it. You can extend it fairly straightforwardly to support input and output ranges and so on, depending on what you need.
So one possible solution (hopefully not the best one) is to write to a file on disk, open that file in a buffer and do :setlocal autoread
so the file autoupdates when it changes.
This autoupdating seems pretty rough, though. Tail Bundle.vim seems to improve a little on it.
Hoping for a better answer.
How about using tee
or :make
, which uses tee.
let fname = tempname()
exec "w ! ruby 2>&1 | tee ".fname
exec "new ".fname
Edit: seems like you're on Linux, or an operating system that creates 4K buffers between pipelined processes. To work around this, install expect
(sudo apt-get install expect-dev
) and use the unbuffer
command to allow streaming on a line-by-line basis (see: https://stackoverflow.com/questions/1000674/turn-off-buffering-in-pipe).
let fname = tempname()
exec "! unbuffer ruby % 2>&1 | tee ".fname
exec "new ".fname
精彩评论