diff --git a/.gitignore b/.gitignore index 68b28910dcb..1e3b14e6771 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ test/issues test/test-completion-bibtex/test_parser_* test/test-quickfix-fix-path/test_hbox* test/example-fzf-lua/fzf-lua +test/example-snacks/snacks .claude CLAUDE.md diff --git a/.luarc.json b/.luarc.json index d06245585f6..55b80faa649 100644 --- a/.luarc.json +++ b/.luarc.json @@ -6,7 +6,8 @@ "workspace": { "library": [ "$VIMRUNTIME", - "${3rd}/luv/library" + "${3rd}/luv/library", + "$HOME/.local/plugged/snacks.nvim" ], "checkThirdParty": false } diff --git a/autoload/vimtex.vim b/autoload/vimtex.vim index 8aa25d8288e..3b914930bc5 100644 --- a/autoload/vimtex.vim +++ b/autoload/vimtex.vim @@ -195,6 +195,7 @@ function! s:init_default_mappings() abort " {{{1 if g:vimtex_compiler_enabled call s:map_prefixed(0, 'n', 'l', '(vimtex-compile)') + call s:map_prefixed(0, 'n', 'S', '(vimtex-compile-ss)') call s:map_prefixed(0, 'n', 'o', '(vimtex-compile-output)') call s:map_prefixed(1, 'n', 'L', '(vimtex-compile-selected)') call s:map_prefixed(1, 'x', 'L', '(vimtex-compile-selected)') diff --git a/autoload/vimtex/cmd.vim b/autoload/vimtex/cmd.vim index 3b8a6510e13..30c0feed8f9 100644 --- a/autoload/vimtex/cmd.vim +++ b/autoload/vimtex/cmd.vim @@ -457,6 +457,9 @@ function! s:get_frac_inline() abort " {{{1 let l:positions += [l:pos_after] endif + let l:re_denom_1 = '\v^\s*[^$()} ]*' + let l:re_denom_2 = '\\%(right|[bB]igg?r?)?\)' + for l:pos in l:positions let l:frac = {'type': 'inline'} @@ -482,9 +485,9 @@ function! s:get_frac_inline() abort " {{{1 " Parse denominator " let l:after = strpart(l:line, l:pos+1) - let l:atoms = l:after =~# '^\s*[^$()} ]*\\)' - \ ? matchstr(l:after, '^\s*[^$()} ]*\ze\\)') - \ : matchstr(l:after, '^\s*[^$()} ]*') + let l:atoms = l:after =~# l:re_denom_1 .. l:re_denom_2 + \ ? matchstr(l:after, l:re_denom_1 .. '\ze' .. l:re_denom_2) + \ : matchstr(l:after, l:re_denom_1) let l:pos_after = l:pos + strlen(l:atoms) let l:after = strpart(l:line, l:pos_after+1) if l:after =~# '^(' diff --git a/autoload/vimtex/compiler/_template.vim b/autoload/vimtex/compiler/_template.vim index f31cf38f28e..6518f66d456 100644 --- a/autoload/vimtex/compiler/_template.vim +++ b/autoload/vimtex/compiler/_template.vim @@ -62,6 +62,41 @@ function! s:compiler.__check_requirements() abort dict " {{{1 endfunction " }}}1 + +function! s:compiler._get_executable_string() abort dict " {{{1 + " Convert executable (string or list) to a command string + " + " The executable property can be: + " - A string: 'latexmk' + " - A list: ['docker', 'exec', 'my-container', 'latexmk'] + " + if type(self.executable) == v:t_string + return self.executable + elseif type(self.executable) == v:t_list + return join(self.executable) + endif + + throw 'VimTeX: executable must be a string or list' +endfunction + +" }}}1 +function! s:compiler._is_executable_available() abort dict " {{{1 + " Check if the executable is available + " + " For string executables, check directly. + " For list executables, check only the first element. + " + if type(self.executable) == v:t_string + return executable(self.executable) + endif + + return type(self.executable) == v:t_list + \ && !empty(self.executable) + \ && executable(self.executable[0]) +endfunction + +" }}}1 + function! s:compiler.__init() abort dict " {{{1 endfunction @@ -136,6 +171,7 @@ function! s:compiler._create_build_dir(path) abort dict " {{{1 call map(l:dirs, {_, x -> \ (vimtex#paths#is_abs(a:path) ? '' : self.file_info.root . '/') \ . a:path . '/' . x}) + call map(l:dirs, {_, x -> simplify(x) }) call filter(l:dirs, '!isdirectory(v:val)') if empty(l:dirs) | return | endif diff --git a/autoload/vimtex/compiler/latexmk.vim b/autoload/vimtex/compiler/latexmk.vim index 653f8a5d555..7eb6d8d08ab 100644 --- a/autoload/vimtex/compiler/latexmk.vim +++ b/autoload/vimtex/compiler/latexmk.vim @@ -102,8 +102,11 @@ let s:compiler = vimtex#compiler#_template#new({ \}) function! s:compiler.__check_requirements() abort dict " {{{1 - if !executable(self.executable) - call vimtex#log#warning(self.executable . ' is not executable') + if !self._is_executable_available() + let l:exe = type(self.executable) == v:t_list + \ ? self.executable[0] + \ : self.executable + call vimtex#log#warning(l:exe . ' is not executable') let self.enabled = v:false endif endfunction @@ -135,7 +138,7 @@ endfunction function! s:compiler.__build_cmd(passed_options) abort dict " {{{1 let l:cmd = (has('win32') \ ? 'set max_print_line=2000 & ' - \ : 'max_print_line=2000 ') . self.executable + \ : 'max_print_line=2000 ') . self._get_executable_string() let l:cmd .= ' ' . join(self.options) . a:passed_options let l:cmd .= ' ' . self.get_engine() @@ -227,7 +230,7 @@ endfunction function! s:compiler.clean(full) abort dict " {{{1 call self.__clean_temp_files(a:full) - let l:cmd = self.executable + let l:cmd = self._get_executable_string() let l:cmd .= a:full ? ' -C' : ' -c' if !empty(self.out_dir) diff --git a/autoload/vimtex/delim.vim b/autoload/vimtex/delim.vim index eb403704076..dd355dc19bc 100644 --- a/autoload/vimtex/delim.vim +++ b/autoload/vimtex/delim.vim @@ -445,17 +445,32 @@ function! vimtex#delim#get_matching(delim) abort " {{{1 endfunction " }}}1 -function! vimtex#delim#get_surrounding(type) abort " {{{1 +function! vimtex#delim#get_surrounding(type, ...) abort " {{{1 + let l:opts = a:0 > 0 ? a:1 : {} + " This is split, because we need some extra conditions to ensure that " delimiters are matched properly. return a:type =~# '^env' - \ ? s:get_surrounding_env(a:type) + \ ? s:get_surrounding_env(a:type, l:opts) \ : s:get_surrounding_delim(a:type) endfunction " }}}1 +function! vimtex#delim#get_surrounding_or_next(type, ...) abort " {{{1 + let l:opts = a:0 > 0 ? a:1 : {} + + " This is split, because we need some extra conditions to ensure that + " delimiters are matched properly. + return a:type =~# '^env' + \ ? s:get_surrounding_or_next_env(a:type, l:opts) + \ : s:get_surrounding_or_next_delim(a:type) +endfunction + +" }}}1 + +function! s:get_surrounding_env(type, opts) abort " {{{1 + let l:opts = extend(a:opts, #{ whitelist: [] }, 'keep') -function! s:get_surrounding_env(type) abort " {{{1 let l:save_pos = vimtex#pos#get_cursor() let l:pos_val_cursor = vimtex#pos#val(l:save_pos) let l:pos_val_last = l:pos_val_cursor @@ -470,11 +485,17 @@ function! s:get_surrounding_env(type) abort " {{{1 let l:open = vimtex#delim#get_prev(a:type, 'open') if empty(l:open) | break | endif - let l:close = vimtex#delim#get_matching(l:open) - let l:pos_val_try = vimtex#pos#val(l:close) + strlen(l:close.match) - 1 - if l:pos_val_try >= l:pos_val_cursor - call vimtex#pos#set_cursor(l:save_pos) - return [l:open, l:close] + if len(l:opts.whitelist) == 0 + \ || index( + \ l:opts.whitelist, + \ substitute(l:open.name, '\*$', '', '') + \) >= 0 + let l:close = vimtex#delim#get_matching(l:open) + let l:pos_val_try = vimtex#pos#val(l:close) + strlen(l:close.match) - 1 + if l:pos_val_try >= l:pos_val_cursor + call vimtex#pos#set_cursor(l:save_pos) + return [l:open, l:close] + endif endif call vimtex#pos#set_cursor(vimtex#pos#prev(l:open)) @@ -527,6 +548,59 @@ function! s:get_surrounding_delim(type) abort " {{{1 return [{}, {}] endfunction +" }}}1 +function! s:get_surrounding_or_next_env(type, opts) abort " {{{1 + let l:opts = extend(a:opts, #{ whitelist: [] }, 'keep') + + let [l:open, l:close] = s:get_surrounding_env(a:type, a:opts) + if !empty(l:open) + return [l:open, l:close] + endif + + let l:save_pos = vimtex#pos#get_cursor() + + let l:count = 0 + let l:max_tries = a:type ==# 'env_math' ? 3 : 100 + + while l:count < l:max_tries + let l:count += 1 + let l:open = vimtex#delim#get_next(a:type, 'open') + if empty(l:open) + call vimtex#pos#set_cursor(l:save_pos) + return [{}, {}] + endif + + if len(l:opts.whitelist) == 0 + \ || index( + \ l:opts.whitelist, + \ substitute(l:open.name, '\*$', '', '') + \) >= 0 + break + endif + + call vimtex#pos#set_cursor(vimtex#pos#next(l:open)) + endwhile + + call vimtex#pos#set_cursor(l:save_pos) + + let l:close = vimtex#delim#get_matching(l:open) + return [l:open, l:close] +endfunction + +" }}}1 +function! s:get_surrounding_or_next_delim(type) abort " {{{1 + let [l:open, l:close] = s:get_surrounding_delim(a:type) + if !empty(l:open) + return [l:open, l:close] + endif + + let l:next = vimtex#delim#get_next(a:type, 'open') + if empty(l:open) | return [{}, {}] | endif + + let l:close = vimtex#delim#get_matching(l:open) + return [l:open, l:close] +endfunction + " }}}1 function! s:operator_setup(operator) abort " {{{1 diff --git a/autoload/vimtex/env.vim b/autoload/vimtex/env.vim index 324a7bb4b32..8e6f22e9c2d 100644 --- a/autoload/vimtex/env.vim +++ b/autoload/vimtex/env.vim @@ -55,22 +55,51 @@ function! vimtex#env#get_surrounding(type) abort let [l:open, l:close] = vimtex#delim#get_surrounding('env_math') if !empty(l:open) | return [l:open, l:close] | endif - " Next check for standard math environments (recursively) - let l:save_pos = vimtex#pos#get_cursor() - while v:true - let [l:open, l:close] = vimtex#delim#get_surrounding('env_tex') - if empty(l:open) - call vimtex#pos#set_cursor(l:save_pos) - return [l:open, l:close] - endif + " Next check for standard math environments + let [l:open, l:close] = vimtex#delim#get_surrounding( + \ 'env_tex', + \ #{ whitelist: s:math_envs } + \) + return [l:open, l:close] +endfunction - if index(s:math_envs, substitute(l:open.name, '\*$', '', '')) >= 0 - call vimtex#pos#set_cursor(l:save_pos) - return [l:open, l:close] - endif +function! vimtex#env#get_surrounding_or_next(type) abort + if a:type ==# 'normal' + return vimtex#delim#get_surrounding_or_next('env_tex') + endif - call vimtex#pos#set_cursor(vimtex#pos#prev(l:open)) - endwhile + if a:type !=# 'math' + call vimtex#log#error('Wrong argument!') + return [{}, {}] + endif + + " Now we check for math envs/regions + let l:posval_cursor = vimtex#pos#val(vimtex#pos#get_cursor()) + + " Check for special math env delimiters ($..$, etc) + let [l:open_sp, l:close_sp] = vimtex#delim#get_surrounding_or_next('env_math') + let l:posval_sp = empty(l:open_sp) + \ ? 500*l:posval_cursor + \ : vimtex#pos#val(l:open_sp) + + " Early return if this match surrounds the cursor + if l:posval_sp <= l:posval_cursor + return [l:open_sp, l:close_sp] + endif + + " Check for standard math environments + let [l:open_env, l:close_env] = vimtex#delim#get_surrounding_or_next( + \ 'env_tex', + \ #{ whitelist: s:math_envs } + \) + if empty(l:open_env) + return [l:open_sp, l:close_sp] + endif + + let l:posval_env = vimtex#pos#val(l:open_env) + return l:posval_env <= l:posval_cursor || l:posval_env < l:posval_sp + \ ? [l:open_env, l:close_env] + \ : [l:open_sp, l:close_sp] endfunction let s:math_envs = [ @@ -365,6 +394,7 @@ function! vimtex#env#toggle_math() abort let l:current = get(l:open, 'name', l:open.match) let l:target = get(g:vimtex_env_toggle_math_map, l:current, '$') + \ .. (get(l:open, 'starred', 0) ? '*' : '') call vimtex#env#change(l:open, l:close, l:target) endfunction diff --git a/autoload/vimtex/fold/envs.vim b/autoload/vimtex/fold/envs.vim index 34f27ae23ac..b45fb3d56a7 100644 --- a/autoload/vimtex/fold/envs.vim +++ b/autoload/vimtex/fold/envs.vim @@ -14,9 +14,10 @@ endfunction let s:folder = { \ 'name' : 'environments', \ 're' : { - \ 'start' : g:vimtex#re#not_comment . '\\begin\s*\{.{-}\}', - \ 'end' : g:vimtex#re#not_comment . '\\end\s*\{.{-}\}', - \ 'name' : g:vimtex#re#not_comment . '\\%(begin|end)\s*\{\zs.{-}\ze\}' + \ 'start' : g:vimtex#re#not_comment .. '\\begin\s*\{.{-}\}', + \ 'end' : g:vimtex#re#not_comment .. '\\end\s*\{.{-}\}', + \ 'name' : g:vimtex#re#not_comment + \ .. '\\%(begin|end)\s*\{(.{-})\}(\s*\{.*\})?' \ }, \ 'whitelist' : [], \ 'blacklist' : [], @@ -46,7 +47,7 @@ endfunction " }}}1 function! s:folder.level(line, lnum) abort dict " {{{1 - let l:env = matchstr(a:line, self.re.name) + let l:env = matchlist(a:line, self.re.name)[1] if !empty(l:env) && self.validate(l:env) if a:line =~# self.re.start @@ -63,7 +64,8 @@ endfunction " }}}1 function! s:folder.text(line, level) abort dict " {{{1 - let env = matchstr(a:line, self.re.name) + let match = matchlist(a:line, self.re.name) + let env = match[1] if !self.validate(env) | return | endif " Set caption/label based on type of environment @@ -84,7 +86,7 @@ function! s:folder.text(line, level) abort dict " {{{1 " Always make room for the label let width_rhs = 0 if !empty(label) - let label = '(' . label . ')' + let label = '(' .. label .. ')' let width_rhs += len(label) endif @@ -96,7 +98,7 @@ function! s:folder.text(line, level) abort dict " {{{1 if len(env) > width_lhs - width_ind - 8 let env = strpart(env, 0, width_lhs - width_ind - 8) endif - let title = repeat(' ', width_ind) . '\begin{' . env . '}' + let title = repeat(' ', width_ind) .. '\begin{' .. env .. '}' .. match[2] " Add option group text if !empty(option) @@ -116,7 +118,7 @@ function! s:folder.text(line, level) abort dict " {{{1 if width_available >= 5 if strchars(caption) > width_available - let caption = strpart(caption, 0, width_available - 1) . '…' + let caption = strpart(caption, 0, width_available - 1) .. '…' endif let title .= caption endif diff --git a/autoload/vimtex/options.vim b/autoload/vimtex/options.vim index b9a5403c1b6..5042b917d1c 100644 --- a/autoload/vimtex/options.vim +++ b/autoload/vimtex/options.vim @@ -339,6 +339,7 @@ function! vimtex#options#init() abort " {{{1 \ 'ligatures': 1, \ 'cites': 1, \ 'fancy': 1, + \ 'texTabularChar': 1, \ 'spacing': 1, \ 'greek': 1, \ 'math_bounds': 1, diff --git a/autoload/vimtex/syntax/core.vim b/autoload/vimtex/syntax/core.vim index d93b5148b9c..da6b03011f8 100644 --- a/autoload/vimtex/syntax/core.vim +++ b/autoload/vimtex/syntax/core.vim @@ -51,6 +51,8 @@ function! vimtex#syntax#core#init_rules() abort " {{{1 syntax cluster texClusterOpt contains= \texCmd, \texComment, + \texTabularChar, + \texSpecialChar, \texGroup, \texLength, \texOpt, @@ -261,7 +263,7 @@ function! vimtex#syntax#core#init_rules() abort " {{{1 \}) call vimtex#syntax#core#new_arg('texNewcmdArgBody') " The default regexp v2 seems to be faster here: - syntax match texNewcmdParm contained "#\+\d" containedin=texNewcmdArgBody + syntax match texNewcmdParm contained "#\+[1-9]" containedin=texNewcmdArgBody " \newenvironment syntax match texCmdNewenv nextgroup=texNewenvArgName skipwhite skipnl "\%#=1\\\%(re\)\?newenvironment\>" @@ -272,15 +274,15 @@ function! vimtex#syntax#core#init_rules() abort " {{{1 \}) call vimtex#syntax#core#new_arg('texNewenvArgBegin', {'next': 'texNewenvArgEnd'}) call vimtex#syntax#core#new_arg('texNewenvArgEnd') - syntax match texNewenvParm contained "#\+\d" containedin=texNewenvArgBegin,texNewenvArgEnd + syntax match texNewenvParm contained "#\+[1-9]" containedin=texNewenvArgBegin,texNewenvArgEnd " Definitions/Commands " E.g. \def \foo #1#2 {foo #1 bar #2 baz} - syntax match texCmdDef "\%#=1\\def\>" nextgroup=texDefArgName skipwhite skipnl + syntax match texCmdDef "\%#=1\\[egx]\?def\>" nextgroup=texDefArgName skipwhite skipnl syntax match texDefArgName contained nextgroup=texDefParmPre,texDefArgBody skipwhite skipnl "\%#=1\\[a-zA-Z@]\+" syntax match texDefArgName contained nextgroup=texDefParmPre,texDefArgBody skipwhite skipnl "\%#=1\\[^a-zA-Z@]" syntax match texDefParmPre contained nextgroup=texDefArgBody skipwhite skipnl "#[^{]*" - syntax match texDefParm contained "#\+\d" containedin=texDefParmPre,texDefArgBody + syntax match texDefParm contained "#\+[1-9]" containedin=texDefParmPre,texDefArgBody call vimtex#syntax#core#new_arg('texDefArgBody') " \let @@ -533,7 +535,7 @@ function! vimtex#syntax#core#init_rules() abort " {{{1 \ 'contains': 'TOP,@NoSpell,TexError', \}) - syntax match texE3Cmd "\\\w\+" + syntax match texE3Cmd "\\\h\+" \ contained containedin=@texClusterE3 \ nextgroup=texE3Opt,texE3Arg skipwhite skipnl call vimtex#syntax#core#new_opt('texE3Opt', {'next': 'texE3Arg'}) @@ -554,7 +556,7 @@ function! vimtex#syntax#core#init_rules() abort " {{{1 \ contains=texE3Type syntax match texE3Type ":[a-zA-Z]*" contained - syntax match texE3Parm "#\+\d" contained containedin=@texClusterE3 + syntax match texE3Parm "#\+[1-9]" contained containedin=@texClusterE3 syntax cluster texClusterE3 contains=texE3Zone,texE3Arg,texE3Group,texE3Opt @@ -702,6 +704,11 @@ function! vimtex#syntax#core#init_rules() abort " {{{1 call s:match_conceal_fancy() endif + " Conceal tabular characters + if g:vimtex_syntax_conceal.texTabularChar + syntax match texTabularChar "\\\\" conceal cchar=⏎ + endif + " Conceal spacing commands if g:vimtex_syntax_conceal.spacing call s:match_conceal_spacing() @@ -733,6 +740,15 @@ function! vimtex#syntax#core#init_rules() abort " {{{1 endif endif + " }}}2 + " {{{2 Commands: \begin{macrocode} + + " * In documented TeX Format, the 'macrocode' environment separates + " documentation from actual code, hence should get special highlighting. + if expand('%:e') ==# 'dtx' + syntax match texDtxMacrocode "\%#=2^% \{4}\\\(begin\|end\){macrocode}" + endif + " }}}2 let b:current_syntax = 'tex' @@ -763,7 +779,6 @@ function! vimtex#syntax#core#init_rules() abort " {{{1 \texMathDelimMod, \texMathDelim, \@NoSpell - endfunction " }}}1 @@ -823,6 +838,7 @@ function! vimtex#syntax#core#init_highlights() abort " {{{1 " See :help group-name for list of conventional group names " Primitive TeX highlighting groups + highlight def link texDtxMacrocode Special highlight def link texArg Include highlight def link texCmd Statement highlight def link texCmdSpaceCodeChar Special @@ -2486,7 +2502,6 @@ function! s:match_conceal_fancy() abort " {{{1 syntax match texCmd "\%#=1\\dots\>" conceal cchar=… syntax match texCmd "\%#=1\\slash\>" conceal cchar=/ syntax match texCmd "\%#=1\\ldots\>" conceal cchar=… - syntax match texTabularChar "\\\\" conceal cchar=⏎ syntax match texCmdItem "\%#=1\\item\>" conceal cchar=○ \ nextgroup=texItemLabelConcealed diff --git a/autoload/vimtex/syntax/p/biblatex.vim b/autoload/vimtex/syntax/p/biblatex.vim index a15726c8424..b25c7108898 100644 --- a/autoload/vimtex/syntax/p/biblatex.vim +++ b/autoload/vimtex/syntax/p/biblatex.vim @@ -23,6 +23,33 @@ function! vimtex#syntax#p#biblatex#load(cfg) abort " {{{1 syntax match texCmdRef nextgroup=texRefOpt,texRefArg skipwhite skipnl "\\[Ppf]\?[Nn]otecite\>" syntax match texCmdRef nextgroup=texRefOpt,texRefArg skipwhite skipnl "\\\%(text\|block\)cquote\>\*\?" + if g:vimtex_syntax_conceal.cites + let l:re_concealed_cites = '\v\\%(' . join([ + \ '%([Tt]ext|[Ss]mart|[Aa]uto)cite', + \ '(foot)?cite[tp]?', + \ '[Cc]ite%(title|author|year%(par)?|date)', + \ '[Pp]arencite', + \ '[Ppf]?[Nn]otecite', + \ '[Ss]upercite', + \ 'Cite', + \ 'cite%(num|text|url|field|list|name)', + \ 'citeal[tp]', + \ 'foot%(full)?cite%(text)?', + \ 'footcite', + \ 'fullcite', + \ ], '|') . ')>\*?' + + if g:vimtex_syntax_conceal_cites.type ==# 'brackets' + execute 'syntax match texCmdRefConcealed' + \ '"' . l:re_concealed_cites . '"' + \ 'conceal skipwhite nextgroup=texRefConcealedOpt1,texRefConcealedArg' + elseif !empty(g:vimtex_syntax_conceal_cites.icon) + execute 'syntax match texCmdRefConcealed' + \ '"' . l:re_concealed_cites . '%(\[[^]]*\]){,2}\{[^}]*\}"' + \ 'conceal cchar=' . g:vimtex_syntax_conceal_cites.icon + endif + endif + syntax match texCmdRef nextgroup=texRefOpts,texRefArgs skipwhite skipnl "\\[Cc]ites\>" syntax match texCmdRef nextgroup=texRefOpts,texRefArgs skipwhite skipnl "\\[Pp]arencites\>" syntax match texCmdRef nextgroup=texRefOpts,texRefArgs skipwhite skipnl "\\footcite\%(s\|texts\)\>" @@ -37,34 +64,6 @@ function! vimtex#syntax#p#biblatex#load(cfg) abort " {{{1 highlight def link texRefArgs texRefArg highlight def link texRefOpts texRefOpt - - if !g:vimtex_syntax_conceal.cites | return | endif - - let l:re_concealed_cites = '\v\\%(' . join([ - \ '%([Tt]ext|[Ss]mart|[Aa]uto)cite[s]?', - \ '(foot)?cite[tp]?', - \ '[Aa]utocite[s]?', - \ '[Cc]ite%(title|author|year%(par)?|date)[s]?', - \ '[Pp]arencite[s]?', - \ '[Ppf]?[Nn]otecite', - \ '[Ss]upercite[s]?', - \ 'Cite', - \ 'cite%(num|text|url|field|list|name)', - \ 'citeal[tp]', - \ 'foot%(full)?cite%(text)?', - \ 'footcite%(s|texts)', - \ 'fullcite[s]?', - \ ], '|') . ')>\*?' - - if g:vimtex_syntax_conceal_cites.type ==# 'brackets' - execute 'syntax match texCmdRefConcealed' - \ '"' . l:re_concealed_cites . '"' - \ 'conceal skipwhite nextgroup=texRefConcealedOpt1,texRefConcealedArg' - elseif !empty(g:vimtex_syntax_conceal_cites.icon) - execute 'syntax match texCmdRefConcealed' - \ '"' . l:re_concealed_cites . '%(\[[^]]*\]){,2}\{[^}]*\}"' - \ 'conceal cchar=' . g:vimtex_syntax_conceal_cites.icon - endif endfunction " }}}1 diff --git a/autoload/vimtex/text_obj.vim b/autoload/vimtex/text_obj.vim index 24adcd2ad0f..e032b41f4f7 100644 --- a/autoload/vimtex/text_obj.vim +++ b/autoload/vimtex/text_obj.vim @@ -122,7 +122,7 @@ function! vimtex#text_obj#delimited(is_inner, mode, type) abort " {{{1 if a:mode let l:object = s:get_sel_delimited_visual(a:is_inner, a:type, l:startpos) else - let [l:open, l:close] = s:get_surrounding(a:type) + let [l:open, l:close] = s:get_surrounding_or_next(a:type) let l:object = empty(l:open) \ ? {} : s:get_sel_delimited(l:open, l:close, a:is_inner) endif @@ -463,6 +463,15 @@ endfunction " }}}1 +function! s:get_surrounding_or_next(type) abort " {{{1 + if a:type ==# 'delims' + return vimtex#delim#get_surrounding_or_next('delim_all') + else + return vimtex#env#get_surrounding_or_next(a:type) + endif +endfunction + +" }}}1 function! s:get_surrounding(type) abort " {{{1 if a:type ==# 'delims' return vimtex#delim#get_surrounding('delim_all') diff --git a/autoload/vimtex/view.vim b/autoload/vimtex/view.vim index 261a3e64a0a..d973c4c3e7a 100644 --- a/autoload/vimtex/view.vim +++ b/autoload/vimtex/view.vim @@ -97,17 +97,19 @@ function! vimtex#view#inverse_search(line, filename, column = 0) abort endif endif - " Get buffer, window, and tab numbers - " * If tab/window exists, switch to it/them let l:bufnr = bufnr(l:file) - try - let [l:winid; _] = win_findbuf(l:bufnr) - let [l:tabnr, l:winnr] = win_id2tabwin(l:winid) - execute l:tabnr . 'tabnext' - execute l:winnr . 'wincmd w' - catch - execute g:vimtex_view_reverse_search_edit_cmd l:file - endtry + let l:bufnr_current = bufnr() + if l:bufnr != l:bufnr_current + " Switch to the right tab + window if we can find them + try + let [l:winid; _] = win_findbuf(l:bufnr) + let [l:tabnr, l:winnr] = win_id2tabwin(l:winid) + execute l:tabnr . 'tabnext' + execute l:winnr . 'wincmd w' + catch + execute g:vimtex_view_reverse_search_edit_cmd l:file + endtry + endif execute 'normal!' a:line . 'G' if a:column > 0 diff --git a/doc/vimtex.txt b/doc/vimtex.txt index e3c878169fb..8110ed275c7 100644 --- a/doc/vimtex.txt +++ b/doc/vimtex.txt @@ -80,6 +80,7 @@ CONTENTS *vimtex-contents* Denite/Unite source |vimtex-denite| / |vimtex-unite| fzf.vim integration |vimtex-fzf| fzf-lua integration |vimtex-fzf-lua| + Snacks integration |vimtex-snacks| Compilation |vimtex-compiler| Latexmk |vimtex-compiler-latexmk| Latexrun |vimtex-compiler-latexrun| @@ -145,7 +146,7 @@ files by default will be recognized as the filetype `plaintex` detection for `.tex`. The user may prevent this overriding by specifying the |g:tex_flavor| option something different than `'latex'`. ------------------------------------------------------------------------------ +------------------------------------------------------------------------------ FEATURE OVERVIEW *vimtex-features* - Document compilation with `latexmk`, `latexrun`, `tectonic` or `arara` @@ -515,8 +516,8 @@ PACKAGE DETECTION *vimtex-package-detection* VimTeX maintains a list of latex packages that are required by the current project. This list is used by VimTeX for instance to determine which commands to suggest during command completion (see |vimtex-complete-commands|) and -which packages to look up documentation for (see |vimtex-doc-package|). The -list can be viewed with |:VimtexInfo|. +which packages to look up documentation for (see +|(vimtex-doc-package)|). The list can be viewed with |:VimtexInfo|. The package list is determined in two ways: @@ -805,8 +806,8 @@ USAGE *vimtex-usage* ------------------------------------------------------------------------------ DEFAULT MAPPINGS *vimtex-default-mappings* -VimTeX is designed to be controlled by a selection of mappings. Note, -though, that most of the mappings are also available as commands, see +VimTeX is designed to be controlled by a selection of mappings. Note, though, +that most of the mappings are also available as commands, see |vimtex-commands|. Many of the mappings use `l` as a common prefix, where the @@ -815,7 +816,7 @@ mean `\ll`. The prefix may be changed with |g:vimtex_mappings_prefix|. The right-hand sides are provided as -mappings, see |using-|. For any given map, the default mapping will only be created if it does not -already exist. This means that if a user defines a custom mapping, e.g. with >vim +already exist. This means that if a user defines a custom mapping with >vim nmap li (vimtex-info) @@ -848,6 +849,7 @@ This feature is explained in more detail later, see |vimtex-imaps|. lr |(vimtex-reverse-search)| `n` ll |(vimtex-compile)| `n` lL |(vimtex-compile-selected)| `nx` + lS |(vimtex-compile-ss)| `n` lk |(vimtex-stop)| `n` lK |(vimtex-stop-all)| `n` le |(vimtex-errors)| `n` @@ -872,10 +874,10 @@ This feature is explained in more detail later, see |vimtex-imaps|. tsf |(vimtex-cmd-toggle-frac)| `nx` |(vimtex-cmd-toggle-star-agn)| `n` tsc |(vimtex-cmd-toggle-star)| `n` + tsb |(vimtex-cmd-toggle-break)| `n` tss |(vimtex-env-toggle-star)| `n` tse |(vimtex-env-toggle)| `n` ts$ |(vimtex-env-toggle-math)| `n` - tsb |(vimtex-env-toggle-break)| `n` |(vimtex-env-surround-line)| `n` |(vimtex-env-surround-operator)| `n` |(vimtex-env-surround-visual)| `x` @@ -1108,7 +1110,10 @@ OPTIONS *vimtex-options* are only relevant when this option is enabled. executable ~ - The name/path to the `latexmk` executable. + The name/path to the `latexmk` executable. Can be a string or a list. + If a list is provided, it will be interpreted as a command sequence + (e.g., `['docker', 'exec', 'container', 'latexmk']` for running latexmk + through a container). hooks ~ A list of |Funcref|s. If running in continuous mode, each hook will be @@ -2517,6 +2522,9 @@ OPTIONS *vimtex-options* fancy ~ Some extra fancy replacements, e.g. `\item` --> ○. + texTabularChar ~ + Conceal tabular line breaks, i.e. `\\` --> `⏎`. + spacing ~ Conceal spacing commands such as `\quad` and `\hspace{1em}` in both normal mode and math mode. @@ -2567,6 +2575,7 @@ OPTIONS *vimtex-options* \ 'ligatures': 1, \ 'cites': 1, \ 'fancy': 1, + \ 'texTabularChar': 1, \ 'spacing': 1, \ 'greek': 1, \ 'math_bounds': 1, @@ -3410,14 +3419,19 @@ OPTIONS *vimtex-options* Default: `general` *g:vimtex_view_general_options* - Set options for the specified general viewer, see |vimtex-view-general|. - The options are parsed to substitute the following keywords: + Set options for the specified general viewer. The options are parsed + to substitute the following keywords: `@pdf` Path to pdf file `@tex` Path to tex file `@line` Current line number `@col` Current column number + For some examples on how to use this, see + * |vimtex-view-evince| + * |vimtex-view-okular| + * |vimtex-view-sumatrapdf| + Default value: `'@pdf'` *g:vimtex_view_mupdf_options* @@ -3430,7 +3444,7 @@ OPTIONS *vimtex-options* Default value: `''` *g:vimtex_view_general_viewer* - Use generic viewer application, see |vimtex-view-general|. + Use generic viewer application. Default value: Linux: `xdg-open` @@ -3727,9 +3741,10 @@ COMMANDS *vimtex-commands* *:VimtexCountLetters!* *:VimtexCountWords!* -:VimtexCountLetters! Similar to |:VimtexCountLetters|/|:VimtexCountWords|, but -:VimtexCountWords! show separate reports for included files. I.e. - presents the result of: >bash +:VimtexCountLetters! Similar to the un-banged versions +:VimtexCountWords! |:VimtexCountLetters| and |:VimtexCountWords|, + except these show separate reports for included + files. I.e. presents the result of: >bash texcount -nosub -sum [-letter] -inc FILE < @@ -3815,7 +3830,7 @@ MAP DEFINITIONS *vimtex-mappings* *(vimtex-cmd-toggle-star-agn)* Toggle starred command or environment, whichever is closest to the cursor. This is not mapped by default. Some users may prefer the combined behaviour - and may want to map it, e.g. like this in their personal `ftplugin/tex.vim`: + and may want to map it, e.g. like this in their personal `ftplugin/tex.vim`: >vim nmap tss (vimtex-cmd-toggle-star-agn) < @@ -3993,8 +4008,8 @@ MAP DEFINITIONS *vimtex-mappings* INSERT MODE MAPPINGS *vimtex-imaps* Some LaTeX commands are very common, and so it is both natural and convenient -to have insert mode mappings/abbreviations for them. VimTeX therefore -provides a list of such mappings that are enabled by default, see +to have insert mode mappings/abbreviations for them. VimTeX therefore provides +a list of such mappings that are enabled by default, see |g:vimtex_imaps_list|. The mappings utilize a map leader defined by |g:vimtex_imaps_leader|. The default list of maps are all math mode mappings, but one may also add mappings that are available and useful outside of math @@ -4101,6 +4116,7 @@ or |neosnippet|. The imaps feature of VimTeX previously supported `automatic` snippets, but these have been removed after careful considerations and input from VimTeX users, please see VimTeX issue #295: https://github.com/lervag/vimtex/issues/295#issuecomment-164262446 + It has been decided that the best approach is to only provide basic mappings, and to let users manually create automatic snippets through the anonymous snippet functions in |UltiSnips| and |neosnippet|, please see |UltiSnips#Anon| @@ -4307,7 +4323,7 @@ typed in the middle, and the result on the right. The bar "█" indicates the cursor position before the operation. > BEFORE KEYS AFTER - \comm█and{arg} dic \command{} + \comm█and{arg} dic \{arg} \command{a█rg} gUac \COMMAND{ARG} \lef█t( asd \right) cid \left(█ \right) @@ -4342,9 +4358,9 @@ Associated settings: ============================================================================== COMPLETION *vimtex-completion* -If |g:vimtex_complete_enabled| is 1 (default), then VimTeX sets the -'omnifunc' to provide omni completion, see |compl-omni|. Omni completion is -then accessible with |i_CTRL-X_CTRL-O|. If desired, one may set +If |g:vimtex_complete_enabled| is 1 (default), then VimTeX sets the 'omnifunc' +to provide omni completion, see |compl-omni|. Omni completion is then +accessible with |i_CTRL-X_CTRL-O|. If desired, one may set |g:vimtex_complete_close_braces|, which makes the completion include closing braces. @@ -4402,10 +4418,10 @@ applied as a regular expression. ------------------------------------------------------------------------------ COMPLETE LABELS *vimtex-complete-labels* -Label completion is triggered by `\ref{` commands. The completion parses every -relevant aux file to gather the completion candidates. This is important, -because it means that the completion only works when the LaTeX document has -been compiled. +Label completion is triggered by `\ref{` commands. The completion parses +every relevant aux file to gather the completion candidates. This is +important, because it means that the completion only works when the LaTeX +document has been compiled. As an example: > @@ -4436,10 +4452,10 @@ COMPLETE COMMANDS AND ENVIRONMENTS *vimtex-complete-commands* Command completion is available after `\` and should provide completion candidates for relevant LaTeX commands. The document's preamble is analysed, and commands will be completed for the loaded packages as well as those -defined within the preamble using `\newcommand`, `\let` and `\def`. Environment -completion is also available after `\begin{` or `\end{`. As with commands, the -suggested environment names come from the loaded packages and `\newenvironment` -definitions in the preamble. +defined within the preamble using `\newcommand`, `\let` and `\def`. +Environment completion is also available after `\begin{` or `\end{`. As with +commands, the suggested environment names come from the loaded packages and +`\newenvironment` definitions in the preamble. A lot of packages are supported, see the path `/autoload/vimtex/complete` for a relevant file listing. @@ -4708,9 +4724,9 @@ To configure for VimTeX, one can use the following code: >vim YouCompleteMe ~ *vimtex-complete-youcompleteme* -|youcompleteme| is probably the most popular code-completion engine for Vim. The -github repository is here: https://github.com/ycm-core/YouCompleteMe. -It is described as: +|youcompleteme| is probably the most popular code-completion engine for Vim. +The github repository is here: https://github.com/ycm-core/YouCompleteMe. It +is described as: > YouCompleteMe is a fast, as-you-type, fuzzy-search code completion engine > for Vim. It has several completion engines: an identifier-based engine that @@ -4721,7 +4737,8 @@ It is described as: > Vim's omnicomplete system to provide semantic completions for many other > languages (Ruby, PHP etc.). -To enable automatic completion with |youcompleteme|, use the following options: >vim +To enable automatic completion with |youcompleteme|, use the following +options: >vim if !exists('g:ycm_semantic_triggers') let g:ycm_semantic_triggers = {} @@ -5057,17 +5074,16 @@ the type `\name` + `[optional group(s)]` + `{argument group(s)}`, where there can often (not always) be white spaces and newlines between the elements. An argument group can often consist of other top level elements, but not always. Further, since LaTeX is designed to have very strong support for typing -mathematical equations, there are several ways to start math mode, e.g. -`$ ... $`, `$$ ... $$`, `\( ... \)`, `\[ ... \]`, and `\begin{equation}` -matched with `\end{equation}`. Within math mode, there's a different subset of -commands available, and it is common to want a slightly different highlighting -of the math mode regions. +mathematical equations, there are several ways to start math mode, e.g. `$ ... +$`, `$$ ... $$`, `\( ... \)`, `\[ ... \]`, and `\begin{equation}` matched with +`\end{equation}`. Within math mode, there's a different subset of commands +available, and it is common to want a slightly different highlighting of the +math mode regions. VimTeX's syntax script is implemented to support these basic structures as well as a large set of more specific commands and elements. The more specific -rules define groups whose names are more specific, and it is usually -possible to define custom highlighting of specific commands and argument -groups. +rules define groups whose names are more specific, and it is usually possible +to define custom highlighting of specific commands and argument groups. Finally, it is useful to explain the naming scheme of specialized groups. The general idea can be described as follows. @@ -5289,9 +5305,9 @@ parsing the LaTeX project and displaying a table of contents in a separate window. For more info, see |vimtex-toc|. The "engine" for collecting the table-of-content entries may also be used as -a backend for external plugins. There are sources for |denite.nvim|, |unite.vim| -and |fzf.vim| that should work well. The source code may be used as inspiration -to write custom sources or sources for other, similar plugins. +a backend for external plugins. There are sources for |denite.nvim|, +|unite.vim| and |fzf.vim| that should work well. The source code may be used +as inspiration to write custom sources or sources for other, similar plugins. ------------------------------------------------------------------------------ INCLUDE EXPRESSION *vimtex-includeexpr* @@ -5313,9 +5329,9 @@ documentclass and `.sty` files for packages). ------------------------------------------------------------------------------ TABLE OF CONTENTS *vimtex-toc* -|vimtex-toc| displays a table of contents (ToC) for the current LaTeX document. -The ToC entries may be activated/jumped to with or . There are -currently four different "layers" of entries: +|vimtex-toc| displays a table of contents (ToC) for the current LaTeX +document. The ToC entries may be activated/jumped to with or . +There are currently four different "layers" of entries: * content This is the main part and the "real" ToC * todo This shows TODOs from comments and `\todo{...}` commands @@ -5327,9 +5343,9 @@ where the ToC window is positioned to which layers to show and more. Please read the option help for details. The ToC parser uses a list of matchers to parse the LaTeX project for the ToC -entries. One may add custom matchers through the |g:vimtex_toc_custom_matchers| -option. The syntax of a custom matcher is specified here: -|toc_matcher_specification|. +entries. One may add custom matchers through the +|g:vimtex_toc_custom_matchers| option. The syntax of a custom matcher is +specified here: |toc_matcher_specification|. Note: By setting the `mode` configuration key to > 2, the separate ToC window is not opened and most of the features mentioned here will be irrelevant. @@ -5396,24 +5412,24 @@ Although VimTeX includes a simple interface for a tables of contents, it also makes sense to provide these as a source to |denite.nvim|. The source name is simply `vimtex`. -|unite.vim| is the predecessor to |denite.nvim|. As for denite, there is a source -called `vimtex`. +|unite.vim| is the predecessor to |denite.nvim|. As for denite, there is +a source called `vimtex`. -If one prefers the |denite.nvim| or |unite.vim| source to the VimTeX interface, -one may override the default mapping, e.g.: >vim +If one prefers the |denite.nvim| or |unite.vim| source to the VimTeX +interface, one may override the default mapping, e.g.: >vim nnoremap lt :Denite vimtex nnoremap lt :Unite vimtex ------------------------------------------------------------------------------ -FZF INTEGRATION *vimtex-fzf* +FZF INTEGRATION *vimtex-fzf* https://github.com/junegunn/fzf.vim https://github.com/junegunn/fzf -|fzf.vim| integrates the general-purpose command-line fuzzy finder |fzf| into vim -and neovim. Similar to the |denite.vim| and |unite.vim| source it may be used to -quickly navigate VimTeX's built-in ToC feature. To use it, just define a -mapping to `vimtex#fzf#run()` in your .vimrc, e.g.: >vim +|fzf.vim| integrates the general-purpose command-line fuzzy finder |fzf| into +vim and neovim. Similar to the |denite.vim| and |unite.vim| source it may be +used to quickly navigate VimTeX's built-in ToC feature. To use it, just define +a mapping to `vimtex#fzf#run()` in your .vimrc, e.g.: >vim nnoremap lt :call vimtex#fzf#run() @@ -5430,8 +5446,8 @@ The default behavior is to show all layers, i.e. `'ctli'`. To only show :call vimtex#fzf#run('cl') -On Windows the python package Colorama is required for colored output. -For Linux and MacOS colors should work out-of-the-box, even without Colorama. +On Windows the python package Colorama is required for colored output. For +Linux and MacOS colors should work out-of-the-box, even without Colorama. A second argument can be passed to this function to customize the FZF options. It should be an object containing the parameters passed to `fzf#run()`. For @@ -5441,9 +5457,9 @@ example, if you've defined `g:fzf_layout`, then those options can be passed to :call vimtex#fzf#run('ctli', g:fzf_layout) ------------------------------------------------------------------------------ -FZF-LUA INTEGRATION *vimtex-fzf-lua* +FZF-LUA INTEGRATION *vimtex-fzf-lua* - https://github.com/ibhagwan/fzf-lua/ + https://github.com/ibhagwan/fzf-lua |fzf-lua| integrates the general-purpose command-line fuzzy finder |fzf| into neovim through Lua. It may be used to quickly navigate VimTeX's built-in ToC feature. To use it, define a mapping to `require("vimtex.fzf-lua").run(options)`, @@ -5453,11 +5469,30 @@ e.g. >lua return require("vimtex.fzf-lua").run() end) -Currently two options are supported: "layers" and "fzf_opts". You can pass -custom options to fzf-lua via "fzf_opts". -You can also choose to only show certain entry "layers" by passing a layer -string. By default, all layers are displayed. To only show `content` and -`label`s use `require("vimtex.fzf-lua").run({layers ="cl"})`. +Currently two options are supported: "layers" and "fzf_opts". You can pass +custom options to fzf-lua via "fzf_opts". You can also choose to only show +certain entry "layers" by passing a layer string. By default, all layers are +displayed. To only show `content` and `label`s use +`require("vimtex.fzf-lua").run({layers ="cl"})`. + +Note: This requires fzf version 0.60.2 or newer! + +------------------------------------------------------------------------------ +SNACKS INTEGRATION *vimtex-snacks* + + https://github.com/folke/snacks.nvim +|Snacks| is a collection of quality of life plugins for Neovim. It includes +a picker, which can be used with the table of contents in VimTeX. + +To use it, define a mapping to `require("vimtex.snacks").toc(options)`, e.g. >lua + + vim.keymap.set("n", "lt", function() + return require("vimtex.snacks").toc() + end) + +Currently three options are supported: "layers" and "preview" and "confirm". +The first is similar to |vimtex-fzf-lua|, the latter are passed directly to +the Snacks picker. ============================================================================== COMPILER *vimtex-compiler* @@ -5540,9 +5575,9 @@ be configured through the |g:vimtex_compiler_latexmk| option. If the `callback` key is enabled (it is by default and there is really no reason to disable it!), then compilation errors will be parsed automatically. -This is done by utilizing the tricks explained below. Although `latexmk` -can control viewers directly, VimTeX disables this feature with `-view=none` -to get full control of the viewers. +This is done by utilizing the tricks explained below. Although `latexmk` can +control viewers directly, VimTeX disables this feature with `-view=none` to +get full control of the viewers. As stated, one may customize the `latexmk` options through |g:vimtex_compiler_latexmk|. However, one may also configure `latexmk` @@ -5598,8 +5633,8 @@ TECTONIC *vimtex-compiler-tectonic* > by XeTeX and TeXLive. `tectonic` is a compiler backend that features automatic support file -downloading along with reproducible builds and full Unicode and OpenType -fonts support thanks to the power of XeTeX. It does not support continuous +downloading along with reproducible builds and full Unicode and OpenType fonts +support thanks to the power of XeTeX. It does not support continuous compilation like |vimtex-compiler-latexmk|, so the only relevant commands are |:VimtexCompile| to start (single shot) compilation, and |:VimtexCompileOutput| to see the compilation output. @@ -5607,14 +5642,15 @@ compilation like |vimtex-compiler-latexmk|, so the only relevant commands are `tectonic` cleans up intermediate files like `.aux` and log files by default. However, VimTeX's backend invoke it with the flags `--keep-logs` and `--keep-synctex` which enables us to see the errors on the quickfix and it -gives us synctex support. Therefore, by default, |(vimtex-clean)| -and |:VimtexClean| clean these files. +gives us synctex support. Therefore, by default, |(vimtex-clean)| and +|:VimtexClean| clean these files. The compiler may be configured through the |g:vimtex_compiler_tectonic| option. -Some users may be interested in using a custom command for running `tectonic` in -a forced continuous mode by use of external tools like `entr` [0]. This could -be achieved with the |vimtex-compiler-generic| interface, e.g. like this: >vim +Some users may be interested in using a custom command for running `tectonic` +in a forced continuous mode by use of external tools like `entr` [0]. This +could be achieved with the |vimtex-compiler-generic| interface, e.g. like +this: >vim let g:vimtex_compiler_method = 'generic' let g:vimtex_compiler_generic = { @@ -5763,7 +5799,8 @@ allows one to use the location list. For `AsyncRun`, one may define a custom \ AsyncRun -auto=make -program=make The quickfix window that lists the linter errors and warnings can then be -opened by |:cwindow| and they can be jumped to by |:cn| and |:cp| respectively. +opened by |:cwindow| and they can be jumped to by |:cn| and |:cp| +respectively. Often, a syntax error in a BibTeX file is due to a missing comma after an entry. One may define a command to automatically add such missing commas, e.g. @@ -5861,8 +5898,8 @@ a suitable place, the path to it is specified as shown below. On a system like pip install --user yalafi -Configuration is controlled by the Vim dictionary |g:vimtex_grammar_vlty|. -As a minimal example, one could write in |vimrc|: >vim +Configuration is controlled by the Vim dictionary |g:vimtex_grammar_vlty|. As +a minimal example, one could write in |vimrc|: >vim let g:vimtex_grammar_vlty = {'lt_directory': 'path/to/LanguageTool'} set spelllang=en_gb @@ -6061,6 +6098,13 @@ may use the `MacVim` preset. However, it may be more convenient to use a nvim --headless -c "VimtexInverseSearch %line '%file'" +Depending on your system configuration, it may be necessary to specify the +path to the Vim/Neovim binary. For example, if Neovim was installed via +homebrew, one can specify the following in the Skim settings panel. >bash + + Command = /opt/homebrew/bin/nvim + Arguments = --headless -c "VimtexInverseSearch %line '%file'" + Inverse search is activated by pressing `Shift` and `Command`, then clicking the text you want to search. For more info on inverse search, see |vimtex-synctex-inverse-search|. @@ -6084,13 +6128,23 @@ Configuration: >vim For convenience, the above configuration is used by default on Windows if `SumatraPDF` is detected as executable. -Inverse search must be configured under `Settings --> Options` from within -SumatraPDF. Find the section `Set inverse search command-line` in the bottom -and use the following viewer configuration: >bash +To configure inverse search: + +1. Install SumatraPDF for all users and add to `PATH.` +2. Open "Settings -> Advanced Options" in SumatraPDF and edit the following + variables: >bash - cmd /c start /min "" vim -v --not-a-term -T dumb -c "VimtexInverseSearch %l '%f'" + InverseSearchCmdLine = cmd /c start /min "" nvim --headless -c "VimtexInverseSearch %l '%f'" + EnableTeXEnhancements = true +< + For Vim instead of Neovim, use: >bash - cmd /c start /min "" nvim --headless -c "VimtexInverseSearch %l '%f'" + InverseSearchCmdLine = cmd /c start /min "" vim -v --not-a-term -T dumb -c "VimtexInverseSearch %l '%f'" + +If you are using an old version of SumatraPDF where `Advanced Options` is not +available: open "Settings -> Options", Find the section "Set inverse search +command-line" in the bottom, and use the appropriate viewer configuration, +i.e. one of the `InverseSearchCmdLine` from step 2 above. Inverse search is activated with a double click in the PDF file. See |vimtex-synctex-inverse-search| for more info on inverse search. @@ -6216,8 +6270,8 @@ to go from a specific position in the pdf file to the corresponding position in vim (inverse search). To make synctex work, it must be enabled. VimTeX enables this by default by -passing `-synctex=1` on the command line, unless the user overrides the -option (see the `options` key for |g:vimtex_compiler_latexmk| or +passing `-synctex=1` on the command line, unless the user overrides the option +(see the `options` key for |g:vimtex_compiler_latexmk| or |g:vimtex_compiler_latexrun|). Alternatively, for |vimtex-compiler-latexmk|, one can put this in one's @@ -6320,9 +6374,9 @@ ONLINE *vimtex-latexdoc-online* I recommend the LaTeX Wikibook [0] as a good source of documentation for LaTeX. One should also know about the Comprehensive TeX Archive Network, or -CTAN [1], which is the central place for all kinds of material around TeX. -The long-existing unofficial LaTeX(2e) reference manual (latexref) can be -found online at [2]. +CTAN [1], which is the central place for all kinds of material around TeX. The +long-existing unofficial LaTeX(2e) reference manual (latexref) can be found +online at [2]. [0]: https://en.wikibooks.org/wiki/LaTeX [1]: https://ctan.org/ diff --git a/lua/vimtex/fzf-lua/init.lua b/lua/vimtex/fzf-lua/init.lua index ef4161e172b..4ba6b2f8c3e 100644 --- a/lua/vimtex/fzf-lua/init.lua +++ b/lua/vimtex/fzf-lua/init.lua @@ -1,4 +1,8 @@ -local M = {} +local utils = require "vimtex.utils.picker" +local fzf = require "fzf-lua" + +---@type table +local ansi = fzf.utils.ansi_codes -- A mapping of item types to Ansi color codes. -- The values must correspond to the keys in `M.ansi_escseq`, cf.: @@ -10,52 +14,23 @@ local color_map = { todo = "red", } ----Format the section/subsection/... numbers corresponding to an item into a string. ----@param n table The TOC entry ----@return string number -local function format_number(n) - local num = { - n.chapter ~= 0 and n.chapter or nil, - n.section ~= 0 and n.section or nil, - n.subsection ~= 0 and n.subsection or nil, - n.subsubsection ~= 0 and n.subsubsection or nil, - n.subsubsubsection ~= 0 and n.subsubsubsection or nil, - } - num = vim.tbl_filter(function(t) - return t ~= nil - end, num) - if vim.tbl_isempty(num) then - return "" - end - - -- Convert appendix items numbers to letters (e.g. 1 -> A, 2 -> B) - if n.appendix ~= 0 then - num[1] = string.char(num[1] + 64) - end - - num = vim.tbl_map(function(t) - return string.format(t) - end, num) +local M = {} - return table.concat(num, ".") -end +---@class VimtexFzfLuaOptions +---@field layers? string The layers to filter. Can be a substring of "ctli" +--- corresponding to content, todos, labels, and includes. +---@field fzf_opts? table list of options for fzf_exec ---Runs fzf-lua to select and navigate to from a list of TOC items. --- ----@param options table? Available options: ---- - layers: The layers to filter. Can be a substring of `ctli` ---- corresponding to content, todos, labels, and includes. ---- - fzf_opts: list of options for fzf_exec +---@param options VimtexFzfLuaOptions? ---@return nil M.run = function(options) - local layers = "ctli" - if options ~= nil and options["layers"] ~= nil then - layers = options["layers"] - options["layers"] = nil - end - - local fzf = require "fzf-lua" - local ansi = fzf.utils.ansi_codes + local layers = options and options.layers or "ctli" + local fzf_options = vim.tbl_extend("force", { + ["--delimiter"] = "####", + ["--with-nth"] = "{2} {3}", + }, options and options.fzf_opts or {}) local entries = vim.fn["vimtex#parser#toc"]() entries = vim.tbl_filter(function(t) @@ -68,20 +43,12 @@ M.run = function(options) v.file, v.line and v.line or 0, ansi[color_map[v.type]](v.title), - format_number(v.number) + utils.format_number(v.number) ) end, entries) - local fzfoptions = { - ["--delimiter"] = "####", - ["--with-nth"] = "{2} {3}", - } - if options ~= nil and options["fzf_opts"] ~= nil then - fzfoptions = vim.tbl_extend('force', fzfoptions, options["fzf_opts"]) - end - fzf.fzf_exec(fzf_entries, { - fzf_opts = fzfoptions, + fzf_opts = fzf_options, actions = { default = function(selection, o) local s = vim.tbl_map(function(t) diff --git a/lua/vimtex/snacks/init.lua b/lua/vimtex/snacks/init.lua new file mode 100644 index 00000000000..0db5945a08c --- /dev/null +++ b/lua/vimtex/snacks/init.lua @@ -0,0 +1,63 @@ +local utils = require "vimtex.utils.picker" +local snacks = require "snacks" + +local M = {} + +---@class VimtexSnacksOptions +---@field layers? string The layers to filter. Can be a substring of "ctli" +--- corresponding to content, todos, labels, and includes. +---@field preview? snacks.picker.Preview +---@field confirm? snacks.picker.Action.spec + +---Runs Snacks picker to select and navigate to from a list of TOC items. +--- +---@param options VimtexSnacksOptions? +---@return nil +M.toc = function(options) + local layers = options and options.layers or "ctli" + local preview = options and options.preview + or function(ctx) + if ctx.item.file then + snacks.picker.preview.file(ctx) + else + ctx.preview:reset() + ctx.preview:set_title "No preview" + end + end + local confirm = options and options.confirm + or function(picker, item) + picker:close() + vim.cmd.edit(item.file) + vim.api.nvim_win_set_cursor(0, item.pos) + vim.cmd.normal "zz" + end + + local entries = vim.fn["vimtex#parser#toc"]() + entries = vim.tbl_filter(function(t) + return string.find(layers, t.type:sub(1, 1)) ~= nil + end, entries) + + local items = vim.tbl_map(function(v) + local section_num = utils.format_number(v.number) + local display = section_num ~= "" and (section_num .. " " .. v.title) + or v.title + + return { + text = display, + file = v.file, + pos = { v.line or 1, 0 }, + type = v.type, + } + end, entries) + + snacks.picker.pick { + source = "vimtex_toc", + items = items, + format = "text", + layout = { preset = "ivy" }, + preview = preview, + confirm = confirm, + } +end + +return M diff --git a/lua/vimtex/utils.lua b/lua/vimtex/utils/init.lua similarity index 100% rename from lua/vimtex/utils.lua rename to lua/vimtex/utils/init.lua diff --git a/lua/vimtex/utils/picker.lua b/lua/vimtex/utils/picker.lua new file mode 100644 index 00000000000..e2af2fe96b3 --- /dev/null +++ b/lua/vimtex/utils/picker.lua @@ -0,0 +1,34 @@ +local M = {} + +---Format the section numbers corresponding to an item into a string. +--- +---@param n table The TOC entry +---@return string number +M.format_number = function(n) + local num = { + n.chapter ~= 0 and n.chapter or nil, + n.section ~= 0 and n.section or nil, + n.subsection ~= 0 and n.subsection or nil, + n.subsubsection ~= 0 and n.subsubsection or nil, + n.subsubsubsection ~= 0 and n.subsubsubsection or nil, + } + num = vim.tbl_filter(function(t) + return t ~= nil + end, num) + if vim.tbl_isempty(num) then + return "" + end + + -- Convert appendix items numbers to letters (e.g. 1 -> A, 2 -> B) + if n.appendix ~= 0 then + num[1] = string.char(num[1] + 64) + end + + num = vim.tbl_map(function(t) + return string.format(t) + end, num) + + return table.concat(num, ".") +end + +return M diff --git a/test/example-snacks/main.tex b/test/example-snacks/main.tex new file mode 100644 index 00000000000..a859e05c957 --- /dev/null +++ b/test/example-snacks/main.tex @@ -0,0 +1,128 @@ +\documentclass{book} + +\begin{document} + +% Folding of multiline comments +% +% -- Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam +% -- nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, +% -- sed diam voluptua. At vero eos et accusam et justo duo dolores et ea +% -- rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem +% -- ipsum dolor sit amet. + +\frontmatter + +\chapter{Preface} +Preface. + +\section{Acknowledgements} + +\chapter[Other]{Other frontmatter chapter} + +\tableofcontents + +\mainmatter + +\chapter*{Test chapter 1} +Test of starred chapter. + +\chapter{Test chapter 1} +This test document is created to test advanced TOC functionality. + +\begin{table} + \caption[foo]{bar} +\end{table} +\begin{table} + \caption[foo] {bar} +\end{table} + +\section{Test section 1} + +\subsection{sub} + +\subsubsection{subsub} + +\subsubsubsection{subsub} + +\subsection{Test sub section 1} + +\section{$\alpha$} + +\subsection{Test sub section 1} + +\subsection{Test sub section 2} +Some text. + +\chapter{Test chapter 2} + +\section{Testing TOC levels} +Testing more input and TOC levels. + +\subsection{Testing TOC sub levels} + +\subsubsection{Testing TOC sub sub levels} +Hello world. + +\subsubsection{Text $\Gamma^{r}(\ensuremath{{\mathbf{Z}}}_p^d,\mathbf{K})$} + +\subsection{Another test subsection} + +\subsubsection{Other text $\Gamma^{r}$} + +\section{Testing more appendix levels} +Testing more input and TOC levels. + +\subsection{Testing TOC sub levels} + +\appendix + +\chapter{Appendix 1} +This test document is created to test advanced TOC functionality. + +\section{Appendix subsection} + +\subsection{sub} + +\subsubsection{subsub} + +\subsubsubsection{subsub} + +\subsection{Test sub section 1} + +\chapter{Appendix 2} + +\section{Testing TOC levels} +Testing more input and TOC levels. + +\subsection{Testing TOC sub levels} + +\subsubsection{Testing TOC sub sub levels} +Hello world. + +\subsubsection{Text $\Gamma^{r}(\ensuremath{{\mathbf{Z}}}_p^d,\mathbf{K})$} + +\subsection{Another test subsection} + +\subsubsection{Other text $\Gamma^{r}$} + +\section{Testing more appendix levels} +Testing more input and TOC levels. + +\subsection{Testing TOC sub levels} + + +\backmatter + +\chapter{No numbers in backmatter 1} + +\section{Section 1} + +\section{Section 2} + +\chapter{No numbers in backmatter 2} + +\section{Section 1} + +\section{Section 2} + +\end{document} diff --git a/test/example-snacks/test.lua b/test/example-snacks/test.lua new file mode 100644 index 00000000000..80d27d4c70d --- /dev/null +++ b/test/example-snacks/test.lua @@ -0,0 +1,24 @@ +local snacks_path = "./snacks" +if not vim.uv.fs_stat(snacks_path) then + vim.fn.system { + "git", + "clone", + "--filter=blob:none", + "https://github.com/folke/snacks.nvim/", + snacks_path, + } +end +vim.opt.rtp:prepend(snacks_path) + +vim.opt.runtimepath:prepend "../.." +vim.opt.runtimepath:append "../../after" +vim.cmd [[filetype plugin indent on]] + +vim.keymap.set("n", "q", "qall!") +vim.keymap.set("n", "lt", function() + return require("vimtex.snacks").toc() +end) + +vim.g.vimtex_cache_persistent = false + +vim.cmd.edit "main.tex" diff --git a/test/test-commands/test-toggle-frac.vim b/test/test-commands/test-toggle-frac.vim index 8a0df5f3180..4fd6d1eb5d0 100644 --- a/test/test-commands/test-toggle-frac.vim +++ b/test/test-commands/test-toggle-frac.vim @@ -29,6 +29,7 @@ for [s:in, s:out] in [ \ ['$f(x+y)/g(z)$', '$\frac{f(x+y)}{g(z)}$'], \ ['$f(x)g(y)/h(z)$', '$f(x)\frac{g(y)}{h(z)}$'], \ ['$\dfrac{x+1}{x-1}$', '$(x+1)/(x-1)$'], + \ ['$\left(a/b\right)$', '$\left(\frac{a}{b}\right)$'], \] if s:in =~# '\/' call vimtex#test#keys('f/ltsf', s:in, s:out) diff --git a/test/test-compiler/test-executable-list.vim b/test/test-compiler/test-executable-list.vim new file mode 100644 index 00000000000..d95b7da8bf9 --- /dev/null +++ b/test/test-compiler/test-executable-list.vim @@ -0,0 +1,35 @@ +set nocompatible +let &rtp = '../..,' . &rtp +filetype plugin on + +let g:vimtex_compiler_latexmk = {'executable': ['latexmk', '-outdir=build']} + +call vimtex#log#set_silent() + +let g:status = 0 + +augroup test_executable_list + autocmd! + autocmd User VimtexEventCompileSuccess let g:status = 1 + autocmd User VimtexEventCompileFailed let g:status = 2 +augroup END + +silent edit test-builddir.tex + +if empty($INMAKE) | finish | endif + +silent VimtexCompileSS + +let s:n = 0 +while g:status < 1 && s:n < 100 + sleep 20m + let s:n += 1 +endwhile + +call assert_equal(1, g:status) +call assert_true(filereadable('build/test-builddir.pdf')) + +silent VimtexClean! +call assert_false(filereadable('build/test-builddir.pdf')) + +call vimtex#test#finished() diff --git a/test/test-env/test-toggle-math.tex b/test/test-env/test-toggle-math.tex index 2fcff3503c9..aebcf3946e5 100644 --- a/test/test-env/test-toggle-math.tex +++ b/test/test-env/test-toggle-math.tex @@ -14,6 +14,10 @@ 1+1=2 \end{equation} +\begin{equation*} + 1+1=2 +\end{equation*} + World \begin{equation} diff --git a/test/test-env/test-toggle-math.vim b/test/test-env/test-toggle-math.vim index 6ed8df9a668..79d70ffd8f6 100644 --- a/test/test-env/test-toggle-math.vim +++ b/test/test-env/test-toggle-math.vim @@ -7,7 +7,7 @@ nnoremap q :qall! silent edit test-toggle-math.tex -normal! 20G +normal! 24G call vimtex#env#toggle_math() call assert_equal([ \ 'World', @@ -15,7 +15,7 @@ call assert_equal([ \ '$f(x) = 1 + e^x$', \ '', \ '\end{document}', - \], getline(17, 21)) + \], getline(21, 25)) normal! 7G call vimtex#env#toggle_math() @@ -24,4 +24,24 @@ call assert_equal([ \ '\end{proof}', \], getline(5, 6)) +let g:vimtex_env_toggle_math_map = { + \ 'equation': 'align', + \} + +normal! 11G +call vimtex#env#toggle_math() +call assert_equal([ + \ '\begin{align}', + \ ' 1+1=2', + \ '\end{align}', + \], getline(10, 12)) + +normal! 15G +call vimtex#env#toggle_math() +call assert_equal([ + \ '\begin{align*}', + \ ' 1+1=2', + \ '\end{align*}', + \], getline(14, 16)) + call vimtex#test#finished() diff --git a/test/test-folding/test-envs.tex b/test/test-folding/test-envs.tex new file mode 100644 index 00000000000..8dd361c25b0 --- /dev/null +++ b/test/test-folding/test-envs.tex @@ -0,0 +1,10 @@ +\documentclass{article} +\begin{document} + +Hello World + +\begin{foo}{bar} +… +\end{foo} + +\end{document} diff --git a/test/test-folding/test-envs.vim b/test/test-folding/test-envs.vim new file mode 100644 index 00000000000..82bd7094501 --- /dev/null +++ b/test/test-folding/test-envs.vim @@ -0,0 +1,22 @@ +set nocompatible +let &rtp = '../..,' . &rtp +filetype plugin on + +set fillchars=fold:\ +set number +set foldcolumn=4 + +nnoremap q :qall! + +call vimtex#log#set_silent() + +let g:vimtex_fold_enabled = 1 + +silent edit test-envs.tex + +if empty($INMAKE) | finish | endif + +call assert_equal(1, foldlevel(7)) +call assert_match('\\begin{foo}{bar}', foldtextresult(6)) + +call vimtex#test#finished() diff --git a/test/test-syntax/test-biblatex.tex b/test/test-syntax/test-biblatex.tex index b9e78410ca8..7e79a2eff56 100644 --- a/test/test-syntax/test-biblatex.tex +++ b/test/test-syntax/test-biblatex.tex @@ -37,4 +37,6 @@ \volcite{1}[23]{worman} \volcite[23]{worman} +\autocites[7-9]{Hemingway1940}[3-4]{JiM2020} + \end{document} diff --git a/test/test-syntax/test-core.tex b/test/test-syntax/test-core.tex index 402996cb4d9..6d4da5c11a8 100644 --- a/test/test-syntax/test-core.tex +++ b/test/test-syntax/test-core.tex @@ -141,4 +141,9 @@ \section*{Acknowledgement} %mathzone end } +\foo[abc\\def] +\foo[abc\%def] +\foo[abc\\ def] +\foo[abc\% def] + \end{document} diff --git a/test/test-syntax/test-macrocode.dtx b/test/test-syntax/test-macrocode.dtx new file mode 100644 index 00000000000..394c9bb7924 --- /dev/null +++ b/test/test-syntax/test-macrocode.dtx @@ -0,0 +1,77 @@ +% \iffalse meta-comment +% +% Copyright (C) 1993-2025 +% +% The LaTeX Project and any individual authors listed elsewhere +% in this file. +% +% This file is part of the Standard LaTeX `Tools Bundle'. +% ------------------------------------------------------- +% +% It may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3c +% of this license or (at your option) any later version. +% The latest version of this license is in +% https://www.latex-project.org/lppl.txt +% and version 1.3c or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% +% The list of all files belonging to the LaTeX `Tools Bundle' is +% given in the file `manifest.txt'. +% +% \fi +% \iffalse +%% File: indent.dtx Copyright (C) 1991-1994 David Carlisle +% +%\NeedsTeXFormat{LaTeX2e} +%\ProvidesPackage{indentfirst} +% [2023/07/02 v1.03 Indent first paragraph (DPC)] +% +%<*driver> +\documentclass{ltxdoc} +\usepackage{indentfirst} +\GetFileInfo{indentfirst.sty} +\begin{document} +\title{The \textsf{indentfirst} package\thanks{This file + has version number \fileversion, last + revised \filedate.}} +\author{David Carlisle} +\date{\filedate} +\MaintainedByLaTeXTeam{tools} +\maketitle +\DocInput{indentfirst.dtx} +\end{document} +% +% \fi +% +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% \changes{v1.00}{1991/01/02}{Initial version} +% \changes{v1.01}{1992/06/26}{Re-issue for the new doc and docstrip} +% \changes{v1.02}{1994/01/31}{Re-issue for LaTeX2e} +% \changes{v1.03}{1995/11/23}{Typo fixes in documentation} +% +% \begin{abstract} +% Make the first line of all sections etc. be indented by the usual +% paragraph indentation. This should work with all the standard document +% classes. +% \end{abstract} +% +% \CheckSum{4}^^A Still I think a record:-) +% +% \MaybeStop{} +% +% \begin{macro}{\if@afterindent} +% \LaTeX\ uses the switch |\if@afterindent| to decide whether to indent +% after a section heading. We just need to make sure that this is always +% true. +% \begin{macrocode} +%<*package> +\let\@afterindentfalse\@afterindenttrue +\@afterindenttrue +% +% \end{macrocode} +% \end{macro} +% +% \Finale +% diff --git a/test/test-syntax/test-macrocode.vim b/test/test-syntax/test-macrocode.vim new file mode 100644 index 00000000000..1ebc76e186b --- /dev/null +++ b/test/test-syntax/test-macrocode.vim @@ -0,0 +1,7 @@ +source common.vim + +Edit test-macrocode.dtx + +if empty($INMAKE) | finish | endif + +call vimtex#test#finished() diff --git a/test/test-textobj-targets/test.ok b/test/test-textobj-targets/test.ok index ad9fdf00734..72f305eef30 100644 --- a/test/test-textobj-targets/test.ok +++ b/test/test-textobj-targets/test.ok @@ -8,8 +8,6 @@ cic_ a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{_} \cmd{ eeeeeee } \c cac_ a \cmd{ bbbbbbbb } \cmd{ ccccccc } _ \cmd{ eeeeeee } \cmd{ ffffffff } cAc_ a \cmd{ bbbbbbbb } \cmd{ ccccccc } _\cmd{ eeeeeee } \cmd{ ffffffff } cInc_ a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ _ } \cmd{ ffffffff } -cinc_ a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{_} \cmd{ ffffffff } -canc_ a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } _ \cmd{ ffffffff } cAnc_ a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } _\cmd{ ffffffff } c1Ilc_ a \cmd{ bbbbbbbb } \cmd{ _ } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } c1ilc_ a \cmd{ bbbbbbbb } \cmd{_} \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } @@ -20,16 +18,12 @@ c1ic_ a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{_} \cmd{ eeeeeee } \c c1ac_ a \cmd{ bbbbbbbb } \cmd{ ccccccc } _ \cmd{ eeeeeee } \cmd{ ffffffff } c1Ac_ a \cmd{ bbbbbbbb } \cmd{ ccccccc } _\cmd{ eeeeeee } \cmd{ ffffffff } c1Inc_ a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ _ } \cmd{ ffffffff } -c1inc_ a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{_} \cmd{ ffffffff } -c1anc_ a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } _ \cmd{ ffffffff } c1Anc_ a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } _\cmd{ ffffffff } c2Ilc_ a \cmd{ _ } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } c2ilc_ a \cmd{_} \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } c2alc_ a _ \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } c2Alc_ a _\cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } c2Inc_ a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ _ } -c2inc_ a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{_} -c2anc_ a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } _ c2Anc_ a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee }_ dIlc a \cmd{ bbbbbbbb } \cmd{ } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } dilc a \cmd{ bbbbbbbb } \cmd{} \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } @@ -40,8 +34,6 @@ dic a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{} \cmd{ eeeeeee } \cm dac a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ eeeeeee } \cmd{ ffffffff } dAc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ eeeeeee } \cmd{ ffffffff } dInc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ } \cmd{ ffffffff } -dinc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{} \cmd{ ffffffff } -danc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ ffffffff } dAnc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ ffffffff } d1Ilc a \cmd{ bbbbbbbb } \cmd{ } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } d1ilc a \cmd{ bbbbbbbb } \cmd{} \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } @@ -52,8 +44,6 @@ d1ic a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{} \cmd{ eeeeeee } \cm d1ac a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ eeeeeee } \cmd{ ffffffff } d1Ac a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ eeeeeee } \cmd{ ffffffff } d1Inc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ } \cmd{ ffffffff } -d1inc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{} \cmd{ ffffffff } -d1anc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ ffffffff } d1Anc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ ffffffff } d2Ilc a \cmd{ } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } d2ilc a \cmd{} \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } @@ -64,8 +54,6 @@ d2ic a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeee d2ac a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } d2Ac a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } d2Inc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ } -d2inc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{} -d2anc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } d2Anc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } yIlc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } 'ccccccc' yilc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } ' ccccccc ' @@ -76,8 +64,6 @@ yic a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeee yac a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } '\cmd{ xxxxxx }' yAc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } '\cmd{ xxxxxx } ' yInc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } 'eeeeeee' -yinc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } ' eeeeeee ' -yanc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } '\cmd{ eeeeeee }' yAnc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } '\cmd{ eeeeeee } ' y1Ilc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } 'ccccccc' y1ilc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } ' ccccccc ' @@ -88,8 +74,6 @@ y1ic a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeee y1ac a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } '\cmd{ xxxxxx }' y1Ac a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } '\cmd{ xxxxxx } ' y1Inc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } 'eeeeeee' -y1inc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } ' eeeeeee ' -y1anc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } '\cmd{ eeeeeee }' y1Anc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } '\cmd{ eeeeeee } ' y2Ilc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } 'bbbbbbbb' y2ilc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } ' bbbbbbbb ' @@ -100,8 +84,6 @@ y2ic a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeee y2ac a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } '' y2Ac a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } '' y2Inc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } 'ffffffff' -y2inc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } ' ffffffff ' -y2anc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } '\cmd{ ffffffff }' y2Anc a \cmd{ bbbbbbbb } \cmd{ ccccccc } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } ' \cmd{ ffffffff }' vIlc a \cmd{ bbbbbbbb } \cmd{ _______ } \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } vilc a \cmd{ bbbbbbbb } \cmd{_________} \cmd{ xxxxxx } \cmd{ eeeeeee } \cmd{ ffffffff } diff --git a/test/test-textobj-targets/test.vim b/test/test-textobj-targets/test.vim index ab2ca335dc3..4ec13c97836 100644 --- a/test/test-textobj-targets/test.vim +++ b/test/test-textobj-targets/test.vim @@ -13,10 +13,10 @@ silent edit test.tex if empty($INMAKE) | finish | endif -" IMPORTANT NOTE 2025-06-28 -" As of neovim 0.12 there is a default mapping clash that prevents -" vin, v1in, v2in, van, v1an, v2an of working. There are therefore ignored in -" the tests. +" IMPORTANT NOTE 2025-06-28; 2025-12-17 +" As of neovim 0.12 there are default mapping clashes that prevents "in" and +" "an" from working, see `:h v_an` and `:h v_in`. +" There are therefore ignored in the tests. function! s:testVimtexCmdtargets(name) silent! edit! @@ -28,7 +28,7 @@ function! s:testVimtexCmdtargets(name) for iaIA in ['I', 'i', 'a', 'A'] let l:motion = cnt . iaIA . lastnext . 'c' if (operator ==# 'c' && l:motion =~# '^2.c$') - \ || (operator ==# 'v' && l:motion =~# '[ia]nc$') + \ || (l:motion =~# '[ia]nc$') continue endif diff --git a/test/test-textobj/test-other.vim b/test/test-textobj/test-other.vim index fd42f70533c..745a18ab2a8 100644 --- a/test/test-textobj/test-other.vim +++ b/test/test-textobj/test-other.vim @@ -23,4 +23,64 @@ call vimtex#test#keys('f\dac', \ 'a + \; f', \ 'a + f') +call vimtex#test#keys('di$', + \ 'Hello world! $(x)$', + \ 'Hello world! $$') + +call vimtex#test#keys('da$', + \ 'Hello world! $(x)$', + \ 'Hello world! ') + +call vimtex#test#keys('jjda$', + \ [ + \ '\documentclass{minimal}', + \ '\begin{document}', + \ 'Hello world!', + \ '\end{document}', + \ ], + \ [ + \ '\documentclass{minimal}', + \ '\begin{document}', + \ 'Hello world!', + \ '\end{document}', + \ ], + \) + +call vimtex#test#keys('jjfxda$', + \ [ + \ '\documentclass{minimal}', + \ '\begin{document}', + \ '\begin{equation} x \end{equation}', + \ '$y$', + \ '\end{document}', + \ ], + \ [ + \ '\documentclass{minimal}', + \ '\begin{document}', + \ '', + \ '$y$', + \ '\end{document}', + \ ], + \) + +call vimtex#test#keys('jjda$', + \ [ + \ '\documentclass{minimal}', + \ '\begin{document}', + \ 'z', + \ '\begin{equation} x \end{equation}', + \ '$y$', + \ '\end{document}', + \ ], + \ [ + \ '\documentclass{minimal}', + \ '\begin{document}', + \ 'z', + \ '', + \ '$y$', + \ '\end{document}', + \ ], + \) + + call vimtex#test#finished()