-
-
Save bsdelf/1fc1d84bfad406a68f84d578081f2895 to your computer and use it in GitHub Desktop.
A Vim take on Emacs' AceJump mode, itself based on Vim's PreciseJump and EasyMotion plugins
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
" ACEJUMP | |
" Based on emacs' AceJump feature (http://www.emacswiki.org/emacs/AceJump). | |
" AceJump based on these Vim plugins: | |
" EasyMotion (http://www.vim.org/scripts/script.php?script_id=3526) | |
" PreciseJump (http://www.vim.org/scripts/script.php?script_id=3437) | |
" Type AJ mapping, followed by a lower or uppercase letter. | |
" All words on the screen starting with that letter will have | |
" their first letters replaced with a sequential character. | |
" Type this character to jump to that word. | |
highlight AceJumpGrey ctermfg=darkgrey guifg=lightgrey | |
highlight AceJumpRed ctermfg=darkred guibg=NONE guifg=black gui=NONE | |
function! AceJump () | |
" store some current values for restoring later | |
let origPos = getpos('.') | |
let origSearch = @/ | |
" prompt for and capture user's search character | |
echo "AceJump to words starting with letter: " | |
let letter = nr2char(getchar()) | |
" return if invalid key, mouse press, etc. | |
if len(matchstr(letter, '\k')) != 1 | |
echo "" | |
redraw | |
return | |
endif | |
" redraws here and there to get past 'more' prompts | |
redraw | |
" row/col positions of words beginning with user's chosen letter | |
let pos = [] | |
" monotone all text in visible part of window (dark grey by default) | |
call matchadd('AceJumpGrey', '\%'.line('w0').'l\_.*\%'.line('w$').'l', 50) | |
" loop over every line on the screen (just the visible lines) | |
for row in range(line('w0'), line('w$')) | |
" find all columns on this line where a word begins with our letter | |
let col = 0 | |
let matchCol = match(' '.getline(row), '.\<'.letter, col) | |
while matchCol != -1 | |
" store any matching row/col positions | |
call add(pos, [row, matchCol]) | |
let col = matchCol + 1 | |
let matchCol = match(' '.getline(row), '.\<'.letter, col) | |
endwhile | |
endfor | |
if len(pos) > 1 | |
" jump characters used to mark found words (user-editable) | |
let chars = 'abcdefghijlkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.;"[]<>{}|\\' | |
if len(pos) > len(chars) | |
" TODO add groupings here if more pos matches than jump characters | |
endif | |
" trim found positions list; cannot be longer than jump markers list | |
let pos = pos[:len(chars)] | |
" jumps list to pair jump characters with found word positions | |
let jumps = {} | |
" change each found word's first letter to a jump character | |
for [r,c] in pos | |
" stop marking words if there are no more jump characters | |
if len(chars) == 0 | |
break | |
endif | |
" 'pop' the next jump character from the list | |
let char = chars[0] | |
let chars = chars[1:] | |
" move cursor to the next found word | |
call setpos('.', [0,r,c+1,0]) | |
" create jump character key to hold associated found word position | |
let jumps[char] = [0,r,c+1,0] | |
" replace first character in word with current jump character | |
exe 'norm r'.char | |
" change syntax on the jump character to make it highly visible | |
call matchadd('AceJumpRed', '\%'.r.'l\%'.(c+1).'c', 50) | |
endfor | |
call setpos('.', origPos) | |
" this redraw is critical to syntax highlighting | |
redraw | |
" prompt user again for the jump character to jump to | |
echo 'AceJump to words starting with "'.letter.'" ' | |
let jumpChar = nr2char(getchar()) | |
" get rid of our syntax search highlighting | |
call clearmatches() | |
" clear out the status line | |
echo "" | |
redraw | |
" restore previous search register value | |
let @/ = origSearch | |
" undo all the jump character letter replacement | |
norm u | |
" if the user input a proper jump character, jump to it | |
if has_key(jumps, jumpChar) | |
call setpos('.', jumps[jumpChar]) | |
else | |
" if it didn't work out, restore original cursor position | |
call setpos('.', origPos) | |
endif | |
elseif len(pos) == 1 | |
" if we only found one match, just jump to it without prompting | |
" set position to the one match | |
let [r,c] = pos[0] | |
call setpos('.', [0,r,c+1,0]) | |
elseif len(pos) == 0 | |
" no matches; set position back to start | |
call setpos('.', origPos) | |
endif | |
" turn off all search highlighting | |
call clearmatches() | |
" clean up the status line and return | |
echo "" | |
redraw | |
return | |
endfunction | |
nnoremap <Leader>aj :call AceJump()<CR> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment