diff --git a/plugin/EasyMotion.vim b/plugin/EasyMotion.vim index 4704a20..c0644c2 100644 --- a/plugin/EasyMotion.vim +++ b/plugin/EasyMotion.vim @@ -66,6 +66,8 @@ let s:key_to_index[i] = index let index += 1 endfor + + let s:var_reset = {} " }}} " Motion functions {{{ " F key motions {{{ @@ -124,6 +126,20 @@ echo a:message . ': ' echohl None endfunction " }}} + function! s:VarReset(var, ...) " {{{ + if a:0 == 0 && has_key(s:var_reset, a:var) + " Reset var to original value + call setbufvar(bufname(0), a:var, s:var_reset[a:var]) + elseif a:0 == 1 + let new_value = a:0 == 1 ? a:1 : '' + + " Store original value + let s:var_reset[a:var] = getbufvar(bufname(0), a:var) + + " Set new var value + call setbufvar(bufname(0), a:var, new_value) + endif + endfunction " }}} " }}} " Core functions {{{ function! s:PromptUser(groups) "{{{ @@ -167,11 +183,6 @@ let lines_items = items(lines) " }}} - " Store original buffer properties {{{ - let modified = &modified - let modifiable = &modifiable - let readonly = &readonly - " }}} let input_char = '' @@ -179,16 +190,6 @@ " Highlight source let target_hl_id = matchadd(g:EasyMotion_target_hl, join(hl_coords, '\|'), 1) - " Make sure we can change the buffer {{{ - if modifiable == 0 - silent setl modifiable - endif - - if readonly == 1 - silent setl noreadonly - endif - " }}} - " Set lines with markers for [line_num, line] in lines_items try @@ -226,20 +227,6 @@ redraw - " Restore original properties {{{ - if modified == 0 - silent setl nomodified - endif - - if modifiable == 0 - silent setl nomodifiable - endif - - if readonly == 1 - silent setl readonly - endif - " }}} - " Check if the input char is valid if ! has_key(s:key_to_index, input_char) || s:key_to_index[input_char] >= targets_len " Invalid input char @@ -260,94 +247,114 @@ let targets = [] let visualmode = a:0 > 0 ? a:1 : '' - " Store original scrolloff value - let scrolloff = &scrolloff - setl scrolloff=0 + try + " Reset properties + call VarReset('&scrolloff', 0) + call VarReset('&modified', 0) + call VarReset('&modifiable', 1) + call VarReset('&readonly', 0) - " Find motion targets - while 1 - let search_direction = (a:direction == 1 ? 'b' : '') - let search_stopline = line(a:direction == 1 ? 'w0' : 'w$') + " Find motion targets + while 1 + let search_direction = (a:direction == 1 ? 'b' : '') + let search_stopline = line(a:direction == 1 ? 'w0' : 'w$') - let pos = searchpos(a:regexp, search_direction, search_stopline) + let pos = searchpos(a:regexp, search_direction, search_stopline) - " Reached end of search range - if pos == [0, 0] - break + " Reached end of search range + if pos == [0, 0] + break + endif + + " Skip folded lines + if foldclosed(pos[0]) != -1 + continue + endif + + call add(targets, pos) + endwhile + + let targets_len = len(targets) + let groups_len = len(s:index_to_key) + + if targets_len == 0 + throw 'No matches' endif - " Skip folded lines - if foldclosed(pos[0]) != -1 - continue - endif - - call add(targets, pos) - endwhile - - let targets_len = len(targets) - let groups_len = len(s:index_to_key) - - if targets_len == 0 - redraw - - call Message('No matches') - " Restore cursor position call setpos('.', [0, orig_pos[0], orig_pos[1]]) - " Restore original scrolloff value - execute 'setl scrolloff=' . scrolloff + " Split targets into key groups {{{ + let groups = [] + let i = 0 - return - endif + while i < targets_len + call add(groups, targets[i : i + groups_len - 1]) - " Restore cursor position - call setpos('.', [0, orig_pos[0], orig_pos[1]]) + let i += groups_len + endwhile + " }}} + " Too many groups; only display the first ones {{{ + if len(groups) > groups_len + call Message('Only displaying the first matches') - " Split targets into key groups {{{ - let groups = [] - let i = 0 + let groups = groups[0 : groups_len - 1] + endif + " }}} - while i < targets_len - call add(groups, targets[i : i + groups_len - 1]) + " Shade inactive source + if g:EasyMotion_shade + let shade_hl_pos = '\%' . orig_pos[0] . 'l\%'. orig_pos[1] .'c' - let i += groups_len - endwhile - " }}} - " Too many groups; only display the first ones {{{ - if len(groups) > groups_len - call Message('Only displaying the first matches') + if a:direction == 1 + " Backward + let shade_hl_re = '\%'. line('w0') .'l\_.*' . shade_hl_pos + else + " Forward + let shade_hl_re = shade_hl_pos . '\_.*\%'. line('w$') .'l' + endif - let groups = groups[0 : groups_len - 1] + let shade_hl_id = matchadd(g:EasyMotion_shade_hl, shade_hl_re, 0) endif - " }}} - " Shade inactive source - if g:EasyMotion_shade - let shade_hl_pos = '\%' . orig_pos[0] . 'l\%'. orig_pos[1] .'c' + " Prompt user for target group/character + let coords = PromptUser(groups) - if a:direction == 1 - " Backward - let shade_hl_re = '\%'. line('w0') .'l\_.*' . shade_hl_pos + " Remove shading + if g:EasyMotion_shade + call matchdelete(shade_hl_id) + endif + + if len(coords) != 2 + throw 'Cancelled' else - " Forward - let shade_hl_re = shade_hl_pos . '\_.*\%'. line('w$') .'l' + if ! empty(visualmode) + " Store original marks + let m_a = getpos("'a") + let m_b = getpos("'b") + + " Store start/end positions + call setpos("'a", [0, orig_pos[0], orig_pos[1]]) + call setpos("'b", [0, coords[0], coords[1]]) + + " Update selection + silent exec 'normal! `a' . visualmode . '`b' + + " Restore original marks + call setpos("'a", m_a) + call setpos("'b", m_b) + else + " Update cursor position + call setpos('.', [0, coords[0], coords[1]]) + endif + + call Message('Jumping to [' . coords[0] . ', ' . coords[1] . ']') endif + catch /.*/ + redraw - let shade_hl_id = matchadd(g:EasyMotion_shade_hl, shade_hl_re, 0) - endif - - " Prompt user for target group/character - let coords = PromptUser(groups) - - " Remove shading - if g:EasyMotion_shade - call matchdelete(shade_hl_id) - endif - - if len(coords) != 2 - " Cancelled by user - call Message('Operation cancelled') + " Show exception message + call Message(v:exception) " Restore cursor position/selection if ! empty(visualmode) @@ -355,36 +362,14 @@ else call setpos('.', [0, orig_pos[0], orig_pos[1]]) endif + finally + redraw - " Restore original scrolloff value - execute 'setl scrolloff=' . scrolloff - - return - else - if ! empty(visualmode) - " Store original marks - let m_a = getpos("'a") - let m_b = getpos("'b") - - " Store start/end positions - call setpos("'a", [0, orig_pos[0], orig_pos[1]]) - call setpos("'b", [0, coords[0], coords[1]]) - - " Update selection - silent exec 'normal! `a' . visualmode . '`b' - - " Restore original marks - call setpos("'a", m_a) - call setpos("'b", m_b) - else - " Update cursor position - call setpos('.', [0, coords[0], coords[1]]) - endif - - " Restore original scrolloff value - execute 'setl scrolloff=' . scrolloff - - call Message('Jumping to [' . coords[0] . ', ' . coords[1] . ']') - endif + " Restore properties + call VarReset('&scrolloff') + call VarReset('&modified') + call VarReset('&modifiable') + call VarReset('&readonly') + endtry endfunction " }}} " }}}