" Vim global plugin for quickly and easily jumping to positions on screen
" Maintainer: Barry Arthur <barry.arthur@gmail.com>
" Version: 0.3
" Description: Jump to the object you're looking at!
" Last Change: 2014-08-11
" License: Vim License (see :help license)
" Location: plugin/kweasy.vim
" Website: https://github.com/dahu/kweasy
"
" See kweasy.txt for help. This can be accessed by doing:
"
" :helptags ~/.vim/doc
" :help kweasy
let g:kweasy_version = '0.3'
" Vimscript Setup: {{{1
" Allow use of line continuation.
let s:save_cpo = &cpo
set cpo&vim
" load guard
" uncomment after plugin development.
" XXX The conditions are only as examples of how to use them. Change them as
" needed. XXX
"if exists("g:loaded_kweasy")
" \ || v:version < 700
" \ || v:version == 703 && !has('patch338')
" \ || &compatible
" let &cpo = s:save_cpo
" finish
"endif
"let g:loaded_kweasy = 1
" Plugin Options : {{{1
if !exists('g:kweasy_nolist')
let g:kweasy_nolist = 0
endif
if !exists('g:kweasy_hints')
let g:kweasy_hints = 'asdfg;lkjh'
endif
" Private Functions: {{{1
" a-z A-Z 0-9 punct
let s:index = map(range(97,97+25) + range(65,65+25) +range(48,48+9) +
\ range(33,47) + range(58,64) + range(123,126),
\ 'nr2char(v:val)')
" move g:kweasy_hints to the beginning (filtering them out of s:index)
let s:index = split(kweasy_hints, '\zs')
\ + split(substitute(tr(join(s:index, ''),
\ kweasy_hints,
\ repeat(' ', len(kweasy_hints))),
\ ' ', '', 'g'),
\ '\zs')
let s:len = len(s:index)
function! s:trim(str)
return substitute(a:str, '\s\+$', '', '')
endfunction
function! s:with_jump_marks(lines, pattern)
let lines = a:lines
let pattern = a:pattern
let counter = Series()
let newlines = []
let mask = "\n"
let fill = pattern == ' ' ? "\r" : ' '
let lnum = line('w0') - 1
for l in lines
let lnum += 1
" add a single empty line to newlines for each fold group
if foldclosed(lnum) > 0
if foldclosed(lnum) == lnum
call add(newlines, '')
endif
continue
endif
" mark the start of matches with the 'mask' and erasing with 'fill'
let ms = match(l, pattern)
while ms != -1
" use strchars() instead of len() to account for multibyte (wide) chars
let fill_len = len(substitute(matchstr(l, pattern), '.',
\ '\=repeat("x", strchars(submatch(0)))', 'g')) - 1
let l = substitute(l, pattern, mask . repeat(fill, fill_len), '')
let ms = match(l, pattern)
endwhile
" clear stuff that isn't the 'mask' (or tabs to keep alignment)
let l = substitute(l, '[^\t' . mask . ']',
\ '\=repeat(" ", strchars(submatch(0)))', 'g')
" replace 'mask's with jump-mark
let ms = match(l, mask)
while ms != -1
let c = counter.next()
if c >= s:len
break
endif
let l = substitute(l, '\m' . mask, escape(s:index[c], '&~'), '')
let ms = match(l, mask)
endwhile
" we'd only have residual mask chars if there were too many to replace
" with jump hints; erase these unreachable extras
let l = substitute(l, mask, ' ', 'g')
call add(newlines, s:trim(l))
endfor
return newlines
endfunction
function! s:jump_marks_overlay(lines, cur_pos)
let altbuf = bufnr('#')
let cur_pos = a:cur_pos
normal! 0
let first_col = wincol()
let ts = &l:tabstop
hide noautocmd enew
setlocal buftype=nofile
setlocal bufhidden=hide
setlocal noswapfile
let &l:numberwidth = first_col - 1
let &l:tabstop = ts
call append(0, a:lines)
$
delete _
redraw
1
let jump = escape(nr2char(getchar()), '^$.*~]\\')
if jump == '' || jump == "\<esc>" || jump == "\<cr>"
let jump_pos = cur_pos
elseif search(jump . '\C', 'cW') == 0
let jump_pos = cur_pos
else
let jump_pos = getpos('.')
" fix offset if there are tabs before jump target
let jump_pos[2] = virtcol('.')
endif
buffer #
bwipe #
if buflisted(altbuf)
exe 'buffer ' . altbuf
silent! buffer #
endif
return jump_pos
endfunction
function! s:show_jump_marks_for(pattern)
let lines = s:with_jump_marks(getline('w0', 'w$'), a:pattern)
let top_of_window = line('w0')
let cur_pos = getpos('.')
let jump_pos = s:jump_marks_overlay(lines, cur_pos)
" re-centre screen to pre-overlay view
exe "normal! " . top_of_window . 'zt'
call setpos('.', cur_pos)
" jump to relative line,col
exe 'normal! H' . jump_pos[1] . '_'
exe 'normal! ' . jump_pos[2] . '|'
endfunction
function! s:check_dependencies()
" Nexus is used for the Series() number generator
if !exists('g:nexus_version')
echohl Warn
echom "vim-KWEasy depends on https://github.com/dahu/Nexus"
echohl none
return 0
endif
return 1
endfunction
"}}}
" Public Interface: {{{1
function! KWEasyJump(char)
if !s:check_dependencies()
return
endif
let char = '\C' . escape(nr2char(a:char), '^$.*~]\\')
if char == "\\C\<esc>" || char == "\\C\<cr>" || char == '\C'
return
endif
call histadd('input', char)
return KWEasySearch(char)
endfunction
function! KWEasySearch(pattern)
if !s:check_dependencies()
return
endif
let pattern = a:pattern
if pattern == "\<esc>" || pattern == "\<cr>" || pattern == ''
return
endif
if g:kweasy_nolist
let save_list = &list
set nolist
endif
let save_scrolloff = &so
set so=0
call s:show_jump_marks_for(pattern)
let &so = save_scrolloff
if g:kweasy_nolist
let &list = save_list
endif
endfunction
function! KWEasySearchCmd()
let g:kweasy_cmdline = getcmdline()
return "\e:call KWEasySearch(g:kweasy_cmdline)\r"
endfunction
" Maps: {{{1
" nnoremap <Plug>KweasyJump :call KWEasy(getchar())<cr>
nnoremap <silent> <Plug>KweasyJump :call KWEasyJump(getchar())<cr>
if !hasmapto('<Plug>KweasyJump')
nmap <unique><silent> <leader>k <Plug>KweasyJump
endif
nnoremap <silent> <Plug>KweasySearch :call KWEasySearch(input('/'))<cr>
if !hasmapto('<Plug>KweasySearch')
nmap <unique><silent> <leader>s <Plug>KweasySearch
endif
nmap <silent> <plug>KweasyAgain <plug>KweasySearch<up><cr>
if !hasmapto('<Plug>KweasyAgain')
nmap <unique><silent> <leader>n <Plug>KweasyAgain
endif
" Teardown:{{{1
"reset &cpo back to users setting
let &cpo = s:save_cpo
" Template From: https://github.com/dahu/Area-41/
" vim: set sw=2 sts=2 et fdm=marker: