diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 50520584a5..d1054ea72e 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -1158,6 +1158,23 @@ void ex_changes(exarg_T *eap) } \ } +// Like ONE_ADJUST_NODEL(), but if the position is within the deleted range, +// move it to the start of the line before the range. +#define ONE_ADJUST_CURSOR(pp) \ + { \ + pos_T *posp = pp; \ + if (posp->lnum >= line1 && posp->lnum <= line2) { \ + if (amount == MAXLNUM) { /* line with cursor is deleted */ \ + posp->lnum = MAX(line1 - 1, 1); \ + posp->col = 0; \ + } else { /* keep cursor on the same line */ \ + posp->lnum += amount; \ + } \ + } else if (amount_after && posp->lnum > line2) { \ + posp->lnum += amount_after; \ + } \ + } + // Adjust marks between "line1" and "line2" (inclusive) to move "amount" lines. // Must be called before changed_*(), appended_lines() or deleted_lines(). // May be called before or after changing the text. @@ -1316,20 +1333,7 @@ void mark_adjust_buf(buf_T *buf, linenr_T line1, linenr_T line2, linenr_T amount } } if (!by_api && (by_term ? win->w_cursor.lnum < buf->b_ml.ml_line_count : win != curwin)) { - 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; - } - } else if (amount_after && win->w_cursor.lnum > line2) { - win->w_cursor.lnum += amount_after; - } + ONE_ADJUST_CURSOR(&(win->w_cursor)); } if (adjust_folds) { @@ -1340,6 +1344,12 @@ void mark_adjust_buf(buf_T *buf, linenr_T line1, linenr_T line2, linenr_T amount // adjust diffs diff_mark_adjust(buf, line1, line2, amount, amount_after); + + // adjust per-window "last cursor" positions + for (size_t i = 0; i < kv_size(buf->b_wininfo); i++) { + WinInfo *wip = kv_A(buf->b_wininfo, i); + ONE_ADJUST_CURSOR(&(wip->wi_mark.mark)); + } } // This code is used often, needs to be fast. diff --git a/test/old/testdir/test_buffer.vim b/test/old/testdir/test_buffer.vim index 19799a5478..1e4f19eb69 100644 --- a/test/old/testdir/test_buffer.vim +++ b/test/old/testdir/test_buffer.vim @@ -619,17 +619,48 @@ func Test_switch_to_previously_viewed_buffer() vsplit call cursor(100, 3) + call assert_equal('100', getline('.')) edit Xotherbuf buffer Xviewbuf call assert_equal([0, 100, 3, 0], getpos('.')) + call assert_equal('100', getline('.')) + edit Xotherbuf + wincmd p + normal! gg10dd + wincmd p + buffer Xviewbuf + call assert_equal([0, 90, 3, 0], getpos('.')) + call assert_equal('100', getline('.')) + + edit Xotherbuf + wincmd p + normal! ggP + wincmd p + buffer Xviewbuf + call assert_equal([0, 100, 3, 0], getpos('.')) + call assert_equal('100', getline('.')) + + edit Xotherbuf + wincmd p + normal! 96gg10ddgg + wincmd p + buffer Xviewbuf + " The original cursor line was deleted, so cursor is restored to the start + " of the line before the deleted range. + call assert_equal([0, 95, 1, 0], getpos('.')) + call assert_equal('95', getline('.')) + + normal! u exe win_id2win(oldwin) .. 'close' setlocal bufhidden=hide call cursor(200, 3) + call assert_equal('200', getline('.')) edit Xotherbuf buffer Xviewbuf call assert_equal([0, 200, 3, 0], getpos('.')) + call assert_equal('200', getline('.')) bwipe! Xotherbuf bwipe! Xviewbuf