Re: Any automatic bracket-insertion plugins not breaking undo?

406 views
Skip to first unread message

Christian Brabandt

unread,
Jan 16, 2015, 4:42:59 PM1/16/15
to vim...@googlegroups.com, vim...@vim.org
Hi Ben!

On Fr, 16 Jan 2015, Ben Fritz wrote:

> The problem is, there is no way to move the cursor in insert mode,
> without breaking the undo sequence. Such a capability would allow both
> of these mappings:
>
> inore ( ()<Left> inore <expr> ) GetNextChar()==")" ? "\<Right>" : ")"
>
> Alternatively, there is no way in insert mode to insert a character
> after the cursor, or delete the character after the cursor. Such a
> capability would allow:
>
> inore <expr> ( ")".PutCharAfter(")") inore <expr> ) GetNextChar()==")"
> ? DeleteNextChar().")" : ")"
>
> At one point, there was a workaround that exploited a bug in setline()
> that allowed the undo/redo to work. You could use setline() to change
> the line without breaking undo sequence. I don't remember how repeat
> worked, but I think it involved an <Esc> mapping.
>
> If either the abilities above (moving the cursor without breaking
> undo, or insert/delete after the cursor) were implemented as Vim
> insert-mode commands, I would consider dropping the use of a plugin
> and just writing my own mappings.
>
> As it is, I tried the pull request I mentioned on delimitMate, and it
> seems to work for simple cases, but either visual-block mode messes it
> up. I have an unsatisfactory workaround I posted as a comment on that
> pull request that I'm using for the present.

Hm, we already have special cases <C-[Left|Right]> and <S-[Left|Right]>
to move by word|WORD. So how about making <M-Left> and <M-Right> move
without breaking undo?
https://github.com/chrisbra/vim-mq-patches/blob/master/move_cursor_without_breaking_undo


Best,
Christian
--
Wer tugendhaft lebt und handelt, der legt seinen Adel an den Tag.
-- Giovanni Boccaccio, Das Dekameron
move_cursor_without_breaking_undo.diff

Bram Moolenaar

unread,
Jan 16, 2015, 5:10:21 PM1/16/15
to Christian Brabandt, vim...@googlegroups.com, vim...@vim.org
It's very likely there will be a request for other movements, e.g. a
word back. How about a prefix for movement commands? Something
starting with CTRL-G. It's several keys to type, but I assume this will
mostly be used in mappings.


--
From "know your smileys":
=):-) Uncle Sam

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///

Christian Brabandt

unread,
Jan 16, 2015, 5:55:44 PM1/16/15
to vim...@googlegroups.com, vim...@vim.org
Hi Bram!
<C-Right> and <S-Right> does this already.

> How about a prefix for movement commands? Something
> starting with CTRL-G. It's several keys to type, but I assume this will
> mostly be used in mappings.

I thought about that. But my fear is, that this will allow to jump
anywhere in insert mode and I think this would probably break undo (a
problem we have just fixed with <c-r>= in insert mode before 7.4).
So I did intentionally just allow <M-Left> and <M-Right> in the hope,
that this will still allow proper undo and will cover most of the snip
plugin use-cases.

Best,
Christian
--
Es ist ebenso fehlerhaft, nicht überall die Sinnlichkeit, als überall
ihren Sieg voranzusetzen.
-- Jean Paul (eig. Johann Paul Friedrich Richter)

Ben Fritz

unread,
Jan 16, 2015, 10:24:03 PM1/16/15
to vim...@googlegroups.com, vim...@googlegroups.com, vim...@vim.org
On Friday, January 16, 2015 at 4:55:44 PM UTC-6, Christian Brabandt wrote:
> Hi Bram!
>
> On Fr, 16 Jan 2015, Bram Moolenaar wrote:
>
> >
> > Christian Brabandt wrote:
> > > Hm, we already have special cases <C-[Left|Right]> and <S-[Left|Right]>
> > > to move by word|WORD. So how about making <M-Left> and <M-Right> move
> > > without breaking undo?
> > > https://github.com/chrisbra/vim-mq-patches/blob/master/move_cursor_without_breaking_undo
> >
> > It's very likely there will be a request for other movements, e.g. a
> > word back.
> > How about a prefix for movement commands? Something
> > starting with CTRL-G. It's several keys to type, but I assume this will
> > mostly be used in mappings.
>
> I thought about that. But my fear is, that this will allow to jump
> anywhere in insert mode and I think this would probably break undo (a
> problem we have just fixed with <c-r>= in insert mode before 7.4).
> So I did intentionally just allow <M-Left> and <M-Right> in the hope,
> that this will still allow proper undo and will cover most of the snip
> plugin use-cases.
>

