253 lines
6.3 KiB
VimL
253 lines
6.3 KiB
VimL
" vimtex - LaTeX plugin for Vim
|
|
"
|
|
" Maintainer: Karl Yngve Lervåg
|
|
" Email: karl.yngve@gmail.com
|
|
"
|
|
|
|
function! vimtex#cmd#init_options() " {{{1
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! vimtex#cmd#init_script() " {{{1
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! vimtex#cmd#init_buffer() " {{{1
|
|
nnoremap <silent><buffer> <plug>(vimtex-cmd-delete)
|
|
\ :call vimtex#cmd#delete()<cr>
|
|
|
|
nnoremap <silent><buffer> <plug>(vimtex-cmd-change)
|
|
\ :call vimtex#cmd#change()<cr>
|
|
|
|
nnoremap <silent><buffer> <plug>(vimtex-cmd-create)
|
|
\ :call vimtex#cmd#create()<cr>
|
|
|
|
inoremap <silent><buffer> <plug>(vimtex-cmd-create)
|
|
\ <c-r>=vimtex#cmd#create()<cr>
|
|
endfunction
|
|
|
|
" }}}1
|
|
|
|
function! vimtex#cmd#change() " {{{1
|
|
let l:cmd = vimtex#cmd#get_current()
|
|
if empty(l:cmd) | return | endif
|
|
|
|
let l:old_name = l:cmd.name
|
|
let l:lnum = l:cmd.pos_start.lnum
|
|
let l:cnum = l:cmd.pos_start.cnum
|
|
|
|
" Get new command name
|
|
call vimtex#echo#status(['Change command: ', ['VimtexWarning', l:old_name]])
|
|
echohl VimtexMsg
|
|
let l:new_name = input('> ')
|
|
echohl None
|
|
let l:new_name = substitute(l:new_name, '^\\', '', '')
|
|
if empty(l:new_name) | return | endif
|
|
|
|
" Update current position
|
|
let l:save_pos = getpos('.')
|
|
let l:save_pos[2] += strlen(l:new_name) - strlen(l:old_name) + 1
|
|
|
|
" Perform the change
|
|
let l:line = getline(l:lnum)
|
|
call setline(l:lnum,
|
|
\ strpart(l:line, 0, l:cnum)
|
|
\ . l:new_name
|
|
\ . strpart(l:line, l:cnum + strlen(l:old_name) - 1))
|
|
|
|
" Restore cursor position and create repeat hook
|
|
cal setpos('.', l:save_pos)
|
|
silent! call repeat#set("\<plug>(vimtex-cmd-change)" . l:new_name . '
|
|
', v:count)
|
|
endfunction
|
|
|
|
function! vimtex#cmd#delete() " {{{1
|
|
let l:cmd = vimtex#cmd#get_current()
|
|
if empty(l:cmd) | return | endif
|
|
|
|
let l:old_name = l:cmd.name
|
|
let l:lnum = l:cmd.pos_start.lnum
|
|
let l:cnum = l:cmd.pos_start.cnum
|
|
|
|
" Update current position
|
|
let l:save_pos = getpos('.')
|
|
let l:save_pos[2] += 1 - strlen(l:old_name)
|
|
|
|
" Perform the change
|
|
let l:line = getline(l:lnum)
|
|
call setline(l:lnum,
|
|
\ strpart(l:line, 0, l:cnum - 1)
|
|
\ . strpart(l:line, l:cnum + strlen(l:old_name) - 1))
|
|
|
|
" Restore cursor position and create repeat hook
|
|
cal setpos('.', l:save_pos)
|
|
silent! call repeat#set("\<plug>(vimtex-cmd-delete)", v:count)
|
|
endfunction
|
|
|
|
function! vimtex#cmd#create() " {{{1
|
|
let l:re = '\v%(^|\s)\zs\w+\ze%(\s|$)'
|
|
let l:c0 = col('.') - (mode() ==# 'i')
|
|
|
|
let [l:l1, l:c1] = searchpos(l:re, 'bcn', line('.'))
|
|
let l:c1 -= 1
|
|
let l:line = getline(l:l1)
|
|
let l:match = matchstr(l:line, l:re, l:c1)
|
|
let l:c2 = l:c1 + strlen(l:match)
|
|
|
|
if l:c0 > l:c2
|
|
call vimtex#echo#status(['vimtex: ',
|
|
\ ['VimtexWarning', 'Could not create command']])
|
|
return ''
|
|
endif
|
|
|
|
let l:strpart1 = strpart(l:line, 0, l:c1)
|
|
let l:strpart2 = '\' . l:match . '{'
|
|
let l:strpart3 = strpart(l:line, l:c2)
|
|
call setline(l:l1, l:strpart1 . l:strpart2 . l:strpart3)
|
|
call setpos('.', [0, l:l1, l:c2+3, 0])
|
|
|
|
if mode() ==# 'n'
|
|
execute 'startinsert' . (empty(l:strpart3) ? '!' : '')
|
|
endif
|
|
return ''
|
|
endfunction
|
|
|
|
" }}}1
|
|
|
|
function! vimtex#cmd#get_next() " {{{1
|
|
return s:get_cmd('next')
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! vimtex#cmd#get_prev() " {{{1
|
|
return s:get_cmd('prev')
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! vimtex#cmd#get_current() " {{{1
|
|
let pos = getpos('.')
|
|
|
|
let depth = 3
|
|
while depth > 0
|
|
let depth -= 1
|
|
let cmd = s:get_cmd('prev')
|
|
if empty(cmd) | break | endif
|
|
|
|
if 10000*pos[1] + pos[2] <= 10000*cmd.pos_end.lnum + cmd.pos_end.cnum
|
|
return cmd
|
|
endif
|
|
endwhile
|
|
|
|
return {}
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! vimtex#cmd#get_at(lnum, cnum) " {{{1
|
|
let l:pos_saved = getpos('.')
|
|
call setpos('.', [0, a:lnum, a:cnum, 0])
|
|
let l:cmd = vimtex#cmd#get_current()
|
|
call setpos('.', l:pos_saved)
|
|
return l:cmd
|
|
endfunction
|
|
|
|
" }}}1
|
|
|
|
function! s:get_cmd(direction) " {{{1
|
|
let [lnum, cnum, match] = s:get_cmd_name(a:direction ==# 'next')
|
|
if lnum == 0 | return {} | endif
|
|
|
|
let res = {
|
|
\ 'name' : match,
|
|
\ 'pos_start' : { 'lnum' : lnum, 'cnum' : cnum },
|
|
\ 'pos_end' : { 'lnum' : lnum, 'cnum' : cnum + strlen(match) - 1 },
|
|
\ 'args' : [],
|
|
\}
|
|
|
|
" Environments always start with environment name and allows option
|
|
" afterwords
|
|
if res.name ==# '\begin'
|
|
let arg = s:get_cmd_part('{', res.pos_end)
|
|
call add(res.args, arg)
|
|
let res.pos_end.lnum = arg.close.lnum
|
|
let res.pos_end.cnum = arg.close.cnum
|
|
endif
|
|
|
|
" Get options
|
|
let res.opt = s:get_cmd_part('[', res.pos_end)
|
|
if !empty(res.opt)
|
|
let res.pos_end.lnum = res.opt.close.lnum
|
|
let res.pos_end.cnum = res.opt.close.cnum
|
|
endif
|
|
|
|
" Get arguments
|
|
let arg = s:get_cmd_part('{', res.pos_end)
|
|
while !empty(arg)
|
|
call add(res.args, arg)
|
|
let res.pos_end.lnum = arg.close.lnum
|
|
let res.pos_end.cnum = arg.close.cnum
|
|
let arg = s:get_cmd_part('{', res.pos_end)
|
|
endwhile
|
|
|
|
" Include entire cmd text
|
|
let res.text = s:text_between(res.pos_start, res.pos_end, 1)
|
|
|
|
return res
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:get_cmd_name(next) " {{{1
|
|
let [l:lnum, l:cnum] = searchpos('\\\a\+', a:next ? 'nW' : 'cbnW')
|
|
let l:match = matchstr(getline(l:lnum), '^\\\a*', l:cnum-1)
|
|
return [l:lnum, l:cnum, l:match]
|
|
endfunction
|
|
|
|
" }}}1
|
|
function! s:get_cmd_part(part, start_pos) " {{{1
|
|
let l:save_pos = getpos('.')
|
|
call setpos('.', [0, a:start_pos.lnum, a:start_pos.cnum, 0])
|
|
let l:open = vimtex#delim#get_next('delim_tex', 'open')
|
|
call setpos('.', l:save_pos)
|
|
|
|
"
|
|
" Ensure that the delimiter
|
|
" 1) exists,
|
|
" 2) is of the right type,
|
|
" 3) and is the next non-whitespace character.
|
|
"
|
|
if empty(l:open)
|
|
\ || l:open.match !=# a:part
|
|
\ || strlen(substitute(
|
|
\ s:text_between(a:start_pos, l:open), ' ', '', 'g')) != 0
|
|
return {}
|
|
endif
|
|
|
|
let l:close = vimtex#delim#get_matching(l:open)
|
|
if empty(l:close)
|
|
return {}
|
|
endif
|
|
|
|
return {
|
|
\ 'open' : l:open,
|
|
\ 'close' : l:close,
|
|
\ 'text' : s:text_between(l:open, l:close),
|
|
\}
|
|
endfunction
|
|
|
|
" }}}1
|
|
|
|
function! s:text_between(p1, p2, ...) " {{{1
|
|
let [l1, c1] = [a:p1.lnum, a:p1.cnum - (a:0 > 0)]
|
|
let [l2, c2] = [a:p2.lnum, a:p2.cnum - (a:0 <= 0)]
|
|
|
|
let lines = getline(l1, l2)
|
|
if !empty(lines)
|
|
let lines[0] = strpart(lines[0], c1)
|
|
let lines[-1] = strpart(lines[-1], 0,
|
|
\ l1 == l2 ? c2 - c1 : c2)
|
|
endif
|
|
return join(lines, '')
|
|
endfunction
|
|
|
|
" }}}1
|
|
|
|
" vim: fdm=marker sw=2
|