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

Vimtex API function that returns name of the enclosing environment, command or region #1981

Closed
poetaman opened this issue Mar 7, 2021 · 6 comments

Comments

@poetaman
Copy link

poetaman commented Mar 7, 2021

Is there a Vimtex API function that returns the name of enclosing environment, or command? So for a document like the following:

\documentclass[]{}

\usepackage[]{}
\begin{document}

\begin{helloworld}[]
    \mycommandfour{}
\end{helloworld}

 \mycommandthree{}
 \mycommandseven{}

\end{document}

the returned names would be like: documentclass, when the cursor is in the [<optionlist>]{<argument>} part of \documentclass, and so on.

Also, in any region before \begin{document}, while outside a command or environment, the returned string would be preamble. And anywhere after \end{document} would be postamble.

Motivation: Such a function can then be used to set custom completion dictionary based on the name of environment/command. That way user can have a one dictionary per tex enviornment/command to know what key-values it can accept in the optional argument. Not the most robust, but good enough to do the job.

So for instance, if environment helloworld can take a comma separated list consisting ofkey=val, and if the valid keys are width=<width>, height=<height>, hitting some C-x C-<something> would bring up completion list that has the valid key names for helloworld environment.

PS! It would be users responsibility to maintain dictionary of valid key names for their environments/commands, and perhaps share it with world while releasing a latex package with instructions on how users can use this feature with Vim & Vimtex.

@poetaman poetaman changed the title Vimtex API function that returns name of the enclosing environment, or command Vimtex API function that returns name of the enclosing environment, command or region Mar 7, 2021
@lervag
Copy link
Owner

lervag commented Mar 7, 2021

Is there a Vimtex API function that returns the name of enclosing environment, or command?

Yes. There are couple of relevant functions:

  • vimtex#delim#get_surrounding('tex_env'): This gets the surrounding environment. It returns two elements: the opening and the closing parts. An example:

    " Return values are dictionaries
    let [l:open, l:close] = vimtex#delim#get_surrounding('env_tex')
    
    " Empty dicts mean we did not find a surrounding environment
    if empty(l:open) | return | endif
    
    " The dicts have several attributes, the most important are probably these:
    echo l:open.name
    echo l:open.lnum
    echo l:open.cnum
    
    " See autoload/vimtex/delim.vim:s:get_delim() for more information
  • vimtex#cmd#get_current() and the variants #get_next(), #get_prev(), and #get_at(pos)): These functions gets information about a given command. It will consume the name \name, any number of directly following option groups [...], then any number of argument groups {...}. The groups can be separated by whitespaces. Note that this is not LaTeX general, as there are commands that do not take options and arguments, so e.g. \cmd{text} does not necessarily mean that {text} is an argument. VimTeX does not care and parses this as a command with one argument.

    An example, similar to above (less comments):

    let l:cmd = vimtex#cmd#get_current()
    if empty(l:cmd) | return | endif
    
    echo l:cmd.name
    echo l:cmd.pos_start
    echo l:cmd.pos_end
    echo l:cmd.args
    echo l:cmd.opts

@poetaman
Copy link
Author

poetaman commented Mar 8, 2021

@lervag Thanks!! The way I am able to distinguish whether currently cursor is in a command, or environment is to first check the command it is in, if the command is \begin, then cursor is actually in environment & I look for "open" environment name; if the command is something different like \foo ten cursor is in command, and I just use that command name.

One observation: I thinklet l:cmd = vimtex#cmd#get_current() prints text before the cursor on that line in :messages. The behavior doesn't seem consistent/reproducible all the time, so I am not sure. I have tested it enough to narrow down to this. If it is the case. can we disable it? It just adds an unasked line in messages.

P.S. I wonder the reason scrolling with VimTeX is slow is because VimTeX evaluates this (or other information) for all cursor moves? I think there could be an opening for performance improvement? Like for instance, instead of evaluating a bunch of information when cursor moves, VimTeX could evaluate what it needs when that information is needed (like in a VimTeX function). The rationale behind this being, most of the time users are not using VimTeX functions & are doing regular editing of code. Given regular editing involves a lot of scrolling, not slowing down scrolling is always a good idea.

@lervag
Copy link
Owner

lervag commented Mar 8, 2021

@lervag Thanks!! The way I am able to distinguish whether currently cursor is in a command, or environment is to first check the command it is in, if the command is \begin, then cursor is actually in environment & I look for "open" environment name; if the command is something different like \foo ten cursor is in command, and I just use that command name.

I think a simpler solution that should work is to compare the positions of the result of vimtex#delim#get_current and vimtex#cmd#get_current. You can use vimtex#pos#larger to compare positions. E.g.: vimtex#pos#larger(l:open, l:cmd.pos_start) should return true if the l:open has a buffer position larger than l:cmd.pos_start.

One observation: I thinklet l:cmd = vimtex#cmd#get_current() prints text before the cursor on that line in :messages. The behavior doesn't seem consistent/reproducible all the time, so I am not sure. I have tested it enough to narrow down to this. If it is the case. can we disable it? It just adds an unasked line in messages.

I'm not fully sure what you mean. But perhaps there's a spurious echo or echom from some debugging that is forgotten in the code?

P.S. I wonder the reason scrolling with VimTeX is slow is because VimTeX evaluates this (or other information) for all cursor moves? I think there could be an opening for performance improvement? Like for instance, instead of evaluating a bunch of information when cursor moves, VimTeX could evaluate what it needs when that information is needed (like in a VimTeX function). The rationale behind this being, most of the time users are not using VimTeX functions & are doing regular editing of code. Given regular editing involves a lot of scrolling, not slowing down scrolling is always a good idea.

The slowdown is probably caused by the matchparen functionality. You can check that by disabling it with g:vimtex_matchparen_enabled (or vimtex#matchparen#disable()). There's actually a plugin based on this functionality that is probably better: https://github.com/andymass/vim-matchup. I use that myself, and I don't have any noticable delays.

Notice that this is also documented (see e.g. vimtex-faq-slow-matchparen). However, I can understand that it is easy to miss this in the large amount of text in the docs...

@poetaman
Copy link
Author

poetaman commented Mar 9, 2021

@lervag

I think a simpler solution that should work is...

Thanks, will try updating my example with the functions you mention.

I'm not fully sure what you mean. But perhaps there's a spurious echo or echom from some debugging that is forgotten in the code?

Yep that's what I think is going on. I couldn't find anything in my function s:printVimTeXScope() at #1983 (comment) that should be causing that. I even tried adding <silent> to inoremap <buffer> <expr> <C-r> <SID>printVimTeXScope(), but it just changes the instance at which spurious message is printed.

The slowdown is probably caused by the matchparen functionality

Thanks!! a lot, that fixed scrolling slowness completely!!

@lervag
Copy link
Owner

lervag commented Mar 9, 2021

Yep that's what I think is going on. I couldn't find anything in my function s:printVimTeXScope() at #1983 (comment) that should be causing that. I even tried adding <silent> to inoremap <buffer> <expr> <C-r> <SID>printVimTeXScope(), but it just changes the instance at which spurious message is printed.

Ok, I'll look into it and see if I can find the culprit :)

Thanks!! a lot, that fixed scrolling slowness completely!!

Happy to hear it.

By the way: I suggest you read the Github Markdown specs. For inline code, it is sufficient to use single backquotes, i.e. `inline code`. For quotes, you should use >.

@lervag
Copy link
Owner

lervag commented Mar 9, 2021

Ok, I'll look into it and see if I can find the culprit :)

I've looked into it and I can't find anything that should echo anything here. If you can reproduce it reliably, please feel free to open a new issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants