On Mo, 12 Feb 2018, Bram Moolenaar wrote: > > Christian Brabandt wrote: > > > this example throws ml_get errors: > > ,---- > > | set bs=2 > > | exe "normal a\nabcdefghi\njk\tlmn\n opq rst\n\<C-D>uvwxyz" > > | call cursor(1,1) > > | exe "normal gR0\<del> 1\nA\nBCDEFGHIJ\n\tKL\nMNO\nPQR" > > `---- > > > > Problem is, that once a linebreak is deleted in virtual replace mode, > > orig_lines_count is not correctly reset. > > > > Here is a patch that fixes that issue and includes a test. > > > > diff --git a/src/edit.c b/src/edit.c > > index 47227d34b..10bfd08a1 100644 > > --- a/src/edit.c > > +++ b/src/edit.c > > @@ -8927,7 +8927,17 @@ ins_del(void) > > || do_join(2, FALSE, TRUE, FALSE, FALSE) == FAIL) > > vim_beep(BO_BS); > > else > > + { > > curwin->w_cursor.col = temp; > > +#ifdef FEAT_VREPLACE > > + if (State & VREPLACE_FLAG) > > + { > > + orig_line_count = curbuf->b_ml.ml_line_count; > > + if (vr_lines_changed > 1) > > + vr_lines_changed--; > > + } > > +#endif > > Hmm, I suspect this needs a check whether the cursor is in the first > changed line or not.
Why would that matter? If the line count changes we need to adjust orig_line_count or else open_line will throw an error later if adding new lines (which this patch was trying to fix). > Compare with the do_join() in ins_bs(), it doesn't adjust vr_lines_changed or > orig_line_count there. Wait a second. You are talking about this part here, right: ,----[ ins_bs() ]- | #ifdef FEAT_VREPLACE | if (!(State & VREPLACE_FLAG) | || curwin->w_cursor.lnum > orig_line_count) | #endif | { | temp = gchar_cursor(); /* remember current char */ | --curwin->w_cursor.lnum; | | /* When "aw" is in 'formatoptions' we must delete the space at | * the end of the line, otherwise the line will be broken | * again when auto-formatting. */ | if (has_format_option(FO_AUTO) | && has_format_option(FO_WHITE_PAR)) | { | char_u *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, | TRUE); | int len; | | len = (int)STRLEN(ptr); | if (len > 0 && ptr[len - 1] == ' ') | ptr[len - 1] = NUL; | } | | (void)do_join(2, FALSE, FALSE, FALSE, FALSE); | if (temp == NUL && gchar_cursor() != NUL) | inc_cursor(); | } | #ifdef FEAT_VREPLACE | else | dec_cursor(); | #endif `---- If I am reading that correctly, this is only done when not in virtual replace mode (or the current cursor is below orig_line_count, which I think can only happen if we add lines in virtual replace mode). So that means, in virtual replace mode pressing <BS> at the beginning of a line, will only move the cursor (the else part at the bottom). And indeed this is what happens, it doesn't actually delete the newline, only if a newline has been added before and the cursor is below the original line count it will be removed Take this example, [vim --clean]: abcd efgh ijkl Now put the cursor on 'e', press gR type 1234\n5<BS><BS><BS>, you will be at: abcd 123h ijkl Note, the new line has not been deleted. However with this: abcd efgh ijkl Put the cursor on 'e', press gR type 1234\n\n56<BS><BS><BS> abcd 1234 ijkl Note: the second newline has actually been deleted. > It is used to decide whether or not to save the next line for undo. > this is in open_line(). Perhaps you can make a test case that enters NL > in virtual replace mode, then DEL to join the next line, then enters NL > again, check if undo still works as expected. That sounds like a good idea. Will amend the test and I should also add the test case from above (about deleting lines in virtual replace mode....) Best, Christian -- Der Scharfsinn verlässt geistreiche Männer am wenigsten, wenn sie unrecht haben. -- Goethe, Maximen und Reflektionen, Nr. 766 -- -- You received this message from the "vim_dev" 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_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.