Skip to content

Instantly share code, notes, and snippets.

@bsdelf
Forked from gfixler/EasyJumpPreciseMotionAce.vim
Created November 14, 2017 07:32
Show Gist options
  • Save bsdelf/1fc1d84bfad406a68f84d578081f2895 to your computer and use it in GitHub Desktop.
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
" 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