0
0
mirror of https://github.com/vim/vim.git synced 2025-09-29 04:34:16 -04:00

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.
This commit is contained in:
Luuk van Baal
2022-09-11 16:59:53 +01:00
committed by Bram Moolenaar
parent 9510d22463
commit 29ab524358
10 changed files with 287 additions and 10 deletions

View File

@@ -25,6 +25,8 @@ static frame_T *win_altframe(win_T *win, tabpage_T *tp);
static tabpage_T *alt_tabpage(void);
static win_T *frame2win(frame_T *frp);
static int frame_has_win(frame_T *frp, win_T *wp);
static void win_fix_scroll(int resize);
static void win_fix_cursor(int normal);
static void frame_new_height(frame_T *topfrp, int height, int topfirst, int wfh);
static int frame_fixed_height(frame_T *frp);
static int frame_fixed_width(frame_T *frp);
@@ -1323,6 +1325,8 @@ win_split_ins(
win_equal(wp, TRUE,
(flags & WSP_VERT) ? (dir == 'v' ? 'b' : 'h')
: dir == 'h' ? 'b' : 'v');
else if (!p_spsc)
win_fix_scroll(FALSE);
// Don't change the window height/width to 'winheight' / 'winwidth' if a
// size was given.
@@ -1407,6 +1411,13 @@ win_init(win_T *newp, win_T *oldp, int flags UNUSED)
newp->w_prevdir = (oldp->w_prevdir == NULL)
? NULL : vim_strsave(oldp->w_prevdir);
if (!p_spsc)
{
newp->w_botline = oldp->w_botline;
newp->w_prev_height = oldp->w_height - WINBAR_HEIGHT(oldp);
newp->w_prev_winrow = oldp->w_winrow + 2 * WINBAR_HEIGHT(oldp);
}
// copy tagstack and folds
for (i = 0; i < oldp->w_tagstacklen; i++)
{
@@ -1914,6 +1925,8 @@ win_equal(
win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current,
topframe, dir, 0, tabline_height(),
(int)Columns, topframe->fr_height);
if (!p_spsc)
win_fix_scroll(TRUE);
}
/*
@@ -2725,7 +2738,11 @@ win_close(win_T *win, int free_buf)
// only resize that frame. Otherwise resize all windows.
win_equal(curwin, curwin->w_frame->fr_parent == win_frame, dir);
else
{
win_comp_pos();
if (!p_spsc)
win_fix_scroll(FALSE);
}
if (close_curwin)
{
// Pass WEE_ALLOW_PARSE_MESSAGES to decrement dont_parse_messages
@@ -4912,7 +4929,8 @@ win_enter_ext(win_T *wp, int flags)
// Might need to scroll the old window before switching, e.g., when the
// cursor was moved.
update_topline();
if (p_spsc)
update_topline();
// may have to copy the buffer options when 'cpo' contains 'S'
if (wp->w_buffer != curbuf)
@@ -4927,7 +4945,10 @@ win_enter_ext(win_T *wp, int flags)
check_cursor();
if (!virtual_active())
curwin->w_cursor.coladd = 0;
changed_line_abv_curs(); // assume cursor position needs updating
if (p_spsc) // assume cursor position needs updating.
changed_line_abv_curs();
else
win_fix_cursor(TRUE);
// Now it is OK to parse messages again, which may be needed in
// autocommands.
@@ -5458,6 +5479,9 @@ shell_new_rows(void)
compute_cmdrow();
curtab->tp_ch_used = p_ch;
if (!p_spsc)
win_fix_scroll(TRUE);
#if 0
// Disabled: don't want making the screen smaller make a window larger.
if (p_ea)
@@ -5662,6 +5686,9 @@ win_setheight_win(int height, win_T *win)
msg_row = row;
msg_col = 0;
if (!p_spsc)
win_fix_scroll(TRUE);
redraw_all_later(UPD_NOT_VALID);
}
@@ -6190,6 +6217,9 @@ win_drag_status_line(win_T *dragwin, int offset)
p_ch = MAX(Rows - cmdline_row, 1);
curtab->tp_ch_used = p_ch;
if (!p_spsc)
win_fix_scroll(TRUE);
redraw_all_later(UPD_SOME_VALID);
showmode();
}
@@ -6316,6 +6346,97 @@ set_fraction(win_T *wp)
+ FRACTION_MULT / 2) / (long)wp->w_height;
}
/*
* Handle scroll position for 'nosplitscroll'. Replaces scroll_to_fraction()
* call from win_new_height(). Instead we iterate over all windows in a
* tabpage and calculate the new scroll/cursor position.
* TODO: 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).
*/
static void
win_fix_scroll(int resize)
{
win_T *wp;
linenr_T lnum;
FOR_ALL_WINDOWS(wp)
{
// Skip when window height has not changed or when
// buffer has less lines than the window height.
if (wp->w_height != wp->w_prev_height
&& wp->w_height < wp->w_buffer->b_ml.ml_line_count)
{
// Determine botline needed to avoid scrolling and set cursor.
if (wp->w_winrow != wp->w_prev_winrow)
{
lnum = wp->w_cursor.lnum;
wp->w_cursor.lnum = MIN(wp->w_buffer->b_ml.ml_line_count,
wp->w_botline - 1 + (wp->w_prev_height
? (wp->w_winrow - wp->w_prev_winrow)
+ (wp->w_height - wp->w_prev_height)
: -WINBAR_HEIGHT(wp)));
// 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;
}
invalidate_botline_win(wp);
validate_botline_win(wp);
}
wp->w_prev_height = wp->w_height;
wp->w_prev_winrow = wp->w_winrow;
}
// Ensure cursor is valid when not in normal mode or when resized.
if (!(get_real_state() & (MODE_NORMAL|MODE_CMDLINE)))
win_fix_cursor(FALSE);
else if (resize)
win_fix_cursor(TRUE);
}
/*
* Make sure the cursor position is valid for 'nosplitscroll'.
* 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)
{
int top = FALSE;
win_T *wp = curwin;
long so = get_scrolloff_value();
linenr_T nlnum = 0;
if (wp->w_buffer->b_ml.ml_line_count < wp->w_height)
return;
so = MIN(wp->w_height / 2, so);
// Check if cursor position is above topline or below botline.
if (wp->w_cursor.lnum < (wp->w_topline + so) && wp->w_topline != 1)
top = nlnum = MIN(wp->w_topline + so, wp->w_buffer->b_ml.ml_line_count);
else if (wp->w_cursor.lnum > (wp->w_botline - so - 1)
&& (wp->w_botline - wp->w_buffer->b_ml.ml_line_count) != 1)
nlnum = MAX(wp->w_botline - so - 1, 1);
// If cursor was invalid scroll or change cursor.
if (nlnum)
{
if (normal)
{ // Make sure cursor is closer to topline than botline.
if (so == wp->w_height / 2
&& nlnum - wp->w_topline > wp->w_botline - 1 - nlnum)
nlnum--;
setmark('\''); // save cursor position
wp->w_cursor.lnum = nlnum; // change to avoid scrolling
curs_columns(TRUE); // validate w_wrow
}
else
{ // Ensure cursor stays visible if we are not in normal mode.
wp->w_fraction = top ? 0 : FRACTION_MULT;
scroll_to_fraction(wp, wp->w_prev_height);
}
}
}
/*
* Set the height of a window.
* "height" excludes any window toolbar.
@@ -6336,7 +6457,7 @@ win_new_height(win_T *wp, int height)
if (wp->w_height > 0)
{
if (wp == curwin)
if (wp == curwin && p_spsc)
// w_wrow needs to be valid. When setting 'laststatus' this may
// call win_new_height() recursively.
validate_cursor();
@@ -6352,7 +6473,7 @@ win_new_height(win_T *wp, int height)
// There is no point in adjusting the scroll position when exiting. Some
// values might be invalid.
if (!exiting)
if (!exiting && p_spsc)
scroll_to_fraction(wp, prev_height);
}
@@ -6466,7 +6587,7 @@ scroll_to_fraction(win_T *wp, int prev_height)
if (wp == curwin)
{
if (get_scrolloff_value())
if (p_spsc && get_scrolloff_value())
update_topline();
curs_columns(FALSE); // validate w_wrow
}
@@ -6488,11 +6609,15 @@ win_new_width(win_T *wp, int width)
wp->w_width = width;
wp->w_lines_valid = 0;
changed_line_abv_curs_win(wp);
invalidate_botline_win(wp);
if (wp == curwin)
// Handled in win_fix_scroll()
if (p_spsc)
{
update_topline();
curs_columns(TRUE); // validate w_wrow
invalidate_botline_win(wp);
if (wp == curwin)
{
update_topline();
curs_columns(TRUE); // validate w_wrow
}
}
redraw_win_later(wp, UPD_NOT_VALID);
wp->w_redr_status = TRUE;