I'm definitely going to try the patch, but I think I'd prefer a different prefix also. If it works this is exactly what is needed for auto-close, without all the fuss of a big plugin (unless you want that...)

The meta-keys have traditionally been "safe" for mapping in Vim without stepping on existing features, I think keeping it that way is a good idea.

And I agree these will mostly be used in mappings.

CTRL-G_u breaks undo sequence. What about CTRL-G_U keeping undo sequence unbroken?

It's ok for the short term if just CTRL-G_U_<Left> and CTRL-G_U_<Right> are supported to start with...with potential for more if there is a need for them.

I'd probably restrict to movement within a single line, though.

Christian Brabandt

unread,
Jan 17, 2015, 8:41:35 AM1/17/15
to vim...@googlegroups.com, vim...@googlegroups.com, vim...@vim.org
Hi Ben!
Okay, above URL contains an updated version, that won't break undo for a
single <left>/<break> movement after <Ctrl-G>U have been pressed (but
only, if the cursor stays in the same line).


Best,
Christian
--
Wußten Sie schon...
... daß sich die alten Rittersleut' ihre Morgensterne auch
am Abend auf die Schädel droschen?
move_cursor_without_breaking_undo

Nikolay Pavlov

unread,
Jan 17, 2015, 12:09:23 PM1/17/15
to vim...@googlegroups.com, vim-dev Mailingliste
Just `w` and `b` with left and right will already allow to go anywhere, regardless of &whichwrap option.

But if you are going to use the same code for <M-Left> as for <Left> then adding `[` and `]` &whichwrap is just enough for <M-Left> and <M-Right> to go anywhere as well. If you want to restrict motions to a single line <M-Left>/<M-Right> should ignore &whichwrap. Also given that they will be used mostly in mappings which can use <expr> allowing <M-Left>/<M-Right> is just as good as allowing going anywhere in the line plugins wants to go and it may be easier to create code that does random motion after pressing <C-g>, but intentionally breaks undo if this motion happens to end on the other line.
 

Best,
Christian
--
Es ist ebenso fehlerhaft, nicht überall die Sinnlichkeit, als überall
ihren Sieg voranzusetzen.
                -- Jean Paul (eig. Johann Paul Friedrich Richter)

--
--
You received this message from the "vim_use" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

---
You received this message because you are subscribed to the Google Groups "vim_use" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vim_use+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Bram Moolenaar

unread,
Jan 17, 2015, 2:20:04 PM1/17/15
to Ben Fritz, vim...@googlegroups.com, vim...@googlegroups.com, vim...@vim.org

Ben Fritz wrote:

> ------=_Part_1625_1020240385.1421465043545
> Content-Type: text/plain; charset=UTF-8
Since undo works by saving the line before changing it, restricting the
"keep undo" modifier to only work when the cursor remains in the same
line should work. It's also fairly easy to understand, instead of
making a list of specific commands for which undo can be kept.

Note that "." to repeat the insert may not always work properly. Need
to check that.

--
From "know your smileys":
(X0||) Double hamburger with lettuce and tomato

Ben Fritz

unread,
Jan 21, 2015, 12:06:53 PM1/21/15
to vim...@googlegroups.com, fritzo...@gmail.com, vim...@googlegroups.com, vim...@vim.org
On Saturday, January 17, 2015 at 1:20:04 PM UTC-6, Bram Moolenaar wrote:
>
> Since undo works by saving the line before changing it, restricting the
> "keep undo" modifier to only work when the cursor remains in the same
> line should work. It's also fairly easy to understand, instead of
> making a list of specific commands for which undo can be kept.
>
> Note that "." to repeat the insert may not always work properly. Need
> to check that.
>

