mirror of
https://github.com/neovim/neovim.git
synced 2025-10-05 01:16:31 +00:00
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:
@@ -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);
|
||||
|
Reference in New Issue
Block a user