Custom Multiline Search in Vim

Objective

Figure out how to multiline search a code base in a fast manor and avoid
using vim tags. In the past have been using grep but this tool only
searches single lines.

Compatibilty

The function bufload used in my vim script is vim 8 specific. The following is my implementatin in vim 7.

Table of Contents

Solution

Vim tree structure

~/.vim
├── after
│   └── ftplugin
│       ├── cpp.vim
│       ├── cu.vim
│       └── c.vim
├── autoload
│   └── ft
│       └── calter.vim
├── sessions
│   └── mys.vim
└── vimrc

Below code in: calter.vim

" Find a function definition for C/Cpp/Cu
function! ft#calter#Cdef_(funcName)

    exe 'silent grep! -r --include="*.c" --include="*.cpp" ' .
       \ '--include="*.cu" ' . a:funcName . ' .' | redraw!

    let qfLst = getqflist()
    for qfl in qfLst
        let fpath = bufname(qfl.bufnr)
        let _ = bufload(fpath)

        let lineEOF = getbufline(fpath, '$')[0]
        let lineNum = qfl.lnum
        let lineStr = getbufline(fpath, lineNum)[0]
        let matches = match(lineStr, '[/{;]')
        while matches == -1
            if lineEOF == lineStr
                break
            endif

            let lineNum += 1
            let lineStr = getbufline(fpath, lineNum)[0]
            let matches = match(lineStr, '[/{;]')
        endwhile

        if match(lineStr, '{') != -1
            exe 'tabnew +' . qfl.lnum . ' ' . fpath
            echo "File Found at " . qfl.lnum
            return
        endif
    endfor

    echo "File Not Found"
    return

endfunction

Below code in: c.vim

setlocal path=$PWD/**/*src/**,$PWD/**/*inc*/**
setlocal wildignore=*.o,*.d,*.exe,*.a,*.so,*.out

command! -nargs=1 Cdef call ft#calter#Cdef_(<f-args>)

Below code in: cpp.vim and cu.vim where $RTP is my runtime path

runtime $RTP/after/ftplugin/c.vim

Explanation

Important Details

Run Command in c.vim

Code Explained

exe 'silent grep! -r --include="*.c" --include="*.cpp" ' .
    \ '--include="*.cu" ' . a:funcName . ' .' | redraw!

QuickFix List

let qfLst = getqflist()
for qfl in qfLst
" ... more code here ...
endfor
let fpath = bufname(qfl.bufnr)
let _ = bufload(fpath)
let lineEOF = getbufline(fpath, '$')[0]
let lineNum = qfl.lnum
let lineStr = getbufline(fpath, lineNum)[0]
let matches = match(lineStr, '[/{;]')
while matches == -1
    if lineEOF == lineStr
        break
    endif

    let lineNum += 1
    let lineStr = getbufline(fpath, lineNum)[0]
    let matches = match(lineStr, '[/{;]')
endwhile
if match(lineStr, '{') != -1
    exe 'tabnew +' . qfl.lnum . ' ' . fpath
    echo "File Found at " . qfl.lnum
    return
endif

Fun command

If working on a server you can use :mksession <file.vim> to save all
the tabs and settings you have.

Vim Keyboard Cheat Sheet

vimrc file without plugins

set backspace=indent,eol,start
set hidden
set noswapfile
set shiftwidth=4 tabstop=4 softtabstop=4 expandtab
set autoindent smartindent smartcase
set encoding=utf-8
set hls
set wildmenu
set wildmode=list:longest,full
set number
set path=$PWD/**
set colorcolumn=80
set showcmd

filetype detect
filetype plugin indent on

syntax on
colorscheme desert
set t_Co=256

let $RTP=split(&runtimepath,',')[0]
let $RC="$HOME/.vim/vimrc"
let $MYS="$HOME/.vim/sessions/mys.vim"

" Remove highlight after search
nnoremap <silent> <c-\> :nohls<cr><c-\>

" Force use of hjkl-style movement and up(c-b)/down(c-f)
map <up> <nop>
map <down> <nop>
map <left> <nop>
map <right> <nop>
map <pageup> <nop>
map <pagedown> <nop>

" Command line mode without shift+:
noremap ; :

" Faster split window navigation
noremap <c-h> <c-w><c-h>
noremap <c-j> <c-w><c-j>
noremap <c-k> <c-w><c-k>
noremap <c-l> <c-w><c-l>

function Grep_(exts, pattern)
    exe 'silent grep! -r ' a:exts . ' ' . a:pattern .
        \ ' .' | tabnew | copen 42 | redraw!
endfunction

command! -nargs=* Cgrep call Grep_('--include="*.c*"', <f-args>)

" Close buffer without closing window
command! Bd :bp | :sp | :bn | :bd

Vim 7 Version

" Find a function definition for C/Cpp/Cu
function! ft#calter#Cdef_(funcName)

    exe 'silent grep! -r --include="*.c" --include="*.cpp" ' .
       \ '--include="*.cu" ' . a:funcName . ' .' | redraw!

    let qfLst = getqflist()
    for qfl in qfLst
        let fpath = bufname(qfl.bufnr)
        let isLoaded = bufloaded(fpath)
        if isLoaded == 0
            exe 'tabnew ' . fpath
        endif

        let lineEOF = getbufline(fpath, '$')[0]
        let lineNum = qfl.lnum
        let lineStr = getbufline(fpath, lineNum)[0]
        let matches = match(lineStr, '[/{;]')
        while matches == -1
            if lineEOF == lineStr
                break
            endif

            let lineNum += 1
            let lineStr = getbufline(fpath, lineNum)[0]
            let matches = match(lineStr, '[/{;]')
        endwhile

        if isLoaded == 0
            exe 'bdelete ' . fpath
        endif

        if match(lineStr, '{') != -1
            exe 'tabnew +' . qfl.lnum . ' ' . fpath
            echo "File Found at " . qfl.lnum
            return
        endif
    endfor

    echo "File Not Found"
    return

endfunction