"============================================================================= " FILE: jump_list.vim " AUTHOR: Shougo Matsushita " 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. " }}} "============================================================================= let s:save_cpo = &cpo set cpo&vim " Variables "{{{ if !exists('g:unite_kind_jump_list_after_jump_scroll') let g:unite_kind_jump_list_after_jump_scroll = 25 else let g:unite_kind_jump_list_after_jump_scroll = \ min([max([0, g:unite_kind_jump_list_after_jump_scroll]), 100]) endif "}}} function! unite#kinds#jump_list#define() abort "{{{ let kind = { \ 'name' : 'jump_list', \ 'default_action' : 'open', \ 'action_table': {}, \ 'alias_table' : { 'rename' : 'replace' }, \ 'parents': ['common', 'openable'], \} " Actions "{{{ let kind.action_table.open = { \ 'description' : 'jump to this position', \ 'is_selectable' : 1, \ } function! kind.action_table.open.func(candidates) abort "{{{ for candidate in a:candidates " Save current line in jump_list execute 'normal!' line('.').'G' if s:convert_path(bufname('%')) !=# \ s:convert_path(s:get_filename(candidate)) let bufnr = s:open(candidate) call unite#remove_previewed_buffer_list(bufnr) endif call s:jump(candidate, 0) " Open folds. normal! zv call s:adjust_scroll(s:best_winline()) call unite#view#_clear_match_highlight() endfor " Add search history let context = unite#get_context() if has_key(context, 'input_list') \ && len(context.input_list) == 1 \ && context.input != '' call histadd("search", context.input) endif endfunction"}}} let kind.action_table.preview = { \ 'description' : 'preview this position', \ 'is_quit' : 0, \ } function! kind.action_table.preview.func(candidate) abort "{{{ let filename = s:get_filename(a:candidate) let bufwinnr = bufwinnr(filename) let buflisted = buflisted(filename) let preview_windows = filter(range(1, winnr('$')), \ 'getwinvar(v:val, "&previewwindow") != 0') if empty(preview_windows) call unite#view#_preview_file(filename) endif let winnr = winnr() wincmd P try let bufnr = s:open(a:candidate) if bufwinnr < 0 && !buflisted call unite#add_previewed_buffer_list(bufnr) endif call s:jump(a:candidate, 1) finally execute winnr.'wincmd w' endtry endfunction"}}} let kind.action_table.highlight = { \ 'description' : 'highlight this position', \ 'is_quit' : 0, \ } function! kind.action_table.highlight.func(candidate) abort "{{{ let candidate_winnr = bufwinnr(s:get_bufnr(a:candidate)) if candidate_winnr > 0 let unite = unite#get_current_unite() let current_winnr = winnr() noautocmd execute candidate_winnr 'wincmd w' call s:jump(a:candidate, 1) let unite_winnr = bufwinnr(unite.bufnr) if unite_winnr < 0 let unite_winnr = current_winnr endif if unite_winnr > 0 noautocmd execute unite_winnr 'wincmd w' endif endif endfunction"}}} let kind.action_table.replace = { \ 'description' : 'replace with qfreplace', \ 'is_selectable' : 1, \ } function! kind.action_table.replace.func(candidates) abort "{{{ if globpath(&runtimepath, 'autoload/qfreplace.vim') == '' echo 'qfreplace.vim is not installed.' return endif let qflist = [] for candidate in a:candidates if has_key(candidate, 'action__line') \ && has_key(candidate, 'action__text') let filename = s:get_filename(candidate) call add(qflist, { \ 'filename' : filename, \ 'lnum' : candidate.action__line, \ 'text' : candidate.action__text, \ }) endif endfor if !empty(qflist) call setqflist(qflist) call qfreplace#start('') endif endfunction"}}} return kind endfunction"}}} "}}} " Misc. function! s:jump(candidate, is_highlight) abort "{{{ let line = get(a:candidate, 'action__line', 1) let pattern = get(a:candidate, 'action__pattern', '') if line == '' " Use default line number. let line = 1 endif if line !~ '^\d\+$' call unite#print_error('jump_list: Invalid action__line format.') return endif if !has_key(a:candidate, 'action__pattern') " Jump to the line number. let col = get(a:candidate, 'action__col', 0) if col == 0 && has_key(a:candidate, 'action__col_pattern') " Search col pattern. let pattern = a:candidate.action__col_pattern if pattern == '' " Use context.input let pattern = unite#get_context().input endif let col = 0 silent! let col = match(getline(line), pattern) + 1 endif call cursor(line, col) call s:open_current_line(a:is_highlight) return endif " Jump by search(). let source = unite#get_sources(a:candidate.source) if !(has_key(a:candidate, 'action__signature') \ && has_key(source, 'calc_signature')) " Not found signature. if line != '' && getline(line) =~# pattern if line('.') != line execute line endif else silent! call search(pattern, 'w') endif call s:open_current_line(a:is_highlight) return endif silent! call search(pattern, 'w') let lnum_prev = line('.') silent! call search(pattern, 'w') let lnum = line('.') if lnum != lnum_prev " Detected same pattern lines!! let start_lnum = lnum while source.calc_signature(lnum) !=# \ a:candidate.action__signature silent! call search(pattern, 'w') let lnum = line('.') if lnum == start_lnum " Not found. call unite#print_error( \ 'jump_list: Target position is not found.') call cursor(1, 1) return endif endwhile endif call s:open_current_line(a:is_highlight) endfunction"}}} function! s:best_winline() abort "{{{ return max([1, winheight(0) * g:unite_kind_jump_list_after_jump_scroll / 100]) endfunction"}}} function! s:adjust_scroll(best_winline) abort "{{{ normal! zt let save_cursor = getpos('.') let winl = 1 " Scroll the cursor line down. while winl <= a:best_winline let winl_prev = winl execute "normal! \" let winl = winline() if winl == winl_prev break end let winl_prev = winl endwhile if winl > a:best_winline execute "normal! \" endif call setpos('.', save_cursor) endfunction"}}} function! s:open_current_line(is_highlight) abort "{{{ normal! zv normal! zz if a:is_highlight call unite#view#_clear_match_highlight() call unite#view#_match_line('Search', line('.'), 10) endif endfunction"}}} function! s:open(candidate) abort "{{{ let bufnr = s:get_bufnr(a:candidate) if bufnr != bufnr('%') if has_key(a:candidate, 'action__buffer_nr') silent execute 'keepjumps buffer' bufnr else silent call unite#util#smart_execute_command( \ 'keepjumps edit!', unite#util#expand( \ fnamemodify(a:candidate.action__path, ':~:.'))) let bufnr = bufnr('%') endif endif return bufnr endfunction"}}} function! s:get_filename(candidate) abort "{{{ return has_key(a:candidate, 'action__path') ? \ a:candidate.action__path : \ bufname(a:candidate.action__buffer_nr) endfunction"}}} function! s:get_bufnr(candidate) abort "{{{ return has_key(a:candidate, 'action__buffer_nr') ? \ a:candidate.action__buffer_nr : \ bufnr(a:candidate.action__path) endfunction"}}} function! s:convert_path(path) abort "{{{ return unite#util#substitute_path_separator(fnamemodify(a:path, ':p')) endfunction"}}} let &cpo = s:save_cpo unlet s:save_cpo " vim: foldmethod=marker