refactor(change): do API changes to buffer without curbuf switch

Most of the messy things when changing a non-current buffer is
not about the buffer, it is about windows. In particular, it is about
`curwin`.

When editing a non-current buffer which is displayed in some other
window in the current tabpage, one such window will be "borrowed" as the
curwin. But this means if two or more non-current windows displayed the buffers,
one of them will be treated differenty. this is not desirable.

In particular, with nvim_buf_set_text, cursor _column_ position was only
corrected for one single window. Two new tests are added: the test
with just one non-current window passes, but the one with two didn't.

Two corresponding such tests were also added for nvim_buf_set_lines.
This already worked correctly on master, but make sure this is
well-tested for future refactors.

Also, nvim_create_buf no longer invokes autocmds just because you happened
to use `scratch=true`. No option value was changed, therefore OptionSet
must not be fired.
This commit is contained in:
bfredl 2023-08-21 14:52:17 +02:00
parent 1635c9e75e
commit 0081549547
33 changed files with 737 additions and 548 deletions

View File

@ -386,27 +386,29 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ
}
try_start();
aco_save_T aco;
aucmd_prepbuf(&aco, buf);
if (!MODIFIABLE(buf)) {
api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'");
goto end;
}
if (u_save((linenr_T)(start - 1), (linenr_T)end) == FAIL) {
if (!buf_ensure_loaded(buf)) {
goto end;
}
if (u_save_buf(buf, (linenr_T)(start - 1), (linenr_T)end) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to save undo information");
goto end;
}
bcount_t deleted_bytes = get_region_bytecount(curbuf, (linenr_T)start, (linenr_T)end, 0, 0);
bcount_t deleted_bytes = get_region_bytecount(buf, (linenr_T)start, (linenr_T)end, 0, 0);
// If the size of the range is reducing (ie, new_len < old_len) we
// need to delete some old_len. We do this at the start, by
// repeatedly deleting line "start".
size_t to_delete = (new_len < old_len) ? old_len - new_len : 0;
for (size_t i = 0; i < to_delete; i++) {
if (ml_delete((linenr_T)start, false) == FAIL) {
if (ml_delete_buf(buf, (linenr_T)start, false) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to delete line");
goto end;
}
@ -428,7 +430,7 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ
goto end;
});
if (ml_replace((linenr_T)lnum, lines[i], false) == FAIL) {
if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to replace line");
goto end;
}
@ -447,7 +449,7 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ
goto end;
});
if (ml_append((linenr_T)lnum, lines[i], 0, false) == FAIL) {
if (ml_append_buf(buf, (linenr_T)lnum, lines[i], 0, false) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to insert line");
goto end;
}
@ -462,20 +464,18 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ
// Adjust marks. Invalidate any which lie in the
// changed range, and move any in the remainder of the buffer.
// Only adjust marks if we managed to switch to a window that holds
// the buffer, otherwise line numbers will be invalid.
mark_adjust((linenr_T)start,
(linenr_T)(end - 1),
MAXLNUM,
(linenr_T)extra,
kExtmarkNOOP);
mark_adjust_buf(buf, (linenr_T)start, (linenr_T)(end - 1), MAXLNUM, (linenr_T)extra,
true, true, kExtmarkNOOP);
extmark_splice(curbuf, (int)start - 1, 0, (int)(end - start), 0,
extmark_splice(buf, (int)start - 1, 0, (int)(end - start), 0,
deleted_bytes, (int)new_len, 0, inserted_bytes,
kExtmarkUndo);
changed_lines((linenr_T)start, 0, (linenr_T)end, (linenr_T)extra, true);
fix_cursor((linenr_T)start, (linenr_T)end, (linenr_T)extra);
changed_lines(buf, (linenr_T)start, 0, (linenr_T)end, (linenr_T)extra, true);
if (curwin->w_buffer == buf) {
// mark_adjust_buf handles non-current windows
fix_cursor(curwin, (linenr_T)start, (linenr_T)end, (linenr_T)extra);
}
end:
for (size_t i = 0; i < new_len; i++) {
@ -483,7 +483,6 @@ end:
}
xfree(lines);
aucmd_restbuf(&aco);
try_end(err);
}
@ -630,17 +629,19 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In
}
try_start();
aco_save_T aco;
aucmd_prepbuf(&aco, buf);
if (!MODIFIABLE(buf)) {
api_set_error(err, kErrorTypeException, "Buffer is not 'modifiable'");
goto end;
}
if (!buf_ensure_loaded(buf)) {
goto end;
}
// Small note about undo states: unlike set_lines, we want to save the
// undo state of one past the end_row, since end_row is inclusive.
if (u_save((linenr_T)start_row - 1, (linenr_T)end_row + 1) == FAIL) {
if (u_save_buf(buf, (linenr_T)start_row - 1, (linenr_T)end_row + 1) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to save undo information");
goto end;
}
@ -653,7 +654,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In
// repeatedly deleting line "start".
size_t to_delete = (new_len < old_len) ? old_len - new_len : 0;
for (size_t i = 0; i < to_delete; i++) {
if (ml_delete((linenr_T)start_row, false) == FAIL) {
if (ml_delete_buf(buf, (linenr_T)start_row, false) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to delete line");
goto end;
}
@ -674,7 +675,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In
goto end;
});
if (ml_replace((linenr_T)lnum, lines[i], false) == FAIL) {
if (ml_replace_buf(buf, (linenr_T)lnum, lines[i], false) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to replace line");
goto end;
}
@ -691,7 +692,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In
goto end;
});
if (ml_append((linenr_T)lnum, lines[i], 0, false) == FAIL) {
if (ml_append_buf(buf, (linenr_T)lnum, lines[i], 0, false) == FAIL) {
api_set_error(err, kErrorTypeException, "Failed to insert line");
goto end;
}
@ -702,35 +703,37 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In
extra++;
}
// Adjust marks. Invalidate any which lie in the
// changed range, and move any in the remainder of the buffer.
mark_adjust((linenr_T)start_row,
(linenr_T)end_row,
MAXLNUM,
(linenr_T)extra,
kExtmarkNOOP);
colnr_T col_extent = (colnr_T)(end_col
- ((end_row == start_row) ? start_col : 0));
// Adjust marks. Invalidate any which lie in the
// changed range, and move any in the remainder of the buffer.
// Do not adjust any cursors. need to use column-aware logic (below)
mark_adjust_buf(buf, (linenr_T)start_row, (linenr_T)end_row, MAXLNUM, (linenr_T)extra,
true, false, kExtmarkNOOP);
extmark_splice(buf, (int)start_row - 1, (colnr_T)start_col,
(int)(end_row - start_row), col_extent, old_byte,
(int)new_len - 1, (colnr_T)last_item.size, new_byte,
kExtmarkUndo);
changed_lines((linenr_T)start_row, 0, (linenr_T)end_row + 1, (linenr_T)extra, true);
changed_lines(buf, (linenr_T)start_row, 0, (linenr_T)end_row + 1, (linenr_T)extra, true);
// adjust cursor like an extmark ( i e it was inside last_part_len)
if (curwin->w_cursor.lnum == end_row && curwin->w_cursor.col > end_col) {
curwin->w_cursor.col -= col_extent - (colnr_T)last_item.size;
FOR_ALL_TAB_WINDOWS(tp, win) {
if (win->w_buffer == buf) {
// adjust cursor like an extmark ( i e it was inside last_part_len)
if (win->w_cursor.lnum == end_row && win->w_cursor.col > end_col) {
win->w_cursor.col -= col_extent - (colnr_T)last_item.size;
}
fix_cursor(win, (linenr_T)start_row, (linenr_T)end_row, (linenr_T)extra);
}
}
fix_cursor((linenr_T)start_row, (linenr_T)end_row, (linenr_T)extra);
end:
for (size_t i = 0; i < new_len; i++) {
xfree(lines[i]);
}
xfree(lines);
aucmd_restbuf(&aco);
try_end(err);
early_end:
@ -1317,21 +1320,19 @@ Dictionary nvim__buf_stats(Buffer buffer, Error *err)
// Check if deleting lines made the cursor position invalid.
// Changed lines from `lo` to `hi`; added `extra` lines (negative if deleted).
static void fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra)
static void fix_cursor(win_T *win, linenr_T lo, linenr_T hi, linenr_T extra)
{
if (curwin->w_cursor.lnum >= lo) {
if (win->w_cursor.lnum >= lo) {
// Adjust cursor position if it's in/after the changed lines.
if (curwin->w_cursor.lnum >= hi) {
curwin->w_cursor.lnum += extra;
check_cursor_col();
if (win->w_cursor.lnum >= hi) {
win->w_cursor.lnum += extra;
} else if (extra < 0) {
check_cursor();
} else {
check_cursor_col();
check_cursor_lnum(win);
}
changed_cline_bef_curs();
check_cursor_col_win(win);
changed_cline_bef_curs(win);
}
invalidate_botline();
invalidate_botline(win);
}
/// Initialise a string array either:

View File

@ -912,14 +912,17 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err)
goto fail;
}
// Only strictly needed for scratch, but could just as well be consistent
// and do this now. buffer is created NOW, not when it latter first happen
// to reach a window or aucmd_prepbuf() ..
buf_copy_options(buf, BCO_ENTER | BCO_NOHELP);
if (scratch) {
aco_save_T aco;
aucmd_prepbuf(&aco, buf);
set_option_value("bufhidden", STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL);
set_option_value("buftype", STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL);
set_option_value("swapfile", BOOLEAN_OPTVAL(false), OPT_LOCAL);
set_option_value("modeline", BOOLEAN_OPTVAL(false), OPT_LOCAL); // 'nomodeline'
aucmd_restbuf(&aco);
set_string_option_direct_in_buf(buf, "bufhidden", -1, "hide", OPT_LOCAL, 0);
set_string_option_direct_in_buf(buf, "buftype", -1, "nofile", OPT_LOCAL, 0);
assert(buf->b_ml.ml_mfp->mf_fd < 0); // ml_open() should not have opened swapfile already
buf->b_p_swf = false;
buf->b_p_ml = false;
}
return buf->b_fnum;

