if exists('g:ack_use_dispatch') if g:ack_use_dispatch && !exists(':Dispatch') call s:Warn('Dispatch not loaded! Falling back to g:ack_use_dispatch = 0.') let g:ack_use_dispatch = 0 endif else let g:ack_use_dispatch = 0 endif "----------------------------------------------------------------------------- " Public API "----------------------------------------------------------------------------- function! ack#Ack(cmd, args) "{{{ call s:Init(a:cmd) redraw " Local values that we'll temporarily set as options when searching let l:grepprg = g:ackprg let l:grepformat = '%f:%l:%c:%m,%f:%l:%m' " Include column number " Strip some options that are meaningless for path search and set match " format accordingly. if s:SearchingFilepaths() let l:grepprg = substitute(l:grepprg, '-H\|--column', '', 'g') let l:grepformat = '%f' endif " If no pattern is provided, search for the word under the cursor let l:grepargs = empty(a:args) ? expand("") : a:args . join(a:000, ' ') " NOTE: we escape special chars, but not everything using shellescape to " allow for passing arguments etc let l:escaped_args = escape(l:grepargs, '|#%') echo "Searching ..." if g:ack_use_dispatch call s:SearchWithDispatch(l:grepprg, l:escaped_args, l:grepformat) else call s:SearchWithGrep(a:cmd, l:grepprg, l:escaped_args, l:grepformat) endif " Dispatch has no callback mechanism currently, we just have to display the " list window early and wait for it to populate :-/ call ack#ShowResults() call s:Highlight(l:grepargs) endfunction "}}} function! ack#AckFromSearch(cmd, args) "{{{ let search = getreg('/') " translate vim regular expression to perl regular expression. let search = substitute(search, '\(\\<\|\\>\)', '\\b', 'g') call ack#Ack(a:cmd, '"' . search . '" ' . a:args) endfunction "}}} function! ack#AckHelp(cmd, args) "{{{ let args = a:args . ' ' . s:GetDocLocations() call ack#Ack(a:cmd, args) endfunction "}}} function! ack#AckWindow(cmd, args) "{{{ let files = tabpagebuflist() " remove duplicated filenames (files appearing in more than one window) let files = filter(copy(sort(files)), 'index(files,v:val,v:key+1)==-1') call map(files, "bufname(v:val)") " remove unnamed buffers as quickfix (empty strings before shellescape) call filter(files, 'v:val != ""') " expand to full path (avoid problems with cd/lcd in au QuickFixCmdPre) let files = map(files, "shellescape(fnamemodify(v:val, ':p'))") let args = a:args . ' ' . join(files) call ack#Ack(a:cmd, args) endfunction "}}} function! ack#ShowResults() "{{{ let l:handler = s:UsingLocList() ? g:ack_lhandler : g:ack_qhandler execute l:handler call s:ApplyMappings() redraw! endfunction "}}} "----------------------------------------------------------------------------- " Private API "----------------------------------------------------------------------------- function! s:ApplyMappings() "{{{ if !s:UsingListMappings() || &filetype != 'qf' return endif let l:wintype = s:UsingLocList() ? 'l' : 'c' let l:closemap = ':' . l:wintype . 'close' let g:ack_mappings.q = l:closemap nnoremap ? :call QuickHelp() if g:ack_autoclose " We just map the 'go' and 'gv' mappings to close on autoclose, wtf? for key_map in items(g:ack_mappings) execute printf("nnoremap %s %s", get(key_map, 0), get(key_map, 1) . l:closemap) endfor execute "nnoremap " . l:closemap else for key_map in items(g:ack_mappings) execute printf("nnoremap %s %s", get(key_map, 0), get(key_map, 1)) endfor endif if exists("g:ackpreview") " if auto preview in on, remap j and k keys nnoremap j j nnoremap k k nmap j nmap k endif endfunction "}}} function! s:GetDocLocations() "{{{ let dp = '' for p in split(&rtp, ',') let p = p . '/doc/' if isdirectory(p) let dp = p . '*.txt ' . dp endif endfor return dp endfunction "}}} function! s:Highlight(args) "{{{ if !g:ackhighlight return endif let @/ = matchstr(a:args, "\\v(-)\@", "n") endfunction "}}} " Initialize state for an :Ack* or :LAck* search function! s:Init(cmd) "{{{ let s:searching_filepaths = (a:cmd =~# '-g$') ? 1 : 0 let s:using_loclist = (a:cmd =~# '^l') ? 1 : 0 if g:ack_use_dispatch && s:using_loclist call s:Warn('Dispatch does not support location lists! Proceeding with quickfix...') let s:using_loclist = 0 endif endfunction "}}} function! s:QuickHelp() "{{{ execute 'edit' globpath(&rtp, 'doc/ack_quick_help.txt') silent normal gg setlocal buftype=nofile bufhidden=hide nobuflisted setlocal nomodifiable noswapfile setlocal filetype=help setlocal nonumber norelativenumber nowrap setlocal foldmethod=diff foldlevel=20 nnoremap ? :q!:call ack#ShowResults() endfunction "}}} function! s:SearchWithDispatch(grepprg, grepargs, grepformat) "{{{ let l:makeprg_bak = &l:makeprg let l:errorformat_bak = &l:errorformat " We don't execute a :grep command for Dispatch, so add -g here instead if s:SearchingFilepaths() let l:grepprg = a:grepprg . ' -g' else let l:grepprg = a:grepprg endif try let &l:makeprg = l:grepprg . ' ' . a:grepargs let &l:errorformat = a:grepformat Make finally let &l:makeprg = l:makeprg_bak let &l:errorformat = l:errorformat_bak endtry endfunction "}}} function! s:SearchWithGrep(grepcmd, grepprg, grepargs, grepformat) "{{{ let l:grepprg_bak = &l:grepprg let l:grepformat_bak = &grepformat try let &l:grepprg = a:grepprg let &grepformat = a:grepformat silent execute a:grepcmd a:grepargs finally let &l:grepprg = l:grepprg_bak let &grepformat = l:grepformat_bak endtry endfunction "}}} " Are we finding matching files, not lines? (the -g option -- :AckFile) function! s:SearchingFilepaths() "{{{ return get(s:, 'searching_filepaths', 0) endfunction "}}} " Predicate for whether mappings are enabled for list type of current search. function! s:UsingListMappings() "{{{ if s:UsingLocList() return g:ack_apply_lmappings else return g:ack_apply_qmappings endif endfunction "}}} " Were we invoked with a :LAck command? function! s:UsingLocList() "{{{ return get(s:, 'using_loclist', 0) endfunction "}}} function! s:Warn(msg) "{{{ echohl WarningMsg | echomsg 'Ack: ' . a:msg | echohl None endf "}}} " vim:set et sw=2 ts=2 tw=78 fdm=marker