2011-11-07 08:33:20 -05:00
|
|
|
|
" EasyMotion - Vim motions on speed!
|
|
|
|
|
"
|
|
|
|
|
" Author: Kim Silkebækken <kim.silkebaekken+vim@gmail.com>
|
2014-01-10 09:15:40 -05:00
|
|
|
|
" Maintainer: haya14busa <hayabusa1419@gmail.com>
|
|
|
|
|
" Source: https://github.com/haya14busa/vim-easymotion
|
|
|
|
|
" Original: https://github.com/Lokaltog/vim-easymotion
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" == Saving 'cpoptions' {{{
|
2013-12-18 07:42:56 -05:00
|
|
|
|
let s:save_cpo = &cpo
|
|
|
|
|
set cpo&vim
|
|
|
|
|
" }}}
|
2014-01-08 23:45:32 -05:00
|
|
|
|
" == Init {{{
|
|
|
|
|
function! EasyMotion#init()
|
|
|
|
|
" Init Migemo Dictionary
|
2014-01-13 20:44:57 -05:00
|
|
|
|
let s:old = {}
|
2014-01-08 23:45:32 -05:00
|
|
|
|
let s:migemo_dicts = {}
|
|
|
|
|
let s:line_flag = 0
|
|
|
|
|
" Anywhere regular expression: {{{
|
|
|
|
|
let re = '\v' .
|
|
|
|
|
\ '(<.|^$)' . '|' .
|
|
|
|
|
\ '(.>|^$)' . '|' .
|
|
|
|
|
\ '(\l)\zs(\u)' . '|' .
|
|
|
|
|
\ '(_\zs.)' . '|' .
|
|
|
|
|
\ '(#\zs.)'
|
|
|
|
|
" 1. word
|
|
|
|
|
" 2. end of word
|
|
|
|
|
" 3. CamelCase
|
|
|
|
|
" 4. after '_' hoge_foo
|
|
|
|
|
" 5. after '#' hoge#foo
|
|
|
|
|
let g:EasyMotion_re_anywhere = get(g:, 'EasyMotion_re_anywhere', re)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
" Anywhere regular expression within line:
|
|
|
|
|
let re = '\v' .
|
|
|
|
|
\ '(<.|^$)' . '|' .
|
|
|
|
|
\ '(.>|^$)' . '|' .
|
|
|
|
|
\ '(\l)\zs(\u)' . '|' .
|
|
|
|
|
\ '(_\zs.)' . '|' .
|
|
|
|
|
\ '(#\zs.)'
|
|
|
|
|
let g:EasyMotion_re_line_anywhere = get(g:, 'EasyMotion_re_line_anywhere', re)
|
|
|
|
|
"}}}
|
|
|
|
|
|
|
|
|
|
return ""
|
|
|
|
|
endfunction "}}}
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" == Reset {{{
|
2013-12-18 08:39:41 -05:00
|
|
|
|
function! EasyMotion#reset()
|
2014-01-08 23:45:32 -05:00
|
|
|
|
let s:line_flag = 0
|
2014-01-07 03:02:16 -05:00
|
|
|
|
return ""
|
2013-12-18 08:39:41 -05:00
|
|
|
|
endfunction "}}}
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" == Motion functions {{{
|
|
|
|
|
" -- Find Motion -------------------------
|
2014-01-13 10:57:02 -05:00
|
|
|
|
function! EasyMotion#S(num_strokes, visualmode, direction) " {{{
|
2014-01-13 20:44:57 -05:00
|
|
|
|
let s:old['input'] = get(s:old, 'input', '')
|
|
|
|
|
let input = EasyMotion#command_line#GetInput(a:num_strokes, s:old.input)
|
|
|
|
|
let s:old['input'] = input
|
2014-01-10 15:56:41 -05:00
|
|
|
|
|
|
|
|
|
" Check that we have an input char
|
|
|
|
|
if empty(input)
|
|
|
|
|
" Restore selection
|
2014-01-13 10:57:02 -05:00
|
|
|
|
if ! empty(a:visualmode)
|
2014-01-10 15:56:41 -05:00
|
|
|
|
silent exec 'normal! gv'
|
|
|
|
|
endif
|
2014-01-13 20:44:57 -05:00
|
|
|
|
redraw
|
|
|
|
|
echo ''
|
2014-01-10 15:56:41 -05:00
|
|
|
|
return
|
|
|
|
|
endif
|
|
|
|
|
|
|
|
|
|
let re = s:findMotion(input)
|
|
|
|
|
|
2014-01-13 10:57:02 -05:00
|
|
|
|
call s:EasyMotion(re, a:direction, a:visualmode ? visualmode() : '', mode(1))
|
2014-01-10 15:56:41 -05:00
|
|
|
|
endfunction " }}}
|
2014-01-13 10:57:02 -05:00
|
|
|
|
function! EasyMotion#T(num_strokes, visualmode, direction) " {{{
|
2014-01-13 20:44:57 -05:00
|
|
|
|
let s:old['input'] = get(s:old, 'input', '')
|
|
|
|
|
let input = EasyMotion#command_line#GetInput(a:num_strokes, s:old.input)
|
|
|
|
|
let s:old['input'] = input
|
2014-01-07 03:02:16 -05:00
|
|
|
|
|
2014-01-12 07:45:21 -05:00
|
|
|
|
" Check that we have an input char
|
|
|
|
|
if empty(input)
|
|
|
|
|
" Restore selection
|
2014-01-13 10:57:02 -05:00
|
|
|
|
if ! empty(a:visualmode)
|
2014-01-12 07:45:21 -05:00
|
|
|
|
silent exec 'normal! gv'
|
|
|
|
|
endif
|
2014-01-13 20:44:57 -05:00
|
|
|
|
redraw
|
|
|
|
|
echo ''
|
2014-01-07 03:02:16 -05:00
|
|
|
|
return
|
|
|
|
|
endif
|
|
|
|
|
|
2014-01-12 07:45:21 -05:00
|
|
|
|
let re = s:findMotion(input)
|
2014-01-07 03:02:16 -05:00
|
|
|
|
|
|
|
|
|
if a:direction == 1
|
|
|
|
|
" backward
|
|
|
|
|
let re = re . '\zs.'
|
|
|
|
|
else
|
|
|
|
|
" forward
|
|
|
|
|
let re = '.\ze' . re
|
|
|
|
|
endif
|
|
|
|
|
|
2014-01-13 10:57:02 -05:00
|
|
|
|
call s:EasyMotion(re, a:direction, a:visualmode ? visualmode() : '', mode(1))
|
2014-01-07 03:02:16 -05:00
|
|
|
|
endfunction " }}}
|
|
|
|
|
" -- Word Motion -------------------------
|
|
|
|
|
function! EasyMotion#WB(visualmode, direction) " {{{
|
|
|
|
|
call s:EasyMotion('\(\<.\|^$\)', a:direction, a:visualmode ? visualmode() : '', '')
|
|
|
|
|
endfunction " }}}
|
|
|
|
|
function! EasyMotion#WBW(visualmode, direction) " {{{
|
|
|
|
|
call s:EasyMotion('\(\(^\|\s\)\@<=\S\|^$\)', a:direction, a:visualmode ? visualmode() : '', '')
|
|
|
|
|
endfunction " }}}
|
|
|
|
|
function! EasyMotion#E(visualmode, direction) " {{{
|
|
|
|
|
call s:EasyMotion('\(.\>\|^$\)', a:direction, a:visualmode ? visualmode() : '', mode(1))
|
|
|
|
|
endfunction " }}}
|
|
|
|
|
function! EasyMotion#EW(visualmode, direction) " {{{
|
|
|
|
|
call s:EasyMotion('\(\S\(\s\|$\)\|^$\)', a:direction, a:visualmode ? visualmode() : '', mode(1))
|
|
|
|
|
endfunction " }}}
|
|
|
|
|
" -- JK Motion ---------------------------
|
|
|
|
|
function! EasyMotion#JK(visualmode, direction) " {{{
|
|
|
|
|
if g:EasyMotion_startofline
|
|
|
|
|
call s:EasyMotion('^\(\w\|\s*\zs\|$\)', a:direction, a:visualmode ? visualmode() : '', '')
|
|
|
|
|
else
|
|
|
|
|
let prev_column = getpos('.')[2] - 1
|
|
|
|
|
call s:EasyMotion('^.\{,' . prev_column . '}\zs\(.\|$\)', a:direction, a:visualmode ? visualmode() : '', '')
|
|
|
|
|
endif
|
|
|
|
|
endfunction " }}}
|
2014-01-13 20:00:06 -05:00
|
|
|
|
" -- End of Line Motion ---------------------------
|
|
|
|
|
function! EasyMotion#Eol(visualmode, direction) " {{{
|
2014-01-14 19:11:22 -05:00
|
|
|
|
call s:EasyMotion('\(\w\|\s*\zs\|.\|^\)$', a:direction, a:visualmode ? visualmode() : '', '')
|
2014-01-13 20:00:06 -05:00
|
|
|
|
endfunction " }}}
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" -- Search Motion -----------------------
|
|
|
|
|
function! EasyMotion#Search(visualmode, direction) " {{{
|
|
|
|
|
call s:EasyMotion(@/, a:direction, a:visualmode ? visualmode() : '', '')
|
|
|
|
|
endfunction " }}}
|
|
|
|
|
" -- JumpToAnywhere Motion ---------------
|
|
|
|
|
function! EasyMotion#JumpToAnywhere(visualmode, direction) " {{{
|
|
|
|
|
call s:EasyMotion( g:EasyMotion_re_anywhere, a:direction, a:visualmode ? visualmode() : '', '')
|
|
|
|
|
endfunction " }}}
|
|
|
|
|
" -- Line Motion -------------------------
|
2014-01-13 10:57:02 -05:00
|
|
|
|
function! EasyMotion#SL(num_strokes, visualmode, direction) " {{{
|
2014-01-13 20:44:57 -05:00
|
|
|
|
let s:old['input'] = get(s:old, 'input', '')
|
|
|
|
|
let input = EasyMotion#command_line#GetInput(a:num_strokes, s:old.input)
|
|
|
|
|
let s:old['input'] = input
|
2014-01-07 03:02:16 -05:00
|
|
|
|
|
2014-01-13 10:57:02 -05:00
|
|
|
|
" Check that we have an input char
|
|
|
|
|
if empty(input)
|
|
|
|
|
" Restore selection
|
|
|
|
|
if ! empty(a:visualmode)
|
|
|
|
|
silent exec 'normal! gv'
|
|
|
|
|
endif
|
2014-01-13 20:44:57 -05:00
|
|
|
|
redraw
|
|
|
|
|
echo ''
|
2014-01-07 03:02:16 -05:00
|
|
|
|
return
|
|
|
|
|
endif
|
|
|
|
|
|
2014-01-14 03:46:30 -05:00
|
|
|
|
let s:line_flag = 1
|
|
|
|
|
|
2014-01-13 10:57:02 -05:00
|
|
|
|
let re = s:findMotion(input)
|
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
call s:EasyMotion(re, a:direction, a:visualmode ? visualmode() : '', mode(1))
|
|
|
|
|
endfunction " }}}
|
2014-01-13 10:57:02 -05:00
|
|
|
|
function! EasyMotion#TL(num_strokes, visualmode, direction) " {{{
|
2014-01-13 20:44:57 -05:00
|
|
|
|
let s:old['input'] = get(s:old, 'input', '')
|
|
|
|
|
let input = EasyMotion#command_line#GetInput(a:num_strokes, s:old.input)
|
|
|
|
|
let s:old['input'] = input
|
2014-01-08 23:45:32 -05:00
|
|
|
|
|
2014-01-13 10:57:02 -05:00
|
|
|
|
" Check that we have an input char
|
|
|
|
|
if empty(input)
|
|
|
|
|
" Restore selection
|
|
|
|
|
if ! empty(a:visualmode)
|
|
|
|
|
silent exec 'normal! gv'
|
|
|
|
|
endif
|
2014-01-13 20:44:57 -05:00
|
|
|
|
redraw
|
|
|
|
|
echo ''
|
2014-01-08 23:45:32 -05:00
|
|
|
|
return
|
|
|
|
|
endif
|
|
|
|
|
|
2014-01-14 03:46:30 -05:00
|
|
|
|
let s:line_flag = 1
|
|
|
|
|
|
2014-01-13 10:57:02 -05:00
|
|
|
|
let re = s:findMotion(input)
|
2014-01-08 23:45:32 -05:00
|
|
|
|
|
|
|
|
|
if a:direction == 1
|
|
|
|
|
" backward
|
|
|
|
|
let re = re . '\zs.'
|
|
|
|
|
else
|
|
|
|
|
" forward
|
|
|
|
|
let re = '.\ze' . re
|
|
|
|
|
endif
|
|
|
|
|
|
|
|
|
|
call s:EasyMotion(re, a:direction, a:visualmode ? visualmode() : '', mode(1))
|
|
|
|
|
endfunction " }}}
|
|
|
|
|
function! EasyMotion#WBL(visualmode, direction) " {{{
|
|
|
|
|
let s:line_flag = 1
|
|
|
|
|
call s:EasyMotion('\(\<.\|^$\)', a:direction, a:visualmode ? visualmode() : '', '')
|
2014-01-07 03:02:16 -05:00
|
|
|
|
endfunction " }}}
|
|
|
|
|
function! EasyMotion#EL(visualmode, direction) " {{{
|
2014-01-08 23:45:32 -05:00
|
|
|
|
let s:line_flag = 1
|
|
|
|
|
call s:EasyMotion('\(.\>\|^$\)', a:direction, a:visualmode ? visualmode() : '', mode(1))
|
2014-01-07 03:02:16 -05:00
|
|
|
|
endfunction " }}}
|
|
|
|
|
function! EasyMotion#LineAnywhere(visualmode, direction) " {{{
|
2014-01-08 23:45:32 -05:00
|
|
|
|
let s:line_flag = 1
|
|
|
|
|
let re = g:EasyMotion_re_line_anywhere
|
2014-01-07 03:02:16 -05:00
|
|
|
|
call s:EasyMotion(re, a:direction, a:visualmode ? visualmode() : '', '')
|
|
|
|
|
endfunction " }}}
|
|
|
|
|
" -- Special Motion ----------------------
|
|
|
|
|
function! EasyMotion#SelectLines() "{{{
|
|
|
|
|
let orig_pos = [line('.'), col('.')]
|
|
|
|
|
|
|
|
|
|
call s:EasyMotion('^\(\w\|\s*\zs\|$\)', 2, '', '', 0, 0, 1)
|
|
|
|
|
if s:EasyMotion_cancelled
|
|
|
|
|
keepjumps call cursor(orig_pos[0], orig_pos[1])
|
|
|
|
|
return ''
|
|
|
|
|
else
|
|
|
|
|
let pos1 = [line('.'), col('.')]
|
|
|
|
|
keepjumps call cursor(orig_pos[0], orig_pos[1])
|
|
|
|
|
call s:EasyMotion('^\(\w\|\s*\zs\|$\)', 2, '', '', pos1[0], 1, 1)
|
2013-12-20 04:31:20 -05:00
|
|
|
|
if s:EasyMotion_cancelled
|
2013-06-03 17:24:44 -04:00
|
|
|
|
keepjumps call cursor(orig_pos[0], orig_pos[1])
|
2013-05-15 22:32:47 -04:00
|
|
|
|
return ''
|
|
|
|
|
else
|
2014-01-07 03:02:16 -05:00
|
|
|
|
normal! V
|
|
|
|
|
keepjumps call cursor(pos1[0], pos1[1])
|
|
|
|
|
normal! o
|
|
|
|
|
return 1
|
2013-05-15 22:32:47 -04:00
|
|
|
|
endif
|
2014-01-07 03:02:16 -05:00
|
|
|
|
endif
|
|
|
|
|
endfunction "}}}
|
|
|
|
|
function! EasyMotion#SelectLinesYank() "{{{
|
|
|
|
|
let orig_pos = [line('.'), col('.')]
|
|
|
|
|
call EasyMotion#SelectLines()
|
|
|
|
|
normal! y
|
|
|
|
|
keepjumps call cursor(orig_pos[0], orig_pos[1])
|
|
|
|
|
endfunction "}}}
|
|
|
|
|
function! EasyMotion#SelectLinesDelete() "{{{
|
|
|
|
|
let orig_pos = [line('.'), col('.')]
|
|
|
|
|
" if cancelled?
|
|
|
|
|
if EasyMotion#SelectLines()
|
|
|
|
|
" Prepare the number of lines "{{{
|
|
|
|
|
let start_of_line = line("v")
|
|
|
|
|
silent exec "normal!" "o"
|
|
|
|
|
let end_of_line = line("v")
|
|
|
|
|
"}}}
|
|
|
|
|
normal! d
|
|
|
|
|
if orig_pos[0] < max([start_of_line,end_of_line])
|
2013-11-27 09:36:43 -05:00
|
|
|
|
keepjumps call cursor(orig_pos[0], orig_pos[1])
|
2014-01-07 03:02:16 -05:00
|
|
|
|
else
|
|
|
|
|
" if delete lines above cursor line
|
|
|
|
|
keepjumps call cursor(orig_pos[0]-abs(end_of_line-start_of_line)-1, orig_pos[1])
|
2013-11-27 09:36:43 -05:00
|
|
|
|
endif
|
2014-01-07 03:02:16 -05:00
|
|
|
|
else
|
|
|
|
|
keepjumps call cursor(orig_pos[0], orig_pos[1])
|
|
|
|
|
endif
|
|
|
|
|
endfunction "}}}
|
2013-06-03 17:24:44 -04:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
function! EasyMotion#SelectPhrase() "{{{
|
|
|
|
|
let chars = s:GetSearchChar2(0)
|
|
|
|
|
if empty(chars)
|
|
|
|
|
return
|
|
|
|
|
endif
|
2013-06-03 20:26:16 -04:00
|
|
|
|
|
2014-01-10 07:33:17 -05:00
|
|
|
|
" Generate regexp {{{
|
|
|
|
|
if chars[0] ==# chars[1]
|
|
|
|
|
let re = s:findMotion(chars[0])
|
2014-01-07 03:02:16 -05:00
|
|
|
|
else
|
2014-01-10 07:33:17 -05:00
|
|
|
|
" Convert chars {{{
|
|
|
|
|
" let g:EasyMotion_smartcase to 0 temporarily
|
|
|
|
|
let save_smart = g:EasyMotion_smartcase
|
|
|
|
|
let g:EasyMotion_smartcase = 0
|
|
|
|
|
|
|
|
|
|
let re1 = s:findMotion(chars[0])
|
|
|
|
|
let re2 = s:findMotion(chars[1])
|
|
|
|
|
|
|
|
|
|
let g:EasyMotion_smartcase = save_smart
|
|
|
|
|
unlet save_smart
|
|
|
|
|
"}}}
|
|
|
|
|
|
|
|
|
|
let re = re1 . '\|' . re2
|
|
|
|
|
|
|
|
|
|
if g:EasyMotion_smartcase && chars[0] =~# '\U' || chars[1] =~# '\U'
|
|
|
|
|
let re = '\c' . re
|
|
|
|
|
else
|
|
|
|
|
let re = '\C' . re
|
|
|
|
|
endif
|
2014-01-07 03:02:16 -05:00
|
|
|
|
endif
|
2014-01-10 07:33:17 -05:00
|
|
|
|
"}}}
|
|
|
|
|
|
|
|
|
|
" Store original pos
|
|
|
|
|
let orig_pos = [line('.'), col('.')]
|
2013-10-04 09:45:06 -04:00
|
|
|
|
|
2014-01-10 07:33:17 -05:00
|
|
|
|
" First
|
2014-01-07 03:02:16 -05:00
|
|
|
|
call s:EasyMotion(re, 2, '', '', 0, 0, 0, 0)
|
|
|
|
|
if s:EasyMotion_cancelled
|
|
|
|
|
keepjumps call cursor(orig_pos[0], orig_pos[1])
|
|
|
|
|
return ''
|
2014-01-10 07:33:17 -05:00
|
|
|
|
endif
|
|
|
|
|
|
|
|
|
|
" Store first pos
|
|
|
|
|
let pos1 = [line('.'), col('.')]
|
|
|
|
|
keepjumps call cursor(orig_pos[0], orig_pos[1])
|
|
|
|
|
|
|
|
|
|
" Second
|
|
|
|
|
call s:EasyMotion(re, 2, '', '', 0, 0, 0, pos1)
|
|
|
|
|
if s:EasyMotion_cancelled
|
2014-01-07 03:02:16 -05:00
|
|
|
|
keepjumps call cursor(orig_pos[0], orig_pos[1])
|
2014-01-10 07:33:17 -05:00
|
|
|
|
return ''
|
2014-01-07 03:02:16 -05:00
|
|
|
|
endif
|
2014-01-10 07:33:17 -05:00
|
|
|
|
|
|
|
|
|
" Success
|
|
|
|
|
normal! v
|
|
|
|
|
keepjumps call cursor(pos1[0], pos1[1])
|
|
|
|
|
normal! o
|
|
|
|
|
return 1
|
2014-01-07 03:02:16 -05:00
|
|
|
|
endfunction "}}}
|
|
|
|
|
function! EasyMotion#SelectPhraseYank() "{{{
|
|
|
|
|
let orig_pos = [line('.'), col('.')]
|
2013-06-22 17:17:47 -04:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
call EasyMotion#SelectPhrase()
|
|
|
|
|
normal! y
|
|
|
|
|
keepjumps call cursor(orig_pos[0], orig_pos[1])
|
|
|
|
|
endfunction "}}}
|
|
|
|
|
function! EasyMotion#SelectPhraseDelete() "{{{
|
|
|
|
|
let orig_pos = [line('.'), col('.')]
|
|
|
|
|
|
|
|
|
|
" If cancelled?
|
|
|
|
|
if EasyMotion#SelectPhrase()
|
|
|
|
|
" Prepare the number of lines "{{{
|
|
|
|
|
let start_of_line = line("v")
|
|
|
|
|
silent exec "normal!" "o"
|
|
|
|
|
let end_of_line = line("v")
|
|
|
|
|
"}}}
|
|
|
|
|
normal! d
|
|
|
|
|
if orig_pos[0] < max([start_of_line,end_of_line])
|
2013-11-27 09:36:43 -05:00
|
|
|
|
keepjumps call cursor(orig_pos[0], orig_pos[1])
|
2014-01-07 03:02:16 -05:00
|
|
|
|
else
|
|
|
|
|
" if you delete phrase above cursor line and phrase is over lines
|
|
|
|
|
keepjumps call cursor(orig_pos[0]-abs(end_of_line-start_of_line), orig_pos[1])
|
2013-11-27 09:36:43 -05:00
|
|
|
|
endif
|
2014-01-07 03:02:16 -05:00
|
|
|
|
else
|
|
|
|
|
keepjumps call cursor(orig_pos[0], orig_pos[1])
|
|
|
|
|
endif
|
|
|
|
|
endfunction "}}}
|
|
|
|
|
" -- User Motion -------------------------
|
2014-01-13 11:02:43 -05:00
|
|
|
|
function! EasyMotion#User(pattern, mode, direction) " {{{
|
|
|
|
|
let visualmode = match('\v([Vv])|(C-v)', a:mode) > 0 ? visualmode() : ''
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let re = escape(a:pattern, '|')
|
2014-01-13 11:02:43 -05:00
|
|
|
|
call s:EasyMotion(re, a:direction, visualmode, a:mode)
|
2014-01-07 03:02:16 -05:00
|
|
|
|
endfunction " }}}
|
|
|
|
|
function! EasyMotion#UserMapping(re, mapping, direction) " {{{
|
|
|
|
|
silent exec "nnoremap ".a:mapping." :call EasyMotion#User('".a:re."', 0, ".a:direction.")<CR>"
|
|
|
|
|
silent exec "onoremap ".a:mapping." :call EasyMotion#User('".a:re."', 0, ".a:direction.")<CR>"
|
|
|
|
|
silent exec "vnoremap ".a:mapping." :<C-u>call EasyMotion#User('".a:re."', 0,".a:direction.")<CR>"
|
|
|
|
|
endfunction " }}}
|
2014-01-08 23:52:07 -05:00
|
|
|
|
" -- Repeat Motion -----------------------
|
2014-01-13 10:57:02 -05:00
|
|
|
|
function! EasyMotion#Repeat(visualmode) " {{{
|
2014-01-08 23:52:07 -05:00
|
|
|
|
" Repeat previous motion with previous targets
|
2014-01-13 20:44:57 -05:00
|
|
|
|
if s:old ==# {}
|
2014-01-08 23:52:07 -05:00
|
|
|
|
call s:Message("Previous targets doesn't exist")
|
|
|
|
|
return
|
|
|
|
|
endif
|
|
|
|
|
let re = s:old.regexp
|
|
|
|
|
let direction = s:old.direction
|
|
|
|
|
let s:line_flag = s:old.line_flag
|
|
|
|
|
|
|
|
|
|
call s:EasyMotion(re, direction, a:visualmode ? visualmode() : '', mode(1))
|
|
|
|
|
endfunction " }}}
|
2013-12-22 09:47:37 -05:00
|
|
|
|
|
2011-11-07 08:33:20 -05:00
|
|
|
|
" }}}
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" == Helper functions {{{
|
|
|
|
|
" -- Message -----------------------------
|
|
|
|
|
function! s:Message(message) " {{{
|
|
|
|
|
echo 'EasyMotion: ' . a:message
|
|
|
|
|
endfunction " }}}
|
|
|
|
|
function! s:Prompt(message) " {{{
|
|
|
|
|
echohl Question
|
|
|
|
|
echo a:message . ': '
|
|
|
|
|
echohl None
|
|
|
|
|
endfunction " }}}
|
|
|
|
|
" -- Save & Restore values ---------------
|
|
|
|
|
function! s:VarReset(var, ...) " {{{
|
|
|
|
|
if ! exists('s:var_reset')
|
|
|
|
|
let s:var_reset = {}
|
|
|
|
|
endif
|
|
|
|
|
|
|
|
|
|
if a:0 == 0 && has_key(s:var_reset, a:var)
|
|
|
|
|
" Reset var to original value
|
|
|
|
|
" setbufbar( or bufname): '' or '%' can be used for the current buffer
|
|
|
|
|
call setbufvar("", a:var, s:var_reset[a:var])
|
|
|
|
|
elseif a:0 == 1
|
|
|
|
|
" Save original value and set new var value
|
|
|
|
|
|
|
|
|
|
let new_value = a:0 == 1 ? a:1 : ''
|
|
|
|
|
|
|
|
|
|
" Store original value
|
|
|
|
|
let s:var_reset[a:var] = getbufvar("", a:var)
|
|
|
|
|
|
|
|
|
|
" Set new var value
|
|
|
|
|
call setbufvar("", a:var, new_value)
|
|
|
|
|
endif
|
|
|
|
|
endfunction " }}}
|
|
|
|
|
function! s:SaveValue() "{{{
|
|
|
|
|
call s:VarReset('&scrolloff', 0)
|
|
|
|
|
call s:VarReset('&modified', 0)
|
|
|
|
|
call s:VarReset('&modifiable', 1)
|
|
|
|
|
call s:VarReset('&readonly', 0)
|
|
|
|
|
call s:VarReset('&spell', 0)
|
|
|
|
|
call s:VarReset('&virtualedit', '')
|
|
|
|
|
call s:VarReset('&foldmethod', 'manual')
|
|
|
|
|
endfunction "}}}
|
|
|
|
|
function! s:RestoreValue() "{{{
|
|
|
|
|
call s:VarReset('&scrolloff')
|
|
|
|
|
call s:VarReset('&modified')
|
|
|
|
|
call s:VarReset('&modifiable')
|
|
|
|
|
call s:VarReset('&readonly')
|
|
|
|
|
call s:VarReset('&spell')
|
|
|
|
|
call s:VarReset('&virtualedit')
|
|
|
|
|
call s:VarReset('&foldmethod')
|
|
|
|
|
endfunction "}}}
|
|
|
|
|
" -- Draw --------------------------------
|
|
|
|
|
function! s:SetLines(lines, key) " {{{
|
|
|
|
|
for [line_num, line] in a:lines
|
|
|
|
|
call setline(line_num, line[a:key])
|
|
|
|
|
endfor
|
|
|
|
|
endfunction " }}}
|
|
|
|
|
" -- Get characters from user input ------
|
|
|
|
|
function! s:GetChar() " {{{
|
|
|
|
|
let char = getchar()
|
|
|
|
|
|
|
|
|
|
if char == 27
|
|
|
|
|
" Escape key pressed
|
|
|
|
|
redraw
|
|
|
|
|
|
|
|
|
|
call s:Message('Cancelled')
|
|
|
|
|
|
|
|
|
|
return ''
|
|
|
|
|
endif
|
|
|
|
|
|
|
|
|
|
return nr2char(char)
|
|
|
|
|
endfunction " }}}
|
|
|
|
|
function! s:GetSearchChar2(visualmode) " {{{
|
|
|
|
|
|
|
|
|
|
let chars = []
|
|
|
|
|
for i in [1, 2]
|
|
|
|
|
redraw
|
|
|
|
|
|
|
|
|
|
call s:Prompt('Search for character ' . i)
|
2011-11-07 08:33:20 -05:00
|
|
|
|
let char = s:GetChar()
|
|
|
|
|
|
|
|
|
|
" Check that we have an input char
|
|
|
|
|
if empty(char)
|
|
|
|
|
" Restore selection
|
|
|
|
|
if ! empty(a:visualmode)
|
|
|
|
|
silent exec 'normal! gv'
|
|
|
|
|
endif
|
|
|
|
|
|
|
|
|
|
return ''
|
|
|
|
|
endif
|
2014-01-07 03:02:16 -05:00
|
|
|
|
call add(chars, char)
|
|
|
|
|
endfor
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
return chars
|
|
|
|
|
endfunction " }}}
|
|
|
|
|
function! s:GetSearchChar(visualmode) " {{{
|
|
|
|
|
call s:Prompt('Search for character')
|
2013-10-11 23:58:29 -04:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let char = s:GetChar()
|
2013-12-22 09:47:37 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" Check that we have an input char
|
|
|
|
|
if empty(char)
|
|
|
|
|
" Restore selection
|
|
|
|
|
if ! empty(a:visualmode)
|
|
|
|
|
silent exec 'normal! gv'
|
2013-12-22 09:47:37 -05:00
|
|
|
|
endif
|
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
return ''
|
|
|
|
|
endif
|
2013-12-22 09:47:37 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
return char
|
|
|
|
|
endfunction " }}}
|
|
|
|
|
" -- Find Motion Helper ------------------
|
|
|
|
|
function! s:findMotion(char) "{{{
|
|
|
|
|
" Find Motion: S,F,T
|
2014-01-10 07:33:17 -05:00
|
|
|
|
let re = escape(a:char, '.$^~\[]')
|
2013-12-29 00:29:05 -05:00
|
|
|
|
|
2014-01-10 10:06:21 -05:00
|
|
|
|
let should_use_migemo = s:should_use_migemo(a:char)
|
|
|
|
|
if should_use_migemo
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let re = s:convertMigemo(re)
|
|
|
|
|
endif
|
|
|
|
|
|
2014-01-10 07:33:17 -05:00
|
|
|
|
if s:useSmartsign(a:char)
|
|
|
|
|
let re = s:convertSmartsign(re, a:char)
|
|
|
|
|
endif
|
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
if g:EasyMotion_smartcase
|
|
|
|
|
let re = s:convertSmartcase(re, a:char)
|
|
|
|
|
endif
|
|
|
|
|
|
|
|
|
|
return re
|
|
|
|
|
endfunction "}}}
|
|
|
|
|
function! s:convertMigemo(re) "{{{
|
|
|
|
|
let re = a:re
|
2014-01-14 03:46:30 -05:00
|
|
|
|
|
|
|
|
|
if len(re) > 1
|
|
|
|
|
" System cmigemo
|
|
|
|
|
return EasyMotion#cmigemo#getMigemoPattern(re)
|
|
|
|
|
endif
|
|
|
|
|
|
|
|
|
|
" EasyMoton migemo one key dict
|
2014-01-07 03:02:16 -05:00
|
|
|
|
if ! has_key(s:migemo_dicts, &l:encoding)
|
2014-01-13 18:48:26 -05:00
|
|
|
|
let s:migemo_dicts[&l:encoding] = EasyMotion#helper#load_migemo_dict()
|
2014-01-07 03:02:16 -05:00
|
|
|
|
endif
|
|
|
|
|
if re =~# '^\a$'
|
2014-01-14 03:46:30 -05:00
|
|
|
|
let re = get(s:migemo_dicts[&l:encoding], re, a:re)
|
2014-01-07 03:02:16 -05:00
|
|
|
|
endif
|
|
|
|
|
return re
|
|
|
|
|
endfunction "}}}
|
|
|
|
|
function! s:convertSmartcase(re, char) "{{{
|
|
|
|
|
let re = a:re
|
|
|
|
|
if a:char =~# '\U' "nonuppercase
|
|
|
|
|
return '\c' . re
|
|
|
|
|
else "uppercase
|
|
|
|
|
return '\C' . re
|
|
|
|
|
endif
|
|
|
|
|
endfunction "}}}
|
|
|
|
|
function! s:convertSmartsign(re, char) "{{{
|
|
|
|
|
let smart_dict = s:load_smart_dict()
|
|
|
|
|
let upper_sign = escape(get(smart_dict, a:char, ''), '.$^~')
|
|
|
|
|
if upper_sign ==# ''
|
|
|
|
|
return a:re
|
|
|
|
|
else
|
|
|
|
|
let re = a:re . '\|' . upper_sign
|
|
|
|
|
return re
|
|
|
|
|
endif
|
|
|
|
|
endfunction "}}}
|
2014-01-10 07:33:17 -05:00
|
|
|
|
function! s:useSmartsign(char) "{{{
|
|
|
|
|
if (exists('g:EasyMotion_use_smartsign_us') ||
|
|
|
|
|
\ exists('g:EasyMotion_use_smartsign_jp')) &&
|
|
|
|
|
\ a:char =~# '\A'
|
2014-01-07 03:02:16 -05:00
|
|
|
|
return 1
|
|
|
|
|
else
|
|
|
|
|
return 0
|
|
|
|
|
endif
|
|
|
|
|
endfunction "}}}
|
|
|
|
|
function! s:load_smart_dict() "{{{
|
|
|
|
|
if exists('g:EasyMotion_use_smartsign_us')
|
|
|
|
|
return g:EasyMotion#sticky_table#us
|
|
|
|
|
elseif exists('g:EasyMotion_use_smartsign_jp')
|
|
|
|
|
return g:EasyMotion#sticky_table#jp
|
|
|
|
|
else
|
|
|
|
|
return ''
|
|
|
|
|
endif
|
|
|
|
|
endfunction "}}}
|
2014-01-10 10:06:21 -05:00
|
|
|
|
|
|
|
|
|
|
2014-01-08 16:27:37 -05:00
|
|
|
|
" -- Handle Visual Mode ------------------
|
2014-01-08 15:07:17 -05:00
|
|
|
|
function! s:GetVisualStartPosition(c_pos, v_start, v_end, search_direction) "{{{
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let vmode = mode(1)
|
|
|
|
|
if match('Vv',vmode) < 0
|
|
|
|
|
throw 'Unkown visual mode:'.vmode
|
2014-01-13 13:43:22 -05:00
|
|
|
|
endif
|
|
|
|
|
|
|
|
|
|
if vmode ==# 'V' "line-wise Visual
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" Line-wise Visual {{{
|
|
|
|
|
if a:v_start[0] == a:v_end[0]
|
2014-01-08 15:07:17 -05:00
|
|
|
|
if a:search_direction == ''
|
2014-01-13 13:43:22 -05:00
|
|
|
|
return a:v_start
|
2014-01-08 15:07:17 -05:00
|
|
|
|
elseif a:search_direction == 'b'
|
2014-01-13 13:43:22 -05:00
|
|
|
|
return a:v_end
|
2014-01-07 02:11:33 -05:00
|
|
|
|
else
|
2014-01-07 03:02:16 -05:00
|
|
|
|
throw 'Unkown search_direction'
|
2014-01-07 02:11:33 -05:00
|
|
|
|
endif
|
|
|
|
|
else
|
2014-01-07 03:02:16 -05:00
|
|
|
|
if a:c_pos[0] == a:v_start[0]
|
2014-01-13 13:43:22 -05:00
|
|
|
|
return a:v_end
|
2014-01-07 03:02:16 -05:00
|
|
|
|
elseif a:c_pos[0] == a:v_end[0]
|
2014-01-13 13:43:22 -05:00
|
|
|
|
return a:v_start
|
2014-01-07 02:11:33 -05:00
|
|
|
|
endif
|
|
|
|
|
endif
|
|
|
|
|
"}}}
|
2014-01-07 03:02:16 -05:00
|
|
|
|
else
|
|
|
|
|
" Character-wise or Block-wise Visual"{{{
|
|
|
|
|
if a:c_pos == a:v_start
|
2014-01-13 13:43:22 -05:00
|
|
|
|
return a:v_end
|
2014-01-07 03:02:16 -05:00
|
|
|
|
elseif a:c_pos == a:v_end
|
2014-01-13 13:43:22 -05:00
|
|
|
|
return a:v_start
|
|
|
|
|
endif
|
|
|
|
|
|
|
|
|
|
" virtualedit
|
|
|
|
|
if a:c_pos[0] == a:v_start[0]
|
|
|
|
|
return a:v_end
|
|
|
|
|
elseif a:c_pos[0] == a:v_end[0]
|
|
|
|
|
return a:v_start
|
2014-01-07 03:02:16 -05:00
|
|
|
|
else
|
|
|
|
|
throw 'Unkown a:c_pos'
|
|
|
|
|
endif
|
|
|
|
|
"}}}
|
|
|
|
|
endif
|
|
|
|
|
endfunction "}}}
|
2014-01-08 16:27:37 -05:00
|
|
|
|
" -- Others ------------------------------
|
2014-01-13 18:48:26 -05:00
|
|
|
|
function! s:should_use_migemo(char) "{{{
|
2014-01-14 03:46:30 -05:00
|
|
|
|
if ! g:EasyMotion_use_migemo || match(a:char, '\A') != -1
|
2014-01-13 18:48:26 -05:00
|
|
|
|
return 0
|
|
|
|
|
endif
|
|
|
|
|
|
2014-01-14 03:46:30 -05:00
|
|
|
|
" TODO: use direction
|
|
|
|
|
if s:line_flag == 1
|
|
|
|
|
let first_line = line('.')
|
|
|
|
|
let end_line = line('.')
|
|
|
|
|
else
|
|
|
|
|
let first_line = line('w0')
|
|
|
|
|
let end_line = line('w$')
|
|
|
|
|
endif
|
|
|
|
|
|
2014-01-13 18:48:26 -05:00
|
|
|
|
|
|
|
|
|
for line in range(first_line, end_line)
|
|
|
|
|
if s:is_folded(line)
|
|
|
|
|
continue
|
|
|
|
|
endif
|
|
|
|
|
|
|
|
|
|
if EasyMotion#helper#include_multibyte_char(getline(line)) == 1
|
|
|
|
|
return 1
|
|
|
|
|
endif
|
|
|
|
|
endfor
|
|
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
endfunction "}}}
|
2014-01-07 03:02:16 -05:00
|
|
|
|
function! s:is_folded(line) "{{{
|
|
|
|
|
" Return false if g:EasyMotion_skipfoldedline == 1
|
|
|
|
|
" and line is start of folded lines
|
|
|
|
|
return foldclosed(a:line) != -1 &&
|
|
|
|
|
\ (g:EasyMotion_skipfoldedline == 1 ||
|
|
|
|
|
\ a:line != foldclosed(a:line))
|
|
|
|
|
endfunction "}}}
|
2014-01-08 13:01:00 -05:00
|
|
|
|
function! s:is_cmdwin() "{{{
|
|
|
|
|
return bufname('%') ==# '[Command Line]'
|
|
|
|
|
endfunction "}}}
|
|
|
|
|
function! s:use_wundo() "{{{
|
|
|
|
|
" wundu cannot use in command-line window and
|
|
|
|
|
" unless undolist is not empty
|
|
|
|
|
return ! s:is_cmdwin() && undotree().seq_last != 0
|
|
|
|
|
endfunction "}}}
|
2014-01-08 16:27:37 -05:00
|
|
|
|
"}}}
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" == Grouping algorithms {{{
|
|
|
|
|
let s:grouping_algorithms = {
|
|
|
|
|
\ 1: 'SCTree'
|
|
|
|
|
\ , 2: 'Original'
|
|
|
|
|
\ }
|
|
|
|
|
" -- Single-key/closest target priority tree {{{
|
|
|
|
|
" This algorithm tries to assign one-key jumps to all the targets closest to the cursor.
|
|
|
|
|
" It works recursively and will work correctly with as few keys as two.
|
|
|
|
|
function! s:GroupingAlgorithmSCTree(targets, keys) "{{{
|
|
|
|
|
" Prepare variables for working
|
|
|
|
|
let targets_len = len(a:targets)
|
|
|
|
|
let keys_len = len(a:keys)
|
|
|
|
|
|
|
|
|
|
let groups = {}
|
|
|
|
|
|
|
|
|
|
let keys = reverse(copy(a:keys))
|
|
|
|
|
|
|
|
|
|
" Semi-recursively count targets {{{
|
|
|
|
|
" We need to know exactly how many child nodes (targets) this branch will have
|
|
|
|
|
" in order to pass the correct amount of targets to the recursive function.
|
|
|
|
|
|
|
|
|
|
" Prepare sorted target count list {{{
|
|
|
|
|
" This is horrible, I know. But dicts aren't sorted in vim, so we need to
|
|
|
|
|
" work around that. That is done by having one sorted list with key counts,
|
|
|
|
|
" and a dict which connects the key with the keys_count list.
|
|
|
|
|
|
|
|
|
|
let keys_count = []
|
|
|
|
|
let keys_count_keys = {}
|
2013-12-22 09:47:37 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let i = 0
|
|
|
|
|
for key in keys
|
|
|
|
|
call add(keys_count, 0)
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let keys_count_keys[key] = i
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let i += 1
|
|
|
|
|
endfor
|
|
|
|
|
" }}}
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let targets_left = targets_len
|
|
|
|
|
let level = 0
|
|
|
|
|
let i = 0
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
while targets_left > 0
|
|
|
|
|
" Calculate the amount of child nodes based on the current level
|
|
|
|
|
let childs_len = (level == 0 ? 1 : (keys_len - 1) )
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
for key in keys
|
|
|
|
|
" Add child node count to the keys_count array
|
|
|
|
|
let keys_count[keys_count_keys[key]] += childs_len
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" Subtract the child node count
|
|
|
|
|
let targets_left -= childs_len
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
if targets_left <= 0
|
|
|
|
|
" Subtract the targets left if we added too many too
|
|
|
|
|
" many child nodes to the key count
|
|
|
|
|
let keys_count[keys_count_keys[key]] += targets_left
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
break
|
|
|
|
|
endif
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let i += 1
|
|
|
|
|
endfor
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let level += 1
|
|
|
|
|
endwhile
|
|
|
|
|
" }}}
|
|
|
|
|
" Create group tree {{{
|
|
|
|
|
let i = 0
|
|
|
|
|
let key = 0
|
|
|
|
|
|
|
|
|
|
call reverse(keys_count)
|
|
|
|
|
|
|
|
|
|
for key_count in keys_count
|
|
|
|
|
if key_count > 1
|
|
|
|
|
" We need to create a subgroup
|
|
|
|
|
" Recurse one level deeper
|
|
|
|
|
let groups[a:keys[key]] = s:GroupingAlgorithmSCTree(a:targets[i : i + key_count - 1], a:keys)
|
|
|
|
|
elseif key_count == 1
|
|
|
|
|
" Assign single target key
|
|
|
|
|
let groups[a:keys[key]] = a:targets[i]
|
|
|
|
|
else
|
|
|
|
|
" No target
|
|
|
|
|
continue
|
2011-11-07 08:33:20 -05:00
|
|
|
|
endif
|
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let key += 1
|
|
|
|
|
let i += key_count
|
|
|
|
|
endfor
|
2011-11-07 08:33:20 -05:00
|
|
|
|
" }}}
|
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" Finally!
|
|
|
|
|
return groups
|
|
|
|
|
endfunction "}}}
|
|
|
|
|
" }}}
|
|
|
|
|
" -- Original ---------------------------- {{{
|
|
|
|
|
function! s:GroupingAlgorithmOriginal(targets, keys)
|
|
|
|
|
" Split targets into groups (1 level)
|
|
|
|
|
let targets_len = len(a:targets)
|
|
|
|
|
let keys_len = len(a:keys)
|
|
|
|
|
|
|
|
|
|
let groups = {}
|
|
|
|
|
|
|
|
|
|
let i = 0
|
|
|
|
|
let root_group = 0
|
|
|
|
|
try
|
|
|
|
|
while root_group < targets_len
|
|
|
|
|
let groups[a:keys[root_group]] = {}
|
|
|
|
|
|
|
|
|
|
for key in a:keys
|
|
|
|
|
let groups[a:keys[root_group]][key] = a:targets[i]
|
|
|
|
|
|
|
|
|
|
let i += 1
|
2011-11-07 08:33:20 -05:00
|
|
|
|
endfor
|
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let root_group += 1
|
|
|
|
|
endwhile
|
|
|
|
|
catch | endtry
|
|
|
|
|
|
|
|
|
|
" Flatten the group array
|
|
|
|
|
if len(groups) == 1
|
|
|
|
|
let groups = groups[a:keys[0]]
|
|
|
|
|
endif
|
|
|
|
|
|
|
|
|
|
return groups
|
|
|
|
|
endfunction
|
2011-11-07 08:33:20 -05:00
|
|
|
|
" }}}
|
2013-06-03 17:24:44 -04:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" -- Coord/key dictionary creation ------- {{{
|
|
|
|
|
function! s:CreateCoordKeyDict(groups, ...)
|
|
|
|
|
" Dict structure:
|
|
|
|
|
" 1,2 : a
|
|
|
|
|
" 2,3 : b
|
|
|
|
|
let sort_list = []
|
|
|
|
|
let coord_keys = {}
|
|
|
|
|
let group_key = a:0 == 1 ? a:1 : ''
|
|
|
|
|
|
|
|
|
|
for [key, item] in items(a:groups)
|
|
|
|
|
let key = group_key . key
|
|
|
|
|
"let key = ( ! empty(group_key) ? group_key : key)
|
|
|
|
|
|
|
|
|
|
if type(item) == 3 " List
|
|
|
|
|
" Destination coords
|
|
|
|
|
|
|
|
|
|
" The key needs to be zero-padded in order to
|
|
|
|
|
" sort correctly
|
|
|
|
|
let dict_key = printf('%05d,%05d', item[0], item[1])
|
|
|
|
|
let coord_keys[dict_key] = key
|
|
|
|
|
|
|
|
|
|
" We need a sorting list to loop correctly in
|
|
|
|
|
" PromptUser, dicts are unsorted
|
|
|
|
|
call add(sort_list, dict_key)
|
|
|
|
|
else
|
|
|
|
|
" Item is a dict (has children)
|
|
|
|
|
let coord_key_dict = s:CreateCoordKeyDict(item, key)
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" Make sure to extend both the sort list and the
|
|
|
|
|
" coord key dict
|
|
|
|
|
call extend(sort_list, coord_key_dict[0])
|
|
|
|
|
call extend(coord_keys, coord_key_dict[1])
|
|
|
|
|
endif
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
unlet item
|
|
|
|
|
endfor
|
2013-05-14 00:43:58 -04:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
return [sort_list, coord_keys]
|
|
|
|
|
endfunction
|
|
|
|
|
" }}}
|
|
|
|
|
" }}}
|
|
|
|
|
" == Core functions {{{
|
|
|
|
|
function! s:PromptUser(groups, allows_repeat, fixed_column) "{{{
|
|
|
|
|
" -- If only one possible match, jump directly to it {{{
|
|
|
|
|
let group_values = values(a:groups)
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
if len(group_values) == 1
|
|
|
|
|
redraw
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
return group_values[0]
|
|
|
|
|
endif
|
|
|
|
|
" }}}
|
|
|
|
|
" -- Prepare marker lines ---------------- {{{
|
|
|
|
|
let lines = {}
|
|
|
|
|
let hl_coords = []
|
|
|
|
|
let hl2_first_coords = [] " Highlight for two characters
|
|
|
|
|
let hl2_second_coords = [] " Highlight for two characters
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let coord_key_dict = s:CreateCoordKeyDict(a:groups)
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
for dict_key in sort(coord_key_dict[0])
|
|
|
|
|
let target_key = coord_key_dict[1][dict_key]
|
|
|
|
|
let [line_num, col_num] = split(dict_key, ',')
|
2013-05-14 01:53:51 -04:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let line_num = str2nr(line_num)
|
|
|
|
|
let col_num = str2nr(col_num)
|
|
|
|
|
|
|
|
|
|
" Add original line and marker line
|
|
|
|
|
if ! has_key(lines, line_num)
|
|
|
|
|
let current_line = getline(line_num)
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let lines[line_num] = { 'orig': current_line, 'marker': current_line, 'mb_compensation': 0 }
|
2013-10-23 10:26:50 -04:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
endif
|
2013-05-31 01:47:09 -04:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" Solve multibyte issues by matching the byte column
|
|
|
|
|
" number instead of the visual column
|
|
|
|
|
let col_num -= lines[line_num]['mb_compensation']
|
2013-10-23 10:26:50 -04:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" Compensate for byte difference between marker
|
|
|
|
|
" character and target character
|
|
|
|
|
"
|
|
|
|
|
" This has to be done in order to match the correct
|
|
|
|
|
" column; \%c matches the byte column and not display
|
|
|
|
|
" column.
|
|
|
|
|
let target_char_len = strdisplaywidth(matchstr(lines[line_num]['marker'], '\%' . col_num . 'c.'))
|
|
|
|
|
let target_key_len = strdisplaywidth(target_key)
|
2013-10-23 10:26:50 -04:00
|
|
|
|
|
2013-05-31 01:47:09 -04:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let target_line_byte_len = strlen(lines[line_num]['marker'])
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let target_char_byte_len = strlen(matchstr(lines[line_num]['marker'], '\%' . col_num . 'c.'))
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
if a:fixed_column
|
|
|
|
|
let firstS = match(lines[line_num]['marker'], '\S')
|
|
|
|
|
if firstS >= 4
|
|
|
|
|
let leftText = strpart(lines[line_num]['marker'], 0, firstS - 3)
|
2013-05-31 01:47:09 -04:00
|
|
|
|
else
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let leftText = ''
|
|
|
|
|
endif
|
|
|
|
|
|
|
|
|
|
if firstS >= 1
|
|
|
|
|
let rightText = strpart(lines[line_num]['marker'], firstS - 1)
|
|
|
|
|
elseif firstS == 0
|
|
|
|
|
let rightText = ' ' . lines[line_num]['marker']
|
|
|
|
|
else
|
|
|
|
|
let rightText = ''
|
|
|
|
|
endif
|
|
|
|
|
|
|
|
|
|
if target_key_len < 2
|
|
|
|
|
let text = ' ' . target_key
|
|
|
|
|
call add(hl_coords, '\%' . line_num . 'l\%2c')
|
|
|
|
|
else
|
|
|
|
|
let text = target_key
|
|
|
|
|
call add(hl2_first_coords, '\%' . line_num . 'l\%1c')
|
|
|
|
|
call add(hl2_second_coords, '\%' . line_num . 'l\%2c')
|
|
|
|
|
endif
|
|
|
|
|
let lines[line_num]['marker'] = text . ' ' . lines[line_num]['marker']
|
|
|
|
|
else
|
|
|
|
|
if strlen(lines[line_num]['marker']) > 0
|
|
|
|
|
" Substitute marker character if line length > 0
|
|
|
|
|
let c = 0
|
|
|
|
|
while c < target_key_len && c < 2
|
|
|
|
|
if strlen(lines[line_num]['marker']) >= col_num + c
|
|
|
|
|
" Substitute marker character if line length > 0
|
|
|
|
|
if c == 0
|
|
|
|
|
let lines[line_num]['marker'] = substitute(
|
|
|
|
|
\ lines[line_num]['marker'],
|
|
|
|
|
\ '\%' . (col_num + c) . 'c.',
|
|
|
|
|
\ strpart(target_key, c, 1) . repeat(' ', target_char_len - 1),
|
|
|
|
|
\ '')
|
2013-05-15 17:05:02 -04:00
|
|
|
|
else
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let lines[line_num]['marker'] = substitute(
|
|
|
|
|
\ lines[line_num]['marker'],
|
|
|
|
|
\ '\%' . (col_num + c) . 'c.',
|
|
|
|
|
\ strpart(target_key, c, 1),
|
|
|
|
|
\ '')
|
2013-05-15 17:05:02 -04:00
|
|
|
|
endif
|
2014-01-07 03:02:16 -05:00
|
|
|
|
else
|
|
|
|
|
let lines[line_num]['marker'] = lines[line_num]['marker'] . strpart(target_key, c, 1)
|
|
|
|
|
endif
|
|
|
|
|
let c += 1
|
|
|
|
|
endwhile
|
|
|
|
|
else
|
|
|
|
|
" Set the line to the marker character if the line is empty
|
|
|
|
|
let lines[line_num]['marker'] = target_key
|
2013-05-31 01:47:09 -04:00
|
|
|
|
endif
|
2014-01-07 03:02:16 -05:00
|
|
|
|
endif
|
2013-05-31 01:47:09 -04:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" Add highlighting coordinates
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
if !a:fixed_column
|
|
|
|
|
if target_key_len == 1
|
|
|
|
|
call add(hl_coords, '\%' . line_num . 'l\%' . col_num . 'c')
|
|
|
|
|
else
|
|
|
|
|
call add(hl2_first_coords, '\%' . line_num . 'l\%' . (col_num) . 'c')
|
|
|
|
|
call add(hl2_second_coords, '\%' . line_num . 'l\%' . (col_num + 1) . 'c')
|
2013-05-31 01:47:09 -04:00
|
|
|
|
endif
|
2014-01-07 03:02:16 -05:00
|
|
|
|
endif
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" Add marker/target length difference for multibyte
|
|
|
|
|
" compensation
|
|
|
|
|
let lines[line_num]['mb_compensation'] += (target_line_byte_len - strlen(lines[line_num]['marker']) )
|
|
|
|
|
endfor
|
|
|
|
|
|
|
|
|
|
let lines_items = items(lines)
|
|
|
|
|
" }}}
|
|
|
|
|
" -- Highlight targets ------------------- {{{
|
|
|
|
|
if len(hl_coords) > 0
|
|
|
|
|
let target_hl_id = matchadd(g:EasyMotion_hl_group_target, join(hl_coords, '\|'), 1)
|
|
|
|
|
endif
|
|
|
|
|
if len(hl2_second_coords) > 0
|
|
|
|
|
let target_hl2_second_id = matchadd(g:EasyMotion_hl2_second_group_target, join(hl2_second_coords, '\|'), 1)
|
|
|
|
|
endif
|
|
|
|
|
if len(hl2_first_coords) > 0
|
|
|
|
|
let target_hl2_first_id = matchadd(g:EasyMotion_hl2_first_group_target, join(hl2_first_coords, '\|'), 1)
|
|
|
|
|
endif
|
|
|
|
|
" }}}
|
|
|
|
|
|
|
|
|
|
" -- Put labels on targets & Get User Input & Restore all {{{
|
|
|
|
|
" Save undo tree {{{
|
|
|
|
|
let s:undo_file = tempname()
|
2014-01-08 13:01:00 -05:00
|
|
|
|
if s:use_wundo()
|
|
|
|
|
execute "wundo" s:undo_file
|
|
|
|
|
endif
|
2014-01-07 03:02:16 -05:00
|
|
|
|
"}}}
|
|
|
|
|
try
|
|
|
|
|
" Set lines with markers
|
|
|
|
|
call s:SetLines(lines_items, 'marker')
|
|
|
|
|
redraw
|
|
|
|
|
" Get target character {{{
|
|
|
|
|
call s:Prompt('Target key')
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let char = s:GetChar()
|
|
|
|
|
if g:EasyMotion_use_upper == 1 && match(g:EasyMotion_keys, '\l') == -1
|
|
|
|
|
let char = toupper(char)
|
|
|
|
|
endif
|
2014-01-08 23:52:48 -05:00
|
|
|
|
if char ==# '
' && g:EasyMotion_enter_jump_first == 1
|
|
|
|
|
let char = g:EasyMotion_keys[0]
|
|
|
|
|
endif
|
2011-11-07 08:33:20 -05:00
|
|
|
|
" }}}
|
2014-01-07 03:02:16 -05:00
|
|
|
|
finally
|
|
|
|
|
" Restore original lines
|
|
|
|
|
call s:SetLines(lines_items, 'orig')
|
2013-05-14 01:53:51 -04:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" Un-highlight targets {{{
|
|
|
|
|
if exists('target_hl_id')
|
|
|
|
|
call matchdelete(target_hl_id)
|
|
|
|
|
endif
|
|
|
|
|
if exists('target_hl2_first_id')
|
|
|
|
|
call matchdelete(target_hl2_first_id)
|
|
|
|
|
endif
|
|
|
|
|
if exists('target_hl2_second_id')
|
|
|
|
|
call matchdelete(target_hl2_second_id)
|
|
|
|
|
endif
|
2011-11-07 08:33:20 -05:00
|
|
|
|
" }}}
|
2014-01-05 23:44:46 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" Restore undo tree {{{
|
2014-01-08 13:01:00 -05:00
|
|
|
|
if s:use_wundo() && filereadable(s:undo_file)
|
2014-01-07 03:02:16 -05:00
|
|
|
|
silent execute "rundo" s:undo_file
|
|
|
|
|
unlet s:undo_file
|
|
|
|
|
else
|
|
|
|
|
" Break undo history (undobreak)
|
2014-01-08 13:01:00 -05:00
|
|
|
|
let old_undolevels = &undolevels
|
|
|
|
|
set undolevels=-1
|
|
|
|
|
call setline('.', getline('.'))
|
|
|
|
|
let &undolevels = old_undolevels
|
|
|
|
|
unlet old_undolevels
|
|
|
|
|
" FIXME: Error occur by GundoToggle for undo number 2 is empty
|
|
|
|
|
call setline('.', getline('.'))
|
2014-01-07 03:02:16 -05:00
|
|
|
|
endif "}}}
|
2014-01-05 19:24:32 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
redraw
|
|
|
|
|
endtry "}}}
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" -- Check if we have an input char ------ {{{
|
|
|
|
|
if empty(char)
|
|
|
|
|
throw 'Cancelled'
|
|
|
|
|
endif
|
|
|
|
|
" }}}
|
|
|
|
|
" -- Repeat EasyMotion ------------------- {{{
|
2014-01-08 20:30:51 -05:00
|
|
|
|
if a:allows_repeat &&
|
|
|
|
|
\ char == '.' &&
|
|
|
|
|
\ exists('s:old_target_coord')
|
|
|
|
|
" For SelectLines
|
|
|
|
|
return s:old_target_coord
|
2014-01-07 03:02:16 -05:00
|
|
|
|
endif "}}}
|
|
|
|
|
" -- Check if the input char is valid ---- {{{
|
|
|
|
|
if ! has_key(a:groups, char)
|
|
|
|
|
throw 'Invalid target'
|
|
|
|
|
endif
|
|
|
|
|
" }}}
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let target = a:groups[char]
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
if type(target) == 3
|
|
|
|
|
" Return target coordinates
|
|
|
|
|
return target
|
|
|
|
|
else
|
|
|
|
|
" Prompt for new target character
|
|
|
|
|
return s:PromptUser(target, a:allows_repeat, a:fixed_column)
|
|
|
|
|
endif
|
|
|
|
|
endfunction "}}}
|
|
|
|
|
function! s:EasyMotion(regexp, direction, visualmode, mode, ...) " {{{
|
2014-01-13 10:57:02 -05:00
|
|
|
|
" For Special Function {{{
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" For SelectLines(), to highlight previous selected line
|
|
|
|
|
let hlcurrent = a:0 >= 1 ? a:1 : 0
|
|
|
|
|
" For SelectLines(), to allows '.' to repeat the previously pressed
|
|
|
|
|
" character
|
|
|
|
|
let allows_repeat = a:0 >= 2 ? a:2 : 0
|
|
|
|
|
" For SelectLines(), a flag to display character only at the beginning
|
|
|
|
|
" of the line
|
|
|
|
|
let fixed_column = a:0 >= 3 ? a:3 : 0
|
|
|
|
|
|
2014-01-13 10:57:02 -05:00
|
|
|
|
" For SelectPhrase()
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let hlchar = a:0 >= 4 ? a:4 : 0
|
2014-01-13 10:57:02 -05:00
|
|
|
|
"}}}
|
|
|
|
|
|
|
|
|
|
let orig_pos = [line('.'), col('.')]
|
|
|
|
|
let win_first_line = line('w0')
|
|
|
|
|
let win_last_line = line('w$')
|
2014-01-07 03:02:16 -05:00
|
|
|
|
|
|
|
|
|
let targets = []
|
|
|
|
|
|
2014-01-08 23:52:07 -05:00
|
|
|
|
" Store Regular Expression
|
2014-01-13 20:44:57 -05:00
|
|
|
|
let s:old['regexp'] = a:regexp
|
|
|
|
|
let s:old['direction'] = a:direction
|
2014-01-13 10:57:02 -05:00
|
|
|
|
let s:old['line_flag'] = s:line_flag == 1 ? 1 : 0
|
2014-01-08 23:52:07 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
try
|
|
|
|
|
" -- Reset properties -------------------- {{{
|
|
|
|
|
" Save original value and set new value
|
|
|
|
|
call s:SaveValue()
|
|
|
|
|
" }}}
|
|
|
|
|
" -- Find motion targets ----------------- {{{
|
|
|
|
|
" Setup searchpos args {{{
|
|
|
|
|
let search_direction = (a:direction >= 1 ? 'b' : '')
|
2014-01-13 10:57:02 -05:00
|
|
|
|
let search_stopline = a:direction >= 1 ? win_first_line : win_last_line
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let search_at_cursor = fixed_column ? 'c' : ''
|
2014-01-08 23:45:32 -05:00
|
|
|
|
|
|
|
|
|
if s:line_flag == 1
|
2014-01-13 10:57:02 -05:00
|
|
|
|
let search_stopline = orig_pos[0]
|
2014-01-08 23:45:32 -05:00
|
|
|
|
endif
|
2014-01-07 03:02:16 -05:00
|
|
|
|
"}}}
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" Handle visual mode {{{
|
|
|
|
|
if ! empty(a:visualmode)
|
|
|
|
|
" Decide at where visual mode start {{{
|
|
|
|
|
normal! gv
|
2014-01-13 10:57:02 -05:00
|
|
|
|
let c_pos = orig_pos " current_position
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let v_start = [line("'<"),col("'<")] " visual_start_position
|
|
|
|
|
let v_end = [line("'>"),col("'>")] " visual_end_position
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-08 15:07:17 -05:00
|
|
|
|
let v_original_pos = s:GetVisualStartPosition(c_pos, v_start, v_end, search_direction)
|
2014-01-07 03:02:16 -05:00
|
|
|
|
"}}}
|
2014-01-05 23:44:46 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" Reselect visual text {{{
|
|
|
|
|
keepjumps call cursor(v_original_pos)
|
|
|
|
|
exec "normal! " . a:visualmode
|
|
|
|
|
keepjumps call cursor(c_pos)
|
|
|
|
|
"}}}
|
|
|
|
|
" Update orig_pos {{{
|
|
|
|
|
let orig_pos = v_original_pos
|
|
|
|
|
" }}}
|
|
|
|
|
endif
|
|
|
|
|
" }}}
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" Construct match dict {{{
|
|
|
|
|
while 1
|
|
|
|
|
" Note: searchpos() has side effect which call jump cursor position.
|
|
|
|
|
" You can disable this side effect by add 'n' flags,
|
|
|
|
|
" but in this case, it's better to allows jump side effect.
|
|
|
|
|
let pos = searchpos(a:regexp, search_direction . search_at_cursor, search_stopline)
|
|
|
|
|
let search_at_cursor = ''
|
|
|
|
|
|
|
|
|
|
" Reached end of search range
|
|
|
|
|
if pos == [0, 0]
|
|
|
|
|
break
|
2011-11-07 08:33:20 -05:00
|
|
|
|
endif
|
2014-01-07 03:02:16 -05:00
|
|
|
|
|
2014-01-10 10:50:17 -05:00
|
|
|
|
" Skip folded lines {{{
|
2014-01-07 03:02:16 -05:00
|
|
|
|
if s:is_folded(pos[0])
|
2014-01-10 10:50:17 -05:00
|
|
|
|
if search_direction ==# 'b'
|
|
|
|
|
keepjumps call cursor(foldclosed(pos[0]-1), 0)
|
|
|
|
|
else
|
|
|
|
|
keepjumps call cursor(foldclosedend(pos[0]+1), 0)
|
|
|
|
|
endif
|
2014-01-07 03:02:16 -05:00
|
|
|
|
continue
|
2014-01-10 10:50:17 -05:00
|
|
|
|
endif "}}}
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
call add(targets, pos)
|
|
|
|
|
endwhile
|
|
|
|
|
"}}}
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" Handle bidirection "{{{
|
|
|
|
|
" Reconstruct match dict
|
|
|
|
|
if a:direction == 2
|
2014-01-10 10:50:17 -05:00
|
|
|
|
" Forward
|
2014-01-07 03:02:16 -05:00
|
|
|
|
if ! empty(a:visualmode)
|
|
|
|
|
keepjumps call cursor(c_pos[0], c_pos[1])
|
2013-05-23 04:02:03 -04:00
|
|
|
|
else
|
2014-01-07 03:02:16 -05:00
|
|
|
|
keepjumps call cursor(orig_pos[0], orig_pos[1])
|
2013-05-23 04:02:03 -04:00
|
|
|
|
endif
|
2014-01-13 10:57:02 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let targets2 = []
|
2014-01-08 23:45:32 -05:00
|
|
|
|
if s:line_flag == 0
|
2014-01-13 10:57:02 -05:00
|
|
|
|
let search_stopline = win_last_line
|
2014-01-08 23:45:32 -05:00
|
|
|
|
else
|
2014-01-13 10:57:02 -05:00
|
|
|
|
let search_stopline = !empty(a:visualmode) ? c_pos[0] : orig_pos[0]
|
2014-01-08 23:45:32 -05:00
|
|
|
|
endif
|
2014-01-07 03:02:16 -05:00
|
|
|
|
while 1
|
2014-01-08 23:45:32 -05:00
|
|
|
|
let pos = searchpos(a:regexp, '', search_stopline)
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" Reached end of search range
|
|
|
|
|
if pos == [0, 0]
|
|
|
|
|
break
|
2013-11-13 14:19:40 -05:00
|
|
|
|
endif
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" Skip folded lines {{{
|
|
|
|
|
if s:is_folded(pos[0])
|
2014-01-10 10:50:17 -05:00
|
|
|
|
" Always forward
|
|
|
|
|
keepjumps call cursor(foldclosedend(pos[0]+1), 0)
|
2014-01-07 03:02:16 -05:00
|
|
|
|
continue
|
2013-05-15 17:05:02 -04:00
|
|
|
|
endif
|
2013-11-13 13:57:20 -05:00
|
|
|
|
"}}}
|
2013-05-15 17:05:02 -04:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
call add(targets2, pos)
|
|
|
|
|
endwhile
|
|
|
|
|
" Merge match target dict"{{{
|
2014-01-08 23:45:32 -05:00
|
|
|
|
let t1 = 0 " backward
|
|
|
|
|
let t2 = 0 " forward
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let targets3 = []
|
|
|
|
|
while t1 < len(targets) || t2 < len(targets2)
|
2014-01-08 23:45:32 -05:00
|
|
|
|
" Forward -> Backward -> F -> B -> ...
|
2014-01-07 03:02:16 -05:00
|
|
|
|
if t2 < len(targets2)
|
|
|
|
|
call add(targets3, targets2[t2])
|
|
|
|
|
let t2 += 1
|
2013-06-03 20:26:16 -04:00
|
|
|
|
endif
|
2014-01-08 23:45:32 -05:00
|
|
|
|
if t1 < len(targets)
|
|
|
|
|
call add(targets3, targets[t1])
|
|
|
|
|
let t1 += 1
|
|
|
|
|
endif
|
2014-01-07 03:02:16 -05:00
|
|
|
|
endwhile
|
|
|
|
|
let targets = targets3
|
2013-11-13 13:57:20 -05:00
|
|
|
|
"}}}
|
2014-01-07 03:02:16 -05:00
|
|
|
|
endif
|
|
|
|
|
"}}}
|
|
|
|
|
" Handle no match"{{{
|
|
|
|
|
let targets_len = len(targets)
|
|
|
|
|
if targets_len == 0
|
|
|
|
|
throw 'No matches'
|
|
|
|
|
endif
|
|
|
|
|
"}}}
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
let GroupingFn = function('s:GroupingAlgorithm' . s:grouping_algorithms[g:EasyMotion_grouping])
|
|
|
|
|
let groups = GroupingFn(targets, split(g:EasyMotion_keys, '\zs'))
|
|
|
|
|
|
|
|
|
|
" -- Shade inactive source --------------- {{{
|
2014-01-13 10:57:02 -05:00
|
|
|
|
if g:EasyMotion_do_shade && targets_len != 1
|
|
|
|
|
if !empty(a:visualmode)
|
|
|
|
|
let shade_hl_pos = '\%' . c_pos[0] . 'l\%'. c_pos[1] .'c'
|
|
|
|
|
else
|
|
|
|
|
let shade_hl_pos = '\%' . orig_pos[0] . 'l\%'. orig_pos[1] .'c'
|
|
|
|
|
endif
|
2014-01-07 03:02:16 -05:00
|
|
|
|
|
|
|
|
|
if a:direction == 1
|
|
|
|
|
" Backward
|
2014-01-13 10:57:02 -05:00
|
|
|
|
let shade_hl_re = '\%'. win_first_line .'l\_.*' . shade_hl_pos
|
2014-01-07 03:02:16 -05:00
|
|
|
|
elseif a:direction == 0
|
|
|
|
|
" Forward
|
2014-01-13 10:57:02 -05:00
|
|
|
|
let shade_hl_re = shade_hl_pos . '\_.*\%'. win_last_line .'l'
|
2014-01-07 03:02:16 -05:00
|
|
|
|
elseif a:direction == 2
|
|
|
|
|
" Both directions"
|
2014-01-13 10:57:02 -05:00
|
|
|
|
let shade_hl_re = '\%'. win_first_line .'l\_.*\%'. win_last_line .'l'
|
2011-11-07 08:33:20 -05:00
|
|
|
|
endif
|
2014-01-07 03:02:16 -05:00
|
|
|
|
if !fixed_column
|
|
|
|
|
let shade_hl_id = matchadd(g:EasyMotion_hl_group_shade, shade_hl_re, 0)
|
2011-11-07 08:33:20 -05:00
|
|
|
|
endif
|
2014-01-07 03:02:16 -05:00
|
|
|
|
endif
|
|
|
|
|
if hlcurrent != 0
|
|
|
|
|
let shade_hl_line_id = matchadd(g:EasyMotion_hl_line_group_shade, '\%'. hlcurrent .'l.*', 1)
|
|
|
|
|
endif
|
|
|
|
|
if !empty(hlchar)
|
|
|
|
|
let shade_hl_line_id = matchadd(g:EasyMotion_hl_line_group_shade, '\%'. hlchar[0] .'l\%' . hlchar[1] .'c' , 2)
|
|
|
|
|
endif
|
|
|
|
|
" }}}
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-13 10:57:02 -05:00
|
|
|
|
" Jump back before prompt{{{
|
|
|
|
|
" Because searchpos() change current cursor position and
|
|
|
|
|
" if you just use cursor([orig_num, orig_pos]) to jump back,
|
|
|
|
|
" current line will bebecome center of window
|
|
|
|
|
keepjumps call cursor(win_first_line,0)
|
|
|
|
|
normal! zt
|
|
|
|
|
"}}}
|
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" -- Prompt user for target group/character {{{
|
|
|
|
|
let coords = s:PromptUser(groups, allows_repeat, fixed_column)
|
2014-01-08 20:30:51 -05:00
|
|
|
|
let s:old_target_coord = coords
|
2014-01-07 03:02:16 -05:00
|
|
|
|
"}}}
|
2011-11-07 08:33:20 -05:00
|
|
|
|
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" -- Update selection -------------------- {{{
|
|
|
|
|
if ! empty(a:visualmode)
|
|
|
|
|
keepjumps call cursor(orig_pos[0], orig_pos[1])
|
|
|
|
|
|
|
|
|
|
exec 'normal! ' . a:visualmode
|
|
|
|
|
endif
|
|
|
|
|
" }}}
|
2014-01-13 10:57:02 -05:00
|
|
|
|
" -- Update cursor position -------------- {{{
|
|
|
|
|
call cursor(orig_pos[0], orig_pos[1])
|
|
|
|
|
" Handle operator-pending mode {{{
|
2014-01-07 03:02:16 -05:00
|
|
|
|
if a:mode == 'no'
|
|
|
|
|
" This mode requires that we eat one more
|
|
|
|
|
" character to the right if we're using
|
|
|
|
|
" a forward motion
|
2014-01-13 10:57:02 -05:00
|
|
|
|
normal! v
|
2014-01-07 03:02:16 -05:00
|
|
|
|
endif
|
|
|
|
|
" }}}
|
2014-01-13 10:57:02 -05:00
|
|
|
|
call cursor(win_first_line, 0)
|
|
|
|
|
normal! zt
|
|
|
|
|
keepjumps call cursor(coords[0], coords[1])
|
2014-01-07 03:02:16 -05:00
|
|
|
|
|
|
|
|
|
call s:Message('Jumping to [' . coords[0] . ', ' . coords[1] . ']')
|
|
|
|
|
let s:EasyMotion_cancelled = 0
|
|
|
|
|
"}}}
|
|
|
|
|
catch
|
|
|
|
|
redraw
|
|
|
|
|
|
|
|
|
|
" Show exception message
|
|
|
|
|
call s:Message(v:exception)
|
|
|
|
|
|
|
|
|
|
" -- Restore original cursor position/selection {{{
|
|
|
|
|
if ! empty(a:visualmode)
|
|
|
|
|
silent exec 'normal! gv'
|
|
|
|
|
keepjumps call cursor(c_pos[0], c_pos[1])
|
|
|
|
|
else
|
|
|
|
|
keepjumps call cursor(orig_pos[0], orig_pos[1])
|
|
|
|
|
endif
|
|
|
|
|
" }}}
|
|
|
|
|
let s:EasyMotion_cancelled = 1
|
|
|
|
|
finally
|
|
|
|
|
" -- Restore properties ------------------ {{{
|
2014-01-08 23:45:32 -05:00
|
|
|
|
call s:RestoreValue()
|
|
|
|
|
call EasyMotion#reset()
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" }}}
|
|
|
|
|
" -- Remove shading ---------------------- {{{
|
|
|
|
|
if g:EasyMotion_do_shade && exists('shade_hl_id') && (!fixed_column)
|
|
|
|
|
call matchdelete(shade_hl_id)
|
|
|
|
|
endif
|
|
|
|
|
if (hlcurrent || !empty(hlchar)) && exists('shade_hl_line_id')
|
|
|
|
|
call matchdelete(shade_hl_line_id)
|
|
|
|
|
endif
|
|
|
|
|
" }}}
|
|
|
|
|
endtry
|
|
|
|
|
endfunction " }}}
|
|
|
|
|
"}}}
|
2014-01-08 23:45:32 -05:00
|
|
|
|
"}}}
|
|
|
|
|
" == Call init {{{
|
|
|
|
|
call EasyMotion#init()
|
2013-12-18 08:39:41 -05:00
|
|
|
|
"}}}
|
2014-01-07 03:02:16 -05:00
|
|
|
|
" == Restore 'cpoptions' {{{
|
2013-12-18 07:42:56 -05:00
|
|
|
|
let &cpo = s:save_cpo
|
|
|
|
|
unlet s:save_cpo
|
|
|
|
|
" }}}
|
2011-11-07 08:33:20 -05:00
|
|
|
|
" vim: fdm=marker:noet:ts=4:sw=4:sts=4
|