mirror of
https://github.com/chenasraf/vim-matchup.git
synced 2026-05-18 01:38:57 +00:00
Add custom motion api, resolves #49
This commit is contained in:
@@ -118,6 +118,17 @@ function! s:init_oldstyle_ops() " {{{1
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:make_oldstyle_omaps(lhs, rhs)
|
||||
if !s:old_style_ops
|
||||
return 0
|
||||
endif
|
||||
for l:opforce in ['', 'v', 'V', '<c-v>']
|
||||
silent! execute 'omap' l:opforce.a:lhs
|
||||
\ '<plug>(matchup-o_'.l:opforce.')<plug>(matchup-'.a:rhs.')'
|
||||
endfor
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
let s:old_style_ops = !has('patch-8.1.0648')
|
||||
|
||||
let g:v_motion_force = ''
|
||||
|
||||
143
autoload/matchup/custom.vim
Normal file
143
autoload/matchup/custom.vim
Normal file
@@ -0,0 +1,143 @@
|
||||
" vim match-up - matchit replacement and more
|
||||
"
|
||||
" 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
|
||||
|
||||
return matchup#custom#suggest_pos(l:delim, a:opts)
|
||||
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 <silent> <plug>(matchup-custom-'.a:keys.')'
|
||||
\ ':<c-u>call matchup#custom#wrap(0, '.l:k.')<cr>'
|
||||
execute 'nmap' a:keys '<plug>(matchup-custom-'.a:keys.')'
|
||||
endif
|
||||
|
||||
if a:modes =~# '[xo]'
|
||||
let l:sid = substitute(matchup#motion_sid(), "\<snr>", '<snr>', '')
|
||||
execute 'xnoremap <silent>' l:sid.'(matchup-custom-'.l:k.')'
|
||||
\ ':<c-u>call matchup#custom#wrap(1, '.l:k.')<cr>'
|
||||
endif
|
||||
|
||||
if a:modes =~# 'x'
|
||||
execute 'xmap <silent> <plug>(matchup-custom-'.a:keys.')'
|
||||
\ l:sid.'(matchup-custom-'.l:k.')'
|
||||
execute 'xmap <silent>' a:keys '<plug>(matchup-custom-'.a:keys.')'
|
||||
endif
|
||||
|
||||
if a:modes =~# 'o'
|
||||
execute 'onoremap <silent> <plug>(matchup-custom-'.a:keys.')'
|
||||
\ ':<c-u>call matchup#motion#op('
|
||||
\ . string('custom-'.l:k).')<cr>'
|
||||
if !call(matchup#motion_sid().'make_oldstyle_omaps',
|
||||
\ [a:keys, 'custom-'.a:keys])
|
||||
execute 'omap' a:keys '<plug>(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! \<esc>"
|
||||
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
|
||||
|
||||
@@ -17,6 +17,10 @@ function! matchup#motion#op(motion) abort
|
||||
unlet s:v_operator
|
||||
endfunction
|
||||
|
||||
function matchup#motion#getoper()
|
||||
return get(s:, 'v_operator', '')
|
||||
endfunction
|
||||
|
||||
function! matchup#motion#find_matching_pair(visual, down) " {{{1
|
||||
let [l:count, l:count1] = [v:count, v:count1]
|
||||
|
||||
|
||||
@@ -33,6 +33,12 @@ endfunction
|
||||
|
||||
" }}}1
|
||||
|
||||
function! matchup#pos#(...) abort " {{{1
|
||||
let [l:lnum, l:cnum; l:rest] = s:parse_args(a:000)
|
||||
return [l:lnum, l:cnum]
|
||||
endfunction
|
||||
|
||||
" }}}1
|
||||
function! matchup#pos#val(...) " {{{1
|
||||
let [l:lnum, l:cnum; l:rest] = s:parse_args(a:000)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
Author: Andy Massimino <a@normed.space>
|
||||
Web: https://github.com/andymass/vim-matchup
|
||||
Script ID: 5624
|
||||
Version: 0.3.a
|
||||
Version: 0.4.1-git
|
||||
License: MIT license {{{
|
||||
|
||||
Copyright (c) 2019 Andy Massimino
|
||||
|
||||
18
test/bootstrap.vim
Normal file
18
test/bootstrap.vim
Normal file
@@ -0,0 +1,18 @@
|
||||
set nocompatible
|
||||
|
||||
" load match-up
|
||||
let s:path = simplify(expand('<sfile>:h').'/..')
|
||||
let &rtp = s:path.',' . &rtp
|
||||
let &rtp .= ','.s:path.'/after'
|
||||
|
||||
" rtp for testing files
|
||||
let &rtp = s:path.'/test/rtp,' . &rtp
|
||||
|
||||
" load other plugins, if necessary
|
||||
" let &rtp = '~/path/to/other/plugin,' . &rtp
|
||||
|
||||
filetype plugin indent on
|
||||
syntax enable
|
||||
|
||||
" match-up options go here
|
||||
|
||||
7
test/issues/49/example.vim
Normal file
7
test/issues/49/example.vim
Normal file
@@ -0,0 +1,7 @@
|
||||
source ../../bootstrap.vim
|
||||
|
||||
call matchup#custom#define_motion('nox', '%',
|
||||
\ 'matchup#custom#example_motion', { 'down': 1 })
|
||||
call matchup#custom#define_motion('nox', 'g%',
|
||||
\ 'matchup#custom#example_motion', { 'down': 0 })
|
||||
|
||||
7
test/issues/49/test.sh
Normal file
7
test/issues/49/test.sh
Normal file
@@ -0,0 +1,7 @@
|
||||
# `%` jumps to fi
|
||||
if test -z ""; then
|
||||
echo "cursor_position"
|
||||
else
|
||||
true
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user