diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index d36f0dd050..b8cb09ceb3 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -464,7 +464,8 @@ 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. - mark_adjust_buf(buf, (linenr_T)start, (linenr_T)(end - 1), MAXLNUM, (linenr_T)extra, + linenr_T adjust = end > start ? MAXLNUM : 0; + mark_adjust_buf(buf, (linenr_T)start, (linenr_T)(end - 1), adjust, (linenr_T)extra, true, true, kExtmarkNOOP); extmark_splice(buf, (int)start - 1, 0, (int)(end - start), 0, @@ -711,7 +712,8 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In // 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, + linenr_T adjust = end_row >= start_row ? MAXLNUM : 0; + mark_adjust_buf(buf, (linenr_T)start_row, (linenr_T)end_row, adjust, (linenr_T)extra, true, true, kExtmarkNOOP); extmark_splice(buf, (int)start_row - 1, (colnr_T)start_col, diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 584a6c5827..39fc623676 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -1249,7 +1249,8 @@ void mark_adjust_buf(buf_T *buf, linenr_T line1, linenr_T line2, linenr_T amount if (line1 <= 1) { win->w_topline = 1; } else { - win->w_topline = line1 - 1; + // api: if the deleted region was replaced with new contents, display that + win->w_topline = (by_api && amount_after > line1 - line2 - 1) ? line1 : line1 - 1; } } else if (win->w_topline > line1) { // keep topline on the same line, unless inserting just @@ -1257,7 +1258,9 @@ void mark_adjust_buf(buf_T *buf, linenr_T line1, linenr_T line2, linenr_T amount win->w_topline += amount; } win->w_topfill = 0; - } else if (amount_after && win->w_topline > line2) { + // api: display new line if inserted right at topline + // TODO(bfredl): maybe always? + } else if (amount_after && win->w_topline > line2 + (by_api ? 1 : 0)) { win->w_topline += amount_after; win->w_topfill = 0; } diff --git a/test/functional/api/buffer_spec.lua b/test/functional/api/buffer_spec.lua index 73a8749682..aea1f359e6 100644 --- a/test/functional/api/buffer_spec.lua +++ b/test/functional/api/buffer_spec.lua @@ -182,8 +182,8 @@ describe('api/buf', function() {2:[No Name] }| | ]]} - meths.buf_set_lines(buf, 0, 2, true, {"aaabbb"}) + meths.buf_set_lines(buf, 0, 2, true, {"aaabbb"}) screen:expect{grid=[[ | {1:~ }| @@ -198,6 +198,72 @@ describe('api/buf', function() {2:[No Name] [+] }| | ]]} + + -- replacing topline keeps it the topline + meths.buf_set_lines(buf, 3, 4, true, {"wwweeee"}) + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {3:[No Name] }| + wwweeee | + xxx | + yyy | + ^zzz | + {2:[No Name] [+] }| + | + ]]} + + -- inserting just before topline does not scroll up if cursor would be moved + meths.buf_set_lines(buf, 3, 3, true, {"mmm"}) + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {3:[No Name] }| + wwweeee | + xxx | + yyy | + ^zzz | + {2:[No Name] [+] }| + | + ]], unchanged=true} + + meths.win_set_cursor(0, {7, 0}) + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {3:[No Name] }| + wwweeee | + xxx | + ^yyy | + zzz | + {2:[No Name] [+] }| + | + ]]} + + meths.buf_set_lines(buf, 4, 4, true, {"mmmeeeee"}) + screen:expect{grid=[[ + | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {3:[No Name] }| + mmmeeeee | + wwweeee | + xxx | + ^yyy | + {2:[No Name] [+] }| + | + ]]} end) it('of non-current window', function() @@ -237,6 +303,40 @@ describe('api/buf', function() {3:[No Name] [+] }| | ]]} + + -- replacing topline keeps it the topline + meths.buf_set_lines(buf, 3, 4, true, {"wwweeee"}) + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:[No Name] }| + wwweeee | + xxx | + yyy | + zzz | + {3:[No Name] [+] }| + | + ]]} + + -- inserting just before topline scrolls up + meths.buf_set_lines(buf, 3, 3, true, {"mmm"}) + screen:expect{grid=[[ + ^ | + {1:~ }| + {1:~ }| + {1:~ }| + {1:~ }| + {2:[No Name] }| + mmm | + wwweeee | + xxx | + yyy | + {3:[No Name] [+] }| + | + ]]} end) it('of split windows with same buffer', function() @@ -277,6 +377,40 @@ describe('api/buf', function() {3:[No Name] [+] }| | ]]} + + -- replacing topline keeps it the topline + meths.buf_set_lines(buf, 3, 4, true, {"wwweeee"}) + screen:expect{grid=[[ + ^aaabbb | + ccc | + ddd | + wwweeee | + xxx | + {2:[No Name] [+] }| + wwweeee | + xxx | + yyy | + zzz | + {3:[No Name] [+] }| + | + ]]} + + -- inserting just before topline scrolls up + meths.buf_set_lines(buf, 3, 3, true, {"mmm"}) + screen:expect{grid=[[ + ^aaabbb | + ccc | + ddd | + mmm | + wwweeee | + {2:[No Name] [+] }| + mmm | + wwweeee | + xxx | + yyy | + {3:[No Name] [+] }| + | + ]]} end) end)