4

I understand that we can use da{ to delete a whole {} block in vim. I am wondering if there is a corresponding version with { replaced by $ (similarly for di{) as this would be very useful for people typing latex with vim (math enviroments are enclosed between 2 $ symbols).

I tried to make my own

map da$ ?\$?<CR>v/\$/e<CR>d

but it's very slow.

3

Such a mapping is quite hard to get right, including all corner cases.

Typically, you should try to use an "operator-pending" mapping to define the a$ part, so you can use it in da$ but also in commands such as ya$, ca$, etc. In fact if you define other custom commands that take a "motion", then a$ will be a valid one.

A naive solution using an operator-pending mapping and assuming the $...$ expression is in a single line (for inline math in TeX/LaTeX) would be:

onoremap <silent> a$ :<C-U>normal! F$v,<CR>

But this has some shortcomings, such as it only working from inside the $...$ block (not from the cursor being right at the first $) or if you have two $...$ blocks on the same line this mapping will select the text between the two if your cursor is on that region.

You can get Vim to use more advanced logic to select the delimiters for such a region very precisely, but that probably involves writing a Vimscript function to handle all corner cases correctly. (You can also do that to handle more complex matches such as a math environment covering multiple lines.)

Fortunately, there are plug-ins which can help you with that!

If you want to define your own, then the vim-textobj-user plug-in can help you create new operator-pending mappings (and also visual mappings) based on patterns you define. This plug-in hides a lot of the complexity of these mappings in a way that avoids many of the pitfalls. Also, in many cases, using a simple regex to define the region to use as a text object is a much simpler approach.

If you're looking specifically into TeX/LaTeX, then consider the vimtex plug-in, which already defines an a$ text object for inline math structures. Also an ae for LaTeX environments, which you might find useful as well.

| improve this answer | |
3

If you are not against plugins, you can try targets.vim https://github.com/wellle/targets.vim

It has $ separator text object:

SEPARATOR TEXT OBJECTS                        *targets-separator-text-objects*

These text objects are based on single separator characters like the comma in
one of our |targets-examples|. The text between two instances of the separator
character can be operated on with these targets.

Supported separators:

    , . ; : + - = ~ _ * # / | \ & $ ~

Separator text objects work over multiple lines and support
|targets-separator-seek|.

| improve this answer | |
  • 1
    Maybe it is worthwhile to point out that a user can change $ to become a quote text object in targets.vim. I have shown this in my answer here. – Hotschke Apr 7 at 12:48
2

This solves most corner cases

onoremap <expr> a$ col('.') >= (col('$') - 1) && getline('.')[0] == '$' ? ':<C-U>normal! Bf$v,<CR>' : ':<C-U>normal! wBf$v,<CR>'
onoremap <expr> i$ col('.') >= (col('$') - 1) && getline('.')[0] == '$' ? ':<C-U>normal! Bt$v,<CR>' : ':<C-U>normal! wBt$v,<CR>'

Above operator-pending mappings solve most corner cases:

  • cursor and $ at the beginning of the line,
  • cursor at the opening $,
  • cursor in between $ … $,
  • multiple white space in a $ … $ block,
  • cursor at the closing $,
  • multiple $ … $ blocks on the same line,
  • cursor and $ at the end of the line,
  • closing $ immediately followed by any other character,
  • closing $ at the end of the buffer,
  • empty line.

What still remains possible, is to select text in between two $ … $ blocks. In other words, there is no strict $ … $ environment detection.

However, in my personal opinion, this is quite acceptable. After all, it saves one from installing a large plug-in, which may import other problems. It comes in quite handy for editing TeX math formulae in Markdown.

| improve this answer | |
  • 2
    Does it work on the last character of the buffer? What about if it's on a blank line? (Corner cases are aplenty with Vim...) – filbranden May 6 at 0:05
  • 1
    @filbranden Excellent comment! I updated my answer for these two additional corner cases. It works like a charm now. – Serge Stroobandt May 6 at 10:16
  • 1
    Development of this answer essentially took place here at vi.stackechange.com To better understand how these mappings work, click here and here. – Serge Stroobandt May 6 at 21:12
0

I tried these and seemed to work and be fast:

nnoremap ca$ f$vF$c "Change with $
nnoremap da$ f$vF$d "Delete with $
nnoremap ci$ f$hvF$lc "Change in $
nnoremap di$ f$hvF$lc "Delete in $

This assumes that you can't have a $ inside $..$. What it does is it searches for the first next occurance of $ then does a visual block. Then does a reverse search to find the previous $. Having selected visually the $...$ it just does a c for change or d for delete. Same for the 2 below which all they do is they move one to the left and to the right so it doesn't select the $.

| improve this answer | |
  • 2
    As filbranden points out, with onoremap you only need two mappings – D. Ben Knoble Apr 7 at 13:23
0

You could also have operators for the next/previous pair of '$':

onoremap in$ :<c-u>normal! f$lvt$<cr>
onoremap an$ :<c-u>normal! f$vf$<cr>
onoremap iN$ :<c-u>normal! F$hvT$<cr>
onoremap aN$ :<c-u>normal! F$vF$<cr>

(With inside / around variants)

| improve this answer | |

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.