"=============================================================================
" FILE: grep.vim
" AUTHOR: Shougo Matsushita <Shougo.Matsu at gmail.com>
" Tomohiro Nishimura <tomohiro68 at gmail.com>
" License: MIT license {{{
" Permission is hereby granted, free of charge, to any person obtaining
" a copy of this software and associated documentation files (the
" "Software"), to deal in the Software without restriction, including
" without limitation the rights to use, copy, modify, merge, publish,
" distribute, sublicense, and/or sell copies of the Software, and to
" permit persons to whom the Software is furnished to do so, subject to
" the following conditions:
"
" The above copyright notice and this permission notice shall be included
" in all copies or substantial portions of the Software.
"
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
" }}}
"=============================================================================
" Variables "{{{
" Set from grepprg.
call unite#util#set_default(
\ 'g:unite_source_grep_command', 'grep')
call unite#util#set_default(
\ 'g:unite_source_grep_default_opts', '-inH')
call unite#util#set_default('g:unite_source_grep_recursive_opt', '-r')
call unite#util#set_default('g:unite_source_grep_search_word_highlight', 'Search')
call unite#util#set_default('g:unite_source_grep_encoding', 'char')
"}}}
function! unite#sources#grep#define() abort "{{{
return s:source
endfunction "}}}
let s:source = {
\ 'name': 'grep',
\ 'max_candidates': 100,
\ 'hooks' : {},
\ 'syntax' : 'uniteSource__Grep',
\ 'matchers' : 'matcher_regexp',
\ 'sorters' : 'sorter_nothing',
\ 'ignore_globs' : [
\ '*~', '*.o', '*.exe', '*.bak',
\ 'DS_Store', '*.pyc', '*.sw[po]', '*.class',
\ '.hg/**', '.git/**', '.bzr/**', '.svn/**',
\ 'tags', 'tags-*'
\ ],
\ }
function! s:source.hooks.on_init(args, context) abort "{{{
if !unite#util#has_vimproc()
call unite#print_source_error(
\ 'vimproc is not installed.', s:source.name)
return
endif
let target = get(a:args, 0, '')
if target ==# ''
let target = isdirectory(a:context.path) ?
\ a:context.path :
\ unite#util#input('Target: ', '.', 'file')
endif
if target ==# ''
let a:context.source__targets = []
let a:context.source__input = ''
return
endif
let targets = split(target, "\n")
if target ==# '%' || target ==# '#'
let targets = [bufname(target)]
elseif target ==# '$buffers'
let targets = map(filter(range(1, bufnr('$')),
\ 'buflisted(v:val) && filereadable(bufname(v:val))'),
\ 'bufname(v:val)')
elseif target ==# '**'
" Optimized.
let targets = ['.']
endif
let targets = map(targets, 'substitute(v:val, "\\*\\+$", "", "")')
let a:context.source__targets =
\ map(targets, 'unite#helper#parse_source_path(v:val)')
let a:context.source__extra_opts = get(a:args, 1, '')
let a:context.source__input = get(a:args, 2, a:context.input)
if a:context.source__input == '' || a:context.unite__is_restart
let a:context.source__input = unite#util#input('Pattern: ',
\ a:context.source__input,
\ 'customlist,unite#helper#complete_search_history')
endif
call unite#print_source_message('Pattern: '
\ . a:context.source__input, s:source.name)
let a:context.source__directory =
\ (len(a:context.source__targets) == 1) ?
\ unite#util#substitute_path_separator(
\ unite#util#expand(a:context.source__targets[0])) : ''
endfunction"}}}
function! s:source.hooks.on_syntax(args, context) abort "{{{
if !unite#util#has_vimproc()
return
endif
syntax case ignore
syntax match uniteSource__GrepHeader /[^:]*: \d\+: \(\d\+: \)\?/ contained
\ containedin=uniteSource__Grep
syntax match uniteSource__GrepFile /[^:]*: / contained
\ containedin=uniteSource__GrepHeader
\ nextgroup=uniteSource__GrepLineNR
syntax match uniteSource__GrepLineNR /\d\+: / contained
\ containedin=uniteSource__GrepHeader
\ nextgroup=uniteSource__GrepPattern
execute 'syntax match uniteSource__GrepPattern /'
\ . substitute(a:context.source__input, '\([/\\]\)', '\\\1', 'g')
\ . '/ contained containedin=uniteSource__Grep'
syntax match uniteSource__GrepSeparator /:/ contained conceal
\ containedin=uniteSource__GrepFile,uniteSource__GrepLineNR
highlight default link uniteSource__GrepFile Comment
highlight default link uniteSource__GrepLineNr LineNR
execute 'highlight default link uniteSource__GrepPattern'
\ get(a:context, 'custom_grep_search_word_highlight',
\ g:unite_source_grep_search_word_highlight)
endfunction"}}}
function! s:source.hooks.on_close(args, context) abort "{{{
if has_key(a:context, 'source__proc')
call a:context.source__proc.kill()
endif
endfunction "}}}
function! s:source.hooks.on_post_filter(args, context) abort "{{{
for candidate in a:context.candidates
let candidate.kind = ['file', 'jump_list']
let candidate.action__col_pattern = a:context.source__input
let candidate.is_multiline = 1
let candidate.action__line = candidate.source__info[1]
let candidate.action__text = candidate.source__info[2]
endfor
endfunction"}}}
function! s:source.gather_candidates(args, context) abort "{{{
let command = get(a:context, 'custom_grep_command',
\ g:unite_source_grep_command)
let default_opts = get(a:context, 'custom_grep_default_opts',
\ g:unite_source_grep_default_opts)
let recursive_opt = get(a:context, 'custom_grep_recursive_opt',
\ g:unite_source_grep_recursive_opt)
if !executable(command)
call unite#print_source_message(printf(
\ 'command "%s" is not executable.', command), s:source.name)
let a:context.is_async = 0
return []
endif
if !unite#util#has_vimproc()
call unite#print_source_message(
\ 'vimproc plugin is not installed.', self.name)
let a:context.is_async = 0
return []
endif
if empty(a:context.source__targets)
\ || a:context.source__input == ''
call unite#print_source_message('Canceled.', s:source.name)
let a:context.is_async = 0
return []
endif
if a:context.is_redraw
let a:context.is_async = 1
endif
let cmdline = printf('"%s" %s %s %s -- %s %s',
\ unite#util#substitute_path_separator(command),
\ default_opts,
\ recursive_opt,
\ a:context.source__extra_opts,
\ string(a:context.source__input),
\ unite#helper#join_targets(a:context.source__targets)
\)
call unite#add_source_message('Command-line: ' . cmdline, s:source.name)
let save_term = $TERM
try
" Disable colors.
let $TERM = 'dumb'
let a:context.source__proc = vimproc#plineopen3(
\ vimproc#util#iconv(cmdline, &encoding,
\ g:unite_source_grep_encoding),
\ unite#helper#is_pty(command))
finally
let $TERM = save_term
endtry
return self.async_gather_candidates(a:args, a:context)
endfunction "}}}
function! s:source.async_gather_candidates(args, context) abort "{{{
let default_opts = get(a:context, 'custom_grep_default_opts',
\ g:unite_source_grep_default_opts)
if !has_key(a:context, 'source__proc')
let a:context.is_async = 0
return []
endif
let stderr = a:context.source__proc.stderr
if !stderr.eof
" Print error.
let errors = filter(unite#util#read_lines(stderr, 200),
\ "v:val !~ '^\\s*$'")
if !empty(errors)
call unite#print_source_error(errors, s:source.name)
endif
endif
let stdout = a:context.source__proc.stdout
if stdout.eof
" Disable async.
let a:context.is_async = 0
call a:context.source__proc.waitpid()
endif
let lines = map(unite#util#read_lines(stdout, 1000),
\ "unite#util#iconv(v:val, g:unite_source_grep_encoding, &encoding)")
if default_opts =~ '^-[^-]*l'
\ || a:context.source__extra_opts =~ '^-[^-]*l'
let lines = map(filter(lines, 'v:val != ""'),
\ '[v:val, [v:val[2:], 0]]')
else
let lines = map(filter(lines, 'v:val =~ "^.\\+:.\\+$"'),
\ '[v:val, split(v:val[2:], ":", 1)]')
endif
let candidates = []
for [line, fields] in lines
let col = 0
if len(fields) <= 1 || fields[1] !~ '^\d\+$'
let path = a:context.source__targets[0]
if len(fields) <= 1
let linenr = line[:1][0]
let text = fields[0]
else
let linenr = line[:1] . fields[0]
let text = join(fields[1:], ':')
endif
else
let path = line[:1] . fields[0]
let linenr = fields[1]
let text = join(fields[2:], ':')
if text =~ '^\d\+:'
let col = matchstr(text, '^\d\+')
let text = text[len(col)+1 :]
endif
endif
if path ==# '.'
call unite#print_source_error(
\ 'Your grep configuration is wrong.'
\ . ' Please check ":help unite-source-grep" example.',
\ s:source.name)
break
endif
call add(candidates, {
\ 'word' : printf('%s: %s: %s', path,
\ linenr . (col != 0 ? ': '.col : ''), text),
\ 'action__path' :
\ unite#util#substitute_path_separator(
\ fnamemodify(path, ':p')),
\ 'action__col' : col,
\ 'source__info' : [path, linenr, text]
\ })
endfor
return candidates
endfunction "}}}
function! s:source.complete(args, context, arglead, cmdline, cursorpos) abort "{{{
return ['%', '#', '$buffers'] + unite#sources#file#complete_directory(
\ a:args, a:context, a:arglead, a:cmdline, a:cursorpos)
endfunction"}}}
" vim: foldmethod=marker