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)