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

Already on GitHub? Sign in to your account

delimitMate breaks the repeat command #138

neitanod opened this Issue Jul 29, 2013 · 37 comments


None yet

If in normal mode you type:


You get:


inserted into the document. But if you then go down a line and press the "repeat" command (the dot) you just get:


inserted into the document.

¿Shouldn't you get everything you typed inserted again?

qstrahl commented Jul 29, 2013

Ideally, yes, but vim lacks decent support for hooking custom edit commands into the repeat command. There is vim-repeat, if plugin maintainers decide to make use of it. I'm not sure if delimitMate uses it.


Raimondi commented Jul 29, 2013

@qstrahl is right about Vim being the issue here. vim-repeat works for ex and normal mode commands, I don't see how to use it inside an insert session.

Bram proposed a solution for this but it hasn't been implemented yet.

@Raimondi Raimondi closed this Jul 29, 2013


blueyed commented Jul 30, 2013

@Raimondi can you please re-open the issue?
Although it appears to need a fix in Vim itself, it's still an issue with delimitMate.

Would it be an option to use <C-o> (used to issue normal commands without leaving INSERT mode) and make vim-repeat handle the work of repeating?


Raimondi commented Jul 30, 2013

I don't think that approach would work, you need to "join" the buffer change history items used in the insert session, and only those that should be joined (good luck with that!). vim-repeat can't do that.

I don't see any way to fix this issue with viml, but I'll leave it open for a while.

@Raimondi Raimondi reopened this Jul 30, 2013


blueyed commented Jul 30, 2013

I see.

The help mentions the following (:h ins-special-special):

Using CTRL-O splits undo: the text typed before and after it is undone
separately.  If you want to avoid this (e.g., in a mapping) you might be able
to use CTRL-R = |i_CTRL-R|.  E.g., to call a function: >
    :imap <F2> <C-R>=MyFunc()<CR>

I guess this has been tried already, or is it not appropriate here?!


Raimondi commented Jul 30, 2013

The problem is not inserting the text, it's that we either need to move the cursor back after inserting the closing delimiter or insert it directly after the cursor.


blueyed commented Jul 31, 2013

Isn't it possible to also move the cursor within the function, via normal h etc?

qstrahl commented Jul 31, 2013

Could also use the cursor function.


Raimondi commented Jul 31, 2013

Yes to both of you, but I wasn't clear about the issue. The problem with moving the cursor is that vim will start a new entry in the change history, and the same problem with using setline() from <C-R>=. So, we need to move the cursor or insert text after the cursor while keeping vim from breaking the insert session. That's why Bram's suggestion would be the most appropriate way to solve it, Vim wouldn't split the insert session when the cursor moves inside the inserted text anymore.

@Raimondi Raimondi closed this Dec 19, 2013


Raimondi commented Jan 12, 2014

No, as explained above.

I think I've found a way to "fix" undo/redo:

inoremap ( ()<esc>:undojoin<cr>i

Since <esc> moves the cursor to the left, the arrow keys are never touched.

Repeat . still doesn't work with this approach, but that could be solved easily with tpope's repeat.vim (I can send a PR if you like).

I've only tested on Vim 7.4.155 but this should work with previous versions.

edit: simplified map, no need for <C-r>='()'<cr>

@justinmk justinmk referenced this issue Feb 19, 2014


atomic undo #171

Also, this achieves the "pass through" behavior when the closing paren is reached:

inoremap ) <C-\><C-o>:undojoin<cr><C-\><C-o>a

This is just a proof of concept, since of course it isn't checking to see if the next char is actually a paren.


Raimondi commented Feb 20, 2014

This looks really nice! a PR would be great, just keep in mind that the issue with the closing paren was fixed with #169. So, just the opening paren and repeat need fixing.

@Raimondi Raimondi reopened this Feb 20, 2014

This does indeed fix undo, but unfortunately it introduces a different problem with block-inserts. Let's say you select a block with Ctrl-V and want to change it with c or insert something at the beginning with I. Then when you type one of the delimiters this mapping will leave insert mode, causing the text entered so far to be inserted in all of the selected lines, but it won't continue doing so after the mapping finishes. This means that everything that is entered after the delimiter will only appear on the current line.

Good catch. I wonder if there is a way to detect visual-block insert-mode...

I can't find a way to detect that specific mode, mode() just return i like with normal insert mode, and visualmode() doesn't get cleared after the replacement finishes. The only way I've found that may work is use an autocommand:

autocmd InsertLeave * call visualmode(1)

and then check for mode() == 'i' && visualmode() == '�^V'. But that autocommand may have unintended side-effects.


blueyed commented May 6, 2014

@majutsushi @justinmk
Any updates? Have you been using/testing the autocommand approach?

And the help for mode() states that it would return ^V (and does so for me).

Tested with au CursorMoved * echom "v:" visualmode() "m:" mode() "m(1):" mode(1).

(For some reason mode(1) does not return the full name like stated in the help, also for normal mode).

Can we have a pull request for this please?
This would make it easier to test and improve it.

justinmk commented May 7, 2014

@blueyed after @majutsushi 's edge case I never got around to implementing. I was hoping to find a reliable way to address the edge case (even posted on vim_use). If what you say is true then that solves the edge case I think. PR tonight.

As far as I can see mode() only returns ^V while you're actually still in visual mode, not after you've pressed something like I or c to write the new/replacement text, and that's where you actually want to detect the mode to change the behaviour. So I don't think this is going to work, but I'd be happy to be proven wrong.


