aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/change.c
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2023-08-21 14:52:17 +0200
committerbfredl <bjorn.linse@gmail.com>2023-08-26 12:02:05 +0200
commit008154954791001efcc46c28146e21403f3a698b (patch)
tree306721ca60456ba9562c16b9d41cf5ec8d5a360c /src/nvim/change.c
parent1635c9e75e21e07c4331cf983e14a11c7e09b119 (diff)
downloadrneovim-008154954791001efcc46c28146e21403f3a698b.tar.gz
rneovim-008154954791001efcc46c28146e21403f3a698b.tar.bz2
rneovim-008154954791001efcc46c28146e21403f3a698b.zip
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.
Diffstat (limited to 'src/nvim/change.c')
-rw-r--r--src/nvim/change.c122
1 files changed, 65 insertions, 57 deletions
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 36f0fc70a1..067b48faee 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -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);