# HG changeset patch # Parent e5298cdcba7cd36f422816c9e879047d5ff066a9 Do not break undo on left/right with U From https://groups.google.com/d/msg/vim_use/klj6nlDOriI/aeNjtWp_U80J This will allow to use U and U to move the cursor without breaking the undo sequence. However, a new undo change will be created if left/right move across lines, so that undo is still workable. This should fix the problem to undo/redo delimate like plugins (hopefully). Example: imap ( ()U Now enter foobar(eins '.' on a new empty line will now repeat to: foobar(eins) Suggested mappings: " Move cursor in insert mode without splitting undo 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('.')) imap imap 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* + (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: > + + 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 @@ -201,7 +201,7 @@ static void insert_special __ARGS((int, static void internal_format __ARGS((int textwidth, int second_indent, int flags, int format_only, int c)); 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 __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 +241,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 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 change)); static void ins_s_right __ARGS((void)); static void ins_up __ARGS((int startcol)); static void ins_pageup __ARGS((void)); @@ -297,6 +297,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 stop_sync_undo = FALSE; /* CTRL-G U prevents syncing undo for + the next left/right cursor */ /* * edit(): Start inserting text. @@ -767,6 +769,11 @@ edit(cmdchar, startln, count) */ if (c != K_CURSORHOLD) lastc = c; /* remember the previous char for CTRL-D */ + + if (stop_sync_undo == MAYBE) /* cursor might come next */ + stop_sync_undo = TRUE; + else + stop_sync_undo = FALSE; /* sync undo with next char, if needed */ do { c = safe_vgetc(); @@ -1237,7 +1244,7 @@ doESCkey: if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)) ins_s_left(); else - ins_left(); + ins_left(stop_sync_undo == FALSE); break; case K_S_LEFT: /* */ @@ -1249,7 +1256,7 @@ doESCkey: if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)) ins_s_right(); else - ins_right(); + ins_right(stop_sync_undo == FALSE); break; case K_S_RIGHT: /* */ @@ -6786,10 +6793,11 @@ redo_literal(c) * For undo/redo it resembles hitting the key. */ static void -start_arrow(end_insert_pos) +start_arrow(end_insert_pos, change) pos_T *end_insert_pos; /* can be NULL */ -{ - if (!arrow_used) /* something has been inserted */ + int change; /* if true, start a new change */ +{ + if (!arrow_used && change) /* something has been inserted */ { AppendToRedobuff(ESC_STR); stop_insert(end_insert_pos, FALSE, FALSE); @@ -6828,7 +6836,7 @@ spell_back_to_badword() spell_bad_len = spell_move_to(curwin, BACKWARD, TRUE, TRUE, NULL); if (curwin->w_cursor.col != tpos.col) - start_arrow(&tpos); + start_arrow(&tpos, TRUE); } #endif @@ -8359,6 +8367,12 @@ 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 */ + stop_sync_undo = MAYBE; + break; + /* Unknown CTRL-G command, reserved for future expansion. */ default: vim_beep(BO_CTRLG); } @@ -9267,7 +9281,7 @@ ins_mouse(c) curbuf = curwin->w_buffer; } #endif - start_arrow(curwin == old_curwin ? &tpos : NULL); + start_arrow(curwin == old_curwin ? &tpos : NULL, TRUE); #ifdef FEAT_WINDOWS if (curwin != new_curwin && win_valid(new_curwin)) { @@ -9371,7 +9385,7 @@ ins_mousescroll(dir) if (!equalpos(curwin->w_cursor, tpos)) { - start_arrow(&tpos); + start_arrow(&tpos, TRUE); # ifdef FEAT_CINDENT can_cindent = TRUE; # endif @@ -9389,7 +9403,7 @@ ins_tabline(c) || (current_tab != 0 && current_tab != tabpage_index(curtab))) { undisplay_dollar(); - start_arrow(&curwin->w_cursor); + start_arrow(&curwin->w_cursor, TRUE); # ifdef FEAT_CINDENT can_cindent = TRUE; # endif @@ -9415,7 +9429,7 @@ ins_scroll() tpos = curwin->w_cursor; if (gui_do_scroll()) { - start_arrow(&tpos); + start_arrow(&tpos, TRUE); # ifdef FEAT_CINDENT can_cindent = TRUE; # endif @@ -9431,7 +9445,7 @@ ins_horscroll() tpos = curwin->w_cursor; if (gui_do_horiz_scroll(scrollbar_value, FALSE)) { - start_arrow(&tpos); + start_arrow(&tpos, TRUE); # ifdef FEAT_CINDENT can_cindent = TRUE; # endif @@ -9440,7 +9454,8 @@ ins_horscroll() #endif static void -ins_left() +ins_left(change) + int change; /* start a new change */ { pos_T tpos; @@ -9457,7 +9472,15 @@ ins_left() * break undo. K_LEFT is inserted in im_correct_cursor(). */ if (!im_is_preediting()) #endif - start_arrow(&tpos); + { + start_arrow(&tpos, change); + if (!change) + { + AppendCharToRedobuff(Ctrl_G); + AppendCharToRedobuff('U'); + 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,13 +9495,15 @@ ins_left() */ else if (vim_strchr(p_ww, '[') != NULL && curwin->w_cursor.lnum > 1) { - start_arrow(&tpos); + /* always break undo when moving upwards/downwards, else undo may break */ + start_arrow(&tpos, TRUE); --(curwin->w_cursor.lnum); coladvance((colnr_T)MAXCOL); curwin->w_set_curswant = TRUE; /* so we stay at the end */ } else vim_beep(BO_CRSR); + stop_sync_undo = FALSE; } static void @@ -9500,7 +9525,7 @@ ins_home(c) curwin->w_cursor.coladd = 0; #endif curwin->w_curswant = 0; - start_arrow(&tpos); + start_arrow(&tpos, TRUE); } static void @@ -9520,7 +9545,7 @@ ins_end(c) coladvance((colnr_T)MAXCOL); curwin->w_curswant = MAXCOL; - start_arrow(&tpos); + start_arrow(&tpos, TRUE); } static void @@ -9533,7 +9558,7 @@ ins_s_left() undisplay_dollar(); if (curwin->w_cursor.lnum > 1 || curwin->w_cursor.col > 0) { - start_arrow(&curwin->w_cursor); + start_arrow(&curwin->w_cursor, TRUE); (void)bck_word(1L, FALSE, FALSE); curwin->w_set_curswant = TRUE; } @@ -9542,7 +9567,8 @@ ins_s_left() } static void -ins_right() +ins_right(change) + int change; /* start a new change */ { #ifdef FEAT_FOLDING if ((fdo_flags & FDO_HOR) && KeyTyped) @@ -9555,7 +9581,13 @@ ins_right() #endif ) { - start_arrow(&curwin->w_cursor); + start_arrow(&curwin->w_cursor, change); + if (!change) + { + AppendCharToRedobuff(Ctrl_G); + AppendCharToRedobuff('U'); + AppendCharToRedobuff(K_RIGHT); + } curwin->w_set_curswant = TRUE; #ifdef FEAT_VIRTUALEDIT if (virtual_active()) @@ -9582,13 +9614,14 @@ ins_right() else if (vim_strchr(p_ww, ']') != NULL && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { - start_arrow(&curwin->w_cursor); + start_arrow(&curwin->w_cursor, TRUE); curwin->w_set_curswant = TRUE; ++curwin->w_cursor.lnum; curwin->w_cursor.col = 0; } else vim_beep(BO_CRSR); + stop_sync_undo = FALSE; } static void @@ -9602,7 +9635,7 @@ ins_s_right() if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count || gchar_cursor() != NUL) { - start_arrow(&curwin->w_cursor); + start_arrow(&curwin->w_cursor, TRUE); (void)fwd_word(1L, FALSE, 0); curwin->w_set_curswant = TRUE; } @@ -9632,7 +9665,7 @@ ins_up(startcol) #endif ) redraw_later(VALID); - start_arrow(&tpos); + start_arrow(&tpos, TRUE); #ifdef FEAT_CINDENT can_cindent = TRUE; #endif @@ -9654,7 +9687,7 @@ ins_pageup() /* : tab page back */ if (first_tabpage->tp_next != NULL) { - start_arrow(&curwin->w_cursor); + start_arrow(&curwin->w_cursor, TRUE); goto_tabpage(-1); } return; @@ -9664,7 +9697,7 @@ ins_pageup() tpos = curwin->w_cursor; if (onepage(BACKWARD, 1L) == OK) { - start_arrow(&tpos); + start_arrow(&tpos, TRUE); #ifdef FEAT_CINDENT can_cindent = TRUE; #endif @@ -9695,7 +9728,7 @@ ins_down(startcol) #endif ) redraw_later(VALID); - start_arrow(&tpos); + start_arrow(&tpos, TRUE); #ifdef FEAT_CINDENT can_cindent = TRUE; #endif @@ -9717,7 +9750,7 @@ ins_pagedown() /* : tab page forward */ if (first_tabpage->tp_next != NULL) { - start_arrow(&curwin->w_cursor); + start_arrow(&curwin->w_cursor, TRUE); goto_tabpage(0); } return; @@ -9727,7 +9760,7 @@ ins_pagedown() tpos = curwin->w_cursor; if (onepage(FORWARD, 1L) == OK) { - start_arrow(&tpos); + start_arrow(&tpos, TRUE); #ifdef FEAT_CINDENT can_cindent = TRUE; #endif 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