" vim match-up - even better matching " " Maintainer: Andy Massimino " Email: a@normed.space " let s:save_cpo = &cpo set cpo&vim "" " example motion as described in issues/49: " - if on a delim, go to {count} next matching delim, up or down " - if not on a delim, go to {count} local surrounding, up or down " " {info} dict with the following fields: " visual : 1 if visual or operator mode " count/count1: v:count/v:count1 for this map " operator : if non-empty, the operator in op mode " motion_force: forced operator mode, e.g, for 'dvx' this is 'v' " {opts} user data dict from motion definition function! matchup#custom#example_motion(info, opts) abort let l:delim = matchup#delim#get_current('all', 'both_all') if !empty(l:delim) let l:matches = matchup#delim#get_matching(l:delim, 1) if len(l:matches) for _ in range(a:info.count1) let l:delim = l:delim.links[a:opts.down ? 'next': 'prev'] endfor return matchup#custom#suggest_pos(l:delim, a:opts) endif endif let [l:open_, l:close_] = matchup#delim#get_surrounding( \ 'delim_all', v:count1) if empty(l:open_) || empty(l:close_) return [] endif let [l:open, l:close] = matchup#delim#get_surround_nearest(l:open_) if empty(l:open) let [l:open, l:close] = [l:open_, l:open_.links.next] endif let l:delim = a:opts.down ? l:close : l:open " exclude delim in operators unless v is given if !empty(a:info.operator) && a:info.motion_force !=# 'v' if a:opts.down return matchup#pos#prev(l:delim) else return matchup#pos#next(matchup#delim#end_pos(l:delim)) endif else return matchup#custom#suggest_pos(l:delim, a:opts) endif endfunction "" " api function: get the preferred cursor location for delim " {delim} delimiter object " {opts} field 'down' denotes motion direction function! matchup#custom#suggest_pos(delim, opts) abort if g:matchup_motion_cursor_end && (a:delim.side ==# 'close' \ || a:delim.side ==# 'mid' && get(a:opts, 'down', 0)) return [a:delim.lnum, matchup#delim#jump_target(a:delim)] endif return matchup#pos#(a:delim) endfunction "" " define a custom motion " {modes} specify which modes modes of {n,o,x} the mapping is active in " {keys} key sequence for map " {fcn} function to call, must take two arguments " [@opts] user data dict passed to function function! matchup#custom#define_motion(modes, keys, fcn, ...) abort if a:modes !~# '^[nox]\+$' echoerr "invalid modes" endif let s:custom_counter += 1 let l:k = s:custom_counter let l:opts = a:0 ? deepcopy(a:1) : {} call extend(l:opts, { 'fcn': a:fcn, 'keys': a:keys }) let s:custom_opts[l:k] = l:opts if a:modes =~# 'n' execute 'nnoremap (matchup-custom-'.a:keys.')' \ ':call matchup#custom#wrap(0, '.l:k.')' execute 'nmap' a:keys '(matchup-custom-'.a:keys.')' endif if a:modes =~# '[xo]' let l:sid = substitute(matchup#motion_sid(), "\", '', '') execute 'xnoremap ' l:sid.'(matchup-custom-'.l:k.')' \ ':call matchup#custom#wrap(1, '.l:k.')' endif if a:modes =~# 'x' execute 'xmap (matchup-custom-'.a:keys.')' \ l:sid.'(matchup-custom-'.l:k.')' execute 'xmap ' a:keys '(matchup-custom-'.a:keys.')' endif if a:modes =~# 'o' execute 'onoremap (matchup-custom-'.a:keys.')' \ ':call matchup#motion#op(' \ . string('custom-'.l:k).')' if !call(matchup#motion_sid().'make_oldstyle_omaps', \ [a:keys, 'custom-'.a:keys]) execute 'omap' a:keys '(matchup-custom-'.a:keys.')' endif endif endfunction if !exists('s:custom_opts') let s:custom_opts = {} let s:custom_counter = 0 endif " motion wrapper function! matchup#custom#wrap(visual, id) abort " default to 1 second (can override in custom motion) call matchup#perf#timeout_start(1000) let l:info = { \ 'visual': a:visual, \ 'count': v:count, \ 'count1': v:count1, \ 'operator': matchup#motion#getoper(), \ 'motion_force': g:v_motion_force, \} let l:is_oper = !empty(l:info.operator) let l:opts = s:custom_opts[a:id] if a:visual normal! gv endif let l:ret = call(l:opts.fcn, [l:info, l:opts]) if type(l:ret) != type([]) || empty(l:ret) if !a:visual || l:is_oper execute "normal! \" endif elseif type(l:ret) == type([]) && len(l:ret) >= 2 call matchup#pos#set_cursor(l:ret) endif endfunction let &cpo = s:save_cpo " vim: fdm=marker sw=2