mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 11:28:22 +00:00
feat(window/ui): add splitkeep option (#19243)
vim-patch:9.0.0445: when opening/closing window text moves up/down Problem: When opening/closing window text moves up/down. Solution: Add the 'splitscroll' option. When off text will keep its position as much as possible.29ab524358
vim-patch:9.0.0455: a few problems with 'splitscroll' Problem: A few problems with 'splitscroll'. Solution: Fix 'splitscroll' problems. (Luuk van Baal, closes vim/vim#11117)5ed391708a
vim-patch:9.0.0461: 'scroll' is not always updated Problem: 'scroll' is not always updated. Solution: Call win_init_size() at the right place.470a14140b
vim-patch:9.0.0465: cursor moves when cmdwin is closed when 'splitscroll' is off Problem: Cursor moves when cmdwin is closed when 'splitscroll' is off. Solution: Temporarily set 'splitscroll' when jumping back to the original window. (closes vim/vim#11128)e697d48890
vim-patch:9.0.0469: cursor moves if cmdwin is closed when 'splitscroll' is off Problem: Cursor moves if cmdwin is closed when 'splitscroll' is off. Solution: Skip win_fix_cursor if called when cmdwin is open or closing. (Luuk van Baal, closes vim/vim#11134)3735f11050
vim-patch:9.0.0478: test for 'splitscroll' takes too much time Problem: Test for 'splitscroll' takes too much time. Solution: Only test some of the combinations. (Luuk van Baal, closes vim/vim#11139)594f9e09cd
vim-patch:9.0.0486: text scrolled with 'nosplitscroll', autocmd win and help Problem: Text scrolled with 'nosplitscroll', autocmd win opened and help window closed. Solution: Skip win_fix_scroll() in more situations. (Luuk van Baal, closes vim/vim#11150)d5bc762dea
vim-patch:9.0.0505: various problems with 'nosplitscroll' Problem: Various problems with 'nosplitscroll'. Solution: Fix 'nosplitscroll' problems. (Luuk van Baal, closes vim/vim#11166)faf1d412f5
vim-patch:9.0.0555: scrolling with 'nosplitscroll' in callback changing curwin Problem: Scrolling with 'nosplitscroll' in callback changing curwin. Solution: Invalidate w_cline_row in the right place. (Luuk van Baal, closes vim/vim#11185)20e58561ab
vim-patch:9.0.0603: with 'nosplitscroll' folds are not handled correctly Problem: With 'nosplitscroll' folds are not handled correctly. Solution: Take care of closed folds when moving the cursor. (Luuk van Baal, closes vim/vim#11234)7c1cbb6cd4
vim-patch:9.0.0605: dump file missing Problem: Dump file missing. Solution: Add the missing dump file. (issue vim/vim#11234)439a2ba174
vim-patch:9.0.0647: the 'splitscroll' option is not a good name Problem: The 'splitscroll' option is not a good name. Solution: Rename 'splitscroll' to 'splitkeep' and make it a string option, also supporting "topline". (Luuk van Baal, closes vim/vim#11258)13ece2ae1d
vim-patch:9.0.0667: ml_get error when 'splitkeep' is "screen" Problem: ml_get error when 'splitkeep' is "screen". (Marius Gedminas) Solution: Check the botline is not too large. (Luuk van Baal, closes vim/vim#11293, closes vim/vim#11292)346823d3e5
This commit is contained in:
@@ -5961,6 +5961,22 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
When on, splitting a window will put the new window below the current
|
When on, splitting a window will put the new window below the current
|
||||||
one. |:split|
|
one. |:split|
|
||||||
|
|
||||||
|
*'splitkeep'* *'spk'*
|
||||||
|
'splitkeep' 'spk' string (default "cursor")
|
||||||
|
global
|
||||||
|
The value of this option determines the scroll behavior when opening,
|
||||||
|
closing or resizing horizontal splits.
|
||||||
|
|
||||||
|
Possible values are:
|
||||||
|
cursor Keep the same relative cursor position.
|
||||||
|
screen Keep the text on the same screen line.
|
||||||
|
topline Keep the topline the same.
|
||||||
|
|
||||||
|
For the "screen" and "topline" values, the cursor position will be
|
||||||
|
changed when necessary. In this case, the jumplist will be populated
|
||||||
|
with the previous cursor position. For "screen", the text cannot always
|
||||||
|
be kept on the same screen line when 'wrap' is enabled.
|
||||||
|
|
||||||
*'splitright'* *'spr'* *'nosplitright'* *'nospr'*
|
*'splitright'* *'spr'* *'nosplitright'* *'nospr'*
|
||||||
'splitright' 'spr' boolean (default off)
|
'splitright' 'spr' boolean (default off)
|
||||||
global
|
global
|
||||||
|
@@ -890,6 +890,7 @@ Short explanation of each option: *option-list*
|
|||||||
'spelloptions' 'spo' options for spell checking
|
'spelloptions' 'spo' options for spell checking
|
||||||
'spellsuggest' 'sps' method(s) used to suggest spelling corrections
|
'spellsuggest' 'sps' method(s) used to suggest spelling corrections
|
||||||
'splitbelow' 'sb' new window from split is below the current one
|
'splitbelow' 'sb' new window from split is below the current one
|
||||||
|
'splitkeep' 'spk' determines scroll behavior for split windows
|
||||||
'splitright' 'spr' new window is put right of the current one
|
'splitright' 'spr' new window is put right of the current one
|
||||||
'startofline' 'sol' commands move cursor to first non-blank in line
|
'startofline' 'sol' commands move cursor to first non-blank in line
|
||||||
'statusline' 'stl' custom format for the status line
|
'statusline' 'stl' custom format for the status line
|
||||||
|
@@ -511,6 +511,8 @@ call append("$", "\tto a buffer")
|
|||||||
call <SID>OptionG("swb", &swb)
|
call <SID>OptionG("swb", &swb)
|
||||||
call append("$", "splitbelow\ta new window is put below the current one")
|
call append("$", "splitbelow\ta new window is put below the current one")
|
||||||
call <SID>BinOptionG("sb", &sb)
|
call <SID>BinOptionG("sb", &sb)
|
||||||
|
call append("$", "splitkeep\ta determines scroll behavior for split windows")
|
||||||
|
call <SID>BinOptionG("spk", &spk)
|
||||||
call append("$", "splitright\ta new window is put right of the current one")
|
call append("$", "splitright\ta new window is put right of the current one")
|
||||||
call <SID>BinOptionG("spr", &spr)
|
call <SID>BinOptionG("spr", &spr)
|
||||||
call append("$", "scrollbind\tthis window scrolls together with other bound windows")
|
call append("$", "scrollbind\tthis window scrolls together with other bound windows")
|
||||||
|
@@ -1202,6 +1202,8 @@ struct window_S {
|
|||||||
int w_winrow; // first row of window in screen
|
int w_winrow; // first row of window in screen
|
||||||
int w_height; // number of rows in window, excluding
|
int w_height; // number of rows in window, excluding
|
||||||
// status/command line(s)
|
// status/command line(s)
|
||||||
|
int w_prev_winrow; // previous winrow used for 'splitkeep'
|
||||||
|
int w_prev_height; // previous height used for 'splitkeep'
|
||||||
int w_status_height; // number of status lines (0 or 1)
|
int w_status_height; // number of status lines (0 or 1)
|
||||||
int w_winbar_height; // number of window bars (0 or 1)
|
int w_winbar_height; // number of window bars (0 or 1)
|
||||||
int w_wincol; // Leftmost column of window in screen.
|
int w_wincol; // Leftmost column of window in screen.
|
||||||
|
@@ -2541,25 +2541,24 @@ int oneleft(void)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @oaram upd_topline When true: update topline
|
/// Move the cursor up "n" lines in window "wp".
|
||||||
int cursor_up(long n, int upd_topline)
|
/// Takes care of closed folds.
|
||||||
|
/// Returns the new cursor line or zero for failure.
|
||||||
|
linenr_T cursor_up_inner(win_T *wp, long n)
|
||||||
{
|
{
|
||||||
linenr_T lnum;
|
linenr_T lnum = wp->w_cursor.lnum;
|
||||||
|
|
||||||
if (n > 0) {
|
|
||||||
lnum = curwin->w_cursor.lnum;
|
|
||||||
|
|
||||||
// This fails if the cursor is already in the first line.
|
// This fails if the cursor is already in the first line.
|
||||||
if (lnum <= 1) {
|
if (lnum <= 1) {
|
||||||
return FAIL;
|
return 0;
|
||||||
}
|
}
|
||||||
if (n >= lnum) {
|
if (n >= lnum) {
|
||||||
lnum = 1;
|
lnum = 1;
|
||||||
} else if (hasAnyFolding(curwin)) {
|
} else if (hasAnyFolding(wp)) {
|
||||||
// Count each sequence of folded lines as one logical line.
|
// Count each sequence of folded lines as one logical line.
|
||||||
|
|
||||||
// go to the start of the current fold
|
// go to the start of the current fold
|
||||||
(void)hasFolding(lnum, &lnum, NULL);
|
(void)hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL);
|
||||||
|
|
||||||
while (n--) {
|
while (n--) {
|
||||||
// move up one line
|
// move up one line
|
||||||
@@ -2571,7 +2570,7 @@ int cursor_up(long n, int upd_topline)
|
|||||||
// Insert mode or when 'foldopen' contains "all": it will open
|
// Insert mode or when 'foldopen' contains "all": it will open
|
||||||
// in a moment.
|
// in a moment.
|
||||||
if (n > 0 || !((State & MODE_INSERT) || (fdo_flags & FDO_ALL))) {
|
if (n > 0 || !((State & MODE_INSERT) || (fdo_flags & FDO_ALL))) {
|
||||||
(void)hasFolding(lnum, &lnum, NULL);
|
(void)hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lnum < 1) {
|
if (lnum < 1) {
|
||||||
@@ -2580,7 +2579,16 @@ int cursor_up(long n, int upd_topline)
|
|||||||
} else {
|
} else {
|
||||||
lnum -= (linenr_T)n;
|
lnum -= (linenr_T)n;
|
||||||
}
|
}
|
||||||
curwin->w_cursor.lnum = lnum;
|
|
||||||
|
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) {
|
||||||
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to advance to the column we want to be at
|
// try to advance to the column we want to be at
|
||||||
@@ -2593,45 +2601,52 @@ int cursor_up(long n, int upd_topline)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cursor down a number of logical lines.
|
/// Move the cursor down "n" lines in window "wp".
|
||||||
///
|
/// Takes care of closed folds.
|
||||||
/// @param upd_topline When true: update topline
|
/// Returns the new cursor line or zero for failure.
|
||||||
int cursor_down(long n, int upd_topline)
|
linenr_T cursor_down_inner(win_T *wp, long n)
|
||||||
{
|
{
|
||||||
linenr_T lnum;
|
linenr_T lnum = wp->w_cursor.lnum;
|
||||||
|
linenr_T line_count = wp->w_buffer->b_ml.ml_line_count;
|
||||||
|
|
||||||
if (n > 0) {
|
|
||||||
lnum = curwin->w_cursor.lnum;
|
|
||||||
// Move to last line of fold, will fail if it's the end-of-file.
|
// Move to last line of fold, will fail if it's the end-of-file.
|
||||||
(void)hasFolding(lnum, NULL, &lnum);
|
(void)hasFoldingWin(wp, lnum, NULL, &lnum, true, NULL);
|
||||||
|
|
||||||
// This fails if the cursor is already in the last line.
|
// This fails if the cursor is already in the last line.
|
||||||
if (lnum >= curbuf->b_ml.ml_line_count) {
|
if (lnum >= line_count) {
|
||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
if (lnum + n >= curbuf->b_ml.ml_line_count) {
|
if (lnum + n >= line_count) {
|
||||||
lnum = curbuf->b_ml.ml_line_count;
|
lnum = line_count;
|
||||||
} else if (hasAnyFolding(curwin)) {
|
} else if (hasAnyFolding(wp)) {
|
||||||
linenr_T last;
|
linenr_T last;
|
||||||
|
|
||||||
// count each sequence of folded lines as one logical line
|
// count each sequence of folded lines as one logical line
|
||||||
while (n--) {
|
while (n--) {
|
||||||
if (hasFolding(lnum, NULL, &last)) {
|
if (hasFoldingWin(wp, lnum, NULL, &last, true, NULL)) {
|
||||||
lnum = last + 1;
|
lnum = last + 1;
|
||||||
} else {
|
} else {
|
||||||
lnum++;
|
lnum++;
|
||||||
}
|
}
|
||||||
if (lnum >= curbuf->b_ml.ml_line_count) {
|
if (lnum >= line_count) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lnum > curbuf->b_ml.ml_line_count) {
|
if (lnum > line_count) {
|
||||||
lnum = curbuf->b_ml.ml_line_count;
|
lnum = line_count;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
lnum += (linenr_T)n;
|
lnum += (linenr_T)n;
|
||||||
}
|
}
|
||||||
curwin->w_cursor.lnum = lnum;
|
|
||||||
|
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) {
|
||||||
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to advance to the column we want to be at
|
// try to advance to the column we want to be at
|
||||||
|
@@ -4359,6 +4359,7 @@ static int open_cmdwin(void)
|
|||||||
// First go back to the original window.
|
// First go back to the original window.
|
||||||
wp = curwin;
|
wp = curwin;
|
||||||
set_bufref(&bufref, curbuf);
|
set_bufref(&bufref, curbuf);
|
||||||
|
skip_win_fix_cursor = true;
|
||||||
win_goto(old_curwin);
|
win_goto(old_curwin);
|
||||||
|
|
||||||
// win_goto() may trigger an autocommand that already closes the
|
// win_goto() may trigger an autocommand that already closes the
|
||||||
@@ -4375,6 +4376,7 @@ static int open_cmdwin(void)
|
|||||||
|
|
||||||
// Restore window sizes.
|
// Restore window sizes.
|
||||||
win_size_restore(&winsizes);
|
win_size_restore(&winsizes);
|
||||||
|
skip_win_fix_cursor = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ga_clear(&winsizes);
|
ga_clear(&winsizes);
|
||||||
|
@@ -1071,4 +1071,11 @@ EXTERN char windowsVersion[20] INIT(= { 0 });
|
|||||||
|
|
||||||
EXTERN int exit_need_delay INIT(= 0);
|
EXTERN int exit_need_delay INIT(= 0);
|
||||||
|
|
||||||
|
///< Skip win_fix_cursor() call for 'splitkeep' when cmdwin is closed.
|
||||||
|
EXTERN bool skip_win_fix_cursor INIT(= false);
|
||||||
|
///< Skip win_fix_scroll() call for 'splitkeep' when closing tab page.
|
||||||
|
EXTERN bool skip_win_fix_scroll INIT(= false);
|
||||||
|
///< Skip update_topline() call while executing win_fix_scroll().
|
||||||
|
EXTERN bool skip_update_topline INIT(= false);
|
||||||
|
|
||||||
#endif // NVIM_GLOBALS_H
|
#endif // NVIM_GLOBALS_H
|
||||||
|
@@ -346,6 +346,7 @@ int main(int argc, char **argv)
|
|||||||
ui_builtin_start();
|
ui_builtin_start();
|
||||||
}
|
}
|
||||||
TIME_MSG("done waiting for UI");
|
TIME_MSG("done waiting for UI");
|
||||||
|
firstwin->w_prev_height = firstwin->w_height; // may have changed
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare screen now
|
// prepare screen now
|
||||||
|
@@ -140,6 +140,11 @@ void update_topline(win_T *wp)
|
|||||||
long *so_ptr = wp->w_p_so >= 0 ? &wp->w_p_so : &p_so;
|
long *so_ptr = wp->w_p_so >= 0 ? &wp->w_p_so : &p_so;
|
||||||
long save_so = *so_ptr;
|
long save_so = *so_ptr;
|
||||||
|
|
||||||
|
// Cursor is updated instead when this is true for 'splitkeep'.
|
||||||
|
if (skip_update_topline) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If there is no valid screen and when the window height is zero just use
|
// If there is no valid screen and when the window height is zero just use
|
||||||
// the cursor line.
|
// the cursor line.
|
||||||
if (!default_grid.chars || wp->w_height_inner == 0) {
|
if (!default_grid.chars || wp->w_height_inner == 0) {
|
||||||
|
@@ -729,6 +729,7 @@ EXTERN unsigned int tpf_flags; ///< flags from 'termpastefilter'
|
|||||||
EXTERN char *p_tfu; ///< 'tagfunc'
|
EXTERN char *p_tfu; ///< 'tagfunc'
|
||||||
EXTERN char *p_spc; ///< 'spellcapcheck'
|
EXTERN char *p_spc; ///< 'spellcapcheck'
|
||||||
EXTERN char *p_spf; ///< 'spellfile'
|
EXTERN char *p_spf; ///< 'spellfile'
|
||||||
|
EXTERN char *p_spk; ///< 'splitkeep'
|
||||||
EXTERN char *p_spl; ///< 'spelllang'
|
EXTERN char *p_spl; ///< 'spelllang'
|
||||||
EXTERN char *p_spo; // 'spelloptions'
|
EXTERN char *p_spo; // 'spelloptions'
|
||||||
EXTERN unsigned int spo_flags;
|
EXTERN unsigned int spo_flags;
|
||||||
|
@@ -2356,6 +2356,13 @@ return {
|
|||||||
varname='p_sb',
|
varname='p_sb',
|
||||||
defaults={if_true=false}
|
defaults={if_true=false}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
full_name='splitkeep', abbreviation='spk',
|
||||||
|
short_desc=N_("determines scroll behavior for split windows"),
|
||||||
|
type='string', scope={'global'},
|
||||||
|
varname='p_spk',
|
||||||
|
defaults={if_true='cursor'}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
full_name='splitright', abbreviation='spr',
|
full_name='splitright', abbreviation='spr',
|
||||||
short_desc=N_("new window is put right of the current one"),
|
short_desc=N_("new window is put right of the current one"),
|
||||||
|
@@ -75,6 +75,7 @@ static char *(p_ssop_values[]) = { "buffers", "winpos", "resize", "winsize", "lo
|
|||||||
// Keep in sync with SWB_ flags in option_defs.h
|
// Keep in sync with SWB_ flags in option_defs.h
|
||||||
static char *(p_swb_values[]) = { "useopen", "usetab", "split", "newtab", "vsplit", "uselast",
|
static char *(p_swb_values[]) = { "useopen", "usetab", "split", "newtab", "vsplit", "uselast",
|
||||||
NULL };
|
NULL };
|
||||||
|
static char *(p_spk_values[]) = { "cursor", "screen", "topline", NULL };
|
||||||
static char *(p_tc_values[]) = { "followic", "ignore", "match", "followscs", "smart", NULL };
|
static char *(p_tc_values[]) = { "followic", "ignore", "match", "followscs", "smart", NULL };
|
||||||
static char *(p_ve_values[]) = { "block", "insert", "all", "onemore", "none", "NONE", NULL };
|
static char *(p_ve_values[]) = { "block", "insert", "all", "onemore", "none", "NONE", NULL };
|
||||||
static char *(p_wop_values[]) = { "tagfile", "pum", NULL };
|
static char *(p_wop_values[]) = { "tagfile", "pum", NULL };
|
||||||
@@ -1095,6 +1096,10 @@ char *did_set_string_option(int opt_idx, char **varp, char *oldval, char *errbuf
|
|||||||
if (opt_strings_flags(p_swb, p_swb_values, &swb_flags, true) != OK) {
|
if (opt_strings_flags(p_swb, p_swb_values, &swb_flags, true) != OK) {
|
||||||
errmsg = e_invarg;
|
errmsg = e_invarg;
|
||||||
}
|
}
|
||||||
|
} else if (varp == &p_spk) { // 'splitkeep'
|
||||||
|
if (check_opt_strings(p_spk, p_spk_values, false) != OK) {
|
||||||
|
errmsg = e_invarg;
|
||||||
|
}
|
||||||
} else if (varp == &p_debug) { // 'debug'
|
} else if (varp == &p_debug) { // 'debug'
|
||||||
if (check_opt_strings(p_debug, p_debug_values, true) != OK) {
|
if (check_opt_strings(p_debug, p_debug_values, true) != OK) {
|
||||||
errmsg = e_invarg;
|
errmsg = e_invarg;
|
||||||
|
@@ -1,5 +1,8 @@
|
|||||||
" Tests for window cmd (:wincmd, :split, :vsplit, :resize and etc...)
|
" Tests for window cmd (:wincmd, :split, :vsplit, :resize and etc...)
|
||||||
|
|
||||||
|
source check.vim
|
||||||
|
source screendump.vim
|
||||||
|
|
||||||
func Test_window_cmd_ls0_with_split()
|
func Test_window_cmd_ls0_with_split()
|
||||||
set ls=0
|
set ls=0
|
||||||
set splitbelow
|
set splitbelow
|
||||||
@@ -1486,5 +1489,258 @@ func Test_win_equal_last_status()
|
|||||||
set laststatus&
|
set laststatus&
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" Test "screen" and "cursor" values for 'splitkeep' with a sequence of
|
||||||
|
" split operations for various options: with and without a winbar,
|
||||||
|
" tabline, for each possible value of 'laststatus', 'scrolloff',
|
||||||
|
" 'equalalways', and with the cursor at the top, middle and bottom.
|
||||||
|
func Test_splitkeep_options()
|
||||||
|
" disallow window resizing
|
||||||
|
" let save_WS = &t_WS
|
||||||
|
" set t_WS=
|
||||||
|
|
||||||
|
let gui = has("gui_running")
|
||||||
|
inoremap <expr> c "<cmd>copen<bar>wincmd k<CR>"
|
||||||
|
for run in range(0, 20)
|
||||||
|
let &splitkeep = run > 10 ? 'topline' : 'screen'
|
||||||
|
let &scrolloff = (!(run % 4) ? 0 : run)
|
||||||
|
let &laststatus = (run % 3)
|
||||||
|
let &splitbelow = (run % 3)
|
||||||
|
let &equalalways = (run % 2)
|
||||||
|
" Nvim: both windows have a winbar after splitting
|
||||||
|
" let wsb = (run % 2) && &splitbelow
|
||||||
|
let wsb = 0
|
||||||
|
let tl = (gui ? 0 : ((run % 5) ? 1 : 0))
|
||||||
|
let pos = !(run % 3) ? 'H' : ((run % 2) ? 'M' : 'L')
|
||||||
|
tabnew | tabonly! | redraw
|
||||||
|
execute (run % 5) ? 'tabnew' : ''
|
||||||
|
" execute (run % 2) ? 'nnoremenu 1.10 WinBar.Test :echo' : ''
|
||||||
|
let &winbar = (run % 2) ? '%f' : ''
|
||||||
|
call setline(1, range(1, 256))
|
||||||
|
" No scroll for restore_snapshot
|
||||||
|
norm G
|
||||||
|
try
|
||||||
|
copen | close | colder
|
||||||
|
catch /E380/
|
||||||
|
endtry
|
||||||
|
call assert_equal(257 - winheight(0), line("w0"))
|
||||||
|
|
||||||
|
" No scroll for firstwin horizontal split
|
||||||
|
execute 'norm gg' . pos
|
||||||
|
split | redraw | wincmd k
|
||||||
|
call assert_equal(1, line("w0"))
|
||||||
|
call assert_equal(&scroll, winheight(0) / 2)
|
||||||
|
wincmd j
|
||||||
|
call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
|
||||||
|
|
||||||
|
" No scroll when resizing windows
|
||||||
|
wincmd k | resize +2 | redraw
|
||||||
|
call assert_equal(1, line("w0"))
|
||||||
|
wincmd j
|
||||||
|
call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
|
||||||
|
|
||||||
|
" No scroll when dragging statusline
|
||||||
|
call win_move_statusline(1, -3)
|
||||||
|
call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
|
||||||
|
wincmd k
|
||||||
|
call assert_equal(1, line("w0"))
|
||||||
|
|
||||||
|
" No scroll when changing shellsize
|
||||||
|
set lines+=2
|
||||||
|
call assert_equal(1, line("w0"))
|
||||||
|
wincmd j
|
||||||
|
call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
|
||||||
|
set lines-=2
|
||||||
|
call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
|
||||||
|
wincmd k
|
||||||
|
call assert_equal(1, line("w0"))
|
||||||
|
|
||||||
|
" No scroll when equalizing windows
|
||||||
|
wincmd =
|
||||||
|
call assert_equal(1, line("w0"))
|
||||||
|
wincmd j
|
||||||
|
call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
|
||||||
|
wincmd k
|
||||||
|
call assert_equal(1, line("w0"))
|
||||||
|
|
||||||
|
" No scroll in windows split multiple times
|
||||||
|
vsplit | split | 4wincmd w
|
||||||
|
call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
|
||||||
|
1wincmd w | quit | wincmd l | split
|
||||||
|
call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
|
||||||
|
wincmd j
|
||||||
|
call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
|
||||||
|
|
||||||
|
" No scroll in small window
|
||||||
|
2wincmd w | only | 5split | wincmd k
|
||||||
|
call assert_equal(1, line("w0"))
|
||||||
|
wincmd j
|
||||||
|
call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
|
||||||
|
|
||||||
|
" No scroll for vertical split
|
||||||
|
quit | vsplit | wincmd l
|
||||||
|
call assert_equal(1, line("w0"))
|
||||||
|
wincmd h
|
||||||
|
call assert_equal(1, line("w0"))
|
||||||
|
|
||||||
|
" No scroll in windows split and quit multiple times
|
||||||
|
quit | redraw | split | split | quit | redraw
|
||||||
|
call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl - wsb, line("w0"))
|
||||||
|
|
||||||
|
" No scroll for new buffer
|
||||||
|
1wincmd w | only | copen | wincmd k
|
||||||
|
call assert_equal(1, line("w0"))
|
||||||
|
only
|
||||||
|
call assert_equal(1, line("w0"))
|
||||||
|
above copen | wincmd j
|
||||||
|
call assert_equal(&spk == 'topline' ? 1 : win_screenpos(0)[0] - tl, line("w0"))
|
||||||
|
|
||||||
|
" No scroll when opening cmdwin, and no cursor move when closing cmdwin.
|
||||||
|
only | norm ggL
|
||||||
|
let curpos = getcurpos()
|
||||||
|
norm q:
|
||||||
|
call assert_equal(1, line("w0"))
|
||||||
|
call assert_equal(curpos, getcurpos())
|
||||||
|
|
||||||
|
" Scroll when cursor becomes invalid in insert mode
|
||||||
|
norm Lic
|
||||||
|
call assert_equal(curpos, getcurpos())
|
||||||
|
|
||||||
|
" No scroll when topline not equal to 1
|
||||||
|
only | execute "norm gg5\<C-e>" | split | wincmd k
|
||||||
|
call assert_equal(6, line("w0"))
|
||||||
|
wincmd j
|
||||||
|
call assert_equal(&spk == 'topline' ? 6 : 5 + win_screenpos(0)[0] - tl - wsb, line("w0"))
|
||||||
|
endfor
|
||||||
|
|
||||||
|
tabnew | tabonly! | %bwipeout!
|
||||||
|
iunmap c
|
||||||
|
set scrolloff&
|
||||||
|
set splitbelow&
|
||||||
|
set laststatus&
|
||||||
|
set equalalways&
|
||||||
|
set splitkeep&
|
||||||
|
" let &t_WS = save_WS
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
function Test_splitkeep_cmdwin_cursor_position()
|
||||||
|
set splitkeep=screen
|
||||||
|
call setline(1, range(&lines))
|
||||||
|
|
||||||
|
" No scroll when cursor is at near bottom of window and cusor position
|
||||||
|
" recompution (done by line('w0') in this test) happens while in cmdwin.
|
||||||
|
normal! G
|
||||||
|
let firstline = line('w0')
|
||||||
|
autocmd CmdwinEnter * ++once autocmd WinEnter * ++once call line('w0')
|
||||||
|
execute "normal! q:\<C-w>q"
|
||||||
|
redraw!
|
||||||
|
call assert_equal(firstline, line('w0'))
|
||||||
|
|
||||||
|
" User script can change cursor position successfully while in cmdwin and it
|
||||||
|
" shouldn't be changed when closing cmdwin.
|
||||||
|
execute "normal! Gq:\<Cmd>call win_execute(winnr('#')->win_getid(), 'call cursor(1, 1)')\<CR>\<C-w>q"
|
||||||
|
call assert_equal(1, line('.'))
|
||||||
|
call assert_equal(1, col('.'))
|
||||||
|
|
||||||
|
execute "normal! Gq:\<Cmd>autocmd WinEnter * ++once call cursor(1, 1)\<CR>\<C-w>q"
|
||||||
|
call assert_equal(1, line('.'))
|
||||||
|
call assert_equal(1, col('.'))
|
||||||
|
|
||||||
|
%bwipeout!
|
||||||
|
set splitkeep&
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function Test_splitkeep_misc()
|
||||||
|
set splitkeep=screen
|
||||||
|
set splitbelow
|
||||||
|
|
||||||
|
call setline(1, range(1, &lines))
|
||||||
|
norm Gzz
|
||||||
|
let top = line('w0')
|
||||||
|
" No scroll when aucmd_win is opened
|
||||||
|
call setbufvar(bufnr("test", 1) , '&buftype', 'nofile')
|
||||||
|
call assert_equal(top, line('w0'))
|
||||||
|
" No scroll when tab is changed/closed
|
||||||
|
tab help | close
|
||||||
|
call assert_equal(top, line('w0'))
|
||||||
|
" No scroll when help is closed and buffer line count < window height
|
||||||
|
norm ggdG
|
||||||
|
call setline(1, range(1, &lines - 10))
|
||||||
|
norm G
|
||||||
|
let top = line('w0')
|
||||||
|
help | quit
|
||||||
|
call assert_equal(top, line('w0'))
|
||||||
|
" No error when resizing window in autocmd and buffer length changed
|
||||||
|
autocmd FileType qf exe "resize" line('$')
|
||||||
|
cexpr getline(1, '$')
|
||||||
|
copen
|
||||||
|
wincmd p
|
||||||
|
norm dd
|
||||||
|
cexpr getline(1, '$')
|
||||||
|
|
||||||
|
%bwipeout!
|
||||||
|
set splitbelow&
|
||||||
|
set splitkeep&
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
function Test_splitkeep_callback()
|
||||||
|
CheckScreendump
|
||||||
|
let lines =<< trim END
|
||||||
|
set splitkeep=screen
|
||||||
|
call setline(1, range(&lines))
|
||||||
|
function C1(a, b)
|
||||||
|
split | wincmd p
|
||||||
|
endfunction
|
||||||
|
function C2(a, b)
|
||||||
|
close | split
|
||||||
|
endfunction
|
||||||
|
nn j <cmd>call job_start([&sh, &shcf, "true"], { 'exit_cb': 'C1' })<CR>
|
||||||
|
nn t <cmd>call popup_create(term_start([&sh, &shcf, "true"],
|
||||||
|
\ { 'hidden': 1, 'exit_cb': 'C2' }), {})<CR>
|
||||||
|
END
|
||||||
|
call writefile(lines, 'XTestSplitkeepCallback', 'D')
|
||||||
|
let buf = RunVimInTerminal('-S XTestSplitkeepCallback', #{rows: 8})
|
||||||
|
|
||||||
|
call term_sendkeys(buf, "j")
|
||||||
|
call VerifyScreenDump(buf, 'Test_splitkeep_callback_1', {})
|
||||||
|
|
||||||
|
call term_sendkeys(buf, ":quit\<CR>Ht")
|
||||||
|
call VerifyScreenDump(buf, 'Test_splitkeep_callback_2', {})
|
||||||
|
|
||||||
|
call term_sendkeys(buf, ":set sb\<CR>:quit\<CR>Gj")
|
||||||
|
call VerifyScreenDump(buf, 'Test_splitkeep_callback_3', {})
|
||||||
|
|
||||||
|
call term_sendkeys(buf, ":quit\<CR>Gt")
|
||||||
|
call VerifyScreenDump(buf, 'Test_splitkeep_callback_4', {})
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
function Test_splitkeep_fold()
|
||||||
|
CheckScreendump
|
||||||
|
|
||||||
|
let lines =<< trim END
|
||||||
|
set splitkeep=screen
|
||||||
|
set foldmethod=marker
|
||||||
|
set number
|
||||||
|
let line = 1
|
||||||
|
for n in range(1, &lines)
|
||||||
|
call setline(line, ['int FuncName() {/*{{{*/', 1, 2, 3, 4, 5, '}/*}}}*/',
|
||||||
|
\ 'after fold'])
|
||||||
|
let line += 8
|
||||||
|
endfor
|
||||||
|
END
|
||||||
|
call writefile(lines, 'XTestSplitkeepFold', 'D')
|
||||||
|
let buf = RunVimInTerminal('-S XTestSplitkeepFold', #{rows: 10})
|
||||||
|
|
||||||
|
call term_sendkeys(buf, "L:wincmd s\<CR>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_splitkeep_fold_1', {})
|
||||||
|
|
||||||
|
call term_sendkeys(buf, ":quit\<CR>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_splitkeep_fold_2', {})
|
||||||
|
|
||||||
|
call term_sendkeys(buf, "H:below split\<CR>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_splitkeep_fold_3', {})
|
||||||
|
|
||||||
|
call term_sendkeys(buf, ":wincmd k\<CR>:quit\<CR>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_splitkeep_fold_4', {})
|
||||||
|
endfunction
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@@ -1487,6 +1487,8 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
|
|||||||
// equalize the window sizes.
|
// equalize the window sizes.
|
||||||
if (do_equal || dir != 0) {
|
if (do_equal || dir != 0) {
|
||||||
win_equal(wp, true, (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h') : (dir == 'h' ? 'b' : 'v'));
|
win_equal(wp, true, (flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h') : (dir == 'h' ? 'b' : 'v'));
|
||||||
|
} else if (*p_spk != 'c' && wp != aucmd_win) {
|
||||||
|
win_fix_scroll(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't change the window height/width to 'winheight' / 'winwidth' if a
|
// Don't change the window height/width to 'winheight' / 'winwidth' if a
|
||||||
@@ -1558,6 +1560,12 @@ static void win_init(win_T *newp, win_T *oldp, int flags)
|
|||||||
newp->w_prevdir = (oldp->w_prevdir == NULL)
|
newp->w_prevdir = (oldp->w_prevdir == NULL)
|
||||||
? NULL : xstrdup(oldp->w_prevdir);
|
? NULL : xstrdup(oldp->w_prevdir);
|
||||||
|
|
||||||
|
if (*p_spk != 'c') {
|
||||||
|
newp->w_botline = oldp->w_botline;
|
||||||
|
newp->w_prev_height = oldp->w_height;
|
||||||
|
newp->w_prev_winrow = oldp->w_winrow;
|
||||||
|
}
|
||||||
|
|
||||||
// copy tagstack and folds
|
// copy tagstack and folds
|
||||||
for (i = 0; i < oldp->w_tagstacklen; i++) {
|
for (i = 0; i < oldp->w_tagstacklen; i++) {
|
||||||
taggy_T *tag = &newp->w_tagstack[i];
|
taggy_T *tag = &newp->w_tagstack[i];
|
||||||
@@ -2066,6 +2074,9 @@ void win_equal(win_T *next_curwin, bool current, int dir)
|
|||||||
win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current,
|
win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current,
|
||||||
topframe, dir, 0, tabline_height(),
|
topframe, dir, 0, tabline_height(),
|
||||||
Columns, topframe->fr_height);
|
Columns, topframe->fr_height);
|
||||||
|
if (*p_spk != 'c' && next_curwin != aucmd_win) {
|
||||||
|
win_fix_scroll(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a frame to a new position and height, spreading the available room
|
/// Set a frame to a new position and height, spreading the available room
|
||||||
@@ -2858,6 +2869,9 @@ int win_close(win_T *win, bool free_buf, bool force)
|
|||||||
win_equal(curwin, curwin->w_frame->fr_parent == win_frame, dir);
|
win_equal(curwin, curwin->w_frame->fr_parent == win_frame, dir);
|
||||||
} else {
|
} else {
|
||||||
(void)win_comp_pos();
|
(void)win_comp_pos();
|
||||||
|
if (*p_spk != 'c') {
|
||||||
|
win_fix_scroll(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3944,6 +3958,7 @@ static void new_frame(win_T *wp)
|
|||||||
void win_init_size(void)
|
void win_init_size(void)
|
||||||
{
|
{
|
||||||
firstwin->w_height = (int)ROWS_AVAIL;
|
firstwin->w_height = (int)ROWS_AVAIL;
|
||||||
|
firstwin->w_prev_height = (int)ROWS_AVAIL;
|
||||||
firstwin->w_height_inner = firstwin->w_height - firstwin->w_winbar_height;
|
firstwin->w_height_inner = firstwin->w_height - firstwin->w_winbar_height;
|
||||||
firstwin->w_height_outer = firstwin->w_height;
|
firstwin->w_height_outer = firstwin->w_height;
|
||||||
firstwin->w_winrow_off = firstwin->w_winbar_height;
|
firstwin->w_winrow_off = firstwin->w_winbar_height;
|
||||||
@@ -4050,6 +4065,7 @@ int win_new_tabpage(int after, char_u *filename)
|
|||||||
|
|
||||||
win_init_size();
|
win_init_size();
|
||||||
firstwin->w_winrow = tabline_height();
|
firstwin->w_winrow = tabline_height();
|
||||||
|
firstwin->w_prev_winrow = firstwin->w_winrow;
|
||||||
win_comp_scroll(curwin);
|
win_comp_scroll(curwin);
|
||||||
|
|
||||||
newtp->tp_topframe = topframe;
|
newtp->tp_topframe = topframe;
|
||||||
@@ -4407,6 +4423,7 @@ void goto_tabpage_tp(tabpage_T *tp, bool trigger_enter_autocmds, bool trigger_le
|
|||||||
// Don't repeat a message in another tab page.
|
// Don't repeat a message in another tab page.
|
||||||
set_keep_msg(NULL, 0);
|
set_keep_msg(NULL, 0);
|
||||||
|
|
||||||
|
skip_win_fix_scroll = true;
|
||||||
if (tp != curtab && leave_tabpage(tp->tp_curwin->w_buffer,
|
if (tp != curtab && leave_tabpage(tp->tp_curwin->w_buffer,
|
||||||
trigger_leave_autocmds) == OK) {
|
trigger_leave_autocmds) == OK) {
|
||||||
if (valid_tabpage(tp)) {
|
if (valid_tabpage(tp)) {
|
||||||
@@ -4417,6 +4434,7 @@ void goto_tabpage_tp(tabpage_T *tp, bool trigger_enter_autocmds, bool trigger_le
|
|||||||
trigger_leave_autocmds);
|
trigger_leave_autocmds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
skip_win_fix_scroll = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Go to the last accessed tab page, if there is one.
|
/// Go to the last accessed tab page, if there is one.
|
||||||
@@ -4747,7 +4765,9 @@ static void win_enter_ext(win_T *const wp, const int flags)
|
|||||||
|
|
||||||
// Might need to scroll the old window before switching, e.g., when the
|
// Might need to scroll the old window before switching, e.g., when the
|
||||||
// cursor was moved.
|
// cursor was moved.
|
||||||
|
if (*p_spk == 'c') {
|
||||||
update_topline(curwin);
|
update_topline(curwin);
|
||||||
|
}
|
||||||
|
|
||||||
// may have to copy the buffer options when 'cpo' contains 'S'
|
// may have to copy the buffer options when 'cpo' contains 'S'
|
||||||
if (wp->w_buffer != curbuf) {
|
if (wp->w_buffer != curbuf) {
|
||||||
@@ -4764,7 +4784,11 @@ static void win_enter_ext(win_T *const wp, const int flags)
|
|||||||
if (!virtual_active()) {
|
if (!virtual_active()) {
|
||||||
curwin->w_cursor.coladd = 0;
|
curwin->w_cursor.coladd = 0;
|
||||||
}
|
}
|
||||||
|
if (*p_spk == 'c') {
|
||||||
changed_line_abv_curs(); // assume cursor position needs updating
|
changed_line_abv_curs(); // assume cursor position needs updating
|
||||||
|
} else {
|
||||||
|
win_fix_cursor(true);
|
||||||
|
}
|
||||||
|
|
||||||
fix_current_dir();
|
fix_current_dir();
|
||||||
|
|
||||||
@@ -5238,6 +5262,10 @@ void win_new_screen_rows(void)
|
|||||||
win_reconfig_floats(); // The size of floats might change
|
win_reconfig_floats(); // The size of floats might change
|
||||||
compute_cmdrow();
|
compute_cmdrow();
|
||||||
curtab->tp_ch_used = p_ch;
|
curtab->tp_ch_used = p_ch;
|
||||||
|
|
||||||
|
if (*p_spk != 'c' && !skip_win_fix_scroll) {
|
||||||
|
win_fix_scroll(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called from win_new_screensize() after Columns changed.
|
/// Called from win_new_screensize() after Columns changed.
|
||||||
@@ -5435,6 +5463,11 @@ void win_setheight_win(int height, win_T *win)
|
|||||||
curtab->tp_ch_used = p_ch;
|
curtab->tp_ch_used = p_ch;
|
||||||
msg_row = row;
|
msg_row = row;
|
||||||
msg_col = 0;
|
msg_col = 0;
|
||||||
|
|
||||||
|
if (*p_spk != 'c') {
|
||||||
|
win_fix_scroll(true);
|
||||||
|
}
|
||||||
|
|
||||||
redraw_all_later(UPD_NOT_VALID);
|
redraw_all_later(UPD_NOT_VALID);
|
||||||
redraw_cmdline = true;
|
redraw_cmdline = true;
|
||||||
}
|
}
|
||||||
@@ -5921,6 +5954,11 @@ void win_drag_status_line(win_T *dragwin, int offset)
|
|||||||
cmdline_row = row;
|
cmdline_row = row;
|
||||||
p_ch = MAX(Rows - cmdline_row, p_ch_was_zero ? 0 : 1);
|
p_ch = MAX(Rows - cmdline_row, p_ch_was_zero ? 0 : 1);
|
||||||
curtab->tp_ch_used = p_ch;
|
curtab->tp_ch_used = p_ch;
|
||||||
|
|
||||||
|
if (*p_spk != 'c') {
|
||||||
|
win_fix_scroll(true);
|
||||||
|
}
|
||||||
|
|
||||||
redraw_all_later(UPD_SOME_VALID);
|
redraw_all_later(UPD_SOME_VALID);
|
||||||
showmode();
|
showmode();
|
||||||
}
|
}
|
||||||
@@ -6043,6 +6081,99 @@ 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).
|
||||||
|
void win_fix_scroll(int resize)
|
||||||
|
{
|
||||||
|
linenr_T lnum;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
// 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);
|
||||||
|
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.
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
win_comp_scroll(wp);
|
||||||
|
wp->w_prev_height = wp->w_height;
|
||||||
|
wp->w_prev_winrow = wp->w_winrow;
|
||||||
|
}
|
||||||
|
skip_update_topline = false;
|
||||||
|
// Ensure cursor is valid when not in normal mode or when resized.
|
||||||
|
if (!(get_real_state() & (MODE_NORMAL|MODE_CMDLINE|MODE_TERMINAL))) {
|
||||||
|
win_fix_cursor(false);
|
||||||
|
} else if (resize) {
|
||||||
|
win_fix_cursor(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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, scroll to make valid instead.
|
||||||
|
static void win_fix_cursor(int 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) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine valid cursor range.
|
||||||
|
so = MIN(wp->w_height_inner / 2, so);
|
||||||
|
wp->w_cursor.lnum = wp->w_topline;
|
||||||
|
linenr_T top = cursor_down_inner(wp, so);
|
||||||
|
wp->w_cursor.lnum = wp->w_botline - 1;
|
||||||
|
linenr_T bot = cursor_up_inner(wp, so);
|
||||||
|
wp->w_cursor.lnum = lnum;
|
||||||
|
// Check if cursor position is above or below valid cursor range.
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nlnum) { // 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.
|
||||||
|
wp->w_fraction = (nlnum == bot) ? FRACTION_MULT : 0;
|
||||||
|
scroll_to_fraction(wp, wp->w_prev_height);
|
||||||
|
validate_botline(curwin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Set the height of a window.
|
// Set the height of a window.
|
||||||
// "height" excludes any window toolbar.
|
// "height" excludes any window toolbar.
|
||||||
// This takes care of the things inside the window, not what happens to the
|
// This takes care of the things inside the window, not what happens to the
|
||||||
@@ -6181,7 +6312,7 @@ void win_set_inner_size(win_T *wp, bool valid_cursor)
|
|||||||
|
|
||||||
if (height != prev_height) {
|
if (height != prev_height) {
|
||||||
if (height > 0 && valid_cursor) {
|
if (height > 0 && valid_cursor) {
|
||||||
if (wp == curwin) {
|
if (wp == curwin && *p_spk == 'c') {
|
||||||
// w_wrow needs to be valid. When setting 'laststatus' this may
|
// w_wrow needs to be valid. When setting 'laststatus' this may
|
||||||
// call win_new_height() recursively.
|
// call win_new_height() recursively.
|
||||||
validate_cursor();
|
validate_cursor();
|
||||||
@@ -6198,7 +6329,7 @@ void win_set_inner_size(win_T *wp, bool valid_cursor)
|
|||||||
|
|
||||||
// There is no point in adjusting the scroll position when exiting. Some
|
// There is no point in adjusting the scroll position when exiting. Some
|
||||||
// values might be invalid.
|
// values might be invalid.
|
||||||
if (!exiting && valid_cursor) {
|
if (valid_cursor && !exiting && *p_spk == 'c') {
|
||||||
scroll_to_fraction(wp, prev_height);
|
scroll_to_fraction(wp, prev_height);
|
||||||
}
|
}
|
||||||
redraw_later(wp, UPD_SOME_VALID);
|
redraw_later(wp, UPD_SOME_VALID);
|
||||||
@@ -6211,8 +6342,10 @@ void win_set_inner_size(win_T *wp, bool valid_cursor)
|
|||||||
changed_line_abv_curs_win(wp);
|
changed_line_abv_curs_win(wp);
|
||||||
invalidate_botline_win(wp);
|
invalidate_botline_win(wp);
|
||||||
if (wp == curwin) {
|
if (wp == curwin) {
|
||||||
|
skip_update_topline = (*p_spk != 'c');
|
||||||
update_topline(wp);
|
update_topline(wp);
|
||||||
curs_columns(wp, true); // validate w_wrow
|
curs_columns(wp, true); // validate w_wrow
|
||||||
|
skip_update_topline = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
redraw_later(wp, UPD_NOT_VALID);
|
redraw_later(wp, UPD_NOT_VALID);
|
||||||
@@ -6252,7 +6385,7 @@ void win_comp_scroll(win_T *wp)
|
|||||||
{
|
{
|
||||||
const long old_w_p_scr = wp->w_p_scr;
|
const long old_w_p_scr = wp->w_p_scr;
|
||||||
|
|
||||||
wp->w_p_scr = wp->w_height / 2;
|
wp->w_p_scr = wp->w_height_inner / 2;
|
||||||
if (wp->w_p_scr == 0) {
|
if (wp->w_p_scr == 0) {
|
||||||
wp->w_p_scr = 1;
|
wp->w_p_scr = 1;
|
||||||
}
|
}
|
||||||
@@ -6606,6 +6739,10 @@ static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global)
|
|||||||
}
|
}
|
||||||
comp_col();
|
comp_col();
|
||||||
}
|
}
|
||||||
|
// Set prev_height when difference is due to 'laststatus'.
|
||||||
|
if (abs(wp->w_height - wp->w_prev_height) == 1) {
|
||||||
|
wp->w_prev_height = wp->w_height;
|
||||||
|
}
|
||||||
} else if (wp->w_status_height != 0 && is_stl_global) {
|
} else if (wp->w_status_height != 0 && is_stl_global) {
|
||||||
// If statusline is global and the window has a statusline, replace it with a horizontal
|
// If statusline is global and the window has a statusline, replace it with a horizontal
|
||||||
// separator
|
// separator
|
||||||
|
196
test/functional/legacy/window_cmd_spec.lua
Normal file
196
test/functional/legacy/window_cmd_spec.lua
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
local helpers = require('test.functional.helpers')(after_each)
|
||||||
|
local Screen = require('test.functional.ui.screen')
|
||||||
|
local clear = helpers.clear
|
||||||
|
local exec = helpers.exec
|
||||||
|
local exec_lua = helpers.exec_lua
|
||||||
|
local feed = helpers.feed
|
||||||
|
|
||||||
|
describe('splitkeep', function()
|
||||||
|
local screen = Screen.new()
|
||||||
|
before_each(function()
|
||||||
|
clear('--cmd', 'set splitkeep=screen')
|
||||||
|
screen:attach()
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- oldtest: Test_splitkeep_callback()
|
||||||
|
it('does not scroll when split in callback', function()
|
||||||
|
exec([[
|
||||||
|
call setline(1, range(&lines))
|
||||||
|
function C1(a, b, c)
|
||||||
|
split | wincmd p
|
||||||
|
endfunction
|
||||||
|
function C2(a, b, c)
|
||||||
|
close | split
|
||||||
|
endfunction
|
||||||
|
]])
|
||||||
|
exec_lua([[
|
||||||
|
vim.api.nvim_set_keymap("n", "j", "", { callback = function()
|
||||||
|
vim.cmd("call jobstart([&sh, &shcf, 'true'], { 'on_exit': 'C1' })")
|
||||||
|
end
|
||||||
|
})]])
|
||||||
|
exec_lua([[
|
||||||
|
vim.api.nvim_set_keymap("n", "t", "", { callback = function()
|
||||||
|
vim.api.nvim_set_current_win(
|
||||||
|
vim.api.nvim_open_win(vim.api.nvim_create_buf(false, {}), false, {
|
||||||
|
width = 10,
|
||||||
|
relative = "cursor",
|
||||||
|
height = 4,
|
||||||
|
row = 0,
|
||||||
|
col = 0,
|
||||||
|
}))
|
||||||
|
vim.cmd("call termopen([&sh, &shcf, 'true'], { 'on_exit': 'C2' })")
|
||||||
|
end
|
||||||
|
})]])
|
||||||
|
feed('j')
|
||||||
|
screen:expect([[
|
||||||
|
0 |
|
||||||
|
1 |
|
||||||
|
2 |
|
||||||
|
3 |
|
||||||
|
4 |
|
||||||
|
5 |
|
||||||
|
[No Name] [+] |
|
||||||
|
^7 |
|
||||||
|
8 |
|
||||||
|
9 |
|
||||||
|
10 |
|
||||||
|
11 |
|
||||||
|
[No Name] [+] |
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
feed(':quit<CR>Ht')
|
||||||
|
screen:expect([[
|
||||||
|
^0 |
|
||||||
|
1 |
|
||||||
|
2 |
|
||||||
|
3 |
|
||||||
|
4 |
|
||||||
|
5 |
|
||||||
|
[No Name] [+] |
|
||||||
|
7 |
|
||||||
|
8 |
|
||||||
|
9 |
|
||||||
|
10 |
|
||||||
|
11 |
|
||||||
|
[No Name] [+] |
|
||||||
|
:quit |
|
||||||
|
]])
|
||||||
|
feed(':set sb<CR>:quit<CR>Gj')
|
||||||
|
screen:expect([[
|
||||||
|
1 |
|
||||||
|
2 |
|
||||||
|
3 |
|
||||||
|
4 |
|
||||||
|
^5 |
|
||||||
|
[No Name] [+] |
|
||||||
|
7 |
|
||||||
|
8 |
|
||||||
|
9 |
|
||||||
|
10 |
|
||||||
|
11 |
|
||||||
|
12 |
|
||||||
|
[No Name] [+] |
|
||||||
|
:quit |
|
||||||
|
]])
|
||||||
|
feed(':quit<CR>Gt')
|
||||||
|
screen:expect([[
|
||||||
|
1 |
|
||||||
|
2 |
|
||||||
|
3 |
|
||||||
|
4 |
|
||||||
|
5 |
|
||||||
|
[No Name] [+] |
|
||||||
|
7 |
|
||||||
|
8 |
|
||||||
|
9 |
|
||||||
|
10 |
|
||||||
|
11 |
|
||||||
|
^12 |
|
||||||
|
[No Name] [+] |
|
||||||
|
:quit |
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- oldtest: Test_splitkeep_fold()
|
||||||
|
it('does not scroll when window has closed folds', function()
|
||||||
|
exec([[
|
||||||
|
set splitkeep=screen
|
||||||
|
set foldmethod=marker
|
||||||
|
set number
|
||||||
|
let line = 1
|
||||||
|
for n in range(1, &lines)
|
||||||
|
call setline(line, ['int FuncName() {/*{{{*/', 1, 2, 3, 4, 5, '}/*}}}*/',
|
||||||
|
\ 'after fold'])
|
||||||
|
let line += 8
|
||||||
|
endfor
|
||||||
|
]])
|
||||||
|
feed('L:wincmd s<CR>')
|
||||||
|
screen:expect([[
|
||||||
|
1 +-- 7 lines: int FuncName() {···················|
|
||||||
|
8 after fold |
|
||||||
|
9 +-- 7 lines: int FuncName() {···················|
|
||||||
|
16 after fold |
|
||||||
|
17 +-- 7 lines: int FuncName() {···················|
|
||||||
|
24 ^after fold |
|
||||||
|
[No Name] [+] |
|
||||||
|
32 after fold |
|
||||||
|
33 +-- 7 lines: int FuncName() {···················|
|
||||||
|
40 after fold |
|
||||||
|
41 +-- 7 lines: int FuncName() {···················|
|
||||||
|
48 after fold |
|
||||||
|
[No Name] [+] |
|
||||||
|
:wincmd s |
|
||||||
|
]])
|
||||||
|
feed(':quit<CR>')
|
||||||
|
screen:expect([[
|
||||||
|
1 +-- 7 lines: int FuncName() {···················|
|
||||||
|
8 after fold |
|
||||||
|
9 +-- 7 lines: int FuncName() {···················|
|
||||||
|
16 after fold |
|
||||||
|
17 +-- 7 lines: int FuncName() {···················|
|
||||||
|
24 after fold |
|
||||||
|
25 +-- 7 lines: int FuncName() {···················|
|
||||||
|
32 after fold |
|
||||||
|
33 +-- 7 lines: int FuncName() {···················|
|
||||||
|
40 after fold |
|
||||||
|
41 +-- 7 lines: int FuncName() {···················|
|
||||||
|
48 after fold |
|
||||||
|
49 ^+-- 7 lines: int FuncName() {···················|
|
||||||
|
:quit |
|
||||||
|
]])
|
||||||
|
feed('H:below split<CR>')
|
||||||
|
screen:expect([[
|
||||||
|
1 +-- 7 lines: int FuncName() {···················|
|
||||||
|
8 after fold |
|
||||||
|
9 +-- 7 lines: int FuncName() {···················|
|
||||||
|
16 after fold |
|
||||||
|
17 +-- 7 lines: int FuncName() {···················|
|
||||||
|
[No Name] [+] |
|
||||||
|
25 ^+-- 7 lines: int FuncName() {···················|
|
||||||
|
32 after fold |
|
||||||
|
33 +-- 7 lines: int FuncName() {···················|
|
||||||
|
40 after fold |
|
||||||
|
41 +-- 7 lines: int FuncName() {···················|
|
||||||
|
48 after fold |
|
||||||
|
[No Name] [+] |
|
||||||
|
:below split |
|
||||||
|
]])
|
||||||
|
feed(':wincmd k<CR>:quit<CR>')
|
||||||
|
screen:expect([[
|
||||||
|
1 +-- 7 lines: int FuncName() {···················|
|
||||||
|
8 after fold |
|
||||||
|
9 +-- 7 lines: int FuncName() {···················|
|
||||||
|
16 after fold |
|
||||||
|
17 +-- 7 lines: int FuncName() {···················|
|
||||||
|
24 after fold |
|
||||||
|
25 ^+-- 7 lines: int FuncName() {···················|
|
||||||
|
32 after fold |
|
||||||
|
33 +-- 7 lines: int FuncName() {···················|
|
||||||
|
40 after fold |
|
||||||
|
41 +-- 7 lines: int FuncName() {···················|
|
||||||
|
48 after fold |
|
||||||
|
49 +-- 7 lines: int FuncName() {···················|
|
||||||
|
:quit |
|
||||||
|
]])
|
||||||
|
end)
|
||||||
|
end)
|
Reference in New Issue
Block a user