diff options
author | Bram Moolenaar <Bram@vim.org> | 2015-09-01 19:26:12 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2015-09-01 19:26:12 +0200 |
commit | 8b5f65a527c353b9942e362e719687c3a7592309 (patch) | |
tree | 655108e877377b6dcba8e066f87f00df2e982a90 | |
parent | 5adfea1ac63e252556bccce54e92e8e10b58f592 (diff) |
patch 7.4.849v7.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)
-rw-r--r-- | runtime/doc/insert.txt | 25 | ||||
-rw-r--r-- | src/edit.c | 73 | ||||
-rw-r--r-- | src/testdir/test_mapping.in | 15 | ||||
-rw-r--r-- | src/testdir/test_mapping.ok | 10 | ||||
-rw-r--r-- | src/version.c | 2 |
5 files changed, 115 insertions, 10 deletions
diff --git a/runtime/doc/insert.txt b/runtime/doc/insert.txt index 0aa989c548..b0eae9fee1 100644 --- a/runtime/doc/insert.txt +++ b/runtime/doc/insert.txt @@ -377,6 +377,9 @@ CTRL-O execute one command, return to Insert mode *i_CTRL-O* 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 <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('.')) + inoremap ( ()<C-G>U<Left> + +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 index b48a2176f7..db4a079e40 100644 --- a/src/edit.c +++ b/src/edit.c @@ -202,6 +202,8 @@ static void internal_format __ARGS((int textwidth, int second_indent, int flags, 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 dir)); #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_save() before inserting a 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: /* <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: /* <S-Right> */ @@ -6787,9 +6797,34 @@ redo_literal(c) */ static void start_arrow(end_insert_pos) - pos_T *end_insert_pos; /* can be NULL */ + 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 */ { - if (!arrow_used) /* something has been inserted */ + 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 index d6c1b2d5db..f900f421e2 100644 --- a/src/testdir/test_mapping.in +++ b/src/testdir/test_mapping.in @@ -45,6 +45,21 @@ o+ :/^a b 0qqdw.ifooqj0@q:unmap . +:" <c-g>U<cursor> works only within a single line +:imapclear +:imap ( ()<c-g>U<left> +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\<C-G>U\<Right>new line here\<esc>\<up>\<up>." + + :/^test/,$w! test.out :qa! diff --git a/src/testdir/test_mapping.ok b/src/testdir/test_mapping.ok index 51cc49bf7d..b493cff2b1 100644 --- 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 index b50521b626..eac1f1b173 100644 --- 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, |