2

Suppose I have a line of LaTeX code as follows

We have two equations $E=mc^2$ and $F=ma$.

How do I quickly jump between inline math equations? Let's say I'm editing the first equation $E=mc^2$, how do I quickly move my cursor to be inside the second equation $F=ma$? Obviously I can do fF is this case, but I would like a more systematic way to help me navigate to the next $..$

  • As a naive start: /\$[^$]*\$ – D. Ben Knoble Mar 21 at 13:20
  • 1
    @D.BenKnoble But this will match $ and $, which is obviously not the desired jump target... – filbranden Mar 21 at 15:33
  • What about going backward? I tried to do something with lookahead, I don't know vim-regex much, it didn't work. – Mahbub Alam May 22 at 23:01
2

Combine vim-ninja-feet and targets.vim

Preliminary steps

  1. Change $ from separator to quote

    augroup mytargets
        autocmd!
        autocmd User targets#mappings#user call targets#mappings#extend({
            \ '$':{'quote': [{'d': '\$'}]},
            \ })
    augroup END
    

    I do not know how to make this change filetype-specific. If someone knows this, feel free to adjust this section

  2. vimtex user
    Since the OP has added the tag plugin-vimtex, I assume that the text objects i$ and a$ are defined by vimtex. To have consistent experience you should unmap them to use i$ and a$ from targets.vim. To do this add following lines to ~/vim/after/ftplugin/tex.vim:

    " Unmap vimtex versions of i$ and a$ to use versions of targets.vim:
    xunmap <buffer> i$
    ounmap <buffer> i$
    xunmap <buffer> a$
    ounmap <buffer> a$
    

Now we can combine:

z[/z] + in$,il$, ...

To illustrate how this works, consider the line from the OP

We have two equations $<CURSOR>E=mc^2$ and $<JUMP HERE>F=ma$.

Return to normal mode when in the first equation and then press

z[in$

to jump at the beginning of the next equation and switch into insert mode.

You have many variations at your disposal:

  • z] + in$ jump to the end within the next equation
  • z] + il$ jump to the end within the previous equation
  • z] + 2in$ jump to the end within the 2nd next equation
  • ...

Unfortunately, at the moment staying in normal mode is not supported by vim-ninja-feet (see issue 3 'Make it work in Normal mode' on github).

Relevant excerpts from the docs:

vim-ninja-feet:

z[{motion}              Enter |Insert| mode at the beginning of {motion}. For
                        |characterwise| motions, this is like pressing `i`;
                        for |linewise| motions, this is like pressing `O`.


z]{motion}              Enter |Insert| mode at the end of {motion}. For
                        |characterwise| motions, this is like pressing `a`;
                        for |linewise| motions, this is like pressing `o`.

targets.vim provides many text objects and many variations of them, please consult the webpage and the full documentation. I just add the beginning of the section about the quote text objects:

QUOTE TEXT OBJECTS                                *targets-quote-text-objects*

These text objects are similar to the built in text objects such as |i'|.
Supported trigger characters:

    '         (work on single quotes)
    "         (work on double quotes)
    `         (work on back ticks)

These quote text objects try to be smarter than the default ones. They count
the quotation marks from the beginning of the line to decide which of these
are the beginning of a quote and which ones are the end.

If you type `ci"` on the `,` in the example below, it will automatically skip
and change `world` instead of changing `,` between `hello` and `world`.

    join("hello", "world") ~
         └─────┘  └─────┘     proper quotes
               └──┘           false quotes


Quote text objects work over multiple lines and support |targets-quote-seek|.

Following features of targets.vim are in particular relevant in this context:

| improve this answer | |
1

You can use a match for a \$, using a look-behind to match other equations enclosed in pairs of $s. That way you'll know you're always matching the first $ of each equation.

This search will work:

/\(^\([^$]\|\$[^$]\+\$\)\+\)\@<=\$

See :help /\@<= for the look-behind operator.

The rest of the regex should be (relatively) straightforward, the look-behind part is matching sequences of $...$ or characters other than $. The look-behind is anchored at the beginning of the line, to ensure it's capturing all pairs in the line correctly.

It works as expected on the example you provided.

You can use "very magic" mode to avoid having to escape so many metacharacters with backslashes:

/\v(^([^$]|\$[^$]+\$)+)@<=\$

You can also consider extending the match to the whole expression inside $...$, that way search highlighting will be more useful.

You can consider adding mappings to these commands (search it forward and backward) when editing LaTeX files, since typing the whole search expression is definitely cumbersome. Consider adding the mappings in both directions.

| improve this answer | |
  • 1
    The mapping is just /... then you can use n and N – D. Ben Knoble Mar 22 at 13:08
  • What about going backward? – Mahbub Alam May 23 at 17:50
  • @MahbubAlam What's the problem going backwards? It should just work, doesn't it? If it doesn't for you, can you be more specific about it? – filbranden May 23 at 18:19
  • 1
    I understand that this behaviour is the same as w and b. – Mahbub Alam May 23 at 22:04
  • 1
    @MahbubAlam Also same as ?word goes to the w even if your cursor is in one of the other letters of word... So that's consistent with how ? otherwise works and it's actually hard to come up with a regex that would go to the previous block directly... But see Hotschke's answer using vim-ninja-feet + targets.vim, I think that one does exactly what you want, if you use the p modifier for "previous" block... – filbranden May 24 at 0:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.