Skip to content

Instantly share code, notes, and snippets.

@romainl
Last active October 20, 2025 23:56
Show Gist options
  • Save romainl/eae0a260ab9c135390c30cd370c20cd7 to your computer and use it in GitHub Desktop.
Save romainl/eae0a260ab9c135390c30cd370c20cd7 to your computer and use it in GitHub Desktop.
Redirect the output of a Vim or external command into a scratch buffer

Redirect the output of a Vim or external command into a scratch buffer

Usage (any shell)

Show the full output of command :hi in a scratch buffer:

:Redir hi

Show the full output of command :!ls -al in a scratch buffer:

:Redir !ls -al

Show the full output of the previous command in a scratch buffer:

:Redir!

Additional usage (depends on non-standard shell features so YMMV)

Evaluate the current line with node and show the full output in a scratch buffer:

" current line
console.log(Math.random());

" Ex command
:.Redir !node

" scratch window
0.03987581000754448

Evaluate the current buffer + positional parameters with bash and show the full output in a scratch buffer:

" content of buffer
echo ${1}
echo ${2}

" Ex command
:%Redir !bash -s foo bar

" scratch window
foo
bar

My Vim-related gists.

function! Redir(cmd = '', rng = 0, start = 1, end = 1, bang = '')
let cmd = a:cmd->trim()
for win in range(1, winnr('$'))
if getwinvar(win, 'scratch')
execute win . 'windo close'
endif
endfor
if a:bang == '!' && cmd->empty()
let cmd = expand(@:)->trim()
endif
if cmd =~ '^!'
let ext_cmd = cmd =~' %'
\ ? matchstr(substitute(cmd, ' %', ' ' . shellescape(escape(expand('%:p'), '\')), ''), '^!\zs.*')
\ : matchstr(cmd, '^!\zs.*')
if a:rng == 0
let output = systemlist(ext_cmd)
else
let joined_lines = join(getline(a:start, a:end), '\n')
let cleaned_lines = substitute(shellescape(joined_lines), "'\\\\''", "\\\\'", 'g')
let output = systemlist(ext_cmd . " <<< $" . cleaned_lines)
endif
else
redir => output
execute cmd
redir END
let output = split(output, "\n")
endif
vnew
let w:scratch = 1
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile
call setline(1, output)
endfunction
" This command definition includes -bar, so that it is possible to "chain" Vim commands.
" Side effect: double quotes can't be used in external commands
command! -nargs=? -complete=command -bar -range -bang Redir silent call Redir(<q-args>, <range>, <line1>, <line2>, '<bang>')
" This command definition doesn't include -bar, so that it is possible to use double quotes in external commands.
" Side effect: Vim commands can't be "chained".
command! -nargs=? -complete=command -range -bang Redir silent call Redir(<q-args>, <range>, <line1>, <line2>, '<bang>')
@Leenuus
Copy link

Leenuus commented Jun 17, 2024

guys can you give me something in luascript?!

Thanks romainl for amazing work! I implement this command with lua script, with some extra commands to get repl-like features.

Also, this lua implementations support vertical and horizontal modifiers.

And note that this lua script doesn't use sh -c to do things, it spawns process directly, so no shell commands available but also no shell escaping needed.

My implementation in lua

@romainl
Copy link
Author

romainl commented Jun 18, 2024

Thanks, @Leenuus.

@gachikuku it looks like your wish came true.

@gachikuku
Copy link

Thank you @Leenuus! 🤗
@romainl it did.

@Leenuus
Copy link

Leenuus commented Jul 9, 2024

Thank you @Leenuus! 🤗 @romainl it did.

Thanks, @Leenuus.

@gachikuku it looks like your wish came true.

Hi, @gachikuku , I rewrite my ugly codes and write a README like @romainl did.

And with vim.uv power, this implementation is totally async.

Split direction and stderr are handled too.

Can't thank @romainl more for such a simple, elegant, and powerful solution.

My gist here

@romainl
Copy link
Author

romainl commented Jul 9, 2024

You are very welcome, @Leenuus. Your gist seems almost plugin-ready.

@Leenuus
Copy link

Leenuus commented Jul 9, 2024

You are very welcome, @Leenuus. Your gist seems almost plugin-ready.

Hope that I don't overengineer. 😂

@gachikuku
Copy link

@Leenuus @romainl is right!
That thing reserves a repo not a gist.
Plus it would be easier for folks to set it up, so make it a plugin.

@gn0
Copy link

gn0 commented Aug 29, 2025

@romainl Would you be open to turning this gist into a plugin? I would do it (even just for my own convenience), but not being the author, I couldn't properly license it.

@MicahMartin
Copy link

any idea how to do this when you're already in the 'hit-enter' / 'more-prompt'

@romainl
Copy link
Author

romainl commented Oct 19, 2025

@MicahMartin The output of the previous command is not accessible so we have to re-run it. I have added that feature: at the "hit enter" or "more" prompt, do :Redir!.

@romainl
Copy link
Author

romainl commented Oct 20, 2025

FWIW, I already refactored this into a plugin some time ago. I finally published it here.

@MicahMartin
Copy link

awesome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment