# HG changeset patch # User Christian Brabandt # Date 1441128604 -7200 # Node ID c8efa41dd4514a10295e303bcf840f51f320ecd1 # Parent 1b4f682069c92f700298d7657227278a60c24b81 commit https://github.com/vim/vim/commit/8b5f65a527c353b9942e362e719687c3a7592309 Author: Bram Moolenaar Date: Tue Sep 1 19:26:12 2015 +0200 patch 7.4.849 Problem: Moving the cursor in Insert mode starts new undo sequence. Solution: Add CTRL-G U to keep the undo sequence for the following cursor movement command. (Christian Brabandt) diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt --- a/runtime/doc/insert.txt +++ b/runtime/doc/insert.txt @@ -377,6 +377,9 @@ CTRL-O execute one command, return to I CTRL-\ CTRL-O like CTRL-O but don't move the cursor *i_CTRL-\_CTRL-O* CTRL-L when 'insertmode' is set: go to Normal mode *i_CTRL-L* CTRL-G u break undo sequence, start new change *i_CTRL-G_u* +CTRL-G U don't break undo with next left/right cursor *i_CTRL-G_U* + movement (but only if the cursor stays + within same the line) ----------------------------------------------------------------------- Note: If the cursor keys take you out of Insert mode, check the 'noesckeys' @@ -416,6 +419,28 @@ that, with CTRL-O u. Another example: > This breaks undo at each line break. It also expands abbreviations before this. +An example for using CTRL-G U: > + + inoremap U + inoremap U + inoremap col('.') == match(getline('.'), '\S') + 1 ? + \ repeat('U', col('.') - 1) : + \ (col('.') < match(getline('.'), '\S') ? + \ repeat('U', match(getline('.'), '\S') + 0) : + \ repeat('U', col('.') - 1 - match(getline('.'), '\S'))) + inoremap repeat('U', col('$') - col('.')) + inoremap ( ()U + +This makes it possible to use the cursor keys in Insert mode, without breaking +the undo sequence and therefore using |.| (redo) will work as expected. +Also entering a text like (with the "(" mapping from above): > + + Lorem ipsum (dolor + +will be repeatable by the |.|to the expected + + Lorem ipsum (dolor) + 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: > diff --git a/src/edit.c b/src/edit.c --- a/src/edit.c +++ b/src/edit.c @@ -202,6 +202,8 @@ static void internal_format __ARGS((int static void check_auto_format __ARGS((int)); static void redo_literal __ARGS((int c)); static void start_arrow __ARGS((pos_T *end_insert_pos)); +static void start_arrow_with_change __ARGS((pos_T *end_insert_pos, int change)); +static void start_arrow_common __ARGS((pos_T *end_insert_pos, int change)); #ifdef FEAT_SPELL static void check_spell_redraw __ARGS((void)); static void spell_back_to_badword __ARGS((void)); @@ -241,11 +243,11 @@ static void ins_mousescroll __ARGS((int #if defined(FEAT_GUI_TABLINE) || defined(PROTO) static void ins_tabline __ARGS((int c)); #endif -static void ins_left __ARGS((void)); +static void ins_left __ARGS((int end_change)); static void ins_home __ARGS((int c)); static void ins_end __ARGS((int c)); static void ins_s_left __ARGS((void)); -static void ins_right __ARGS((void)); +static void ins_right __ARGS((int end_change)); static void ins_s_right __ARGS((void)); static void ins_up __ARGS((int startcol)); static void ins_pageup __ARGS((void)); @@ -297,6 +299,8 @@ static int ins_need_undo; /* call u_sav static int did_add_space = FALSE; /* auto_format() added an extra space under the cursor */ +static int dont_sync_undo = FALSE; /* CTRL-G U prevents syncing undo for + the next left/right cursor */ /* * edit(): Start inserting text. @@ -767,6 +771,12 @@ edit(cmdchar, startln, count) */ if (c != K_CURSORHOLD) lastc = c; /* remember the previous char for CTRL-D */ + + /* After using CTRL-G U the next cursor key will not break undo. */ + if (dont_sync_undo == MAYBE) + dont_sync_undo = TRUE; + else + dont_sync_undo = FALSE; do { c = safe_vgetc(); @@ -1237,7 +1247,7 @@ doESCkey: if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)) ins_s_left(); else - ins_left(); + ins_left(dont_sync_undo == FALSE); break; case K_S_LEFT: /* */ @@ -1249,7 +1259,7 @@ doESCkey: if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)) ins_s_right(); else - ins_right(); + ins_right(dont_sync_undo == FALSE); break; case K_S_RIGHT: /* */ @@ -6787,9 +6797,34 @@ redo_literal(c) */ static void start_arrow(end_insert_pos) - pos_T *end_insert_pos; /* can be NULL */ -{ - if (!arrow_used) /* something has been inserted */ + pos_T *end_insert_pos; /* can be NULL */ +{ + start_arrow_common(end_insert_pos, TRUE); +} + +/* + * Like start_arrow() but with end_change argument. + * Will prepare for redo of CTRL-G U if "end_change" is FALSE. + */ + static void +start_arrow_with_change(end_insert_pos, end_change) + pos_T *end_insert_pos; /* can be NULL */ + int end_change; /* end undoable change */ +{ + start_arrow_common(end_insert_pos, end_change); + if (!end_change) + { + AppendCharToRedobuff(Ctrl_G); + AppendCharToRedobuff('U'); + } +} + + static void +start_arrow_common(end_insert_pos, end_change) + pos_T *end_insert_pos; /* can be NULL */ + int end_change; /* end undoable change */ +{ + if (!arrow_used && end_change) /* something has been inserted */ { AppendToRedobuff(ESC_STR); stop_insert(end_insert_pos, FALSE, FALSE); @@ -8359,6 +8394,13 @@ ins_ctrl_g() Insstart = curwin->w_cursor; break; + /* CTRL-G U: do not break undo with the next char */ + case 'U': + /* Allow one left/right cursor movement with the next char, + * without breaking undo. */ + dont_sync_undo = MAYBE; + break; + /* Unknown CTRL-G command, reserved for future expansion. */ default: vim_beep(BO_CTRLG); } @@ -9440,7 +9482,8 @@ ins_horscroll() #endif static void -ins_left() +ins_left(end_change) + int end_change; /* end undoable change */ { pos_T tpos; @@ -9457,7 +9500,11 @@ ins_left() * break undo. K_LEFT is inserted in im_correct_cursor(). */ if (!im_is_preediting()) #endif - start_arrow(&tpos); + { + start_arrow_with_change(&tpos, end_change); + if (!end_change) + AppendCharToRedobuff(K_LEFT); + } #ifdef FEAT_RIGHTLEFT /* If exit reversed string, position is fixed */ if (revins_scol != -1 && (int)curwin->w_cursor.col >= revins_scol) @@ -9472,6 +9519,7 @@ ins_left() */ else if (vim_strchr(p_ww, '[') != NULL && curwin->w_cursor.lnum > 1) { + /* always break undo when moving upwards/downwards, else undo may break */ start_arrow(&tpos); --(curwin->w_cursor.lnum); coladvance((colnr_T)MAXCOL); @@ -9479,6 +9527,7 @@ ins_left() } else vim_beep(BO_CRSR); + dont_sync_undo = FALSE; } static void @@ -9542,7 +9591,8 @@ ins_s_left() } static void -ins_right() +ins_right(end_change) + int end_change; /* end undoable change */ { #ifdef FEAT_FOLDING if ((fdo_flags & FDO_HOR) && KeyTyped) @@ -9555,7 +9605,9 @@ ins_right() #endif ) { - start_arrow(&curwin->w_cursor); + start_arrow_with_change(&curwin->w_cursor, end_change); + if (!end_change) + AppendCharToRedobuff(K_RIGHT); curwin->w_set_curswant = TRUE; #ifdef FEAT_VIRTUALEDIT if (virtual_active()) @@ -9589,6 +9641,7 @@ ins_right() } else vim_beep(BO_CRSR); + dont_sync_undo = FALSE; } static void diff --git a/src/testdir/test_mapping.in b/src/testdir/test_mapping.in --- a/src/testdir/test_mapping.in +++ b/src/testdir/test_mapping.in @@ -45,6 +45,21 @@ o+ :/^a b 0qqdw.ifooqj0@q:unmap . +:" U works only within a single line +:imapclear +:imap ( ()U +G2oki +Test1: text with a (here some more textk. +:" test undo +G2oki +Test2: text wit a (here some more text [und undo]uk.u +:" +:imapclear +:set whichwrap=<,>,[,] +G3o2k +:exe ":norm! iTest3: text with a (parenthesis here\U\new line here\\\." + + :/^test/,$w! test.out :qa! diff --git a/src/testdir/test_mapping.ok b/src/testdir/test_mapping.ok --- a/src/testdir/test_mapping.ok +++ b/src/testdir/test_mapping.ok @@ -10,3 +10,13 @@ vmap works + + + + +Test1: text with a (here some more text) +Test1: text with a (here some more text) + + +Test2: text wit a (here some more text [und undo]) + +new line here +Test3: text with a (parenthesis here +new line here diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -742,6 +742,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 849, +/**/ 848, /**/ 847,