Files
vim-matchup/autoload/matchup.vim
Luis Calle ea01ae7b54 fix: enable treesitter virtual text by default (#396)
* fix: enable treesitter virtual text by default

* fix: use an empty list instead of an empty object
2025-07-07 21:57:10 -04:00

453 lines
14 KiB
VimL

" vim match-up - even better matching
"
" Maintainer: Andy Massimino
" Email: a@normed.space
"
scriptencoding utf-8
let s:save_cpo = &cpo
set cpo&vim
function! matchup#init() abort
call matchup#perf#tic('loading')
call s:init_options()
call s:init_modules()
call s:init_default_mappings()
call matchup#perf#toc('loading', 'init_done')
endfunction
function! s:init_options()
call s:init_option('matchup_matchparen_enabled',
\ !(&t_Co < 8 && !has('gui_running')))
let l:offs = {'method': 'status'}
if !get(g:, 'matchup_matchparen_status_offscreen', 1)
let l:offs = {}
endif
if get(g:, 'matchup_matchparen_status_offscreen_manual', 0)
let l:offs.method = 'status_manual'
endif
if exists('g:matchup_matchparen_scrolloff')
let l:offs.scrolloff = g:matchup_matchparen_scrolloff
endif
call s:init_option('matchup_matchparen_offscreen', l:offs)
call s:init_option('matchup_matchparen_singleton', 0)
call s:init_option('matchup_matchparen_deferred', 0)
call s:init_option('matchup_matchparen_deferred_show_delay', 50)
call s:init_option('matchup_matchparen_deferred_hide_delay', 700)
call s:init_option('matchup_matchparen_deferred_fade_time', 0)
call s:init_option('matchup_matchparen_stopline', 400)
call s:init_option('matchup_matchparen_pumvisible', 1)
call s:init_option('matchup_matchparen_nomode', '')
call s:init_option('matchup_matchparen_hi_surround_always', 0)
call s:init_option('matchup_matchparen_hi_background', 0)
call s:init_option('matchup_matchparen_start_sign', '▶')
call s:init_option('matchup_matchparen_end_sign', '◀')
call s:init_option('matchup_matchparen_timeout',
\ get(g:, 'matchparen_timeout', 300))
call s:init_option('matchup_matchparen_insert_timeout',
\ get(g:, 'matchparen_insert_timeout', 60))
call s:init_option('matchup_delim_count_fail', 0)
call s:init_option('matchup_delim_count_max', 8)
call s:init_option('matchup_delim_start_plaintext', 1)
call s:init_option('matchup_delim_noskips', 0)
call s:init_option('matchup_delim_nomids', 0)
call s:init_option('matchup_motion_enabled', 1)
call s:init_option('matchup_motion_cursor_end', 1)
call s:init_option('matchup_motion_override_Npercent', 6)
call s:init_option('matchup_motion_keepjumps', 0)
call s:init_option('matchup_text_obj_enabled', 1)
call s:init_option('matchup_text_obj_linewise_operators', ['d', 'y'])
call s:init_option('matchup_transmute_enabled', 0)
call s:init_option('matchup_transmute_breakundo', 0)
call s:init_option('matchup_mouse_enabled', 1)
call s:init_option('matchup_surround_enabled', 0)
call s:init_option('matchup_where_enabled', 1)
call s:init_option('matchup_where_separator', '')
call s:init_option('matchup_matchpref', {})
if has('nvim')
call s:init_option('matchup_treesitter_enabled', has('nvim-0.11.2') ? v:true : v:false)
call s:init_option('matchup_treesitter_disabled', [])
call s:init_option('matchup_treesitter_include_match_words', v:false)
call s:init_option('matchup_treesitter_enable_quotes', v:true)
call s:init_option('matchup_treesitter_disable_virtual_text', v:false)
call s:init_option('matchup_treesitter_stopline', 400)
endif
endfunction
function! s:init_option(option, default)
if !has_key(g:, a:option)
let g:[a:option] = a:default
endif
endfunction
function! s:init_modules()
for l:mod in [ 'loader', 'matchparen' ]
if !get(g:, 'matchup_'.l:mod.'_enabled', 1)
continue
endif
call matchup#perf#tic('loading_module')
call matchup#{l:mod}#init_module()
call matchup#perf#toc('loading_module', l:mod)
endfor
call s:motion_init_module()
call s:text_obj_init_module()
call s:misc_init_module()
call s:surround_init_module()
call s:where_init_module()
call s:treesitter_init_module()
endfunction
function! s:init_oldstyle_ops() " {{{1
if get(g:, 'matchup_motion_enabled', 0)
\ || get(g:, 'matchup_text_obj_enabled', 0)
for l:opforce in ['', 'v', 'V', '<c-v>']
call s:map('onore', '<expr> <plug>(matchup-o_'.l:opforce.')',
\ '<sid>force('''.l:opforce.''')')
endfor
endif
if get(g:, 'matchup_motion_enabled', 0)
for l:opforce in ['', 'v', 'V', '<c-v>']
call s:map('o', l:opforce.'%',
\ '<plug>(matchup-o_'.l:opforce.')<plug>(matchup-%)')
call s:map('o', l:opforce.'g%',
\ '<plug>(matchup-o_'.l:opforce.')<plug>(matchup-g%)')
call s:map('o', l:opforce.']%',
\ '<plug>(matchup-o_'.l:opforce.')<plug>(matchup-]%)')
call s:map('o', l:opforce.'[%',
\ '<plug>(matchup-o_'.l:opforce.')<plug>(matchup-[%)')
call s:map('o', l:opforce.'z%',
\ '<plug>(matchup-o_'.l:opforce.')<plug>(matchup-z%)')
endfor
endif
if get(g:, 'matchup_text_obj_enabled', 0)
for l:opforce in ['', 'v', 'V', '<c-v>']
call s:map('o', l:opforce.'i%',
\ '<plug>(matchup-o_'.l:opforce.')<plug>(matchup-i%)')
call s:map('o', l:opforce.'a%',
\ '<plug>(matchup-o_'.l:opforce.')<plug>(matchup-a%)')
endfor
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') || has('nvim-0.5.0'))
let g:v_motion_force = ''
function! s:force(wise)
let g:v_motion_force = a:wise
return ''
endfunction
function! matchup#motion_force() abort
if !s:old_style_ops
let l:mode = mode(1)
let g:v_motion_force = len(l:mode) >= 3
\ && l:mode[0:1] ==# 'no' ? l:mode[2] : ''
endif
return g:v_motion_force
endfunction
" }}}1
let s:ignore_key = len(expand("\<ignore>")) > 0 ? '<ignore>' : ''
function! s:init_default_mappings()
if !get(g:,'matchup_mappings_enabled', 1) | return | endif
function! s:map(mode, lhs, rhs, ...)
if !hasmapto(a:rhs, a:mode)
\ && ((a:0 > 0) || (maparg(a:lhs, a:mode) ==# ''))
silent execute a:mode . 'map <silent> ' a:lhs a:rhs
endif
endfunction
function! s:omap(mode, lhs, rhs, ...) " issues/199
if !hasmapto(a:rhs, a:mode)
\ && ((a:0 > 0) || (maparg(a:lhs, a:mode) ==# ''))
silent execute a:mode . 'map <silent> ' a:lhs s:ignore_key . a:rhs
endif
endfunction
if s:old_style_ops
call s:init_oldstyle_ops()
endif
" these won't conflict since matchit should not be loaded at this point
if get(g:, 'matchup_motion_enabled', 0)
call s:map('n', '%', '<plug>(matchup-%)' )
call s:map('n', 'g%', '<plug>(matchup-g%)')
call s:map('x', '%', '<plug>(matchup-%)' )
call s:map('x', 'g%', '<plug>(matchup-g%)')
call s:map('n', ']%', '<plug>(matchup-]%)')
call s:map('n', '[%', '<plug>(matchup-[%)')
call s:map('x', ']%', '<plug>(matchup-]%)')
call s:map('x', '[%', '<plug>(matchup-[%)')
call s:map('n', 'z%', '<plug>(matchup-z%)')
call s:map('x', 'z%', '<plug>(matchup-z%)')
if !s:old_style_ops
call s:omap('o', '%', '<plug>(matchup-%)')
call s:omap('o', 'g%', '<plug>(matchup-g%)')
call s:map('o', ']%', '<plug>(matchup-]%)')
call s:map('o', '[%', '<plug>(matchup-[%)')
call s:map('o', 'z%', '<plug>(matchup-z%)')
endif
call s:map('i', '<c-g>%', '<plug>(matchup-c_g%)')
endif
if get(g:, 'matchup_text_obj_enabled', 0)
call s:map('x', 'i%', '<plug>(matchup-i%)')
call s:map('x', 'a%', '<plug>(matchup-a%)')
if !s:old_style_ops
call s:map('o', 'i%', '<plug>(matchup-i%)')
call s:map('o', 'a%', '<plug>(matchup-a%)')
endif
endif
if get(g:, 'matchup_mouse_enabled', 1)
call s:map('n', '<2-LeftMouse>', '<plug>(matchup-double-click)')
endif
if get(g:, 'matchup_surround_enabled', 0)
call s:map('n', 'ds%', '<plug>(matchup-ds%)')
call s:map('n', 'cs%', '<plug>(matchup-cs%)')
endif
endfunction
" module initialization
function! s:motion_init_module() " {{{1
if !g:matchup_motion_enabled | return | endif
call matchup#perf#tic('loading_module')
" gets the current forced motion type
nnoremap <silent><expr> <sid>(wise)
\ empty(g:v_motion_force) ? 'v' : g:v_motion_force
" the basic motions % and g%
if has('patch-8.2.1978') || has('nvim')
nnoremap <silent> <plug>(matchup-%)
\ <cmd>call matchup#motion#find_matching_pair(0, 1)<cr>
nnoremap <silent> <plug>(matchup-g%)
\ <cmd>call matchup#motion#find_matching_pair(0, 0)<cr>
else
nnoremap <silent> <plug>(matchup-%)
\ :<c-u>call matchup#motion#find_matching_pair(0, 1)<cr>
nnoremap <silent> <plug>(matchup-g%)
\ :<c-u>call matchup#motion#find_matching_pair(0, 0)<cr>
endif
" visual and operator-pending
xnoremap <silent> <sid>(matchup-%)
\ :<c-u>call matchup#motion#find_matching_pair(1, 1)<cr>
xmap <silent> <plug>(matchup-%) <sid>(matchup-%)
onoremap <silent> <plug>(matchup-%)
\ :<c-u>call matchup#motion#op('%')<cr>
xnoremap <silent> <sid>(matchup-g%)
\ :<c-u>call matchup#motion#find_matching_pair(1, 0)<cr>
xmap <silent> <plug>(matchup-g%) <sid>(matchup-g%)
onoremap <silent> <plug>(matchup-g%)
\ :<c-u>call matchup#motion#op('g%')<cr>
" ]% and [%
if has('patch-8.2.1978') || has('nvim')
nnoremap <silent> <plug>(matchup-]%)
\ <cmd>call matchup#motion#find_unmatched(0, 1)<cr>
nnoremap <silent> <plug>(matchup-[%)
\ <cmd>call matchup#motion#find_unmatched(0, 0)<cr>
else
nnoremap <silent> <plug>(matchup-]%)
\ :<c-u>call matchup#motion#find_unmatched(0, 1)<cr>
nnoremap <silent> <plug>(matchup-[%)
\ :<c-u>call matchup#motion#find_unmatched(0, 0)<cr>
endif
xnoremap <silent> <sid>(matchup-]%)
\ :<c-u>call matchup#motion#find_unmatched(1, 1)<cr>
xnoremap <silent> <sid>(matchup-[%)
\ :<c-u>call matchup#motion#find_unmatched(1, 0)<cr>
xmap <plug>(matchup-]%) <sid>(matchup-]%)
xmap <plug>(matchup-[%) <sid>(matchup-[%)
onoremap <silent> <plug>(matchup-]%)
\ :<c-u>call matchup#motion#op(']%')<cr>
onoremap <silent> <plug>(matchup-[%)
\ :<c-u>call matchup#motion#op('[%')<cr>
" jump inside z%
if has('patch-8.2.1978') || has('nvim')
nnoremap <silent> <plug>(matchup-z%)
\ <cmd>call matchup#motion#jump_inside(0)<cr>
else
nnoremap <silent> <plug>(matchup-z%)
\ :<c-u>call matchup#motion#jump_inside(0)<cr>
endif
xnoremap <silent> <sid>(matchup-z%)
\ :<c-u>call matchup#motion#jump_inside(1)<cr>
xmap <silent> <plug>(matchup-z%) <sid>(matchup-z%)
onoremap <silent> <plug>(matchup-z%)
\ :<c-u>call matchup#motion#op('z%')<cr>
" 'opposite' of z%
if has('patch-8.2.1978') || has('nvim')
nnoremap <silent> <plug>(matchup-Z%)
\ <cmd>call matchup#motion#jump_inside_prev(0)<cr>
else
nnoremap <silent> <plug>(matchup-Z%)
\ :<c-u>call matchup#motion#jump_inside_prev(0)<cr>
endif
xnoremap <silent> <sid>(matchup-Z%)
\ :<c-u>call matchup#motion#jump_inside_prev(1)<cr>
xmap <silent> <plug>(matchup-Z%) <sid>(matchup-Z%)
onoremap <silent> <plug>(matchup-Z%)
\ :<c-u>call matchup#motion#op('Z%')<cr>
inoremap <silent> <plug>(matchup-c_g%)
\ <c-\><c-o>:call matchup#motion#insert_mode()<cr>
call matchup#perf#toc('loading_module', 'motion')
endfunction
" TODO redo this
function! s:snr()
return str2nr(matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze_snr$'))
endfunction
let s:sid = printf("\<SNR>%d_", s:snr())
function! matchup#motion_sid() abort
return s:sid
endfunction
" }}}1
function! s:text_obj_init_module() " {{{1
if !g:matchup_text_obj_enabled | return | endif
call matchup#perf#tic('loading_module')
for [l:map, l:name, l:opt] in [
\ ['%', 'delimited', 'delim_all'],
\]
let l:p1 = 'noremap <silent> <plug>(matchup-'
let l:p2 = l:map . ') :<c-u>call matchup#text_obj#' . l:name
let l:p3 = empty(l:opt) ? ')<cr>' : ', ''' . l:opt . ''')<cr>'
execute 'x' . l:p1 . 'i' . l:p2 . '(1, 1' . l:p3
execute 'x' . l:p1 . 'a' . l:p2 . '(0, 1' . l:p3
execute 'o' . l:p1 . 'i' . l:p2 . '(1, 0' . l:p3
execute 'o' . l:p1 . 'a' . l:p2 . '(0, 0' . l:p3
endfor
nnoremap <silent> <plug>(matchup-double-click)
\ :<c-u>call matchup#text_obj#double_click()<cr>
call matchup#perf#toc('loading_module', 'motion')
endfunction
" }}}1
function! s:misc_init_module() " {{{1
call matchup#perf#tic('loading_module')
command! MatchupReload call matchup#misc#reload()
nnoremap <plug>(matchup-reload) :<c-u>MatchupReload<cr>
call matchup#perf#toc('loading_module', 'misc')
endfunction
" }}}1
function! s:surround_init_module() " {{{1
if !g:matchup_surround_enabled | return | endif
call matchup#perf#tic('loading_module')
for [l:map, l:name, l:opt] in [
\ ['%', 'delimited', 'delim_all'],
\]
let l:p1 = 'noremap <silent> <plug>(matchup-'
let l:p2 = l:map . ') :<c-u>call matchup#surround#' . l:name
let l:p3 = empty(l:opt) ? ')<cr>' : ', ''' . l:opt . ''')<cr>'
execute 'n' . l:p1 . 'ds' . l:p2 . '(0, "d"' . l:p3
execute 'n' . l:p1 . 'cs' . l:p2 . '(0, "c"' . l:p3
endfor
call matchup#perf#toc('loading_module', 'surround')
endfunction
" }}}1
function! s:where_init_module() " {{{1
if !g:matchup_where_enabled | return | endif
command! -nargs=? -bang MatchupWhereAmI
\ call matchup#where#print('<bang>' . <q-args>)
endfunction
" }}}1
function! s:treesitter_init_module() " {{{1
if !matchup#loader#_treesitter_may_be_supported()
return
endif
lua <<LUA
vim.api.nvim_create_autocmd({'FileType'}, {
pattern = {'query'},
group = vim.api.nvim_create_augroup('matchup_filetype_query', {
clear = true
}),
callback = function(ftevent)
vim.api.nvim_create_autocmd({'BufWritePost'}, {
buffer = ftevent.buf,
group = vim.api.nvim_create_augroup('MatchupTreesitter', {
clear = true
}),
callback = function(bwpevent)
local _, _, query_lang = string.find(bwpevent.file, "([^/]*)/matchup.scm$")
if query_lang then
vim.treesitter.query.get:clear(
query_lang,
"matchup"
)
end
end
})
end
})
LUA
endfunction
"}}}1
let &cpo = s:save_cpo
" vim: fdm=marker sw=2