aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2023-08-27 11:20:59 +0200
committerbfredl <bjorn.linse@gmail.com>2023-08-27 12:07:46 +0200
commit9b9030ff2ca820d4c4f4b559f86b0f9a3496645b (patch)
treee380086030f4f5cd8f65ceacaee389bc80911ee2
parentb7d5b55f74fd589dee27d8356d45b31c552705c3 (diff)
downloadrneovim-9b9030ff2ca820d4c4f4b559f86b0f9a3496645b.tar.gz
rneovim-9b9030ff2ca820d4c4f4b559f86b0f9a3496645b.tar.bz2
rneovim-9b9030ff2ca820d4c4f4b559f86b0f9a3496645b.zip
fix(api): fix inconsistent behavior of topline touched in recent refactor
The change in #24824 0081549 was not a regression, however it was an incomplete change. Unfortunately some common plugins come to depend on this exising self-inconsistent behavior. These plugins are going to need to update for 0.10 nvim_buf_set_lines used to NOT adjust the topline correctly if a buffer was displayed in just one window. However, if displayed in multiple windows, it was correctly adjusted for any window not deemed the current window for the buffer (which could be an arbitrary choice if the buffer was not already current, as noted in the last rafactor) This fixes so that all windows have their topline adjusted. The added tests show this behavior, which should be the reasonable one.
-rw-r--r--src/nvim/api/buffer.c10
-rw-r--r--src/nvim/mark.c34
-rw-r--r--test/functional/api/buffer_spec.lua266
3 files changed, 289 insertions, 21 deletions
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index 775b6e8ea7..d36f0dd050 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -472,9 +472,11 @@ void nvim_buf_set_lines(uint64_t channel_id, Buffer buffer, Integer start, Integ
kExtmarkUndo);
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);
+
+ FOR_ALL_TAB_WINDOWS(tp, win) {
+ if (win->w_buffer == buf) {
+ fix_cursor(win, (linenr_T)start, (linenr_T)end, (linenr_T)extra);
+ }
}
end:
@@ -710,7 +712,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In
// 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);
+ true, true, kExtmarkNOOP);
extmark_splice(buf, (int)start_row - 1, (colnr_T)start_col,
(int)(end_row - start_row), col_extent, old_byte,
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index 2e08a6f591..584a6c5827 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -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_buf(curbuf, line1, line2, amount, amount_after, true, true, op);
+ mark_adjust_buf(curbuf, line1, line2, amount, amount_after, true, false, op);
}
// mark_adjust_nofold() does the same as mark_adjust() but without adjusting
@@ -1132,11 +1132,11 @@ 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_buf(curbuf, line1, line2, amount, amount_after, false, true, op);
+ mark_adjust_buf(curbuf, line1, line2, amount, amount_after, false, false, 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)
+ linenr_T amount_after, bool adjust_folds, bool by_api, ExtmarkOp op)
{
int fnum = buf->b_fnum;
linenr_T *lp;
@@ -1243,7 +1243,7 @@ void mark_adjust_buf(buf_T *buf, linenr_T line1, linenr_T line2, linenr_T amount
// topline and cursor position for windows with the same buffer
// other than the current window
- if (win != curwin) {
+ if (win != curwin || by_api) {
if (win->w_topline >= line1 && win->w_topline <= line2) {
if (amount == MAXLNUM) { // topline is deleted
if (line1 <= 1) {
@@ -1261,21 +1261,21 @@ void mark_adjust_buf(buf_T *buf, linenr_T line1, linenr_T line2, linenr_T amount
win->w_topline += amount_after;
win->w_topfill = 0;
}
- 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;
+ }
+ if (win != curwin && !by_api) {
+ 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;
}
- } else if (amount_after && win->w_cursor.lnum > line2) {
- win->w_cursor.lnum += amount_after;
+ 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;
}
}
diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua
index 4784c0a9dd..fda2ea17b8 100644
--- a/test/functional/api/buffer_spec.lua
+++ b/test/functional/api/buffer_spec.lua
@@ -137,6 +137,139 @@ describe('api/buf', function()
-- it's impossible to get out-of-bounds errors for an unloaded buffer
eq({}, buffer('get_lines', bufnr, 8888, 9999, 1))
end)
+
+ describe('handles topline', function()
+ local screen
+ before_each(function()
+ screen = Screen.new(20, 12)
+ screen:set_default_attr_ids {
+ [1] = {bold = true, foreground = Screen.colors.Blue1};
+ [2] = {reverse = true, bold = true};
+ [3] = {reverse = true};
+ }
+ screen:attach()
+ meths.buf_set_lines(0, 0, -1, 1, {"aaa", "bbb", "ccc", "ddd", "www", "xxx", "yyy", "zzz"})
+ meths.set_option_value('modified', false, {})
+ end)
+
+ it('of current window', function()
+ local win = meths.get_current_win()
+ local buf = meths.get_current_buf()
+
+ command('new | wincmd w')
+ meths.win_set_cursor(win, {8,0})
+
+ screen:expect{grid=[[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {3:[No Name] }|
+ www |
+ xxx |
+ yyy |
+ ^zzz |
+ {2:[No Name] }|
+ |
+ ]]}
+ meths.buf_set_lines(buf, 0, 2, true, {"aaabbb"})
+
+ screen:expect{grid=[[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {3:[No Name] }|
+ www |
+ xxx |
+ yyy |
+ ^zzz |
+ {2:[No Name] [+] }|
+ |
+ ]]}
+ end)
+
+ it('of non-current window', function()
+ local win = meths.get_current_win()
+ local buf = meths.get_current_buf()
+
+ command('new')
+ meths.win_set_cursor(win, {8,0})
+
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] }|
+ www |
+ xxx |
+ yyy |
+ zzz |
+ {3:[No Name] }|
+ |
+ ]]}
+
+ meths.buf_set_lines(buf, 0, 2, true, {"aaabbb"})
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] }|
+ www |
+ xxx |
+ yyy |
+ zzz |
+ {3:[No Name] [+] }|
+ |
+ ]]}
+ end)
+
+ it('of split windows with same buffer', function()
+ local win = meths.get_current_win()
+ local buf = meths.get_current_buf()
+
+ command('split')
+ meths.win_set_cursor(win, {8,0})
+ meths.win_set_cursor(0, {1,0})
+
+ screen:expect{grid=[[
+ ^aaa |
+ bbb |
+ ccc |
+ ddd |
+ www |
+ {2:[No Name] }|
+ www |
+ xxx |
+ yyy |
+ zzz |
+ {3:[No Name] }|
+ |
+ ]]}
+ meths.buf_set_lines(buf, 0, 2, true, {"aaabbb"})
+
+ screen:expect{grid=[[
+ ^aaabbb |
+ ccc |
+ ddd |
+ www |
+ xxx |
+ {2:[No Name] [+] }|
+ www |
+ xxx |
+ yyy |
+ zzz |
+ {3:[No Name] [+] }|
+ |
+ ]]}
+ end)
+ end)
end)
describe('deprecated: {get,set,del}_line', function()
@@ -659,6 +792,139 @@ describe('api/buf', function()
]])
eq({'one', 'two'}, get_lines(0, 2, true))
end)
+
+ describe('handles topline', function()
+ local screen
+ before_each(function()
+ screen = Screen.new(20, 12)
+ screen:set_default_attr_ids {
+ [1] = {bold = true, foreground = Screen.colors.Blue1};
+ [2] = {reverse = true, bold = true};
+ [3] = {reverse = true};
+ }
+ screen:attach()
+ meths.buf_set_lines(0, 0, -1, 1, {"aaa", "bbb", "ccc", "ddd", "www", "xxx", "yyy", "zzz"})
+ meths.set_option_value('modified', false, {})
+ end)
+
+ it('of current window', function()
+ local win = meths.get_current_win()
+ local buf = meths.get_current_buf()
+
+ command('new | wincmd w')
+ meths.win_set_cursor(win, {8,0})
+
+ screen:expect{grid=[[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {3:[No Name] }|
+ www |
+ xxx |
+ yyy |
+ ^zzz |
+ {2:[No Name] }|
+ |
+ ]]}
+ meths.buf_set_text(buf, 0,3, 1,0, {"X"})
+
+ screen:expect{grid=[[
+ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {3:[No Name] }|
+ www |
+ xxx |
+ yyy |
+ ^zzz |
+ {2:[No Name] [+] }|
+ |
+ ]]}
+ end)
+
+ it('of non-current window', function()
+ local win = meths.get_current_win()
+ local buf = meths.get_current_buf()
+
+ command('new')
+ meths.win_set_cursor(win, {8,0})
+
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] }|
+ www |
+ xxx |
+ yyy |
+ zzz |
+ {3:[No Name] }|
+ |
+ ]]}
+
+ meths.buf_set_text(buf, 0,3, 1,0, {"X"})
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] }|
+ www |
+ xxx |
+ yyy |
+ zzz |
+ {3:[No Name] [+] }|
+ |
+ ]]}
+ end)
+
+ it('of split windows with same buffer', function()
+ local win = meths.get_current_win()
+ local buf = meths.get_current_buf()
+
+ command('split')
+ meths.win_set_cursor(win, {8,0})
+ meths.win_set_cursor(0, {1,1})
+
+ screen:expect{grid=[[
+ a^aa |
+ bbb |
+ ccc |
+ ddd |
+ www |
+ {2:[No Name] }|
+ www |
+ xxx |
+ yyy |
+ zzz |
+ {3:[No Name] }|
+ |
+ ]]}
+ meths.buf_set_text(buf, 0,3, 1,0, {"X"})
+
+ screen:expect{grid=[[
+ a^aaXbbb |
+ ccc |
+ ddd |
+ www |
+ xxx |
+ {2:[No Name] [+] }|
+ www |
+ xxx |
+ yyy |
+ zzz |
+ {3:[No Name] [+] }|
+ |
+ ]]}
+ end)
+ end)
end)
describe_lua_and_rpc('nvim_buf_get_text', function(api)