Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generalize argument parsing for vimtex#cmd#get functions #2197

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 33 additions & 18 deletions autoload/vimtex/cmd.vim
Original file line number Diff line number Diff line change
Expand Up @@ -603,45 +603,56 @@ function! s:get_cmd(direction) abort " {{{1
\ 'pos_start' : { 'lnum' : lnum, 'cnum' : cnum },
\ 'pos_end' : { 'lnum' : lnum, 'cnum' : cnum + strlen(match) - 1 },
\ 'args' : [],
\ 'args_parens' : [],
\ 'args_chevrons' : [],
\ 'opts' : [],
\}

" Environments always start with environment name and allows option
" afterwords
" afterwards
if res.name ==# '\begin'
let arg = s:get_cmd_part('{', res.pos_end)
let arg = s:get_cmd_part_delim('{', res.pos_end)
if empty(arg) | return res | endif

call add(res.args, arg)
let res.pos_end.lnum = arg.close.lnum
let res.pos_end.cnum = arg.close.cnum
endif

" Get overlay specification
let res.overlay = s:get_cmd_overlay(res.pos_end.lnum, res.pos_end.cnum)
if !empty(res.overlay)
let res.pos_end.lnum = res.overlay.close.lnum
let res.pos_end.cnum = res.overlay.close.cnum
endif

" Get options and arguments
" Parse the arguments
while v:true
let opt = s:get_cmd_part('[', res.pos_end)
let opt = s:get_cmd_part_delim('[', res.pos_end)
if !empty(opt)
call add(res.opts, opt)
let res.pos_end.lnum = opt.close.lnum
let res.pos_end.cnum = opt.close.cnum
continue
endif

let arg = s:get_cmd_part('{', res.pos_end)
let arg = s:get_cmd_part_delim('{', res.pos_end)
if !empty(arg)
call add(res.args, arg)
let res.pos_end.lnum = arg.close.lnum
let res.pos_end.cnum = arg.close.cnum
continue
endif

let arg = s:get_cmd_part_simple(['(', ')'], res.pos_end)
if !empty(arg)
call add(res.args_chevrons, arg)
let res.pos_end.lnum = arg.close.lnum
let res.pos_end.cnum = arg.close.cnum
continue
endif

let arg = s:get_cmd_part_simple(['<', '>'], res.pos_end)
if !empty(arg)
call add(res.args_parens, arg)
let res.pos_end.lnum = arg.close.lnum
let res.pos_end.cnum = arg.close.cnum
continue
endif

break
endwhile

Expand All @@ -661,7 +672,7 @@ function! s:get_cmd_name(next) abort " {{{1
endfunction

" }}}1
function! s:get_cmd_part(part, start_pos) abort " {{{1
function! s:get_cmd_part_delim(open_delim, start_pos) abort " {{{1
let l:save_pos = vimtex#pos#get_cursor()
call vimtex#pos#set_cursor(a:start_pos)
let l:open = vimtex#delim#get_next('delim_tex', 'open')
Expand All @@ -675,7 +686,7 @@ function! s:get_cmd_part(part, start_pos) abort " {{{1
"
let l:separate = s:text_between(a:start_pos, l:open)
let l:newlines = count(l:separate, "\n")
if l:open.match !=# a:part
if l:open.match !=# a:open_delim
\ || strlen(substitute(l:separate, '\_s\+', '', 'g')) != 0
\ || l:newlines > 1
return {}
Expand All @@ -694,14 +705,18 @@ function! s:get_cmd_part(part, start_pos) abort " {{{1
endfunction

" }}}1
function! s:get_cmd_overlay(lnum, cnum) abort " {{{1
let l:match = matchstr(getline(a:lnum), '^\s*[^>]*>', a:cnum)
function! s:get_cmd_part_simple(delims, start_pos) abort " {{{1
let l:lnum = a:start_pos.lnum
let l:cnum = a:start_pos.cnum
let l:regex = '^\s*' . a:delims[0] . '[^' . a:delims[1] . ']*' . a:delims[1]

let l:match = matchstr(getline(l:lnum), l:regex, l:cnum)

return empty(l:match)
\ ? {}
\ : {
\ 'open' : {'lnum' : a:lnum, 'cnum' : a:cnum + 1},
\ 'close' : {'lnum' : a:lnum, 'cnum' : a:cnum + strlen(l:match)},
\ 'open' : {'lnum' : l:lnum, 'cnum' : l:cnum + 1},
\ 'close' : {'lnum' : l:lnum, 'cnum' : l:cnum + strlen(l:match)},
\ 'text' : l:match
\ }
endfunction
Expand Down
13 changes: 9 additions & 4 deletions test/test-parser-cmds/Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
.PHONY: test

MYVIM ?= nvim --clean --headless

INMAKE := 1
export INMAKE

test:
@$(MYVIM) -u test.vim 2>&1
TESTS := $(wildcard test*.vim)
TESTS := $(TESTS:.vim=)

.PHONY: test $(TESTS)

test: $(TESTS)

$(TESTS):
@$(MYVIM) -u $@.vim
23 changes: 23 additions & 0 deletions test/test-parser-cmds/test-args.tex
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
\documentclass{minimal}
\begin{document}

THIS DOCUMENT DOES NOT COMPILE!

\setmainfont{LucidaBrightOT}[
Extension = .otf,
BoldItalicFont = *-DemiItalic
]

\begin{helloworld}[
Extension = .otf,
BoldItalicFont = *-DemiItalic
]
\end{helloworld}

\begin{textblock*}{3in}[0,0] (3in,1in)
Hello world
\end{textblock*}

\test \foo(bar)

\end{document}
25 changes: 25 additions & 0 deletions test/test-parser-cmds/test-args.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
set nocompatible
let &rtp = '../..,' . &rtp
filetype plugin on

nnoremap q :qall!<cr>

silent edit test-args.tex

if empty($INMAKE) | finish | endif

let s:cmd = vimtex#cmd#get_at(6, 1)
call assert_equal('LucidaBrightOT', s:cmd.args[0].text)
call assert_match('BoldItalicFont', s:cmd.opts[0].text)

let s:cmd = vimtex#cmd#get_at(11, 1)
call assert_equal('helloworld', s:cmd.args[0].text)
call assert_match('BoldItalicFont', s:cmd.opts[0].text)

let s:cmd = vimtex#cmd#get_at(17, 1)
call assert_equal('\begin{textblock*}{3in}[0,0] (3in,1in)', s:cmd.text)

let s:cmd = vimtex#cmd#get_at(21, 1)
call assert_equal('\test', s:cmd.text)

call vimtex#test#finished()
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ filetype plugin on

nnoremap q :qall!<cr>

silent edit test.tex
silent edit test-next.tex

if empty($INMAKE) | finish | endif

Expand Down