blueyed commented May 7, 2014

I've just tested it with the autocommand posted above, and it appeared to work.

But then it's just that the autocommand gets not executed after I anymore.

It appears that visualmode() might be used to in this case from the InsertEnter autocommand.

For debugging/inspection:

au CursorMoved,InsertEnter * echom "v:" visualmode() "m:" mode() "m(1):" mode(1) "col:" col(".")

You could use a CursorMovedI autocommand, which would show that mode() returns i after an I (as should be expected). And since the mapping are only useful in insert mode just checking mode() in them won't work.

But by using InsertEnter you could do something like this:

autocmd InsertEnter * let b:pairs_visualmode = visualmode()
autocmd InsertLeave * unlet! b:pairs_visualmode

This would work similarly to the autocommand I posted above but without the potential side effects. You could then put something like this into the pair handling functions:

    if get(b:, 'pairs_visualmode', '') == '�^V'
        return a:char

This would essentially disable the plugin in block-insert mode, but it would be better than breaking block-insert mode. I don't have time to properly implement and test this and send a pull request at the moment, but it sounds like it could work.


blueyed commented May 8, 2014

Thanks @majutsushi for clarifying things!

Will you do the PR soonish? Otherwise I might do it.

justinmk commented May 9, 2014

@blueyed Haven't had time, sorry. Bit of a debacle the last few days.

moll commented May 31, 2014

Any news on this?

@blueyed blueyed added a commit to blueyed/delimitMate that referenced this issue Jun 15, 2014

@blueyed blueyed Fix undo via `<Esc>:undojoin<cr>i` (applied via `s:get_left_motion`)
While this fixes the undo chaining in general, `<Left>` is still being
used in block-wise visual mode, where exiting insert mode would also
exit the block-wise mode.

Ref: Raimondi#138

@blueyed blueyed added a commit to blueyed/delimitMate that referenced this issue Jun 15, 2014

@blueyed blueyed Fix undo via `<Esc>:undojoin<cr>i` (applied via `s:get_left_motion`)
While this fixes the undo chaining in general, `<Left>` is still being
used in block-wise visual mode, where exiting insert mode would also
exit the block-wise mode.

Ref: Raimondi#138

blueyed commented Jun 15, 2014

I have created a pull request finally.

But it is missing support for repeating.

It seems like vim-repeat does not work with expression mappings, like the one being used with delimitMate (first it would append "0" when chained, which could be fixed, but then it expects to be called after the text has been changed anyway).

exec 'inoremap <expr><silent> <Plug>delimitMate' . ld
                            \. ' <SID>TriggerAbb().delimitMate#ParenDelim("' . escape(rd, '|') . '")'

There might be another method of using it..

Do you have it working already? (since you've mentioned it earlier)


blueyed commented Sep 2, 2014

For reference, vim-repeat has this text about its integration (from https://github.com/tpope/vim-repeat):

Adding support to a plugin is generally as simple as the following command at the end of your map functions.
silent! call repeat#set("\<Plug>MyWonderfulMap", v:count)

I have not investigated further, but would appreciate any feedback on this issue (and the PR (#184)).

@justinmk justinmk referenced this issue in cohama/lexima.vim Nov 8, 2014


breaks undo #2

@blueyed blueyed added a commit to blueyed/delimitMate that referenced this issue Nov 26, 2014

@blueyed blueyed Fix undo via `<Esc>:undojoin<cr>i` (applied via `s:get_left_motion`)
While this fixes the undo chaining in general, `<Left>` is still being
used in block-wise visual mode, where exiting insert mode would also
exit the block-wise mode.

Ref: Raimondi#138

@lencioni lencioni added a commit to lencioni/dotfiles that referenced this issue Feb 8, 2015

@lencioni lencioni Vim: remove delimitMate plugin
I almost really like this plugin, but it sometimes gets in the way and
also breaks the repeat command [1], which I really don't like. I'm going
to remove it for a while and see how I get along without it.

[1]: Raimondi/delimitMate#138

Just wanted to express enthusiasm for this being addressed at some point in the future 👍

There's a patch on vim_dev that allows arrow-key movements on a single line without breaking undo. I'm going to merge it into Neovim and be done with it.


blueyed commented May 9, 2015

What's the status of this patch? Is it merged into Neovim?
Can you provide a reference otherwise?

justinmk commented May 9, 2015

@blueyed Here's a reference: neovim/neovim#1025 (comment)

The patch affects only files we have not changed much, so shouldn't be difficult to port.

Konfekt commented Jun 23, 2015

How about endorsing the prompt merge of the existent patch into Vim at

https://groups.google.com/forum/m/#!topic/vim_dev/gBumYDSEJoo ?

chrisbra commented Sep 2, 2015

As of 7.4.859 the fix has been included.

Konfekt commented Sep 2, 2015

Thanks! Does the patch need further adjustments in the plugin to make the dot and undo operator work?

chrisbra commented Sep 2, 2015

Am 2015-09-02 16:45, schrieb Konfekt:

Thanks! Does the patch need further adjustments in the plugin to make
the dot and undo operator work?

Yes. You need to use U to move without breaking undo/redo.
See the help section in the patch for details.


@Raimondi Raimondi closed this in #227 Sep 7, 2015

Repeat still does not work with the latest delimitMate. Please re-open this issue.


blueyed commented Oct 2, 2015

Are you using Vim with the required patch?

FYI, Vim patch 7.4.859 is in Neovim now. neovim/neovim#3306

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment