Skip to content

Instantly share code, notes, and snippets.

@romainl
Last active November 14, 2024 18:54
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 full output of command :hi in scratch window:

:Redir hi

Show full output of command :!ls -al in scratch window:

:Redir !ls -al 

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

Evaluate current line with node and show full output in scratch window:

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

" Ex command
:.Redir !node

" scratch window
0.03987581000754448

Evaluate visual selection + positional parameters with bash and show full output in scratch window:

" 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, start, end)
for win in range(1, winnr('$'))
if getwinvar(win, 'scratch')
execute win . 'windo close'
endif
endfor
if a:cmd =~ '^!'
let cmd = a:cmd =~' %'
\ ? matchstr(substitute(a:cmd, ' %', ' ' . shellescape(escape(expand('%:p'), '\')), ''), '^!\zs.*')
\ : matchstr(a:cmd, '^!\zs.*')
if a:rng == 0
let output = systemlist(cmd)
else
let joined_lines = join(getline(a:start, a:end), '\n')
let cleaned_lines = substitute(shellescape(joined_lines), "'\\\\''", "\\\\'", 'g')
let output = systemlist(cmd . " <<< $" . cleaned_lines)
endif
else
redir => output
execute a: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=1 -complete=command -bar -range Redir silent call Redir(<q-args>, <range>, <line1>, <line2>)
" 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=1 -complete=command -range Redir silent call Redir(<q-args>, <range>, <line1>, <line2>)
@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.

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