View File

@ -164,7 +164,7 @@ static int read_buffer(int read_stdin, exarg_T *eap, int flags)
// Set or reset 'modified' before executing autocommands, so that
// it can be changed there.
if (!readonlymode && !buf_is_empty(curbuf)) {
changed();
changed(curbuf);
} else if (retval != FAIL) {
unchanged(curbuf, false, true);
}
@ -175,20 +175,22 @@ static int read_buffer(int read_stdin, exarg_T *eap, int flags)
return retval;
}
/// Ensure buffer "buf" is loaded. Does not trigger the swap-exists action.
void buffer_ensure_loaded(buf_T *buf)
/// Ensure buffer "buf" is loaded.
bool buf_ensure_loaded(buf_T *buf)
{
if (buf->b_ml.ml_mfp != NULL) {
return;
// already open (common case)
return true;
}
aco_save_T aco;
// Make sure the buffer is in a window.
aucmd_prepbuf(&aco, buf);
swap_exists_action = SEA_NONE;
open_buffer(false, NULL, 0);
// status can be OK or NOTDONE (which also means ok/done)
int status = open_buffer(false, NULL, 0);
aucmd_restbuf(&aco);
return (status != FAIL);
}
/// Open current buffer, that is: open the memfile and read the file into
@ -343,7 +345,7 @@ int open_buffer(int read_stdin, exarg_T *eap, int flags_arg)
if ((got_int && vim_strchr(p_cpo, CPO_INTMOD) != NULL)
|| modified_was_set // ":set modified" used in autocmd
|| (aborting() && vim_strchr(p_cpo, CPO_INTMOD) != NULL)) {
changed();
changed(curbuf);
} else if (retval != FAIL && !read_stdin && !read_fifo) {
unchanged(curbuf, false, true);
}
@ -749,8 +751,6 @@ void buf_clear(void)
ml_delete((linenr_T)1, false);
}
deleted_lines_mark(1, line_count); // prepare for display
ml_close(curbuf, true); // free memline_T
buf_clear_file(curbuf);
}
/// buf_freeall() - free all things allocated for a buffer that are related to
@ -2124,7 +2124,7 @@ void buflist_getfpos(void)
fpos = &buflist_findfmark(curbuf)->mark;
curwin->w_cursor.lnum = fpos->lnum;
check_cursor_lnum();
check_cursor_lnum(curwin);
if (p_sol) {
curwin->w_cursor.col = 0;

View File

@ -101,28 +101,28 @@ void change_warning(buf_T *buf, int col)
}
}
/// Call this function when something in the current buffer is changed.
/// Call this function when something in a buffer is changed.
///
/// Most often called through changed_bytes() and changed_lines(), which also
/// mark the area of the display to be redrawn.
///
/// Careful: may trigger autocommands that reload the buffer.
void changed(void)
void changed(buf_T *buf)
{
if (!curbuf->b_changed) {
if (!buf->b_changed) {
int save_msg_scroll = msg_scroll;
// Give a warning about changing a read-only file. This may also
// check-out the file, thus change "curbuf"!
change_warning(curbuf, 0);
change_warning(buf, 0);
// Create a swap file if that is wanted.
// Don't do this for "nofile" and "nowrite" buffer types.
if (curbuf->b_may_swap && !bt_dontwrite(curbuf)) {
if (buf->b_may_swap && !bt_dontwrite(buf)) {
bool save_need_wait_return = need_wait_return;
need_wait_return = false;
ml_open_file(curbuf);
ml_open_file(buf);
// The ml_open_file() can cause an ATTENTION message.
// Wait two seconds, to make sure the user reads this unexpected
@ -137,9 +137,9 @@ void changed(void)
need_wait_return = save_need_wait_return;
}
}
changed_internal();
changed_internal(buf);
}
buf_inc_changedtick(curbuf);
buf_inc_changedtick(buf);
// If a pattern is highlighted, the position may now be invalid.
highlight_match = false;
@ -147,12 +147,12 @@ void changed(void)
/// Internal part of changed(), no user interaction.
/// Also used for recovery.
void changed_internal(void)
void changed_internal(buf_T *buf)
{
curbuf->b_changed = true;
curbuf->b_changed_invalid = true;
ml_setflags(curbuf);
redraw_buf_status_later(curbuf);
buf->b_changed = true;
buf->b_changed_invalid = true;
ml_setflags(buf);
redraw_buf_status_later(buf);
redraw_tabline = true;
need_maketitle = true; // set window title later
}
@ -160,13 +160,15 @@ void changed_internal(void)
/// Common code for when a change was made.
/// See changed_lines() for the arguments.
/// Careful: may trigger autocommands that reload the buffer.
static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T xtra)
static void changed_common(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T xtra)
{
// mark the buffer as modified
changed();
changed(buf);
if (curwin->w_p_diff && diff_internal()) {
curtab->tp_diff_update = true;
FOR_ALL_WINDOWS_IN_TAB(win, curtab) {
if (win->w_buffer == buf && win->w_p_diff && diff_internal()) {
curtab->tp_diff_update = true;
}
}
// set the '. mark
@ -174,22 +176,25 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T
fmarkv_T view = INIT_FMARKV;
// Set the markview only if lnum is visible, as changes might be done
// outside of the current window view.
if (lnum >= curwin->w_topline && lnum <= curwin->w_botline) {
view = mark_view_make(curwin->w_topline, curwin->w_cursor);
if (curwin->w_buffer == buf) {
if (lnum >= curwin->w_topline && lnum <= curwin->w_botline) {
view = mark_view_make(curwin->w_topline, curwin->w_cursor);
}
}
RESET_FMARK(&curbuf->b_last_change, ((pos_T) { lnum, col, 0 }), curbuf->handle, view);
RESET_FMARK(&buf->b_last_change, ((pos_T) { lnum, col, 0 }), buf->handle, view);
// Create a new entry if a new undo-able change was started or we
// don't have an entry yet.
if (curbuf->b_new_change || curbuf->b_changelistlen == 0) {
if (buf->b_new_change || buf->b_changelistlen == 0) {
int add;
if (curbuf->b_changelistlen == 0) {
if (buf->b_changelistlen == 0) {
add = true;
} else {
// Don't create a new entry when the line number is the same
// as the last one and the column is not too far away. Avoids
// creating many entries for typing "xxxxx".
pos_T *p = &curbuf->b_changelist[curbuf->b_changelistlen - 1].mark;
pos_T *p = &buf->b_changelist[buf->b_changelistlen - 1].mark;
if (p->lnum != lnum) {
add = true;
} else {
@ -204,17 +209,17 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T
// This is the first of a new sequence of undo-able changes
// and it's at some distance of the last change. Use a new
// position in the changelist.
curbuf->b_new_change = false;
buf->b_new_change = false;
if (curbuf->b_changelistlen == JUMPLISTSIZE) {
if (buf->b_changelistlen == JUMPLISTSIZE) {
// changelist is full: remove oldest entry
curbuf->b_changelistlen = JUMPLISTSIZE - 1;
memmove(curbuf->b_changelist, curbuf->b_changelist + 1,
sizeof(curbuf->b_changelist[0]) * (JUMPLISTSIZE - 1));
buf->b_changelistlen = JUMPLISTSIZE - 1;
memmove(buf->b_changelist, buf->b_changelist + 1,
sizeof(buf->b_changelist[0]) * (JUMPLISTSIZE - 1));
FOR_ALL_TAB_WINDOWS(tp, wp) {
// Correct position in changelist for other windows on
// this buffer.
if (wp->w_buffer == curbuf && wp->w_changelistidx > 0) {
if (wp->w_buffer == buf && wp->w_changelistidx > 0) {
wp->w_changelistidx--;
}
}
@ -222,27 +227,29 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T
FOR_ALL_TAB_WINDOWS(tp, wp) {
// For other windows, if the position in the changelist is
// at the end it stays at the end.
if (wp->w_buffer == curbuf
&& wp->w_changelistidx == curbuf->b_changelistlen) {
if (wp->w_buffer == buf
&& wp->w_changelistidx == buf->b_changelistlen) {
wp->w_changelistidx++;
}
}
curbuf->b_changelistlen++;
buf->b_changelistlen++;
}
}
curbuf->b_changelist[curbuf->b_changelistlen - 1] =
curbuf->b_last_change;
buf->b_changelist[buf->b_changelistlen - 1] =
buf->b_last_change;
// The current window is always after the last change, so that "g,"
// takes you back to it.
curwin->w_changelistidx = curbuf->b_changelistlen;
if (curwin->w_buffer == buf) {
curwin->w_changelistidx = buf->b_changelistlen;
}
}
if (VIsual_active) {
if (curwin->w_buffer == buf && VIsual_active) {
check_visual_pos();
}
FOR_ALL_TAB_WINDOWS(tp, wp) {
if (wp->w_buffer == curbuf) {
if (wp->w_buffer == buf) {
// Mark this window to be redrawn later.
if (wp->w_redr_type < UPD_VALID) {
wp->w_redr_type = UPD_VALID;
@ -295,7 +302,7 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T
if (wp->w_cursor.lnum > lnum) {
changed_line_abv_curs_win(wp);
} else if (wp->w_cursor.lnum == lnum && wp->w_cursor.col >= col) {
changed_cline_bef_curs_win(wp);
changed_cline_bef_curs(wp);
}
if (wp->w_botline >= lnum) {
// Assume that botline doesn't change (inserted lines make
@ -361,7 +368,7 @@ static void changed_common(linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T
}
// when the cursor line is changed always trigger CursorMoved
if (last_cursormoved_win == curwin
if (last_cursormoved_win == curwin && curwin->w_buffer == buf
&& lnum <= curwin->w_cursor.lnum
&& lnume + (xtra < 0 ? -xtra : xtra) > curwin->w_cursor.lnum) {
last_cursormoved.lnum = 0;
@ -394,7 +401,7 @@ static void changedOneline(buf_T *buf, linenr_T lnum)
void changed_bytes(linenr_T lnum, colnr_T col)
{
changedOneline(curbuf, lnum);
changed_common(lnum, col, lnum + 1, 0);
changed_common(curbuf, lnum, col, lnum + 1, 0);
// When text has been changed at the end of the line, 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.
@ -438,14 +445,14 @@ void inserted_bytes(linenr_T lnum, colnr_T start_col, int old_col, int new_col)
/// Takes care of marking the buffer to be redrawn and sets the changed flag.
void appended_lines(linenr_T lnum, linenr_T count)
{
changed_lines(lnum + 1, 0, lnum + 1, count, true);
changed_lines(curbuf, lnum + 1, 0, lnum + 1, count, true);
}
/// Like appended_lines(), but adjust marks first.
void appended_lines_mark(linenr_T lnum, int count)
{
mark_adjust(lnum + 1, (linenr_T)MAXLNUM, (linenr_T)count, 0L, kExtmarkUndo);
changed_lines(lnum + 1, 0, lnum + 1, (linenr_T)count, true);
changed_lines(curbuf, lnum + 1, 0, lnum + 1, (linenr_T)count, true);
}
/// Deleted "count" lines at line "lnum" in the current buffer.
@ -453,7 +460,7 @@ void appended_lines_mark(linenr_T lnum, int count)
/// Takes care of marking the buffer to be redrawn and sets the changed flag.
void deleted_lines(linenr_T lnum, linenr_T count)
{
changed_lines(lnum, 0, lnum + count, -count, true);
changed_lines(curbuf, lnum, 0, lnum + count, -count, true);
}
/// Like deleted_lines(), but adjust marks first.
@ -467,7 +474,7 @@ void deleted_lines_mark(linenr_T lnum, int count)
// if we deleted the entire buffer, we need to implicitly add a new empty line
extmark_adjust(curbuf, lnum, (linenr_T)(lnum + count - 1), MAXLNUM,
-(linenr_T)count + (made_empty ? 1 : 0), kExtmarkUndo);
changed_lines(lnum, 0, lnum + (linenr_T)count, (linenr_T)(-count), true);
changed_lines(curbuf, lnum, 0, lnum + (linenr_T)count, (linenr_T)(-count), true);
}
/// Marks the area to be redrawn after a change.
@ -477,7 +484,7 @@ void deleted_lines_mark(linenr_T lnum, int count)
/// @param lnum first line with change
/// @param lnume line below last changed line
/// @param xtra number of extra lines (negative when deleting)
void changed_lines_buf(buf_T *buf, linenr_T lnum, linenr_T lnume, linenr_T xtra)
void buf_redraw_changed_lines_later(buf_T *buf, linenr_T lnum, linenr_T lnume, linenr_T xtra)
{
if (buf->b_mod_set) {
// find the maximum area that must be redisplayed
@ -504,7 +511,7 @@ void changed_lines_buf(buf_T *buf, linenr_T lnum, linenr_T lnume, linenr_T xtra)
}
}
/// Changed lines for the current buffer.
/// Changed lines for a buffer.
/// Must be called AFTER the change and after mark_adjust().
/// - mark the buffer changed by calling changed()
/// - mark the windows on this buffer to be redisplayed
@ -522,11 +529,12 @@ void changed_lines_buf(buf_T *buf, linenr_T lnum, linenr_T lnume, linenr_T xtra)
/// @param do_buf_event some callers like undo/redo call changed_lines() and
/// then increment changedtick *again*. This flag allows these callers to send
/// the nvim_buf_lines_event events after they're done modifying changedtick.
void changed_lines(linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T xtra, bool do_buf_event)
void changed_lines(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T xtra,
bool do_buf_event)
{
changed_lines_buf(curbuf, lnum, lnume, xtra);
buf_redraw_changed_lines_later(buf, lnum, lnume, xtra);
if (xtra == 0 && curwin->w_p_diff && !diff_internal()) {
if (xtra == 0 && curwin->w_p_diff && curwin->w_buffer == buf && !diff_internal()) {
// When the number of lines doesn't change then mark_adjust() isn't
// called and other diff buffers still need to be marked for
// displaying.
@ -537,19 +545,19 @@ void changed_lines(linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T xtra, bo
redraw_later(wp, UPD_VALID);
wlnum = diff_lnum_win(lnum, wp);
if (wlnum > 0) {
changed_lines_buf(wp->w_buffer, wlnum,
lnume - lnum + wlnum, 0L);
buf_redraw_changed_lines_later(wp->w_buffer, wlnum,
lnume - lnum + wlnum, 0L);
}
}
}
}
changed_common(lnum, col, lnume, xtra);
changed_common(buf, lnum, col, lnume, xtra);
if (do_buf_event) {
int64_t num_added = (int64_t)(lnume + xtra - lnum);
int64_t num_removed = lnume - lnum;
buf_updates_send_changes(curbuf, lnum, num_added, num_removed);
buf_updates_send_changes(buf, lnum, num_added, num_removed);
}
}
@ -1119,7 +1127,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
*p_extra = NUL;
}
u_clearline(); // cannot do "U" command when adding lines
u_clearline(curbuf); // cannot do "U" command when adding lines
did_si = false;
ai_col = 0;
@ -1807,7 +1815,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
saved_line = NULL;
if (did_append) {
changed_lines(curwin->w_cursor.lnum, curwin->w_cursor.col,
changed_lines(curbuf, curwin->w_cursor.lnum, curwin->w_cursor.col,
curwin->w_cursor.lnum + 1, 1L, true);
did_append = false;
@ -1833,7 +1841,7 @@ int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
curwin->w_cursor.lnum = old_cursor.lnum + 1;
}
if (did_append) {
changed_lines(curwin->w_cursor.lnum, 0, curwin->w_cursor.lnum, 1L, true);
changed_lines(curbuf, curwin->w_cursor.lnum, 0, curwin->w_cursor.lnum, 1L, true);
// bail out and just get the final length of the line we just manipulated
bcount_t extra = (bcount_t)strlen(ml_get(curwin->w_cursor.lnum));
extmark_splice(curbuf, (int)curwin->w_cursor.lnum - 1, 0,
@ -1958,7 +1966,7 @@ void del_lines(long nlines, bool undo)
// Correct the cursor position before calling deleted_lines_mark(), it may
// trigger a callback to display the cursor.
curwin->w_cursor.col = 0;
check_cursor_lnum();
check_cursor_lnum(curwin);
// adjust marks, mark the buffer as changed and prepare for displaying
deleted_lines_mark(first, n);

View File

@ -324,18 +324,18 @@ void check_pos(buf_T *buf, pos_T *pos)
}
/// Make sure curwin->w_cursor.lnum is valid.
void check_cursor_lnum(void)
void check_cursor_lnum(win_T *win)
{
if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) {
buf_T *buf = win->w_buffer;
if (win->w_cursor.lnum > buf->b_ml.ml_line_count) {
// If there is a closed fold at the end of the file, put the cursor in
// its first line. Otherwise in the last line.
if (!hasFolding(curbuf->b_ml.ml_line_count,
&curwin->w_cursor.lnum, NULL)) {
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
if (!hasFolding(buf->b_ml.ml_line_count, &win->w_cursor.lnum, NULL)) {
win->w_cursor.lnum = buf->b_ml.ml_line_count;
}
}
if (curwin->w_cursor.lnum <= 0) {
curwin->w_cursor.lnum = 1;
if (win->w_cursor.lnum <= 0) {
win->w_cursor.lnum = 1;
}
}
@ -406,7 +406,7 @@ void check_cursor_col_win(win_T *win)
/// Make sure curwin->w_cursor in on a valid character
void check_cursor(void)
{
check_cursor_lnum();
check_cursor_lnum(curwin);
check_cursor_col();
}
@ -451,7 +451,7 @@ bool set_leftcol(colnr_T leftcol)
}
curwin->w_leftcol = leftcol;
changed_cline_bef_curs();
changed_cline_bef_curs(curwin);
// TODO(hinidu): I think it should be colnr_T or int, but p_siso is long.
// Perhaps we can change p_siso to int.
int64_t lastcol = curwin->w_leftcol + curwin->w_width_inner - curwin_col_off() - 1;
@ -481,7 +481,7 @@ bool set_leftcol(colnr_T leftcol)
retval = true;
if (coladvance(e + 1) == FAIL) { // there isn't another character
curwin->w_leftcol = s; // adjust w_leftcol instead
changed_cline_bef_curs();
changed_cline_bef_curs(curwin);
}
}

View File

@ -266,24 +266,25 @@ void diff_invalidate(buf_T *buf)
}
}
/// Called by mark_adjust(): update line numbers in "curbuf".
/// Called by mark_adjust(): update line numbers in "buf".
///
/// @param line1
/// @param line2
/// @param amount
/// @param amount_after
void diff_mark_adjust(linenr_T line1, linenr_T line2, linenr_T amount, linenr_T amount_after)
void diff_mark_adjust(buf_T *buf, linenr_T line1, linenr_T line2, linenr_T amount,
linenr_T amount_after)
{
// Handle all tab pages that use the current buffer in a diff.
// Handle all tab pages that use "buf" in a diff.
FOR_ALL_TABS(tp) {
int idx = diff_buf_idx_tp(curbuf, tp);
int idx = diff_buf_idx_tp(buf, tp);
if (idx != DB_COUNT) {
diff_mark_adjust_tp(tp, idx, line1, line2, amount, amount_after);
}
}
}
/// Update line numbers in tab page "tp" for "curbuf" with index "idx".
/// Update line numbers in tab page "tp" for the buffer with index "idx".
///
/// This attempts to update the changes as much as possible:
/// When inserting/deleting lines outside of existing change blocks, create a
@ -2444,7 +2445,7 @@ void diff_set_topline(win_T *fromwin, win_T *towin)
}
// When w_topline changes need to recompute w_botline and cursor position
invalidate_botline_win(towin);
invalidate_botline(towin);
changed_line_abv_curs_win(towin);
check_topfill(towin, false);
@ -3144,7 +3145,7 @@ static void diffgetput(const int addr_count, const int idx_cur, const int idx_fr
}
}
extmark_adjust(curbuf, lnum, lnum + count - 1, (long)MAXLNUM, added, kExtmarkUndo);
changed_lines(lnum, 0, lnum + count, added, true);
changed_lines(curbuf, lnum, 0, lnum + count, added, true);
if (did_free) {
// Diff is deleted, update folds in other windows.

View File

@ -329,7 +329,7 @@ void screen_resize(int width, int height)
maketitle();
changed_line_abv_curs();
invalidate_botline();
invalidate_botline(curwin);
// We only redraw when it's needed:
// - While at the more prompt or executing an external command, don't

View File

@ -1708,7 +1708,7 @@ void change_indent(int type, int amount, int round, int replaced, int call_chang
curwin->w_cursor.col = (colnr_T)new_cursor_col;
}
curwin->w_set_curswant = true;
changed_cline_bef_curs();
changed_cline_bef_curs(curwin);
// May have to adjust the start of the insert.
if (State & MODE_INSERT) {

View File

@ -301,7 +301,8 @@ void f_bufload(typval_T *argvars, typval_T *unused, EvalFuncData fptr)
buf_T *buf = get_buf_arg(&argvars[0]);
if (buf != NULL) {
buffer_ensure_loaded(buf);
swap_exists_action = SEA_NONE;
buf_ensure_loaded(buf);
}
}

View File

@ -321,7 +321,7 @@ void ex_align(exarg_T *eap)
}
(void)set_indent(new_indent, 0); // set indent
}
changed_lines(eap->line1, 0, eap->line2 + 1, 0L, true);
changed_lines(curbuf, eap->line1, 0, eap->line2 + 1, 0L, true);
curwin->w_cursor = save_curpos;
beginline(BL_WHITE | BL_FIX);
}
@ -702,7 +702,7 @@ void ex_sort(exarg_T *eap)
(int)count, 0, old_count,
lnum - eap->line2, 0, new_count, kExtmarkUndo);
changed_lines(eap->line1, 0, eap->line2 + 1, -deleted, true);
changed_lines(curbuf, eap->line1, 0, eap->line2 + 1, -deleted, true);
}
curwin->w_cursor.lnum = eap->line1;
@ -784,7 +784,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
mark_adjust_nofold(line1, line2, last_line - line2, 0L, kExtmarkNOOP);
disable_fold_update++;
changed_lines(last_line - num_lines + 1, 0, last_line + 1, num_lines, false);
changed_lines(curbuf, last_line - num_lines + 1, 0, last_line + 1, num_lines, false);
disable_fold_update--;
int line_off = 0;
@ -821,7 +821,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
-(last_line - dest - extra), 0L, kExtmarkNOOP);
disable_fold_update++;
changed_lines(last_line - num_lines + 1, 0, last_line + 1, -extra, false);
changed_lines(curbuf, last_line - num_lines + 1, 0, last_line + 1, -extra, false);
disable_fold_update--;
// send update regarding the new lines that were added
@ -859,9 +859,9 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
if (dest > last_line + 1) {
dest = last_line + 1;
}
changed_lines(line1, 0, dest, 0L, false);
changed_lines(curbuf, line1, 0, dest, 0L, false);
} else {
changed_lines(dest + 1, 0, line1 + num_lines, 0L, false);
changed_lines(curbuf, dest + 1, 0, line1 + num_lines, 0L, false);
}
// send nvim_buf_lines_event regarding lines that were deleted
@ -1124,7 +1124,7 @@ static void do_filter(linenr_T line1, linenr_T line2, exarg_T *eap, char *cmd, b
curwin->w_cursor.lnum = line1;
curwin->w_cursor.col = 0;
changed_line_abv_curs();
invalidate_botline();
invalidate_botline(curwin);
// When using temp files:
// 1. * Form temp file names
@ -2088,7 +2088,7 @@ int getfile(int fnum, char *ffname_arg, char *sfname_arg, int setpm, linenr_T ln
if (lnum != 0) {
curwin->w_cursor.lnum = lnum;
}
check_cursor_lnum();
check_cursor_lnum(curwin);
beginline(BL_SOL | BL_FIX);
retval = GETFILE_SAME_FILE; // it's in the same file
} else if (do_ecmd(fnum, ffname, sfname, NULL, lnum,
@ -2652,7 +2652,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum
check_cursor();
} else if (newlnum > 0) { // line number from caller or old position
curwin->w_cursor.lnum = newlnum;
check_cursor_lnum();
check_cursor_lnum(curwin);
if (solcol >= 0 && !p_sol) {
// 'sol' is off: Use last known column.
curwin->w_cursor.col = solcol;
@ -2883,7 +2883,7 @@ void ex_append(exarg_T *eap)
curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
}
curwin->w_cursor.lnum = lnum;
check_cursor_lnum();
check_cursor_lnum(curwin);
beginline(BL_SOL | BL_FIX);
need_wait_return = false; // don't use wait_return() now
@ -2913,7 +2913,7 @@ void ex_change(exarg_T *eap)
}
// make sure the cursor is not beyond the end of the file now
check_cursor_lnum();
check_cursor_lnum(curwin);
deleted_lines_mark(eap->line1, (eap->line2 - lnum));
// ":append" on the line above the deleted lines.
@ -4200,7 +4200,7 @@ skip:
// the line number before the change (same as adding the number of
// deleted lines).
i = curbuf->b_ml.ml_line_count - old_line_count;
changed_lines(first_line, 0, last_line - (linenr_T)i, (linenr_T)i, false);
changed_lines(curbuf, first_line, 0, last_line - (linenr_T)i, (linenr_T)i, false);
int64_t num_added = last_line - first_line;
int64_t num_removed = num_added - i;
@ -4611,9 +4611,6 @@ static int show_sub(exarg_T *eap, pos_T old_cusr, PreviewLines *preview_lines, i
linenr_T linenr_origbuf = 0; // last line added to original buffer
linenr_T next_linenr = 0; // next line to show for the match
// Temporarily switch to preview buffer
aco_save_T aco;
for (size_t matchidx = 0; matchidx < lines.subresults.size; matchidx++) {
SubResult match = lines.subresults.items[matchidx];
@ -4621,6 +4618,9 @@ static int show_sub(exarg_T *eap, pos_T old_cusr, PreviewLines *preview_lines, i
lpos_T p_start = { 0, match.start.col }; // match starts here in preview
lpos_T p_end = { 0, match.end.col }; // ... and ends here
// You Might Gonna Need It
buf_ensure_loaded(cmdpreview_buf);
if (match.pre_match == 0) {
next_linenr = match.start.lnum;
} else {
@ -4656,14 +4656,11 @@ static int show_sub(exarg_T *eap, pos_T old_cusr, PreviewLines *preview_lines, i
// Put "|lnum| line" into `str` and append it to the preview buffer.
snprintf(str, line_size, "|%*" PRIdLINENR "| %s", col_width - 3,
next_linenr, line);
// Temporarily switch to preview buffer
aucmd_prepbuf(&aco, cmdpreview_buf);
if (linenr_preview == 0) {
ml_replace(1, str, true);
ml_replace_buf(cmdpreview_buf, 1, str, true);
} else {
ml_append(linenr_preview, str, (colnr_T)line_size, false);
ml_append_buf(cmdpreview_buf, linenr_preview, str, (colnr_T)line_size, false);
}
aucmd_restbuf(&aco);
linenr_preview += 1;
}
linenr_origbuf = match.end.lnum;

View File

@ -5881,7 +5881,7 @@ static void ex_copymove(exarg_T *eap)
} else {
ex_copy(eap->line1, eap->line2, n);
}
u_clearline();
u_clearline(curbuf);
beginline(BL_SOL | BL_FIX);
ex_may_print(eap);
}

View File

@ -492,7 +492,7 @@ static void may_do_incsearch_highlighting(int firstc, int count, incsearch_state
// first restore the old curwin values, so the screen is
// positioned in the same way as the actual search command
restore_viewstate(curwin, &s->old_viewstate);
changed_cline_bef_curs();
changed_cline_bef_curs(curwin);
update_topline(curwin);
if (found != 0) {
@ -1460,7 +1460,7 @@ static int may_do_command_line_next_incsearch(int firstc, int count, incsearch_s
set_search_match(&s->match_end);
curwin->w_cursor = s->match_start;
changed_cline_bef_curs();
changed_cline_bef_curs(curwin);
update_topline(curwin);
validate_cursor();
highlight_match = true;
@ -4480,7 +4480,7 @@ static int open_cmdwin(void)
curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
curwin->w_cursor.col = ccline.cmdpos;
changed_line_abv_curs();
invalidate_botline();
invalidate_botline(curwin);
if (ui_has(kUICmdline)) {
ccline.redraw_state = kCmdRedrawNone;
ui_call_cmdline_hide(ccline.level);

View File

@ -1784,7 +1784,7 @@ failed:
curbuf->b_p_ro = true;
}
u_clearline(); // cannot use "U" command after adding lines
u_clearline(curbuf); // cannot use "U" command after adding lines
// In Ex mode: cursor at last new line.
// Otherwise: cursor at first new line.
@ -1793,7 +1793,7 @@ failed:
} else {
curwin->w_cursor.lnum = from + 1;
}
check_cursor_lnum();
check_cursor_lnum(curwin);
beginline(BL_WHITE | BL_FIX); // on first non-blank
if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) {

View File

@ -743,8 +743,7 @@ void deleteFold(win_T *const wp, const linenr_T start, const linenr_T end, const
}
if (last_lnum > 0) {
// TODO(teto): pass the buffer
changed_lines(first_lnum, (colnr_T)0, last_lnum, 0L, false);
changed_lines(wp->w_buffer, first_lnum, (colnr_T)0, last_lnum, 0L, false);
// send one nvim_buf_lines_event at the end
// last_lnum is the line *after* the last line of the outermost fold
@ -1580,8 +1579,7 @@ static void foldCreateMarkers(win_T *wp, pos_T start, pos_T end)
// Update both changes here, to avoid all folds after the start are
// changed when the start marker is inserted and the end isn't.
// TODO(teto): pass the buffer
changed_lines(start.lnum, (colnr_T)0, end.lnum, 0L, false);
changed_lines(buf, start.lnum, (colnr_T)0, end.lnum, 0L, false);
// Note: foldAddMarker() may not actually change start and/or end if
// u_save() is unable to save the buffer line, but we send the

View File

@ -836,7 +836,7 @@ void fix_help_buffer(void)
linenr_T appended = lnum - lnum_start;
if (appended) {
mark_adjust(lnum_start + 1, (linenr_T)MAXLNUM, appended, 0L, kExtmarkUndo);
changed_lines_buf(curbuf, lnum_start + 1, lnum_start + 1, appended);
buf_redraw_changed_lines_later(curbuf, lnum_start + 1, lnum_start + 1, appended);
}
break;
}

View File

@ -1083,7 +1083,7 @@ void ex_retab(exarg_T *eap)
redraw_curbuf_later(UPD_NOT_VALID);
}
if (first_line != 0) {
changed_lines(first_line, 0, last_line + 1, 0L, true);
changed_lines(curbuf, first_line, 0, last_line + 1, 0L, true);
}
curwin->w_p_list = save_list; // restore 'list'
@ -1107,7 +1107,7 @@ void ex_retab(exarg_T *eap)
}
coladvance(curwin->w_curswant);
u_clearline();
u_clearline(curbuf);
}
/// Get indent level from 'indentexpr'.

View File

@ -3446,7 +3446,7 @@ void ins_compl_delete(void)
// TODO(vim): is this sufficient for redrawing? Redrawing everything
// causes flicker, thus we can't do that.
changed_cline_bef_curs();
changed_cline_bef_curs(curwin);
// clear v:completed_item
set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc_lock(VAR_FIXED));
}

View File

@ -152,7 +152,17 @@ bool logmsg(int log_level, const char *context, const char *func_name, int line_
#ifdef EXITFREE
// Logging after we've already started freeing all our memory will only cause
// pain. We need access to VV_PROGPATH, homedir, etc.
assert(!entered_free_all_mem);
if (entered_free_all_mem) {
fprintf(stderr, "FATAL: error in free_all_mem\n %s %s %d: ", context, func_name, line_num);
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
if (eol) {
fprintf(stderr, "\n");
}
abort();
}
#endif
log_lock();

View File

@ -1121,7 +1121,7 @@ void ex_changes(exarg_T *eap)
void mark_adjust(linenr_T line1, linenr_T line2, linenr_T amount, linenr_T amount_after,
ExtmarkOp op)
{
mark_adjust_internal(line1, line2, amount, amount_after, true, op);
mark_adjust_buf(curbuf, line1, line2, amount, amount_after, true, true, op);
}
// mark_adjust_nofold() does the same as mark_adjust() but without adjusting
@ -1132,13 +1132,13 @@ void mark_adjust(linenr_T line1, linenr_T line2, linenr_T amount, linenr_T amoun
void mark_adjust_nofold(linenr_T line1, linenr_T line2, linenr_T amount, linenr_T amount_after,
ExtmarkOp op)
{
mark_adjust_internal(line1, line2, amount, amount_after, false, op);
mark_adjust_buf(curbuf, line1, line2, amount, amount_after, false, true, op);
}
static void mark_adjust_internal(linenr_T line1, linenr_T line2, linenr_T amount,
linenr_T amount_after, bool adjust_folds, ExtmarkOp op)
void mark_adjust_buf(buf_T *buf, linenr_T line1, linenr_T line2, linenr_T amount,
linenr_T amount_after, bool adjust_folds, bool adj_cursor, ExtmarkOp op)
{
int fnum = curbuf->b_fnum;
int fnum = buf->b_fnum;
linenr_T *lp;
static pos_T initpos = { 1, 0, 0 };
@ -1149,7 +1149,7 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2, linenr_T amount
if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) {
// named marks, lower case and upper case
for (int i = 0; i < NMARKS; i++) {
ONE_ADJUST(&(curbuf->b_namedm[i].mark.lnum));
ONE_ADJUST(&(buf->b_namedm[i].mark.lnum));
if (namedfm[i].fmark.fnum == fnum) {
ONE_ADJUST_NODEL(&(namedfm[i].fmark.mark.lnum));
}
@ -1161,54 +1161,56 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2, linenr_T amount
}
// last Insert position
ONE_ADJUST(&(curbuf->b_last_insert.mark.lnum));
ONE_ADJUST(&(buf->b_last_insert.mark.lnum));
// last change position
ONE_ADJUST(&(curbuf->b_last_change.mark.lnum));
ONE_ADJUST(&(buf->b_last_change.mark.lnum));
// last cursor position, if it was set
if (!equalpos(curbuf->b_last_cursor.mark, initpos)) {
ONE_ADJUST(&(curbuf->b_last_cursor.mark.lnum));
if (!equalpos(buf->b_last_cursor.mark, initpos)) {
ONE_ADJUST(&(buf->b_last_cursor.mark.lnum));
}
// list of change positions
for (int i = 0; i < curbuf->b_changelistlen; i++) {
ONE_ADJUST_NODEL(&(curbuf->b_changelist[i].mark.lnum));
for (int i = 0; i < buf->b_changelistlen; i++) {
ONE_ADJUST_NODEL(&(buf->b_changelist[i].mark.lnum));
}
// Visual area
ONE_ADJUST_NODEL(&(curbuf->b_visual.vi_start.lnum));
ONE_ADJUST_NODEL(&(curbuf->b_visual.vi_end.lnum));
ONE_ADJUST_NODEL(&(buf->b_visual.vi_start.lnum));
ONE_ADJUST_NODEL(&(buf->b_visual.vi_end.lnum));
// quickfix marks
if (!qf_mark_adjust(NULL, line1, line2, amount, amount_after)) {
curbuf->b_has_qf_entry &= ~BUF_HAS_QF_ENTRY;
if (!qf_mark_adjust(buf, NULL, line1, line2, amount, amount_after)) {
buf->b_has_qf_entry &= ~BUF_HAS_QF_ENTRY;
}
// location lists
bool found_one = false;
FOR_ALL_TAB_WINDOWS(tab, win) {
found_one |= qf_mark_adjust(win, line1, line2, amount, amount_after);
found_one |= qf_mark_adjust(buf, win, line1, line2, amount, amount_after);
}
if (!found_one) {
curbuf->b_has_qf_entry &= ~BUF_HAS_LL_ENTRY;
buf->b_has_qf_entry &= ~BUF_HAS_LL_ENTRY;
}
sign_mark_adjust(line1, line2, amount, amount_after);
sign_mark_adjust(buf, line1, line2, amount, amount_after);
}
if (op != kExtmarkNOOP) {
extmark_adjust(curbuf, line1, line2, amount, amount_after, op);
extmark_adjust(buf, line1, line2, amount, amount_after, op);
}
// previous context mark
ONE_ADJUST(&(curwin->w_pcmark.lnum));
if (curwin->w_buffer == buf) {
// previous context mark
ONE_ADJUST(&(curwin->w_pcmark.lnum));
// previous pcmark
ONE_ADJUST(&(curwin->w_prev_pcmark.lnum));
// previous pcpmark
ONE_ADJUST(&(curwin->w_prev_pcmark.lnum));
// saved cursor for formatting
if (saved_cursor.lnum != 0) {
ONE_ADJUST_NODEL(&(saved_cursor.lnum));
// saved cursor for formatting
if (saved_cursor.lnum != 0) {
ONE_ADJUST_NODEL(&(saved_cursor.lnum));
}
}
// Adjust items in all windows related to the current buffer.
@ -1223,7 +1225,7 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2, linenr_T amount
}
}
if (win->w_buffer == curbuf) {
if (win->w_buffer == buf) {
if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) {
// marks in the tag stack
for (int i = 0; i < win->w_tagstacklen; i++) {
@ -1259,19 +1261,21 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2, linenr_T amount
win->w_topline += amount_after;
win->w_topfill = 0;
}
if (win->w_cursor.lnum >= line1 && win->w_cursor.lnum <= line2) {
if (amount == MAXLNUM) { // line with cursor is deleted
if (line1 <= 1) {
win->w_cursor.lnum = 1;
} else {
win->w_cursor.lnum = line1 - 1;
if (adj_cursor) {
if (win->w_cursor.lnum >= line1 && win->w_cursor.lnum <= line2) {
if (amount == MAXLNUM) { // line with cursor is deleted
if (line1 <= 1) {
win->w_cursor.lnum = 1;
} else {
win->w_cursor.lnum = line1 - 1;
}
win->w_cursor.col = 0;
} else { // keep cursor on the same line
win->w_cursor.lnum += amount;
}
win->w_cursor.col = 0;
} else { // keep cursor on the same line
win->w_cursor.lnum += amount;
} else if (amount_after && win->w_cursor.lnum > line2) {
win->w_cursor.lnum += amount_after;
}
} else if (amount_after && win->w_cursor.lnum > line2) {
win->w_cursor.lnum += amount_after;
}
}
@ -1282,7 +1286,7 @@ static void mark_adjust_internal(linenr_T line1, linenr_T line2, linenr_T amount
}
// adjust diffs
diff_mark_adjust(line1, line2, amount, amount_after);
diff_mark_adjust(buf, line1, line2, amount, amount_after);
}
// This code is used often, needs to be fast.

View File

@ -348,9 +348,8 @@ int ml_open(buf_T *buf)
}
// Fill in root pointer block and write page 1.
if ((hp = ml_new_ptr(mfp)) == NULL) {
goto error;
}
hp = ml_new_ptr(mfp);
assert(hp != NULL);
if (hp->bh_bnum != 1) {
iemsg(_("E298: Didn't get block nr 1?"));
goto error;
@ -1170,7 +1169,7 @@ void ml_recover(bool checkext)
// Recovering an empty file results in two lines and the first line is
// empty. Don't set the modified flag then.
if (!(curbuf->b_ml.ml_line_count == 2 && *ml_get(1) == NUL)) {
changed_internal();
changed_internal(curbuf);
buf_inc_changedtick(curbuf);
}
} else {
@ -1180,7 +1179,7 @@ void ml_recover(bool checkext)
int i = strcmp(p, ml_get(idx + lnum));
xfree(p);
if (i != 0) {
changed_internal();
changed_internal(curbuf);
buf_inc_changedtick(curbuf);
break;
}
@ -2495,6 +2494,19 @@ int ml_delete(linenr_T lnum, bool message)
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.
///
/// @param message Show "--No lines in buffer--" message.
///
/// @return FAIL for failure, OK otherwise
int ml_delete_buf(buf_T *buf, linenr_T lnum, bool message)
{
ml_flush_line(buf);
return ml_delete_int(buf, lnum, message);
}
static int ml_delete_int(buf_T *buf, linenr_T lnum, bool message)
{
if (lnum < 1 || lnum > buf->b_ml.ml_line_count) {

View File

@ -547,13 +547,7 @@ void set_topline(win_T *wp, linenr_T lnum)
/// If the line length changed the number of screen lines might change,
/// requiring updating w_topline. That may also invalidate w_crow.
/// Need to take care of w_botline separately!
void changed_cline_bef_curs(void)
{
curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW
|VALID_CHEIGHT|VALID_TOPLINE);
}
void changed_cline_bef_curs_win(win_T *wp)
void changed_cline_bef_curs(win_T *wp)
{
wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW
|VALID_CHEIGHT|VALID_TOPLINE);
@ -595,13 +589,8 @@ void validate_botline(win_T *wp)
}
}
// Mark curwin->w_botline as invalid (because of some change in the buffer).
void invalidate_botline(void)
{
curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
}
void invalidate_botline_win(win_T *wp)
// Mark wp->w_botline as invalid (because of some change in the buffer).
void invalidate_botline(win_T *wp)
{
wp->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
}
@ -1276,7 +1265,7 @@ bool scrolldown(long line_count, int byfold)
}
}
curwin->w_botline--; // approximate w_botline
invalidate_botline();
invalidate_botline(curwin);
}
curwin->w_wrow += done; // keep w_wrow updated
curwin->w_cline_row += done; // keep w_cline_row updated
@ -2651,7 +2640,7 @@ void halfpage(bool flag, linenr_T Prenum)
} else {
curwin->w_cursor.lnum += n;
}
check_cursor_lnum();
check_cursor_lnum(curwin);
}
} else {
// scroll the text down

View File

@ -3922,7 +3922,7 @@ static void nv_gotofile(cmdarg_T *cap)
buf_hide(curbuf) ? ECMD_HIDE : 0, curwin) == OK
&& cap->nchar == 'F' && lnum >= 0) {
curwin->w_cursor.lnum = lnum;
check_cursor_lnum();
check_cursor_lnum(curwin);
beginline(BL_SOL | BL_FIX);
}
xfree(ptr);
@ -4771,7 +4771,7 @@ static void n_swapchar(cmdarg_T *cap)
if (u_savesub(curwin->w_cursor.lnum) == false) {
break;
}
u_clearline();
u_clearline(curbuf);
}
} else {
break;
@ -4782,7 +4782,7 @@ static void n_swapchar(cmdarg_T *cap)
check_cursor();
curwin->w_set_curswant = true;
if (did_change) {
changed_lines(startpos.lnum, startpos.col, curwin->w_cursor.lnum + 1,
changed_lines(curbuf, startpos.lnum, startpos.col, curwin->w_cursor.lnum + 1,
0L, true);
curbuf->b_op_start = startpos;
curbuf->b_op_end = curwin->w_cursor;
@ -5363,7 +5363,7 @@ static void nv_gi_cmd(cmdarg_T *cap)
{
if (curbuf->b_last_insert.mark.lnum != 0) {
curwin->w_cursor = curbuf->b_last_insert.mark;
check_cursor_lnum();
check_cursor_lnum(curwin);
int i = (int)strlen(get_cursor_line_ptr());
if (curwin->w_cursor.col > (colnr_T)i) {
if (virtual_active()) {

View File

@ -281,7 +281,7 @@ void op_shift(oparg_T *oap, int curs_top, int amount)
}
}
changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L, true);
changed_lines(curbuf, oap->start.lnum, 0, oap->end.lnum + 1, 0L, true);
}
/// Shift the current line one shiftwidth left (if left != 0) or right
@ -626,7 +626,7 @@ static void block_insert(oparg_T *oap, char *s, int b_insert, struct block_def *
State = oldstate;
changed_lines(oap->start.lnum + 1, 0, oap->end.lnum + 1, 0L, true);
changed_lines(curbuf, oap->start.lnum + 1, 0, oap->end.lnum + 1, 0L, true);
}
/// Handle reindenting a block of lines.
@ -690,7 +690,7 @@ void op_reindent(oparg_T *oap, Indenter how)
// highlighting was present, need to continue until the last line. When
// there is no change still need to remove the Visual highlighting.
if (last_changed != 0) {
changed_lines(first_changed, 0,
changed_lines(curbuf, first_changed, 0,
oap->is_VIsual ? start_lnum + (linenr_T)oap->line_count :
last_changed + 1, 0L, true);
} else if (oap->is_VIsual) {
@ -1593,7 +1593,7 @@ int op_delete(oparg_T *oap)
}
check_cursor_col();
changed_lines(curwin->w_cursor.lnum, curwin->w_cursor.col,
changed_lines(curbuf, curwin->w_cursor.lnum, curwin->w_cursor.col,
oap->end.lnum + 1, 0L, true);
oap->line_count = 0; // no lines deleted
} else if (oap->motion_type == kMTLineWise) {
@ -1628,12 +1628,12 @@ int op_delete(oparg_T *oap)
// leave cursor past last char in line
if (oap->line_count > 1) {
u_clearline(); // "U" command not possible after "2cc"
u_clearline(curbuf); // "U" command not possible after "2cc"
}
} else {
del_lines(oap->line_count, true);
beginline(BL_WHITE | BL_FIX);
u_clearline(); // "U" command not possible after "dd"
u_clearline(curbuf); // "U" command not possible after "dd"
}
} else {
if (virtual_op) {
@ -2030,7 +2030,7 @@ static int op_replace(oparg_T *oap, int c)
curwin->w_cursor = oap->start;
check_cursor();
changed_lines(oap->start.lnum, oap->start.col, oap->end.lnum + 1, 0L, true);
changed_lines(curbuf, oap->start.lnum, oap->start.col, oap->end.lnum + 1, 0L, true);
if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) {
// Set "'[" and "']" marks.
@ -2064,7 +2064,7 @@ void op_tilde(oparg_T *oap)
did_change |= one_change;
}
if (did_change) {
changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L, true);
changed_lines(curbuf, oap->start.lnum, 0, oap->end.lnum + 1, 0L, true);
}
} else { // not block mode
if (oap->motion_type == kMTLineWise) {
@ -2092,7 +2092,7 @@ void op_tilde(oparg_T *oap)
}
}
if (did_change) {
changed_lines(oap->start.lnum, oap->start.col, oap->end.lnum + 1,
changed_lines(curbuf, oap->start.lnum, oap->start.col, oap->end.lnum + 1,
0L, true);
}
}
@ -2531,7 +2531,7 @@ int op_change(oparg_T *oap)
}
}
check_cursor();
changed_lines(oap->start.lnum + 1, 0, oap->end.lnum + 1, 0L, true);
changed_lines(curbuf, oap->start.lnum + 1, 0, oap->end.lnum + 1, 0L, true);
xfree(ins_text);
}
}
@ -3365,7 +3365,7 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
}
}
changed_lines(lnum, 0, curbuf->b_op_start.lnum + (linenr_T)y_size
changed_lines(curbuf, lnum, 0, curbuf->b_op_start.lnum + (linenr_T)y_size
- nr_lines, nr_lines, true);
// Set '[ mark.
@ -3481,8 +3481,8 @@ void do_put(int regname, yankreg_T *reg, int dir, long count, int flags)
// Place cursor on last putted char.
if (lnum == curwin->w_cursor.lnum) {
// make sure curwin->w_virtcol is updated
changed_cline_bef_curs();
invalidate_botline();
changed_cline_bef_curs(curwin);
invalidate_botline(curwin);
curwin->w_cursor.col += (colnr_T)(totlen - 1);
}
changed_bytes(lnum, col);
@ -3620,10 +3620,10 @@ error:
// note changed text for displaying and folding
if (y_type == kMTCharWise) {
changed_lines(curwin->w_cursor.lnum, col,
changed_lines(curbuf, curwin->w_cursor.lnum, col,
curwin->w_cursor.lnum + 1, nr_lines, true);
} else {
changed_lines(curbuf->b_op_start.lnum, 0,
changed_lines(curbuf, curbuf->b_op_start.lnum, 0,
curbuf->b_op_start.lnum, nr_lines, true);
}
@ -4159,7 +4159,7 @@ int do_join(size_t count, int insert_space, int save_undo, int use_formatoptions
// Only report the change in the first line here, del_lines() will report
// the deleted line.
changed_lines(curwin->w_cursor.lnum, currsize,
changed_lines(curbuf, curwin->w_cursor.lnum, currsize,
curwin->w_cursor.lnum + 1, 0L, true);
// Delete following lines. To do this we move the cursor there
@ -4379,7 +4379,7 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd)
change_cnt = do_addsub(oap->op_type, &pos, 0, amount);
disable_fold_update--;
if (change_cnt) {
changed_lines(pos.lnum, 0, pos.lnum + 1, 0L, true);
changed_lines(curbuf, pos.lnum, 0, pos.lnum + 1, 0L, true);
}
} else {
int length;
@ -4437,7 +4437,7 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd)
disable_fold_update--;
if (change_cnt) {
changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L, true);
changed_lines(curbuf, oap->start.lnum, 0, oap->end.lnum + 1, 0L, true);
}
if (!change_cnt && oap->is_VIsual) {

View File

@ -406,6 +406,19 @@ void set_string_option_direct_in_win(win_T *wp, const char *name, int opt_idx, c
unblock_autocmds();
}
/// Like set_string_option_direct(), but for a buffer-local option in "buf".
/// Blocks autocommands to avoid the old curwin becoming invalid.
void set_string_option_direct_in_buf(buf_T *buf, const char *name, int opt_idx, const char *val,
int opt_flags, int set_sid)
{
buf_T *save_curbuf = curbuf;
block_autocmds();
curbuf = buf;
set_string_option_direct(name, opt_idx, val, opt_flags, set_sid);
curbuf = save_curbuf;
unblock_autocmds();
}
/// Set a string option to a new value, handling the effects
///
/// @param[in] opt_idx Option to set.

View File

@ -3433,14 +3433,17 @@ static void qf_free(qf_list_T *qfl)
qfl->qf_changedtick = 0L;
}
// qf_mark_adjust: adjust marks
bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, linenr_T amount,
/// Adjust error list entries for changed line numbers
///
/// Note: `buf` is the changed buffer, but `wp` is a potential location list
/// into that buffer, or NULL to check the quickfix list.
bool qf_mark_adjust(buf_T *buf, win_T *wp, linenr_T line1, linenr_T line2, linenr_T amount,
linenr_T amount_after)
{
qf_info_T *qi = &ql_info;
int buf_has_flag = wp == NULL ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
if (!(curbuf->b_has_qf_entry & buf_has_flag)) {
if (!(buf->b_has_qf_entry & buf_has_flag)) {
return false;
}
if (wp != NULL) {
@ -3457,7 +3460,7 @@ bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, linenr_T amount,
qf_list_T *qfl = qf_get_list(qi, idx);
if (!qf_list_empty(qfl)) {
FOR_ALL_QFL_ITEMS(qfl, qfp, i) {
if (qfp->qf_fnum == curbuf->b_fnum) {
if (qfp->qf_fnum == buf->b_fnum) {
found_one = true;
if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2) {
if (amount == MAXLNUM) {

View File

@ -766,7 +766,8 @@ static linenr_T sign_adjust_one(const linenr_T se_lnum, linenr_T line1, linenr_T
}
/// Adjust placed signs for inserted/deleted lines.
void sign_mark_adjust(linenr_T line1, linenr_T line2, linenr_T amount, linenr_T amount_after)
void sign_mark_adjust(buf_T *buf, linenr_T line1, linenr_T line2, linenr_T amount,
linenr_T amount_after)
{
sign_entry_T *sign; // a sign in a b_signlist
sign_entry_T *next; // the next sign in a b_signlist
@ -774,15 +775,15 @@ void sign_mark_adjust(linenr_T line1, linenr_T line2, linenr_T amount, linenr_T
sign_entry_T **lastp = NULL; // pointer to pointer to current sign
linenr_T new_lnum; // new line number to assign to sign
int is_fixed = 0;
int signcol = win_signcol_configured(curwin, &is_fixed);
int signcol = curwin->w_buffer == buf ? win_signcol_configured(curwin, &is_fixed) : 0;
if (amount == MAXLNUM) { // deleting
buf_signcols_del_check(curbuf, line1, line2);
buf_signcols_del_check(buf, line1, line2);
}
lastp = &curbuf->b_signlist;
lastp = &buf->b_signlist;
for (sign = curbuf->b_signlist; sign != NULL; sign = next) {
for (sign = buf->b_signlist; sign != NULL; sign = next) {
next = sign->se_next;
new_lnum = sign_adjust_one(sign->se_lnum, line1, line2, amount, amount_after);
@ -799,7 +800,7 @@ void sign_mark_adjust(linenr_T line1, linenr_T line2, linenr_T amount, linenr_T
// If the new sign line number is past the last line in the buffer,
// then don't adjust the line number. Otherwise, it will always be past
// the last line and will not be visible.
if (new_lnum <= curbuf->b_ml.ml_line_count) {
if (new_lnum <= buf->b_ml.ml_line_count) {
sign->se_lnum = new_lnum;
}
}
@ -808,9 +809,9 @@ void sign_mark_adjust(linenr_T line1, linenr_T line2, linenr_T amount, linenr_T
lastp = &sign->se_next;
}
new_lnum = sign_adjust_one(curbuf->b_signcols.sentinel, line1, line2, amount, amount_after);
new_lnum = sign_adjust_one(buf->b_signcols.sentinel, line1, line2, amount, amount_after);
if (new_lnum != 0) {
curbuf->b_signcols.sentinel = new_lnum;
buf->b_signcols.sentinel = new_lnum;
}
}
@ -1168,7 +1169,7 @@ static linenr_T sign_jump(int sign_id, char *sign_group, buf_T *buf)
// goto a sign ...
if (buf_jump_open_win(buf) != NULL) { // ... in a current window
curwin->w_cursor.lnum = lnum;
check_cursor_lnum();
check_cursor_lnum(curwin);
beginline(BL_WHITE);
} else { // ... not currently in a window
if (buf->b_fname == NULL) {

View File

@ -1750,7 +1750,7 @@ static void refresh_screen(Terminal *term, buf_T *buf)
int change_start = row_to_linenr(term, term->invalid_start);
int change_end = change_start + changed;
changed_lines(change_start, 0, change_end, added, true);
changed_lines(buf, change_start, 0, change_end, added, true);
term->invalid_start = INT_MAX;
term->invalid_end = -1;
}

View File

@ -250,15 +250,20 @@ int u_save_cursor(void)
/// Returns FAIL when lines could not be saved, OK otherwise.
int u_save(linenr_T top, linenr_T bot)
{
if (top >= bot || bot > (curbuf->b_ml.ml_line_count + 1)) {
return u_save_buf(curbuf, top, bot);
}
int u_save_buf(buf_T *buf, linenr_T top, linenr_T bot)
{
if (top >= bot || bot > (buf->b_ml.ml_line_count + 1)) {
return FAIL; // rely on caller to do error messages
}
if (top + 2 == bot) {
u_saveline((linenr_T)(top + 1));
u_saveline(buf, (linenr_T)(top + 1));
}
return u_savecommon(curbuf, top, bot, (linenr_T)0, false);
return u_savecommon(buf, top, bot, (linenr_T)0, false);
}
/// Save the line "lnum" (used by ":s" and "~" command).
@ -2288,7 +2293,7 @@ static void u_undoredo(int undo, bool do_buf_event)
|| bot > curbuf->b_ml.ml_line_count + 1) {
unblock_autocmds();
iemsg(_("E438: u_undo: line numbers wrong"));
changed(); // don't want UNCHANGED now
changed(curbuf); // don't want UNCHANGED now
return;
}
@ -2373,7 +2378,7 @@ static void u_undoredo(int undo, bool do_buf_event)
}
}
changed_lines(top + 1, 0, bot, newsize - oldsize, 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.
@ -2439,7 +2444,7 @@ static void u_undoredo(int undo, bool do_buf_event)
curbuf->b_ml.ml_flags |= ML_EMPTY;
}
if (old_flags & UH_CHANGED) {
changed();
changed(curbuf);
} else {
unchanged(curbuf, false, true);
}
@ -2980,34 +2985,34 @@ void u_clearall(buf_T *buf)
}
/// save the line "lnum" for the "U" command
void u_saveline(linenr_T lnum)
void u_saveline(buf_T *buf, linenr_T lnum)
{
if (lnum == curbuf->b_u_line_lnum) { // line is already saved
if (lnum == buf->b_u_line_lnum) { // line is already saved
return;
}
if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) { // should never happen
if (lnum < 1 || lnum > buf->b_ml.ml_line_count) { // should never happen
return;
}
u_clearline();
curbuf->b_u_line_lnum = lnum;
if (curwin->w_cursor.lnum == lnum) {
curbuf->b_u_line_colnr = curwin->w_cursor.col;
u_clearline(buf);
buf->b_u_line_lnum = lnum;
if (curwin->w_buffer == buf && curwin->w_cursor.lnum == lnum) {
buf->b_u_line_colnr = curwin->w_cursor.col;
} else {
curbuf->b_u_line_colnr = 0;
buf->b_u_line_colnr = 0;
}
curbuf->b_u_line_ptr = u_save_line(lnum);
buf->b_u_line_ptr = u_save_line_buf(buf, lnum);
}
/// clear the line saved for the "U" command
/// (this is used externally for crossing a line while in insert mode)
void u_clearline(void)
void u_clearline(buf_T *buf)
{
if (curbuf->b_u_line_ptr == NULL) {
if (buf->b_u_line_ptr == NULL) {
return;
}
XFREE_CLEAR(curbuf->b_u_line_ptr);
curbuf->b_u_line_lnum = 0;
XFREE_CLEAR(buf->b_u_line_ptr);
buf->b_u_line_lnum = 0;
}
/// Implementation of the "U" command.

View File

@ -562,7 +562,7 @@ wingotofile:
if (wp != NULL && nchar == 'F' && lnum >= 0) {
curwin->w_cursor.lnum = lnum;
check_cursor_lnum();
check_cursor_lnum(curwin);
beginline(BL_SOL | BL_FIX);
}
xfree(ptr);
@ -6493,7 +6493,7 @@ void win_fix_scroll(int resize)
wp->w_valid &= ~VALID_CROW;
}
invalidate_botline_win(wp);
invalidate_botline(wp);
validate_botline(wp);
}
wp->w_prev_height = wp->w_height;
@ -6666,7 +6666,7 @@ void scroll_to_fraction(win_T *wp, int prev_height)
}
redraw_later(wp, UPD_SOME_VALID);
invalidate_botline_win(wp);
invalidate_botline(wp);
}
void win_set_inner_size(win_T *wp, bool valid_cursor)
@ -6713,7 +6713,7 @@ void win_set_inner_size(win_T *wp, bool valid_cursor)
wp->w_lines_valid = 0;
if (valid_cursor) {
changed_line_abv_curs_win(wp);
invalidate_botline_win(wp);
invalidate_botline(wp);
if (wp == curwin && *p_spk == 'c') {
curs_columns(wp, true); // validate w_wrow
}

View File

@ -76,6 +76,38 @@ describe('api/buf', function()
eq({4, 2}, curwin('get_cursor'))
end)
it('cursor position is maintained in non-current window', function()
meths.buf_set_lines(0, 0, -1, 1, {"line1", "line2", "line3", "line4"})
meths.win_set_cursor(0, {3, 2})
local win = meths.get_current_win()
local buf = meths.get_current_buf()
command('new')
meths.buf_set_lines(buf, 1, 2, 1, {"line5", "line6"})
eq({"line1", "line5", "line6", "line3", "line4"}, meths.buf_get_lines(buf, 0, -1, true))
eq({4, 2}, meths.win_get_cursor(win))
end)
it('cursor position is maintained in TWO non-current windows', function()
meths.buf_set_lines(0, 0, -1, 1, {"line1", "line2", "line3", "line4"})
meths.win_set_cursor(0, {3, 2})
local win = meths.get_current_win()
local buf = meths.get_current_buf()
command('split')
meths.win_set_cursor(0, {4, 2})
local win2 = meths.get_current_win()
-- set current window to third one with another buffer
command("new")
meths.buf_set_lines(buf, 1, 2, 1, {"line5", "line6"})
eq({"line1", "line5", "line6", "line3", "line4"}, meths.buf_get_lines(buf, 0, -1, true))
eq({4, 2}, meths.win_get_cursor(win))
eq({5, 2}, meths.win_get_cursor(win2))
end)
it('line_count has defined behaviour for unloaded buffers', function()
-- we'll need to know our bufnr for when it gets unloaded
local bufnr = curbuf('get_number')
@ -484,6 +516,50 @@ describe('api/buf', function()
eq({1, 9}, curwin('get_cursor'))
end)
it('updates the cursor position in non-current window', function()
insert([[
hello world!]])
-- position the cursor on `!`
meths.win_set_cursor(0, {1, 11})
local win = meths.get_current_win()
local buf = meths.get_current_buf()
command("new")
-- replace 'world' with 'foo'
meths.buf_set_text(buf, 0, 6, 0, 11, {'foo'})
eq({'hello foo!'}, meths.buf_get_lines(buf, 0, -1, true))
-- cursor should be moved left by two columns (replacement is shorter by 2 chars)
eq({1, 9}, meths.win_get_cursor(win))
end)
it('updates the cursor position in TWO non-current windows', function()
insert([[
hello world!]])
-- position the cursor on `!`
meths.win_set_cursor(0, {1, 11})
local win = meths.get_current_win()
local buf = meths.get_current_buf()
command("split")
local win2 = meths.get_current_win()
-- position the cursor on `w`
meths.win_set_cursor(0, {1, 6})
command("new")
-- replace 'hello' with 'foo'
meths.buf_set_text(buf, 0, 0, 0, 5, {'foo'})
eq({'foo world!'}, meths.buf_get_lines(buf, 0, -1, true))
-- both cursors should be moved left by two columns (replacement is shorter by 2 chars)
eq({1, 9}, meths.win_get_cursor(win))
eq({1, 4}, meths.win_get_cursor(win2))
end)
it('can handle NULs', function()
set_text(0, 0, 0, 0, {'ab\0cd'})
eq('ab\0cd', curbuf_depr('get_line', 0))

View File

@ -28,7 +28,6 @@ local write_file = helpers.write_file
local exec_lua = helpers.exec_lua
local exc_exec = helpers.exc_exec
local insert = helpers.insert
local expect_exit = helpers.expect_exit
local skip = helpers.skip
local pcall_err = helpers.pcall_err
@ -2832,7 +2831,9 @@ describe('API', function()
it('does not cause heap-use-after-free on exit while setting options', function()
command('au OptionSet * q')
expect_exit(command, 'silent! call nvim_create_buf(0, 1)')
command('silent! call nvim_create_buf(0, 1)')
-- nowadays this works because we don't execute any spurious autocmds at all #24824
assert_alive()
end)
end)

View File

@ -1251,6 +1251,98 @@ AAAB]]
]]}
end)
end)
it('redraws with a change to non-current buffer', function()
write_file(fname, "aaa\nbbb\nccc\n\nxx", false)
write_file(fname_2, "aaa\nbbb\nccc\n\nyy", false)
reread()
local buf = meths.get_current_buf()
command('botright new')
screen:expect{grid=[[
{1: }aaa {1: }aaa |
{1: }bbb {1: }bbb |
{1: }ccc {1: }ccc |
{1: } {1: } |
{1: }{8:xx}{9: }{1: }{8:yy}{9: }|
{6:~ }{6:~ }|
{3:<onal-diff-screen-1 <l-diff-screen-1.2 }|
^ |
{6:~ }|
{6:~ }|
{6:~ }|
{6:~ }|
{6:~ }|
{6:~ }|
{7:[No Name] }|
:e |
]]}
meths.buf_set_lines(buf, 1, 2, true, {'BBB'})
screen:expect{grid=[[
{1: }aaa {1: }aaa |
{1: }{8:BBB}{9: }{1: }{8:bbb}{9: }|
{1: }ccc {1: }ccc |
{1: } {1: } |
{1: }{8:xx}{9: }{1: }{8:yy}{9: }|
{6:~ }{6:~ }|
{3:<-diff-screen-1 [+] <l-diff-screen-1.2 }|
^ |
{6:~ }|
{6:~ }|
{6:~ }|
{6:~ }|
{6:~ }|
{6:~ }|
{7:[No Name] }|
:e |
]]}
end)
it('redraws with a change current buffer in another window', function()
write_file(fname, "aaa\nbbb\nccc\n\nxx", false)
write_file(fname_2, "aaa\nbbb\nccc\n\nyy", false)
reread()
local buf = meths.get_current_buf()
command('botright split | diffoff')
screen:expect{grid=[[
{1: }aaa {1: }aaa |
{1: }bbb {1: }bbb |
{1: }ccc {1: }ccc |
{1: } {1: } |
{1: }{8:xx}{9: }{1: }{8:yy}{9: }|
{6:~ }{6:~ }|
{3:<onal-diff-screen-1 <l-diff-screen-1.2 }|
^aaa |
bbb |
ccc |
|
xx |
{6:~ }|
{6:~ }|
{7:Xtest-functional-diff-screen-1 }|
:e |
]]}
meths.buf_set_lines(buf, 1, 2, true, {'BBB'})
screen:expect{grid=[[
{1: }aaa {1: }aaa |
{1: }{8:BBB}{9: }{1: }{8:bbb}{9: }|
{1: }ccc {1: }ccc |
{1: } {1: } |
{1: }{8:xx}{9: }{1: }{8:yy}{9: }|
{6:~ }{6:~ }|
{3:<-diff-screen-1 [+] <l-diff-screen-1.2 }|
^aaa |
BBB |
ccc |
|
xx |
{6:~ }|
{6:~ }|
{7:Xtest-functional-diff-screen-1 [+] }|
:e |
]]}
end)
end)
it('win_update redraws lines properly', function()

File diff suppressed because it is too large Load Diff