vimtex/autoload/latex/motion.vim

391 lines
11 KiB
VimL
Raw Normal View History

2014-07-22 18:08:57 -04:00
" LaTeX plugin for Vim
"
" Maintainer: Karl Yngve Lervåg
" Email: karl.yngve@gmail.com
"
function! latex#motion#init(initialized) " {{{1
2015-01-26 09:41:40 -05:00
call latex#util#set_default('g:latex_motion_enabled', 1)
2013-10-05 07:53:42 -04:00
if !g:latex_motion_enabled | return | endif
2015-01-26 09:41:40 -05:00
" Set default options
call latex#util#set_default('g:latex_motion_matchparen', 1)
2013-10-10 15:48:52 -04:00
if g:latex_mappings_enabled
2013-10-06 07:39:25 -04:00
nnoremap <silent><buffer> % :call latex#motion#find_matching_pair()<cr>
2014-07-27 15:18:01 -04:00
xnoremap <silent><buffer> %
2013-10-06 07:39:25 -04:00
\ :<c-u>call latex#motion#find_matching_pair(1)<cr>
onoremap <silent><buffer> % :normal v%<cr>
2013-10-05 07:53:42 -04:00
2013-10-11 17:24:07 -04:00
nnoremap <silent><buffer> ]] :call latex#motion#next_section(0,0,0)<cr>
nnoremap <silent><buffer> ][ :call latex#motion#next_section(1,0,0)<cr>
nnoremap <silent><buffer> [] :call latex#motion#next_section(1,1,0)<cr>
nnoremap <silent><buffer> [[ :call latex#motion#next_section(0,1,0)<cr>
2014-07-27 15:18:01 -04:00
xnoremap <silent><buffer> ]] :<c-u>call latex#motion#next_section(0,0,1)<cr>
xnoremap <silent><buffer> ][ :<c-u>call latex#motion#next_section(1,0,1)<cr>
xnoremap <silent><buffer> [] :<c-u>call latex#motion#next_section(1,1,1)<cr>
xnoremap <silent><buffer> [[ :<c-u>call latex#motion#next_section(0,1,1)<cr>
2013-10-05 07:53:42 -04:00
onoremap <silent><buffer> ]] :normal v]]<cr>
onoremap <silent><buffer> ][ :normal v][<cr>
onoremap <silent><buffer> [] :normal v[]<cr>
onoremap <silent><buffer> [[ :normal v[[<cr>
2014-07-27 15:18:01 -04:00
xnoremap <silent><buffer> ie :<c-u>call latex#motion#sel_environment(1)<cr>
xnoremap <silent><buffer> ae :<c-u>call latex#motion#sel_environment()<cr>
2013-10-05 07:53:42 -04:00
onoremap <silent><buffer> ie :normal vie<cr>
onoremap <silent><buffer> ae :normal vae<cr>
2014-07-27 15:18:01 -04:00
xnoremap <silent><buffer> i$ :<c-u>call latex#motion#sel_inline_math(1)<cr>
xnoremap <silent><buffer> a$ :<c-u>call latex#motion#sel_inline_math()<cr>
2013-10-05 07:53:42 -04:00
onoremap <silent><buffer> i$ :normal vi$<cr>
onoremap <silent><buffer> a$ :normal va$<cr>
2013-10-09 14:34:26 -04:00
2014-07-27 15:18:01 -04:00
xnoremap <silent><buffer> id :<c-u>call latex#motion#sel_delimiter(1)<cr>
xnoremap <silent><buffer> ad :<c-u>call latex#motion#sel_delimiter()<cr>
2013-10-09 14:34:26 -04:00
onoremap <silent><buffer> id :normal vi(<cr>
onoremap <silent><buffer> ad :normal va(<cr>
2013-10-05 07:53:42 -04:00
endif
"
" Highlight matching parens ($, (), ...)
"
if !a:initialized && g:latex_motion_matchparen
augroup latex_motion
autocmd!
" Disable matchparen autocommands
autocmd BufEnter *.tex
\ if !exists("g:loaded_matchparen") || !g:loaded_matchparen
\ | runtime plugin/matchparen.vim
\ | endif
autocmd BufEnter *.tex
\ 3match none | unlet! g:loaded_matchparen | au! matchparen
" Enable latex matchparen functionality
2013-10-06 07:39:25 -04:00
autocmd! CursorMoved *.tex call s:highlight_matching_pair(1)
autocmd! CursorMovedI *.tex call s:highlight_matching_pair()
2013-10-05 07:53:42 -04:00
augroup END
endif
endfunction
function! latex#motion#find_matching_pair(...) " {{{1
2013-10-06 07:39:25 -04:00
if a:0 > 0
2013-10-05 07:53:42 -04:00
normal! gv
endif
if latex#util#in_comment() | return | endif
2013-10-06 07:39:25 -04:00
" Save position
let nl = line('.')
let nc = col('.')
2013-10-05 07:53:42 -04:00
2013-10-06 07:39:25 -04:00
" Find delimiter under cursor
2013-10-09 14:34:26 -04:00
let [lnum, cnum] = searchpos(s:delimiters, 'cbnW', nl-2)
let delim = matchstr(getline(lnum), '^' . s:delimiters, cnum-1)
2013-10-06 07:39:25 -04:00
" If delimiter not found, try to search forward instead
if empty(delim)
2013-10-09 14:34:26 -04:00
let [lnum, cnum] = searchpos(s:delimiters, 'cnW', nl+2)
let delim = matchstr(getline(lnum), '^'. s:delimiters, cnum-1)
2013-10-06 07:39:25 -04:00
if empty(delim)
2013-10-05 07:53:42 -04:00
return
endif
endif
2013-10-06 07:39:25 -04:00
" Utility pattern to NOT match the current cursor position
let not_cursor = '\%(\%'. lnum . 'l\%' . cnum . 'c\)\@!'
" Finally, find the matching delimiter
2013-10-05 07:53:42 -04:00
if delim =~ '^\$'
2013-10-10 15:48:52 -04:00
let inline = s:notcomment . s:notbslash . '\$'
2013-10-05 07:53:42 -04:00
let [lnum0, cnum0] = searchpos('.', 'nW')
if lnum0 && latex#util#has_syntax('texMathZoneX', lnum0, cnum0)
2013-10-06 07:39:25 -04:00
let [lnum2, cnum2] = searchpos(inline, 'nW', 0, 200)
2013-10-05 07:53:42 -04:00
else
2013-10-06 07:39:25 -04:00
let [lnum2, cnum2] = searchpos(not_cursor . inline, 'bnW', 0, 200)
2013-10-05 07:53:42 -04:00
endif
2013-10-06 07:39:25 -04:00
call cursor(lnum2,cnum2)
2013-10-05 07:53:42 -04:00
else
2013-10-09 14:34:26 -04:00
for i in range(len(s:delimiters))
2013-10-10 15:48:52 -04:00
let open_pat = '\C' . s:notbslash . s:delimiters_open[i]
let close_pat = '\C' . s:notbslash . s:delimiters_close[i]
2013-10-05 07:53:42 -04:00
if delim =~# '^' . open_pat
2013-10-06 07:39:25 -04:00
call searchpairpos(open_pat, '', close_pat,
\ 'W', 'latex#util#in_comment()', 0, 200)
call search(close_pat, 'ce')
return
2013-10-05 07:53:42 -04:00
elseif delim =~# '^' . close_pat
2013-10-06 07:39:25 -04:00
call searchpairpos(open_pat, '', not_cursor . close_pat,
\ 'bW', 'latex#util#in_comment()', 0, 200)
return
2013-10-05 07:53:42 -04:00
endif
endfor
endif
endfunction
function! latex#motion#next_section(type, backwards, visual) " {{{1
2013-10-05 07:53:42 -04:00
" Restore visual mode if desired
if a:visual
normal! gv
endif
" For the [] and ][ commands we move up or down before the search
if a:type == 1
if a:backwards
normal! k
else
normal! j
endif
endif
" Define search pattern and do the search while preserving "/
let flags = 'W'
if a:backwards
let flags = 'b' . flags
endif
" Perform the search
2013-10-09 14:34:26 -04:00
call search(s:section, flags)
2013-10-05 07:53:42 -04:00
" For the [] and ][ commands we move down or up after the search
if a:type == 1
if a:backwards
normal! j
else
normal! k
endif
endif
endfunction
function! latex#motion#sel_delimiter(...) " {{{1
2013-10-09 14:34:26 -04:00
let inner = a:0 > 0
let [d1, l1, c1, d2, l2, c2] = latex#util#get_delim()
if inner
let c1 += len(d1)
if c1 != len(getline(l1))
let l1 += 1
let c1 = 1
endif
endif
if inner
let c2 -= 1
if c2 < 1
let l2 -= 1
let c2 = len(getline(l2))
endif
else
let c2 += len(d2) - 1
endif
if l1 < l2 || (l1 == l2 && c1 < c2)
call cursor(l1,c1)
if visualmode() ==# 'V'
normal! V
else
normal! v
endif
call cursor(l2,c2)
endif
endfunction
function! latex#motion#sel_environment(...) " {{{1
2013-10-09 14:34:26 -04:00
let inner = a:0 > 0
2013-10-05 07:53:42 -04:00
let [env, lnum, cnum, lnum2, cnum2] = latex#util#get_env(1)
call cursor(lnum, cnum)
2013-10-09 14:34:26 -04:00
if inner
2013-10-05 07:53:42 -04:00
if env =~ '^\'
call search('\\.\_\s*\S', 'eW')
else
call search('}\(\_\s*\(\[\_[^]]*\]\|{\_\S\{-}}\)\)\?\_\s*\S', 'eW')
2013-10-05 07:53:42 -04:00
endif
endif
if visualmode() ==# 'V'
normal! V
else
normal! v
endif
call cursor(lnum2, cnum2)
2013-10-09 14:34:26 -04:00
if inner
2013-10-05 07:53:42 -04:00
call search('\S\_\s*', 'bW')
else
if env =~ '^\'
normal! l
else
call search('}', 'eW')
endif
endif
endfunction
function! latex#motion#sel_inline_math(...) " {{{1
2013-10-09 14:34:26 -04:00
let inner = a:0 > 0
2013-10-05 07:53:42 -04:00
let dollar_pat = '\\\@<!\$'
if latex#util#has_syntax('texMathZoneX')
call s:search_and_skip_comments(dollar_pat, 'cbW')
elseif getline('.')[col('.') - 1] == '$'
call s:search_and_skip_comments(dollar_pat, 'bW')
else
return
endif
2013-10-09 14:34:26 -04:00
if inner
2013-10-05 07:53:42 -04:00
normal! l
endif
if visualmode() ==# 'V'
normal! V
else
normal! v
endif
call s:search_and_skip_comments(dollar_pat, 'W')
2013-10-09 14:34:26 -04:00
if inner
2013-10-05 07:53:42 -04:00
normal! h
endif
endfunction
" }}}1
2013-10-09 14:34:26 -04:00
" {{{1 Common patterns
2013-10-10 15:48:52 -04:00
let s:notbslash = '\%(\\\@<!\%(\\\\\)*\)\@<='
let s:notcomment = '\%(\%(\\\@<!\%(\\\\\)*\)\@<=%.*\)\@<!'
2013-10-09 14:34:26 -04:00
" Patterns to match opening and closing delimiters/environments
let s:delimiters_open = [
\ '{',
\ '(',
\ '\[',
\ '\\{',
\ '\\(',
\ '\\\[',
\ '\\\Cbegin\s*{.\{-}}',
2013-11-21 04:36:03 -05:00
\ '\\\Cleft\s*\%([^\\a-zA-Z0-9]\|\\.\|\\\a*\)',
2013-10-09 14:34:26 -04:00
\ '\\\cbigg\?\((\|\[\|\\{\)',
\ ]
let s:delimiters_close = [
\ '}',
\ ')',
\ '\]',
\ '\\}',
\ '\\)',
\ '\\\]',
\ '\\\Cend\s*{.\{-}}',
2013-11-21 04:36:03 -05:00
\ '\\\Cright\s*\%([^\\a-zA-Z0-9]\|\\.\|\\\a*\)',
2013-10-09 14:34:26 -04:00
\ '\\\cbigg\?\()\|\]\|\\}\)',
\ ]
let s:delimiters = join(s:delimiters_open + s:delimiters_close, '\|')
let s:delimiters = '\(' . s:delimiters . '\|\$\)'
" Pattern to match section/chapter/...
2013-10-10 15:48:52 -04:00
let s:section = s:notcomment . '\v\s*\\'
2013-10-09 14:34:26 -04:00
let s:section.= '((sub)*section|chapter|part|appendix|(front|back|main)matter)'
let s:section.= '>'
" }}}1
function! s:highlight_matching_pair(...) " {{{1
2013-10-06 07:39:25 -04:00
if latex#util#in_comment() | return | endif
let hmode = a:0 > 0 ? 1 : 0
2match none
" Save position
let nl = line('.')
let nc = col('.')
let line = getline(nl)
" Find delimiter under cursor
2013-10-09 14:34:26 -04:00
let cnum = searchpos(s:delimiters, 'cbnW', nl)[1]
let delim = matchstr(line, '^'. s:delimiters, cnum-1)
2013-10-06 07:39:25 -04:00
" Only highlight when cursor is on delimiters
if empty(delim) || strlen(delim)+cnum-hmode < nc
return
endif
if delim =~ '^\$'
"
" Match inline math
"
let [lnum0, cnum0] = searchpos('.', 'nW')
if lnum0 && latex#util#has_syntax('texMathZoneX', lnum0, cnum0)
2013-10-10 15:48:52 -04:00
let [lnum2, cnum2] = searchpos(s:notcomment . s:notbslash . '\$',
2013-10-06 07:39:25 -04:00
\ 'nW', line('w$'), 200)
else
let [lnum2, cnum2] = searchpos('\%(\%'. nl . 'l\%'
2013-10-10 15:48:52 -04:00
\ . cnum . 'c\)\@!'. s:notcomment . s:notbslash . '\$',
2013-10-06 07:39:25 -04:00
\ 'bnW', line('w0'), 200)
endif
execute '2match MatchParen /\%(\%' . nl . 'l\%'
\ . cnum . 'c\$' . '\|\%' . lnum2 . 'l\%' . cnum2 . 'c\$\)/'
else
"
" Match other delimitors
"
2013-10-09 14:34:26 -04:00
for i in range(len(s:delimiters_open))
2013-10-10 15:48:52 -04:00
let open_pat = '\C' . s:notbslash . s:delimiters_open[i]
let close_pat = '\C' . s:notbslash . s:delimiters_close[i]
2013-10-06 07:39:25 -04:00
if delim =~# '^' . open_pat
let [lnum2, cnum2] = searchpairpos(open_pat, '', close_pat,
\ 'nW', 'latex#util#in_comment()', line('w$'), 200)
execute '2match MatchParen /\%(\%' . nl . 'l\%' . cnum
2013-10-09 14:34:26 -04:00
\ . 'c' . s:delimiters_open[i] . '\|\%'
2013-10-06 07:39:25 -04:00
\ . lnum2 . 'l\%' . cnum2 . 'c'
2013-10-09 14:34:26 -04:00
\ . s:delimiters_close[i] . '\)/'
2013-10-06 07:39:25 -04:00
return
elseif delim =~# '^' . close_pat
let [lnum2, cnum2] = searchpairpos(open_pat, '',
\ '\C\%(\%'. nl . 'l\%' . cnum . 'c\)\@!' . close_pat,
\ 'bnW', 'latex#util#in_comment()', line('w0'), 200)
execute '2match MatchParen /\%(\%' . lnum2 . 'l\%' . cnum2
2013-10-09 14:34:26 -04:00
\ . 'c' . s:delimiters_open[i] . '\|\%'
2013-10-06 07:39:25 -04:00
\ . nl . 'l\%' . cnum . 'c'
2013-10-09 14:34:26 -04:00
\ . s:delimiters_close[i] . '\)/'
2013-10-06 07:39:25 -04:00
return
endif
endfor
endif
endfunction
2013-11-02 12:46:43 -04:00
function! s:search_and_skip_comments(pat, ...) " {{{1
2013-11-02 12:46:43 -04:00
" Usage: s:search_and_skip_comments(pat, [flags, stopline])
let flags = a:0 >= 1 ? a:1 : ''
let stopline = a:0 >= 2 ? a:2 : 0
let saved_pos = getpos('.')
" search once
let ret = search(a:pat, flags, stopline)
if ret
" do not match at current position if inside comment
let flags = substitute(flags, 'c', '', 'g')
" keep searching while in comment
while latex#util#in_comment()
let ret = search(a:pat, flags, stopline)
if !ret
break
endif
endwhile
endif
if !ret
" if no match found, restore position
call setpos('.', saved_pos)
endif
return ret
endfunction
2013-10-06 07:39:25 -04:00
" }}}1
2014-12-08 14:44:17 -05:00
" vim: fdm=marker sw=2