Simple vim plugin I: integrating new commands

Post by Nico Brailovsky @ 2016-11-24 | Permalink | Leave a comment

TL;DR: Here's some code to integrate system commands into vim. You can just drop it in your vimrc, create a small wrapper function in your vimrc and configure a few key binding to make it work.

Longer version: We can extend our quick grep integration to other commands, quite easily. Since we defined a few wrappers to request input, get it from visual mode or just guess it, we can also have a helper function to create a scratch buffer and read a system command into it:

" Find&Grep command wrapper: execute cmd, shows the results in a scratch buffer
function! FG_EvalSysCmdInNewBuff(cmd)
    tabnew
    setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap
    execute '$read !' . a:cmd
    setlocal nomodifiable
endfunction
" Wrap a normal action: ask the user for input, then call func with it
function! FG_RequestInputAction(msg, func)
    let needle = input(a:msg)
    if strlen(needle) > 0
        execute 'call' a:func .'("'. needle . '")'
    endif
endfunction
" Wrap a visual action: call func with whatever is selected under the cursor
function! FG_VAction(func)
    " Copy whatever is selected in visual mode
    try
        silent! let a_save = @a
        silent! normal! gv"ay
        silent! let needle = @a
    finally
        silent! let @a = a_save
    endtry
    " Remove whitespaces
    let needle = substitute(needle, "92n92+","","g")
    let needle = substitute(needle, "92r92+","","g")
    let needle = substitute(needle, "^92s92+92|92s92+$","","g")
    if strlen(needle) > 0
        execute 'call' a:func .'("'. needle . '")'
    endif
endfunction
" Wrap a normal action: call func with whatever is under the cursor
function! FG_NAction(func)
    let needle = expand("")
    if strlen(needle) > 0
        execute 'call' a:func .'("'. needle . '")'
    endif
endfunction

Integrating any new command into our plugin is now trivial. Let's do it for grep and for find:

" Wrap a find command: search for file "needle", show results in a new window
function! FG_DoFindFile(needle)
    let cmd = 'find -type f -iname "' . a:needle . '"'
    call FG_EvalSysCmdInNewBuff(cmd)
endfunction
" Wrap a grep command: search for needle, show results in a new window
function! FG_DoSearchText(needle)
    let cmd = 'grep -nri "' . a:needle . '" *'
    call FG_EvalSysCmdInNewBuff(cmd)
endfunction

Then just add a few key bindings and you're good to go:

gt;f :call FG_NAction("FG_DoFindFile")
vmap f :call FG_VAction("FG_DoFindFile")
map  S :call FG_RequestInputAction("Text search: ", "FG_DoSearchText")
nmap s :call FG_NAction("FG_DoSearchText")
vmap s :call FG_VAction("FG_DoSearchText")
map  F :call FG_RequestInputAction("Find file: ", "FG_DoFindFile")

This is an actual plugin I use in my Vim setup. You can grab the latest version from my Github repo.

Extra tip: add these too if you want to have a GUI menu for your new commands as well.

menu Project.Find\ File :call FG_RequestInputAction("FG_DoFindFile")
menu Project.Text\ Search :call FG_RequestInputAction("FG_DoSearchText")