227 lines
6.6 KiB
VimL
227 lines
6.6 KiB
VimL
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
|
|
end
|
|
|
|
"-----------------------------------------------------------------------------
|
|
" 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("<cword>") : 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<CR>'
|
|
let g:ack_mappings.q = l:closemap
|
|
|
|
nnoremap <buffer> <silent> ? :call <SID>QuickHelp()<CR>
|
|
|
|
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 <buffer> <silent> %s %s", get(key_map, 0), get(key_map, 1) . l:closemap)
|
|
endfor
|
|
|
|
execute "nnoremap <buffer> <silent> <CR> <CR>" . l:closemap
|
|
else
|
|
for key_map in items(g:ack_mappings)
|
|
execute printf("nnoremap <buffer> <silent> %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 <buffer> <silent> j j<CR><C-W><C-W>
|
|
nnoremap <buffer> <silent> k k<CR><C-W><C-W>
|
|
nmap <buffer> <silent> <Down> j
|
|
nmap <buffer> <silent> <Up> 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(-)\@<!(\<)\@<=\\w+|['\"]\\zs.{-}\\ze['\"]")
|
|
call feedkeys(":let &hlsearch=1 \| echo \<CR>", "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 <buffer> <silent> ? :q!<CR>:call ack#ShowResults()<CR>
|
|
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
|