Thursday, April 28, 2011

vim: execute shell command without filtering

I want to select a block of text (eg. V%) and use the text as input to a shell command (eg. wc or pbcopy) - but I DON'T want to alter the current buffer - I just want to see the output of the command (if any) the continue editting without any changes.

Typing V%!wc translates to :'<,'>!wc and switches the block of text for the output of the wc command.

How do you pipe a chunk of text to an arbitrary shell command without affecting the current buffer?

From stackoverflow
  • I know it's not the ideal solution, but if all else fails, you could always just press u after running the command to undo the buffer change.

    searlea : Sure, that's what I do currently - I'm just hoping I'm missing something. I guess if there isn't a built-in way of doing this, a small cmap could do the trick - anyone got a ready-made one?
    Amber : Offtopic: /me wishes tags worked in comments too.
    Amber : After glancing around on meta-SO, using `backticks around text` apparently is supposed to allow code-formatting in comments.
    searlea : Really? `sweet` - that's good to know.
  • One possibility would be to use system() in a custom command, something like this:

    command! -range -nargs=1 SendToCommand <line1>,<line2>call SendToCommand(<q-args>) 
    
    function! SendToCommand(UserCommand) range
        " Get a list of lines containing the selected range
        let SelectedLines = getline(a:firstline,a:lastline)
        " Convert to a single string suitable for passing to the command
        let ScriptInput = join(SelectedLines, "\n") . "\n"
        " Run the command
        let result = system(a:UserCommand, ScriptInput)
        " Echo the result (could just do "echo system(....)")
        echo result
    endfunction
    

    Call this with (e.g.):

    :'<,'>SendToCommand wc -w
    

    Note that if you press V%:, the :'<,'> will be entered for you.

    :help command
    :help command-range
    :help command-nargs
    :help q-args
    :help function
    :help system()
    :help function-range
    
    searlea : My first thought was that it looked really chunky and verbose, but after adding chucking it in my .vimrc and adding a mapping, it's perfect: vmap # :SendToCommand Now I can just do V%# and bang out the command name. Just what I wanted.
    Al : Glad you like it! Your mapping looks like a good idea (I do tend to go for long and verbose command names and rely on tab-completion to save me the effort). Consider putting it in `~/.vim/plugin/sendtocommand.vim` or `~/.vim/autoload/sendtocommand.vim` (the latter will require some changes) to help keep your vimrc manageable.
  • Select your block of text, then type these keys :w !sh

    The whole thing should look like:

    '<,'>w !sh
    

    That's it. Only took me 8 years to learn that one : )

    Michael Anderson : Awesome, neat and builtin --- all one could hope for.

0 comments:

Post a Comment