mirror of
https://github.com/neovim/neovim.git
synced 2025-09-05 19:08:15 +00:00
Merge pull request #25497 from zeertzjq/backport
Backport to release-0.9
This commit is contained in:
@@ -1193,6 +1193,7 @@ struct window_S {
|
||||
int w_hsep_height; // Number of horizontal separator rows (0 or 1)
|
||||
int w_vsep_width; // Number of vertical separator columns (0 or 1).
|
||||
pos_save_T w_save_cursor; // backup of cursor pos and topline
|
||||
bool w_do_win_fix_cursor; // if true cursor may be invalid
|
||||
|
||||
int w_winrow_off; ///< offset from winrow to the inner window area
|
||||
int w_wincol_off; ///< offset from wincol to the inner window area
|
||||
|
@@ -1453,16 +1453,12 @@ static void win_update(win_T *wp, DecorProviders *providers)
|
||||
|
||||
init_search_hl(wp, &screen_search_hl);
|
||||
|
||||
// Force redraw when width of 'number' or 'relativenumber' column
|
||||
// changes.
|
||||
int nrwidth = (wp->w_p_nu || wp->w_p_rnu || *wp->w_p_stc) ? number_width(wp) : 0;
|
||||
if (wp->w_nrwidth != nrwidth) {
|
||||
const int nrwidth_before = wp->w_nrwidth;
|
||||
int nrwidth_new = (wp->w_p_nu || wp->w_p_rnu || *wp->w_p_stc) ? number_width(wp) : 0;
|
||||
// Force redraw when width of 'number' or 'relativenumber' column changes.
|
||||
if (wp->w_nrwidth != nrwidth_new) {
|
||||
type = UPD_NOT_VALID;
|
||||
wp->w_nrwidth = nrwidth;
|
||||
|
||||
if (buf->terminal) {
|
||||
terminal_check_size(buf->terminal);
|
||||
}
|
||||
wp->w_nrwidth = nrwidth_new;
|
||||
} else if (buf->b_mod_set
|
||||
&& buf->b_mod_xlines != 0
|
||||
&& wp->w_redraw_top != 0) {
|
||||
@@ -2414,6 +2410,10 @@ static void win_update(win_T *wp, DecorProviders *providers)
|
||||
}
|
||||
}
|
||||
|
||||
if (nrwidth_before != wp->w_nrwidth && buf->terminal) {
|
||||
terminal_check_size(buf->terminal);
|
||||
}
|
||||
|
||||
// restore got_int, unless CTRL-C was hit while redrawing
|
||||
if (!got_int) {
|
||||
got_int = save_got_int;
|
||||
|
@@ -2549,15 +2549,10 @@ int oneleft(void)
|
||||
|
||||
/// Move the cursor up "n" lines in window "wp".
|
||||
/// Takes care of closed folds.
|
||||
/// Returns the new cursor line or zero for failure.
|
||||
linenr_T cursor_up_inner(win_T *wp, long n)
|
||||
void cursor_up_inner(win_T *wp, long n)
|
||||
{
|
||||
linenr_T lnum = wp->w_cursor.lnum;
|
||||
|
||||
// This fails if the cursor is already in the first line.
|
||||
if (lnum <= 1) {
|
||||
return 0;
|
||||
}
|
||||
if (n >= lnum) {
|
||||
lnum = 1;
|
||||
} else if (hasAnyFolding(wp)) {
|
||||
@@ -2587,15 +2582,16 @@ linenr_T cursor_up_inner(win_T *wp, long n)
|
||||
}
|
||||
|
||||
wp->w_cursor.lnum = lnum;
|
||||
return lnum;
|
||||
}
|
||||
|
||||
/// @param upd_topline When true: update topline
|
||||
int cursor_up(long n, int upd_topline)
|
||||
{
|
||||
if (n > 0 && cursor_up_inner(curwin, n) == 0) {
|
||||
// This fails if the cursor is already in the first line.
|
||||
if (n > 0 && curwin->w_cursor.lnum <= 1) {
|
||||
return FAIL;
|
||||
}
|
||||
cursor_up_inner(curwin, n);
|
||||
|
||||
// try to advance to the column we want to be at
|
||||
coladvance(curwin->w_curswant);
|
||||
@@ -2609,18 +2605,11 @@ int cursor_up(long n, int upd_topline)
|
||||
|
||||
/// Move the cursor down "n" lines in window "wp".
|
||||
/// Takes care of closed folds.
|
||||
/// Returns the new cursor line or zero for failure.
|
||||
linenr_T cursor_down_inner(win_T *wp, long n)
|
||||
void cursor_down_inner(win_T *wp, long n)
|
||||
{
|
||||
linenr_T lnum = wp->w_cursor.lnum;
|
||||
linenr_T line_count = wp->w_buffer->b_ml.ml_line_count;
|
||||
|
||||
// Move to last line of fold, will fail if it's the end-of-file.
|
||||
(void)hasFoldingWin(wp, lnum, NULL, &lnum, true, NULL);
|
||||
// This fails if the cursor is already in the last line.
|
||||
if (lnum >= line_count) {
|
||||
return FAIL;
|
||||
}
|
||||
if (lnum + n >= line_count) {
|
||||
lnum = line_count;
|
||||
} else if (hasAnyFolding(wp)) {
|
||||
@@ -2628,6 +2617,7 @@ linenr_T cursor_down_inner(win_T *wp, long n)
|
||||
|
||||
// count each sequence of folded lines as one logical line
|
||||
while (n--) {
|
||||
// Move to last line of fold, will fail if it's the end-of-file.
|
||||
if (hasFoldingWin(wp, lnum, NULL, &last, true, NULL)) {
|
||||
lnum = last + 1;
|
||||
} else {
|
||||
@@ -2645,15 +2635,16 @@ linenr_T cursor_down_inner(win_T *wp, long n)
|
||||
}
|
||||
|
||||
wp->w_cursor.lnum = lnum;
|
||||
return lnum;
|
||||
}
|
||||
|
||||
/// @param upd_topline When true: update topline
|
||||
int cursor_down(long n, int upd_topline)
|
||||
{
|
||||
if (n > 0 && cursor_down_inner(curwin, n) == 0) {
|
||||
// This fails if the cursor is already in the last line.
|
||||
if (n > 0 && curwin->w_cursor.lnum >= curwin->w_buffer->b_ml.ml_line_count) {
|
||||
return FAIL;
|
||||
}
|
||||
cursor_down_inner(curwin, n);
|
||||
|
||||
// try to advance to the column we want to be at
|
||||
coladvance(curwin->w_curswant);
|
||||
|
@@ -2498,10 +2498,12 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist)
|
||||
curwin->w_curswant -= width2;
|
||||
} else {
|
||||
// to previous line
|
||||
if (!cursor_up_inner(curwin, 1)) {
|
||||
if (curwin->w_cursor.lnum <= 1) {
|
||||
retval = false;
|
||||
break;
|
||||
}
|
||||
cursor_up_inner(curwin, 1);
|
||||
|
||||
linelen = linetabsize(get_cursor_line_ptr());
|
||||
if (linelen > width1) {
|
||||
int w = (((linelen - width1 - 1) / width2) + 1) * width2;
|
||||
@@ -2521,11 +2523,13 @@ static bool nv_screengo(oparg_T *oap, int dir, long dist)
|
||||
curwin->w_curswant += width2;
|
||||
} else {
|
||||
// to next line
|
||||
if (!cursor_down_inner(curwin, 1)) {
|
||||
if (curwin->w_cursor.lnum >= curwin->w_buffer->b_ml.ml_line_count) {
|
||||
retval = false;
|
||||
break;
|
||||
}
|
||||
cursor_down_inner(curwin, 1);
|
||||
curwin->w_curswant %= width2;
|
||||
|
||||
// Check if the cursor has moved below the number display
|
||||
// when width1 < width2 (with cpoptions+=n). Subtract width2
|
||||
// to get a negative value for w_curswant, which will get
|
||||
|
@@ -1573,7 +1573,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
||||
// equalize the window sizes.
|
||||
if (do_equal || dir != 0) {
|
||||
win_equal(wp, true, (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h') : (dir == 'h' ? 'b' : 'v'));
|
||||
} else if (*p_spk != 'c' && !is_aucmd_win(wp)) {
|
||||
} else if (!is_aucmd_win(wp)) {
|
||||
win_fix_scroll(false);
|
||||
}
|
||||
|
||||
@@ -2163,7 +2163,7 @@ void win_equal(win_T *next_curwin, bool current, int dir)
|
||||
win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current,
|
||||
topframe, dir, 0, tabline_height(),
|
||||
Columns, topframe->fr_height);
|
||||
if (*p_spk != 'c' && !is_aucmd_win(next_curwin)) {
|
||||
if (!is_aucmd_win(next_curwin)) {
|
||||
win_fix_scroll(true);
|
||||
}
|
||||
}
|
||||
@@ -2956,9 +2956,7 @@ int win_close(win_T *win, bool free_buf, bool force)
|
||||
win_equal(curwin, curwin->w_frame->fr_parent == win_frame, dir);
|
||||
} else {
|
||||
(void)win_comp_pos();
|
||||
if (*p_spk != 'c') {
|
||||
win_fix_scroll(false);
|
||||
}
|
||||
win_fix_scroll(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5350,7 +5348,7 @@ void win_new_screen_rows(void)
|
||||
compute_cmdrow();
|
||||
curtab->tp_ch_used = p_ch;
|
||||
|
||||
if (*p_spk != 'c' && !skip_win_fix_scroll) {
|
||||
if (!skip_win_fix_scroll) {
|
||||
win_fix_scroll(true);
|
||||
}
|
||||
}
|
||||
@@ -5797,9 +5795,7 @@ void win_setheight_win(int height, win_T *win)
|
||||
msg_row = row;
|
||||
msg_col = 0;
|
||||
|
||||
if (*p_spk != 'c') {
|
||||
win_fix_scroll(true);
|
||||
}
|
||||
win_fix_scroll(true);
|
||||
|
||||
redraw_all_later(UPD_NOT_VALID);
|
||||
redraw_cmdline = true;
|
||||
@@ -6277,9 +6273,7 @@ void win_drag_status_line(win_T *dragwin, int offset)
|
||||
p_ch = MAX(Rows - cmdline_row, p_ch_was_zero ? 0 : 1);
|
||||
curtab->tp_ch_used = p_ch;
|
||||
|
||||
if (*p_spk != 'c') {
|
||||
win_fix_scroll(true);
|
||||
}
|
||||
win_fix_scroll(true);
|
||||
|
||||
redraw_all_later(UPD_SOME_VALID);
|
||||
showmode();
|
||||
@@ -6398,40 +6392,51 @@ void set_fraction(win_T *wp)
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle scroll position for 'splitkeep'. Replaces scroll_to_fraction()
|
||||
/// call from win_set_inner_size(). Instead we iterate over all windows in a
|
||||
/// tabpage and calculate the new scroll position.
|
||||
/// TODO(luukvbaal): Ensure this also works with wrapped lines.
|
||||
/// Requires topline to be able to be set to a bufferline with some
|
||||
/// offset(row-wise scrolling/smoothscroll).
|
||||
/// Handle scroll position, depending on 'splitkeep'. Replaces the
|
||||
/// scroll_to_fraction() call from win_new_height() if 'splitkeep' is "screen"
|
||||
/// or "topline". Instead we iterate over all windows in a tabpage and
|
||||
/// calculate the new scroll position.
|
||||
/// TODO(vim): Ensure this also works with wrapped lines.
|
||||
/// Requires a not fully visible cursor line to be allowed at the bottom of
|
||||
/// a window("zb"), probably only when 'smoothscroll' is also set.
|
||||
void win_fix_scroll(int resize)
|
||||
{
|
||||
linenr_T lnum;
|
||||
if (*p_spk == 'c') {
|
||||
return; // 'splitkeep' is "cursor"
|
||||
}
|
||||
|
||||
skip_update_topline = true;
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
// Skip when window height has not changed or when floating.
|
||||
if (!wp->w_floating && wp->w_height != wp->w_prev_height) {
|
||||
// Cursor position in this window may now be invalid. It is kept
|
||||
// potentially invalid until the window is made the current window.
|
||||
wp->w_do_win_fix_cursor = true;
|
||||
|
||||
// If window has moved update botline to keep the same screenlines.
|
||||
if (*p_spk == 's' && wp->w_winrow != wp->w_prev_winrow
|
||||
&& wp->w_botline - 1 <= wp->w_buffer->b_ml.ml_line_count) {
|
||||
lnum = wp->w_cursor.lnum;
|
||||
int diff = (wp->w_winrow - wp->w_prev_winrow)
|
||||
+ (wp->w_height - wp->w_prev_height);
|
||||
linenr_T lnum = wp->w_cursor.lnum;
|
||||
wp->w_cursor.lnum = wp->w_botline - 1;
|
||||
|
||||
// Add difference in height and row to botline.
|
||||
if (diff > 0) {
|
||||
cursor_down_inner(wp, diff);
|
||||
} else {
|
||||
cursor_up_inner(wp, -diff);
|
||||
}
|
||||
// Bring the new cursor position to the bottom of the screen.
|
||||
|
||||
// Scroll to put the new cursor position at the bottom of the
|
||||
// screen.
|
||||
wp->w_fraction = FRACTION_MULT;
|
||||
scroll_to_fraction(wp, wp->w_prev_height);
|
||||
wp->w_cursor.lnum = lnum;
|
||||
} else if (wp == curwin) {
|
||||
wp->w_valid &= ~VALID_CROW;
|
||||
}
|
||||
|
||||
invalidate_botline_win(wp);
|
||||
validate_botline(wp);
|
||||
}
|
||||
@@ -6449,41 +6454,45 @@ void win_fix_scroll(int resize)
|
||||
|
||||
/// Make sure the cursor position is valid for 'splitkeep'.
|
||||
/// If it is not, put the cursor position in the jumplist and move it.
|
||||
/// If we are not in normal mode ("normal" is zero), make it valid by scrolling
|
||||
/// If we are not in normal mode ("normal" is false), make it valid by scrolling
|
||||
/// instead.
|
||||
static void win_fix_cursor(int normal)
|
||||
static void win_fix_cursor(bool normal)
|
||||
{
|
||||
win_T *wp = curwin;
|
||||
long so = get_scrolloff_value(wp);
|
||||
linenr_T nlnum = 0;
|
||||
linenr_T lnum = wp->w_cursor.lnum;
|
||||
|
||||
if (wp->w_buffer->b_ml.ml_line_count < wp->w_height
|
||||
|| skip_win_fix_cursor) {
|
||||
if (skip_win_fix_cursor
|
||||
|| !wp->w_do_win_fix_cursor
|
||||
|| wp->w_buffer->b_ml.ml_line_count < wp->w_height_inner) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp->w_do_win_fix_cursor = false;
|
||||
// Determine valid cursor range.
|
||||
so = MIN(wp->w_height_inner / 2, so);
|
||||
long so = MIN(wp->w_height_inner / 2, get_scrolloff_value(wp));
|
||||
linenr_T lnum = wp->w_cursor.lnum;
|
||||
|
||||
wp->w_cursor.lnum = wp->w_topline;
|
||||
linenr_T top = cursor_down_inner(wp, so);
|
||||
cursor_down_inner(wp, so);
|
||||
linenr_T top = wp->w_cursor.lnum;
|
||||
|
||||
wp->w_cursor.lnum = wp->w_botline - 1;
|
||||
linenr_T bot = cursor_up_inner(wp, so);
|
||||
cursor_up_inner(wp, so);
|
||||
linenr_T bot = wp->w_cursor.lnum;
|
||||
|
||||
wp->w_cursor.lnum = lnum;
|
||||
// Check if cursor position is above or below valid cursor range.
|
||||
linenr_T nlnum = 0;
|
||||
if (lnum > bot && (wp->w_botline - wp->w_buffer->b_ml.ml_line_count) != 1) {
|
||||
nlnum = bot;
|
||||
} else if (lnum < top && wp->w_topline != 1) {
|
||||
nlnum = (so == wp->w_height / 2) ? bot : top;
|
||||
nlnum = (so == wp->w_height_inner / 2) ? bot : top;
|
||||
}
|
||||
|
||||
if (nlnum) { // Cursor is invalid for current scroll position.
|
||||
if (normal) {
|
||||
// Save to jumplist and set cursor to avoid scrolling.
|
||||
if (nlnum != 0) { // Cursor is invalid for current scroll position.
|
||||
if (normal) { // Save to jumplist and set cursor to avoid scrolling.
|
||||
setmark('\'');
|
||||
wp->w_cursor.lnum = nlnum;
|
||||
} else {
|
||||
// Scroll instead when not in normal mode.
|
||||
} else { // Scroll instead when not in normal mode.
|
||||
wp->w_fraction = (nlnum == bot) ? FRACTION_MULT : 0;
|
||||
scroll_to_fraction(wp, wp->w_prev_height);
|
||||
validate_botline(curwin);
|
||||
|
@@ -43,6 +43,61 @@ describe('splitkeep', function()
|
||||
screen:attach()
|
||||
end)
|
||||
|
||||
-- oldtest: Test_splitkeep_cursor()
|
||||
it('does not adjust cursor in window that did not change size', function()
|
||||
screen:try_resize(75, 8)
|
||||
-- FIXME: bottom window is different without the "vsplit | close"
|
||||
exec([[
|
||||
vsplit | close
|
||||
set scrolloff=5
|
||||
set splitkeep=screen
|
||||
autocmd CursorMoved * wincmd p | wincmd p
|
||||
call setline(1, range(1, 200))
|
||||
func CursorEqualize()
|
||||
call cursor(100, 1)
|
||||
wincmd =
|
||||
endfunc
|
||||
wincmd s
|
||||
call CursorEqualize()
|
||||
]])
|
||||
|
||||
screen:expect([[
|
||||
99 |
|
||||
^100 |
|
||||
101 |
|
||||
[No Name] [+] |
|
||||
5 |
|
||||
6 |
|
||||
[No Name] [+] |
|
||||
|
|
||||
]])
|
||||
|
||||
feed('j')
|
||||
screen:expect([[
|
||||
100 |
|
||||
^101 |
|
||||
102 |
|
||||
[No Name] [+] |
|
||||
5 |
|
||||
6 |
|
||||
[No Name] [+] |
|
||||
|
|
||||
]])
|
||||
|
||||
command('set scrolloff=0')
|
||||
feed('G')
|
||||
screen:expect([[
|
||||
198 |
|
||||
199 |
|
||||
^200 |
|
||||
[No Name] [+] |
|
||||
5 |
|
||||
6 |
|
||||
[No Name] [+] |
|
||||
|
|
||||
]])
|
||||
end)
|
||||
|
||||
-- oldtest: Test_splitkeep_callback()
|
||||
it('does not scroll when split in callback', function()
|
||||
exec([[
|
||||
|
@@ -44,7 +44,7 @@ describe(':terminal window', function()
|
||||
{7:6 } |
|
||||
{3:-- TERMINAL --} |
|
||||
]])
|
||||
feed_data({'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'})
|
||||
feed_data('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
|
||||
screen:expect([[
|
||||
{7:1 }tty ready |
|
||||
{7:2 }rows: 6, cols: 48 |
|
||||
@@ -69,7 +69,7 @@ describe(':terminal window', function()
|
||||
{7: 6 } |
|
||||
{3:-- TERMINAL --} |
|
||||
]])
|
||||
feed_data({' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'})
|
||||
feed_data(' abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
|
||||
screen:expect([[
|
||||
{7: 1 }tty ready |
|
||||
{7: 2 }rows: 6, cols: 48 |
|
||||
@@ -82,6 +82,31 @@ describe(':terminal window', function()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("with 'statuscolumn'", function()
|
||||
it('wraps text', function()
|
||||
command([[set number statuscolumn=++%l\ \ ]])
|
||||
screen:expect([[
|
||||
{7:++1 }tty ready |
|
||||
{7:++2 }rows: 6, cols: 45 |
|
||||
{7:++3 }{1: } |
|
||||
{7:++4 } |
|
||||
{7:++5 } |
|
||||
{7:++6 } |
|
||||
{3:-- TERMINAL --} |
|
||||
]])
|
||||
feed_data('\n\n\n\n\nabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
|
||||
screen:expect([[
|
||||
{7:++4 } |
|
||||
{7:++5 } |
|
||||
{7:++6 } |
|
||||
{7:++7 } |
|
||||
{7:++8 }abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRS|
|
||||
{7:++9 }TUVWXYZ{1: } |
|
||||
{3:-- TERMINAL --} |
|
||||
]])
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("with 'colorcolumn'", function()
|
||||
before_each(function()
|
||||
feed([[<C-\><C-N>]])
|
||||
|
@@ -1765,9 +1765,20 @@ endfunction
|
||||
|
||||
function Test_splitkeep_misc()
|
||||
set splitkeep=screen
|
||||
set splitbelow
|
||||
|
||||
call setline(1, range(1, &lines))
|
||||
" Cursor is adjusted to start and end of buffer
|
||||
norm M
|
||||
wincmd s
|
||||
resize 1
|
||||
call assert_equal(1, line('.'))
|
||||
wincmd j
|
||||
norm GM
|
||||
resize 1
|
||||
call assert_equal(&lines, line('.'))
|
||||
only!
|
||||
|
||||
set splitbelow
|
||||
norm Gzz
|
||||
let top = line('w0')
|
||||
" No scroll when aucmd_win is opened
|
||||
@@ -1796,7 +1807,34 @@ function Test_splitkeep_misc()
|
||||
set splitkeep&
|
||||
endfunc
|
||||
|
||||
function Test_splitkeep_callback()
|
||||
func Test_splitkeep_cursor()
|
||||
CheckScreendump
|
||||
let lines =<< trim END
|
||||
set splitkeep=screen
|
||||
autocmd CursorMoved * wincmd p | wincmd p
|
||||
call setline(1, range(1, 200))
|
||||
func CursorEqualize()
|
||||
call cursor(100, 1)
|
||||
wincmd =
|
||||
endfunc
|
||||
wincmd s
|
||||
call CursorEqualize()
|
||||
END
|
||||
call writefile(lines, 'XTestSplitkeepCallback', 'D')
|
||||
let buf = RunVimInTerminal('-S XTestSplitkeepCallback', #{rows: 8})
|
||||
|
||||
call VerifyScreenDump(buf, 'Test_splitkeep_cursor_1', {})
|
||||
|
||||
call term_sendkeys(buf, "j")
|
||||
call VerifyScreenDump(buf, 'Test_splitkeep_cursor_2', {})
|
||||
|
||||
call term_sendkeys(buf, ":set scrolloff=0\<CR>G")
|
||||
call VerifyScreenDump(buf, 'Test_splitkeep_cursor_3', {})
|
||||
|
||||
call StopVimInTerminal(buf)
|
||||
endfunc
|
||||
|
||||
func Test_splitkeep_callback()
|
||||
CheckScreendump
|
||||
let lines =<< trim END
|
||||
set splitkeep=screen
|
||||
|
Reference in New Issue
Block a user