neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

commit a8dad46e1c3034765e479bae53094398f458dfa8
parent fbaead249b15b2ad408eae689c2407924bc52225
Author: zeertzjq <zeertzjq@outlook.com>
Date:   Thu, 21 Aug 2025 11:31:31 +0800

Merge pull request #35352 from janlazo/vim-8.1.2008

vim-patch:8.1.2008,v8.2.{844,853,3348,3795,4379}
Diffstat:
Msrc/nvim/buffer.c | 6+++---
Msrc/nvim/change.c | 2+-
Msrc/nvim/diff.c | 4++--
Msrc/nvim/eval/buffer.c | 2+-
Msrc/nvim/ex_cmds.c | 12++++++------
Msrc/nvim/ex_docmd.c | 2+-
Msrc/nvim/fileio.c | 8++++----
Msrc/nvim/insexpand.c | 2+-
Msrc/nvim/memline.c | 111++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/nvim/memline.h | 13+++++++++++++
Msrc/nvim/normal.c | 2+-
Msrc/nvim/quickfix.c | 4++--
Msrc/nvim/spell.c | 2+-
Msrc/nvim/terminal.c | 2+-
Msrc/nvim/undo.c | 42+++++++++++++++++++++++++++---------------
Mtest/old/testdir/test_jumplist.vim | 4----
16 files changed, 132 insertions(+), 86 deletions(-)

diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c @@ -157,12 +157,12 @@ static int read_buffer(bool read_stdin, exarg_T *eap, int flags) if (retval == OK) { // Delete the binary lines. while (--line_count >= 0) { - ml_delete(1, false); + ml_delete(1); } } else { // Delete the converted lines. while (curbuf->b_ml.ml_line_count > line_count) { - ml_delete(line_count, false); + ml_delete(line_count); } } // Put the cursor on the first line. @@ -758,7 +758,7 @@ void buf_clear(void) linenr_T line_count = curbuf->b_ml.ml_line_count; extmark_free_all(curbuf); // delete any extmarks while (!(curbuf->b_ml.ml_flags & ML_EMPTY)) { - ml_delete(1, false); + ml_delete(1); } deleted_lines_mark(1, line_count); // prepare for display } diff --git a/src/nvim/change.c b/src/nvim/change.c @@ -1890,7 +1890,7 @@ void del_lines(linenr_T nlines, bool undo) break; } - ml_delete(first, true); + ml_delete_flags(first, ML_DEL_MESSAGE); n++; // If we delete the last line in the file, stop diff --git a/src/nvim/diff.c b/src/nvim/diff.c @@ -3814,7 +3814,7 @@ static void diffgetput(const int addr_count, const int idx_cur, const int idx_fr for (int i = 0; i < count; i++) { // remember deleting the last line of the buffer buf_empty = curbuf->b_ml.ml_line_count == 1; - if (ml_delete(lnum, false) == OK) { + if (ml_delete(lnum) == OK) { added--; } } @@ -3835,7 +3835,7 @@ static void diffgetput(const int addr_count, const int idx_cur, const int idx_fr // which results in inaccurate reporting of the byte count of // previous contents in buffer-update events. buf_empty = false; - ml_delete(2, false); + ml_delete(2); } } linenr_T new_count = dp->df_count[idx_to] + added; diff --git a/src/nvim/eval/buffer.c b/src/nvim/eval/buffer.c @@ -453,7 +453,7 @@ void f_deletebufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } for (linenr_T lnum = first; lnum <= last; lnum++) { - ml_delete(first, true); + ml_delete_flags(first, ML_DEL_MESSAGE); } FOR_ALL_TAB_WINDOWS(tp, wp) { diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c @@ -656,7 +656,7 @@ void ex_sort(exarg_T *eap) // delete the original lines if appending worked if (i == count) { for (i = 0; i < count; i++) { - ml_delete(eap->line1, false); + ml_delete(eap->line1); } } else { count = 0; @@ -855,7 +855,7 @@ void ex_uniq(exarg_T *eap) } if (delete_lnum > 0) { - ml_delete(delete_lnum, false); + ml_delete(delete_lnum); i -= get_lnum - delete_lnum + 1; count--; deleted++; @@ -999,7 +999,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) } for (l = line1; l <= line2; l++) { - ml_delete(line1 + extra, true); + ml_delete_flags(line1 + extra, ML_DEL_MESSAGE); } if (!global_busy && num_lines > p_report) { smsg(0, NGETTEXT("%" PRId64 " line moved", @@ -3075,7 +3075,7 @@ void ex_append(exarg_T *eap) lnum++; if (empty) { - ml_delete(2, false); + ml_delete(2); empty = false; } } @@ -3126,7 +3126,7 @@ void ex_change(exarg_T *eap) if (curbuf->b_ml.ml_flags & ML_EMPTY) { // nothing to delete break; } - ml_delete(eap->line1, false); + ml_delete(eap->line1); } // make sure the cursor is not beyond the end of the file now @@ -4316,7 +4316,7 @@ skip: break; } for (i = 0; i < nmatch_tl; i++) { - ml_delete(lnum, false); + ml_delete(lnum); } mark_adjust(lnum, lnum + nmatch_tl - 1, MAXLNUM, -nmatch_tl, kExtmarkNOOP); if (subflags.do_ask) { diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c @@ -6023,7 +6023,7 @@ static void ex_read(exarg_T *eap) lnum = 1; } if (*ml_get(lnum) == NUL && u_savedel(lnum, 1) == OK) { - ml_delete(lnum, false); + ml_delete(lnum); if (curwin->w_cursor.lnum > 1 && curwin->w_cursor.lnum >= lnum) { curwin->w_cursor.lnum--; diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c @@ -732,7 +732,7 @@ retry: } // Delete the previously read lines. while (lnum > from) { - ml_delete(lnum--, false); + ml_delete(lnum--); } file_rewind = false; if (set_options) { @@ -1659,7 +1659,7 @@ failed: if (!recoverymode) { // need to delete the last line, which comes from the empty buffer if (newfile && wasempty && !(curbuf->b_ml.ml_flags & ML_EMPTY)) { - ml_delete(curbuf->b_ml.ml_line_count, false); + ml_delete(curbuf->b_ml.ml_line_count); linecnt--; } curbuf->deleted_bytes = 0; @@ -2821,7 +2821,7 @@ static int move_lines(buf_T *frombuf, buf_T *tobuf) if (retval != FAIL) { curbuf = frombuf; for (linenr_T lnum = curbuf->b_ml.ml_line_count; lnum > 0; lnum--) { - if (ml_delete(lnum, false) == FAIL) { + if (ml_delete(lnum) == FAIL) { // Oops! We could try putting back the saved lines, but that // might fail again... retval = FAIL; @@ -3137,7 +3137,7 @@ void buf_reload(buf_T *buf, int orig_mode, bool reload_options) // Put the text back from the save buffer. First // delete any lines that readfile() added. while (!buf_is_empty(curbuf)) { - if (ml_delete(buf->b_ml.ml_line_count, false) == FAIL) { + if (ml_delete(buf->b_ml.ml_line_count) == FAIL) { break; } } diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c @@ -4902,7 +4902,7 @@ void ins_compl_delete(bool new_leader) } while (curwin->w_cursor.lnum > compl_lnum) { - if (ml_delete(curwin->w_cursor.lnum, false) == FAIL) { + if (ml_delete(curwin->w_cursor.lnum) == FAIL) { if (remaining.data) { xfree(remaining.data); } diff --git a/src/nvim/memline.c b/src/nvim/memline.c @@ -959,7 +959,7 @@ void ml_recover(bool checkext) // Now that we are sure that the file is going to be recovered, clear the // contents of the current buffer. while (!(curbuf->b_ml.ml_flags & ML_EMPTY)) { - ml_delete(1, false); + ml_delete(1); } // Try reading the original file to obtain the values of 'fileformat', @@ -1183,7 +1183,7 @@ void ml_recover(bool checkext) // empty buffer. These will now be after the last line in the buffer. while (curbuf->b_ml.ml_line_count > lnum && !(curbuf->b_ml.ml_flags & ML_EMPTY)) { - ml_delete(curbuf->b_ml.ml_line_count, false); + ml_delete(curbuf->b_ml.ml_line_count); } curbuf->b_flags |= BF_RECOVERED; check_cursor(curwin); @@ -1973,12 +1973,10 @@ int ml_line_alloced(void) /// @param lnum append after this line (can be 0) /// @param line text of the new line /// @param len length of line, including NUL, or 0 -/// @param newfile flag, see above -/// @param mark mark the new line +/// @param flags ML_APPEND_ flags /// /// @return FAIL for failure, OK otherwise -static int ml_append_int(buf_T *buf, linenr_T lnum, char *line, colnr_T len, bool newfile, - bool mark) +static int ml_append_int(buf_T *buf, linenr_T lnum, char *line, colnr_T len, int flags) FUNC_ATTR_NONNULL_ARG(1) { // lnum out of range @@ -2075,13 +2073,13 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char *line, colnr_T len, boo // copy the text into the block memmove((char *)dp + dp->db_index[db_idx + 1], line, (size_t)len); - if (mark) { + if (flags & ML_APPEND_MARK) { dp->db_index[db_idx + 1] |= DB_MARKED; } // Mark the block dirty. buf->b_ml.ml_flags |= ML_LOCKED_DIRTY; - if (!newfile) { + if (!(flags & ML_APPEND_NEW)) { buf->b_ml.ml_flags |= ML_LOCKED_POS; } } else { // not enough space in data block @@ -2135,7 +2133,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char *line, colnr_T len, boo } int page_count = ((space_needed + (int)HEADER_SIZE) + page_size - 1) / page_size; - hp_new = ml_new_data(mfp, newfile, page_count); + hp_new = ml_new_data(mfp, flags & ML_APPEND_NEW, page_count); if (db_idx < 0) { // left block is new hp_left = hp_new; hp_right = hp; @@ -2159,7 +2157,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char *line, colnr_T len, boo dp_right->db_txt_start -= (unsigned)len; dp_right->db_free -= (unsigned)len + (unsigned)INDEX_SIZE; dp_right->db_index[0] = dp_right->db_txt_start; - if (mark) { + if (flags & ML_APPEND_MARK) { dp_right->db_index[0] |= DB_MARKED; } @@ -2192,7 +2190,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char *line, colnr_T len, boo dp_left->db_txt_start -= (unsigned)len; dp_left->db_free -= (unsigned)len + (unsigned)INDEX_SIZE; dp_left->db_index[line_count_left] = dp_left->db_txt_start; - if (mark) { + if (flags & ML_APPEND_MARK) { dp_left->db_index[line_count_left] |= DB_MARKED; } memmove((char *)dp_left + dp_left->db_txt_start, @@ -2221,7 +2219,7 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char *line, colnr_T len, boo if (lines_moved || in_left) { buf->b_ml.ml_flags |= ML_LOCKED_DIRTY; } - if (!newfile && db_idx >= 0 && in_left) { + if (!(flags & ML_APPEND_NEW) && db_idx >= 0 && in_left) { buf->b_ml.ml_flags |= ML_LOCKED_POS; } mf_put(mfp, hp_new, true, false); @@ -2386,10 +2384,10 @@ static int ml_append_int(buf_T *buf, linenr_T lnum, char *line, colnr_T len, boo /// @param lnum append after this line (can be 0) /// @param line text of the new line /// @param len length of line, including NUL, or 0 -/// @param newfile flag, see above +/// @param flags ML_APPEND_ flags /// /// @return FAIL for failure, OK otherwise -static int ml_append_flush(buf_T *buf, linenr_T lnum, char *line, colnr_T len, bool newfile) +static int ml_append_flush(buf_T *buf, linenr_T lnum, char *line, colnr_T len, int flags) FUNC_ATTR_NONNULL_ARG(1) { if (lnum > buf->b_ml.ml_line_count) { @@ -2400,14 +2398,14 @@ static int ml_append_flush(buf_T *buf, linenr_T lnum, char *line, colnr_T len, b ml_flush_line(buf, false); } - return ml_append_int(buf, lnum, line, len, newfile, false); + return ml_append_int(buf, lnum, line, len, flags); } /// Append a line after lnum (may be 0 to insert a line in front of the file). /// "line" does not need to be allocated, but can't be another line in a /// buffer, unlocking may make it invalid. /// -/// newfile: true when starting to edit a new file, meaning that pe_old_lnum +/// "newfile": true when starting to edit a new file, meaning that pe_old_lnum /// will be set for recovery /// Check: The caller of this function should probably also call /// appended_lines(). @@ -2420,12 +2418,23 @@ static int ml_append_flush(buf_T *buf, linenr_T lnum, char *line, colnr_T len, b /// @return FAIL for failure, OK otherwise int ml_append(linenr_T lnum, char *line, colnr_T len, bool newfile) { + return ml_append_flags(lnum, line, len, newfile ? ML_APPEND_NEW : 0); +} + +/// @param lnum append after this line (can be 0) +/// @param line text of the new line +/// @param len length of new line, including nul, or 0 +/// @param flags ML_APPEND_ values +/// +/// @return FAIL for failure, OK otherwise +int ml_append_flags(linenr_T lnum, char *line, colnr_T len, int flags) +{ // When starting up, we might still need to create the memfile if (curbuf->b_ml.ml_mfp == NULL && open_buffer(false, NULL, 0) == FAIL) { return FAIL; } - return ml_append_flush(curbuf, lnum, line, len, newfile); + return ml_append_flush(curbuf, lnum, line, len, flags); } /// Like ml_append() but for an arbitrary buffer. The buffer must already have @@ -2442,7 +2451,7 @@ int ml_append_buf(buf_T *buf, linenr_T lnum, char *line, colnr_T len, bool newfi return FAIL; } - return ml_append_flush(buf, lnum, line, len, newfile); + return ml_append_flush(buf, lnum, line, len, newfile ? ML_APPEND_NEW : 0); } void ml_add_deleted_len(char *ptr, ssize_t len) @@ -2530,24 +2539,6 @@ int ml_replace_buf(buf_T *buf, linenr_T lnum, char *line, bool copy, bool noallo return OK; } -/// Delete line `lnum` in the current buffer. -/// -/// @note The caller of this function should probably also call -/// deleted_lines() after this. -/// -/// @param message Show "--No lines in buffer--" message. -/// -/// @return FAIL for failure, OK otherwise -int ml_delete(linenr_T lnum, bool message) -{ - ml_flush_line(curbuf, false); - if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) { - return FAIL; - } - - return ml_delete_int(curbuf, lnum, message); -} - /// Delete line `lnum` in buffer /// /// @note The caller of this function should probably also call changed_lines() after this. @@ -2556,12 +2547,20 @@ int ml_delete(linenr_T lnum, bool message) /// /// @return FAIL for failure, OK otherwise int ml_delete_buf(buf_T *buf, linenr_T lnum, bool message) + FUNC_ATTR_NONNULL_ALL { ml_flush_line(buf, false); return ml_delete_int(buf, lnum, message); } -static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message) +/// Delete line `lnum` in the current buffer. +/// +/// @param flags ML_DEL_MESSAGE may give a "No lines in buffer" message. +/// ML_DEL_UNDO this is called from undo. +/// +/// @return FAIL for failure, OK otherwise +static int ml_delete_int(buf_T *buf, linenr_T lnum, int flags) + FUNC_ATTR_NONNULL_ALL { if (lowest_marked && lowest_marked > lnum) { lowest_marked--; @@ -2569,7 +2568,7 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message) // If the file becomes empty the last line is replaced by an empty line. if (buf->b_ml.ml_line_count == 1) { // file becomes empty - if (message) { + if (flags & ML_DEL_MESSAGE) { set_keep_msg(_(no_lines_msg), 0); } @@ -2685,6 +2684,30 @@ static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message) return OK; } +/// Delete line "lnum" in the current buffer. +/// +/// @note The caller of this function should probably also call +/// deleted_lines() after this. +/// +/// @return FAIL for failure, OK otherwise +int ml_delete(linenr_T lnum) +{ + return ml_delete_flags(lnum, 0); +} + +/// Like ml_delete() but using flags (see ml_delete_int()). +/// +/// @return FAIL for failure, OK otherwise +int ml_delete_flags(linenr_T lnum, int flags) +{ + ml_flush_line(curbuf, false); + if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) { + return FAIL; + } + + return ml_delete_int(curbuf, lnum, flags); +} + /// set the B_MARKED flag for line 'lnum' void ml_setmarked(linenr_T lnum) { @@ -2845,7 +2868,9 @@ static void ml_flush_line(buf_T *buf, bool noalloc) memmove(old_line - extra, new_line, (size_t)new_len); buf->b_ml.ml_flags |= (ML_LOCKED_DIRTY | ML_LOCKED_POS); // The else case is already covered by the insert and delete - ml_updatechunk(buf, lnum, extra, ML_CHNK_UPDLINE); + if (extra != 0) { + ml_updatechunk(buf, lnum, extra, ML_CHNK_UPDLINE); + } } else { // Cannot do it in one data block: Delete and append. // Append first, because ml_delete_int() cannot delete the @@ -2853,9 +2878,9 @@ static void ml_flush_line(buf_T *buf, bool noalloc) // that has only one line. // Don't forget to copy the mark! // How about handling errors??? - ml_append_int(buf, lnum, new_line, new_len, false, - (int)(dp->db_index[idx] & DB_MARKED)); - ml_delete_int(buf, lnum, false); + (void)ml_append_int(buf, lnum, new_line, new_len, + (dp->db_index[idx] & DB_MARKED) ? ML_APPEND_MARK : 0); + (void)ml_delete_int(buf, lnum, 0); } } if (!noalloc) { @@ -3978,7 +4003,7 @@ int ml_find_line_or_offset(buf_T *buf, linenr_T lnum, int *offp, bool no_ff) return 1; // Not a "find offset" and offset 0 _must_ be in line 1 } // Find the last chunk before the one containing our line. Last chunk is - // special because it will never qualify + // special because it will never qualify. linenr_T curline = 1; int curix = 0; int size = 0; diff --git a/src/nvim/memline.h b/src/nvim/memline.h @@ -10,3 +10,16 @@ /// LINEEMPTY() - return true if the line is empty #define LINEEMPTY(p) (*ml_get(p) == NUL) + +// Values for the flags argument of ml_delete_flags(). +enum { + ML_DEL_MESSAGE = 1, // may give a "No lines in buffer" message + // ML_DEL_UNDO = 2, // called from undo +}; + +// Values for the flags argument of ml_append_int(). +enum { + ML_APPEND_NEW = 1, // starting to edit a new file + ML_APPEND_MARK = 2, // mark the new line + // ML_APPEND_UNDO = 4, // called from undo +}; diff --git a/src/nvim/normal.c b/src/nvim/normal.c @@ -6589,7 +6589,7 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent) // When all lines were selected and deleted do_put() leaves an empty // line that needs to be deleted now. if (empty && *ml_get(curbuf->b_ml.ml_line_count) == NUL) { - ml_delete(curbuf->b_ml.ml_line_count, true); + ml_delete_flags(curbuf->b_ml.ml_line_count, ML_DEL_MESSAGE); deleted_lines(curbuf->b_ml.ml_line_count + 1, 1); // If the cursor was in that line, move it to the end of the last diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c @@ -4359,7 +4359,7 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0) { // If deletion fails, this loop may run forever, so // signal error and return. - if (ml_delete(1, false) == FAIL) { + if (ml_delete(1) == FAIL) { internal_error("qf_fill_buffer()"); return; } @@ -4429,7 +4429,7 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q } if (old_last == NULL) { // Delete the empty line which is now at the end - ml_delete(lnum + 1, false); + ml_delete(lnum + 1); } qfga_clear(); diff --git a/src/nvim/spell.c b/src/nvim/spell.c @@ -3232,7 +3232,7 @@ void ex_spelldump(exarg_T *eap) // Delete the empty line that we started with. if (curbuf->b_ml.ml_line_count > 1) { - ml_delete(curbuf->b_ml.ml_line_count, false); + ml_delete(curbuf->b_ml.ml_line_count); } redraw_later(curwin, UPD_NOT_VALID); } diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c @@ -2133,7 +2133,7 @@ static void adjust_scrollback(Terminal *term, buf_T *buf) if (scbk < term->sb_current) { size_t diff = term->sb_current - scbk; for (size_t i = 0; i < diff; i++) { - ml_delete(1, false); + ml_delete(1); term->sb_current--; xfree(term->sb_buffer[term->sb_current]); } diff --git a/src/nvim/undo.c b/src/nvim/undo.c @@ -248,7 +248,7 @@ int u_save_cursor(void) } /// Save the lines between "top" and "bot" for both the "u" and "U" command. -/// "top" may be 0 and bot may be curbuf->b_ml.ml_line_count + 1. +/// "top" may be 0 and "bot" may be curbuf->b_ml.ml_line_count + 1. /// Careful: may trigger autocommands that reload the buffer. /// Returns FAIL when lines could not be saved, OK otherwise. int u_save(linenr_T top, linenr_T bot) @@ -2250,6 +2250,7 @@ static void u_undoredo(bool undo, bool do_buf_event) { char **newarray = NULL; linenr_T newlnum = MAXLNUM; + pos_T new_curpos = curwin->w_cursor; u_entry_T *nuep; u_entry_T *newlist = NULL; fmark_T namedm[NMARKS]; @@ -2294,14 +2295,16 @@ static void u_undoredo(bool undo, bool do_buf_event) linenr_T oldsize = bot - top - 1; // number of lines before undo linenr_T newsize = uep->ue_size; // number of lines after undo + // Decide about the cursor position, depending on what text changed. + // Don't set it yet, it may be invalid if lines are going to be added. if (top < newlnum) { // If the saved cursor is somewhere in this undo block, move it to // the remembered position. Makes "gwap" put the cursor back // where it was. linenr_T lnum = curhead->uh_cursor.lnum; if (lnum >= top && lnum <= top + newsize + 1) { - curwin->w_cursor = curhead->uh_cursor; - newlnum = curwin->w_cursor.lnum - 1; + new_curpos = curhead->uh_cursor; + newlnum = new_curpos.lnum - 1; } else { // Use the first line that actually changed. Avoids that // undoing auto-formatting puts the cursor in the previous @@ -2314,17 +2317,17 @@ static void u_undoredo(bool undo, bool do_buf_event) } if (i == newsize && newlnum == MAXLNUM && uep->ue_next == NULL) { newlnum = top; - curwin->w_cursor.lnum = newlnum + 1; + new_curpos.lnum = newlnum + 1; } else if (i < newsize) { newlnum = top + (linenr_T)i; - curwin->w_cursor.lnum = newlnum + 1; + new_curpos.lnum = newlnum + 1; } } } bool empty_buffer = false; - // delete the lines between top and bot and save them in newarray + // Delete the lines between top and bot and save them in newarray. if (oldsize > 0) { newarray = xmalloc(sizeof(char *) * (size_t)oldsize); // delete backwards, it goes faster in most cases @@ -2338,13 +2341,16 @@ static void u_undoredo(bool undo, bool do_buf_event) if (curbuf->b_ml.ml_line_count == 1) { empty_buffer = true; } - ml_delete(lnum, false); + ml_delete(lnum); // ML_DEL_UNDO } } else { newarray = NULL; } - // insert the lines in u_array between top and bot + // make sure the cursor is on a valid line after the deletions + check_cursor_lnum(curwin); + + // Insert the lines in u_array between top and bot. if (newsize) { int i; linenr_T lnum; @@ -2354,7 +2360,7 @@ static void u_undoredo(bool undo, bool do_buf_event) if (empty_buffer && lnum == 0) { ml_replace(1, uep->ue_array[i], true); } else { - ml_append(lnum, uep->ue_array[i], 0, false); + ml_append_flags(lnum, uep->ue_array[i], 0, 0); // ML_APPEND_UNDO } xfree(uep->ue_array[i]); } @@ -2372,12 +2378,14 @@ static void u_undoredo(bool undo, bool do_buf_event) } } - changed_lines(curbuf, top + 1, 0, bot, newsize - oldsize, do_buf_event); - // When text has been changed, possibly the start of the next line - // may have SpellCap that should be removed or it needs to be - // displayed. Schedule the next line for redrawing just in case. - if (spell_check_window(curwin) && bot <= curbuf->b_ml.ml_line_count) { - redrawWinline(curwin, bot); + if (oldsize > 0 || newsize > 0) { + changed_lines(curbuf, top + 1, 0, bot, newsize - oldsize, do_buf_event); + // When text has been changed, possibly the start of the next line + // may have SpellCap that should be removed or it needs to be + // displayed. Schedule the next line for redrawing just in case. + if (spell_check_window(curwin) && bot <= curbuf->b_ml.ml_line_count) { + redrawWinline(curwin, bot); + } } // Set the '[ mark. @@ -2423,6 +2431,10 @@ static void u_undoredo(bool undo, bool do_buf_event) } // Finish adjusting extmarks + // Set the cursor to the desired position. Check that the line is valid. + curwin->w_cursor = new_curpos; + check_cursor_lnum(curwin); + curhead->uh_entry = newlist; curhead->uh_flags = new_flags; if ((old_flags & UH_EMPTYBUF) && buf_is_empty(curbuf)) { diff --git a/test/old/testdir/test_jumplist.vim b/test/old/testdir/test_jumplist.vim @@ -2,10 +2,6 @@ " Tests for the getjumplist() function func Test_getjumplist() - if !has("jumplist") - return - endif - %bwipe clearjumps call assert_equal([[], 0], getjumplist())