Wow. WOW! Thanks for the patch, Christian!

I tested with some fairly simple mappings, and it works perfectly!

Even repeating these mappings with '.' and inserting in visual-block insert works without issue as far as I can tell!

inoremap ( ()<C-G>U<Left>
inoremap (<SPACE> (<SPACE><SPACE>)<C-G>U<Left><C-G>U<Left>
inoremap <expr> ) strpart(getline('.'), col('.')-1, 1) == ")" ? "\<C-G>U\<Right>" : ")"

The only thing that won't work smoothly is a mapping to insert a new indented line between pairs, but it's only repeat that is broken there, and I can live with that:

inoremap <silent> {<CR> {<CR>}<Esc>zv:undojoin<CR>O

I even got a smart mapping done for paired " characters that also works with Vim comments...but that uses some complicated regex so I'll not confuse the issue here :-)

Ben Fritz

unread,
Mar 25, 2015, 3:02:32 PM3/25/15
to vim...@googlegroups.com, fritzo...@gmail.com, vim...@googlegroups.com, vim...@vim.org
On Wednesday, January 21, 2015 at 11:06:53 AM UTC-6, Ben Fritz wrote:
> On Saturday, January 17, 2015 at 1:20:04 PM UTC-6, Bram Moolenaar wrote:
> >
> > Since undo works by saving the line before changing it, restricting the
> > "keep undo" modifier to only work when the cursor remains in the same
> > line should work. It's also fairly easy to understand, instead of
> > making a list of specific commands for which undo can be kept.
> >
> > Note that "." to repeat the insert may not always work properly. Need
> > to check that.
> >
>
> Wow. WOW! Thanks for the patch, Christian!
>
> I tested with some fairly simple mappings, and it works perfectly!
>

Updated patch to apply cleanly (with line offsets but no fuzz) to the latest source.
move_cursor_without_breaking_undo.patch

Thiago Alves

unread,
Mar 26, 2015, 2:08:52 PM3/26/15
to vim...@googlegroups.com, fritzo...@gmail.com, vim...@googlegroups.com, vim...@vim.org
Awesome patch. I tested here it works perfectly. Any chance this to be applied to mainline?

Enno

unread,
Jun 23, 2015, 4:48:00 AM6/23/15
to vim...@googlegroups.com
This would be very useful. For example, when using `cgn` and the dot operator to repeat changes on all matches. This breaks down whenever the changed text contains delimiters such as (,[,{, ... (and using an automatic delimiter-completion plugin such as DelimitMate).

Jacob Niehus

unread,
Aug 3, 2015, 12:05:03 AM8/3/15
to vim_dev, fritzo...@gmail.com, vim...@googlegroups.com, vim...@vim.org
I would love to see this in mainline as well. I've been using it quite extensively for four months now with these maps to move the cursor left/right by word/WORD and to the first column, first non-blank, and last column without breaking undo:

" Move cursor in insert mode without splitting undo
inoremap <Left> <C-g>U<Left>
inoremap <Right> <C-g>U<Right>
inoremap <expr> <Home> col('.') == match(getline('.'), '\S') + 1 ?
\ repeat('<C-g>U<Left>', col('.') - 1) :
\ (col('.') < match(getline('.'), '\S') ?
\ repeat('<C-g>U<Right>', match(getline('.'), '\S') + 0) :
\ repeat('<C-g>U<Left>', col('.') - 1 - match(getline('.'), '\S')))
inoremap <expr> <End> repeat('<C-g>U<Right>', col('$') - col('.'))
imap <C-b> <Home>
imap <C-e> <End>

Here's an update to the patch that applies cleanly to Vim 7.4.803.

-Jake

move_cursor_without_breaking_undo_vim-v7-4-803.patch

Bram Moolenaar

unread,
Aug 4, 2015, 8:42:30 AM8/4/15
to Jacob Niehus, vim_dev, fritzo...@gmail.com, vim...@googlegroups.com, vim...@vim.org
This appears to be OK to include. However, a test is missing.
Especially that using this at the end of the line, then a cursor-right
should work as before, because it moves to the next line.


--
You were lucky to have a LAKE! There were a hundred and sixty of
us living in a small shoebox in the middle of the road.

Christian Brabandt

unread,
Aug 4, 2015, 2:46:24 PM8/4/15
to vim_dev, vim...@googlegroups.com, vim...@vim.org

On Di, 04 Aug 2015, Bram Moolenaar wrote:

> Jacob Niehus wrote:
>
> > I would love to see this in mainline as well. I've been using it quite
> > extensively for four months now with these maps to move the cursor
> > left/right by word/WORD and to the first column, first non-blank, and
> > last column without breaking undo:
> >
> > " Move cursor in insert mode without splitting undo
> > inoremap <Left> <C-g>U<Left>
> > inoremap <Right> <C-g>U<Right>
> > inoremap <expr> <Home> col('.') == match(getline('.'), '\S') + 1 ?
> > \ repeat('<C-g>U<Left>', col('.') - 1) :
> > \ (col('.') < match(getline('.'), '\S') ?
> > \ repeat('<C-g>U<Right>', match(getline('.'), '\S') + 0) :
> > \ repeat('<C-g>U<Left>', col('.') - 1 - match(getline('.'), '\S')))
> > inoremap <expr> <End> repeat('<C-g>U<Right>', col('$') - col('.'))
> > imap <C-b> <Home>
> > imap <C-e> <End>
> >
> > Here's an update to the patch that applies cleanly to Vim 7.4.803.
>
> This appears to be OK to include. However, a test is missing.
> Especially that using this at the end of the line, then a cursor-right
> should work as before, because it moves to the next line.

Here is an update, including 3 tests.

Mit freundlichen Grüßen
Christian
--
Viele Menschen versäumen das kleine Glück, während sie auf das große
vergebens warten.
-- Pearl Sydenstricker Buck (Pseudonym: Sedges, John)
move_cursor_without_breaking_redo

Bram Moolenaar

unread,
Aug 4, 2015, 3:27:31 PM8/4/15
to Christian Brabandt, vim_dev, vim...@googlegroups.com, vim...@vim.org

Christian Brabandt wrote:

> On Di, 04 Aug 2015, Bram Moolenaar wrote:
>
> > Jacob Niehus wrote:
> >
> > > I would love to see this in mainline as well. I've been using it quite
> > > extensively for four months now with these maps to move the cursor
> > > left/right by word/WORD and to the first column, first non-blank, and
> > > last column without breaking undo:
> > >
> > > " Move cursor in insert mode without splitting undo
> > > inoremap <Left> <C-g>U<Left>
> > > inoremap <Right> <C-g>U<Right>
> > > inoremap <expr> <Home> col('.') == match(getline('.'), '\S') + 1 ?
> > > \ repeat('<C-g>U<Left>', col('.') - 1) :
> > > \ (col('.') < match(getline('.'), '\S') ?
> > > \ repeat('<C-g>U<Right>', match(getline('.'), '\S') + 0) :
> > > \ repeat('<C-g>U<Left>', col('.') - 1 - match(getline('.'), '\S')))
> > > inoremap <expr> <End> repeat('<C-g>U<Right>', col('$') - col('.'))
> > > imap <C-b> <Home>
> > > imap <C-e> <End>
> > >
> > > Here's an update to the patch that applies cleanly to Vim 7.4.803.
> >
> > This appears to be OK to include. However, a test is missing.
> > Especially that using this at the end of the line, then a cursor-right
> > should work as before, because it moves to the next line.
>
> Here is an update, including 3 tests.

Thanks. So who wrote the original patch then?


--
FATHER: Who are you?
PRINCE: I'm ... your son ...
FATHER: Not you.
LAUNCELOT: I'm ... er ... Sir Launcelot, sir.
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

Christian Brabandt

unread,
Aug 4, 2015, 3:28:58 PM8/4/15
to vim_dev, vim...@googlegroups.com
On Di, 04 Aug 2015, Bram Moolenaar wrote:

> Thanks. So who wrote the original patch then?

I believe that was me.

Best,
Christian
--
Lieber Lügen als kurze Beine.

Ben Fritz

unread,
Aug 4, 2015, 3:33:21 PM8/4/15
to vim_dev
Yes, that was you, thanks! A couple of us just posted a couple updates to keep line numbers, etc. up to date with the Vim source to aid in getting it merged faster.

herm...@free.fr

unread,
Aug 5, 2015, 5:25:34 AM8/5/15
to vim dev
Hello,

If I understand correctly, undo won't be broken as long as we move the cursor with <left>, <right>, and so on.

Will it be possible to also support moves based on search() and searchpair() ?

--
Luc Hermitte

Christian Brabandt

unread,
Aug 5, 2015, 6:15:26 AM8/5/15
to vim...@googlegroups.com, herm...@free.fr
Am 2015-08-05 11:25, schrieb herm...@free.fr:
> If I understand correctly, undo won't be broken as long as we move the
> cursor with <left>, <right>, and so on.

(and the cursor stays in the same line)

> Will it be possible to also support moves based on search() and
> searchpair() ?

Too complicated. The idea is, to keep things simple and not
overcomplicate things,
only allow movements within a single line. That should fix most of the
snipmate like
plugin usage.

Moving to other parts of the buffer will most likely break undo or redo
again, that's why this has been left out.

Best,
Christian

Ben Fritz

unread,
Aug 5, 2015, 12:41:35 PM8/5/15
to vim_dev
For search and searchpair, you should be able to call those *without* moving the cursor to get a position, and then (if it's in the same line) generate movement sequences to get there. Not exactly elegant but it should work (for single lines).

herm...@free.fr

unread,
Aug 5, 2015, 12:55:12 PM8/5/15
to vim dev
I was expecting to be able to exploit the patch for snippets
like "{\n<+cursor+>\n}<+jump-position+>", or simply "if (cond)\n{..."

Of course, it's stupid to redo the exact same control-statement,
and yet, it would have been useful in some copy-paste like cases.

Anyway.

Thank you all for the patch. I'll see how I can exploit it.

--
Luc Hermitte

Christian Brabandt

unread,
Aug 5, 2015, 2:41:32 PM8/5/15
to vim dev
Hi hermitte!

On Mi, 05 Aug 2015, herm...@free.fr wrote:

> Of course, it's stupid to redo the exact same control-statement,
> and yet, it would have been useful in some copy-paste like cases.

Well, I wouldn't call it stupid exactly, that the mapping isn't done
redone completely and can see, that this might be expected.

On the other hand, I am not sure, that calling search() or searchpair()
from insert mode would not break the undo sequence, but I am not sure,
so this should to be tested.

Best,
Christian
--
Auch die Henne weiß, daß die Sonne aufgeht, aber sie überläßt dem
Hahn das Krähen.
-- Sprichwort aus Ghana

Bram Moolenaar

unread,
Aug 5, 2015, 3:25:03 PM8/5/15
to herm...@free.fr, vim dev

Luc Hermitte wrote:

> If I understand correctly, undo won't be broken as long as we move the
> cursor with <left>, <right>, and so on.
>
> Will it be possible to also support moves based on search() and
> searchpair() ?

That goes in the direction of merging two undo actions. That's
basically making "u" work like "2u"

What Christian's change allows for is also make redo work: ".".
That's quite difficult for not so simple commands.


--
FATHER: Did you kill all those guards?
LAUNCELOT: Yes ... I'm very sorry ...
FATHER: They cost fifty pounds each!

Ben Fritz

unread,
Aug 6, 2015, 12:02:11 AM8/6/15
to vim_dev

If you're satisfied with keeping undo/redo and are OK with sacrificing repeat with '.', you can use undojoin. I use this mapping for example:

Reply all
Reply to author
Forward
0 new messages