changeset 31103:33ca088dbd3e v9.0.0886

patch 9.0.0886: horizontal mouse scroll only works in the GUI Commit: https://github.com/vim/vim/commit/44c2209352d56d70b1fc0215e81f1822d55aa563 Author: Christopher Plewright <chris@createng.com> Date: Tue Nov 15 17:43:36 2022 +0000 patch 9.0.0886: horizontal mouse scroll only works in the GUI Problem: Horizontal mouse scroll only works in the GUI. Solution: Make horizontal mouse scroll also work in a terminal. (Christopher Plewright, closes #11448)
author Bram Moolenaar <Bram@vim.org>
date Tue, 15 Nov 2022 18:45:03 +0100
parents 71da2abdd899
children 86edc0b8966f
files src/edit.c src/ex_getln.c src/gui.c src/mouse.c src/normal.c src/proto/gui.pro src/proto/mouse.pro src/proto/ui.pro src/ui.c src/version.c
diffstat 10 files changed, 238 insertions(+), 251 deletions(-) [+]
line wrap: on
line diff
--- a/src/edit.c
+++ b/src/edit.c
@@ -4499,7 +4499,7 @@ ins_horscroll(void)
 
     undisplay_dollar();
     tpos = curwin->w_cursor;
-    if (gui_do_horiz_scroll(scrollbar_value, FALSE))
+    if (do_mousescroll_horiz(scrollbar_value))
     {
 	start_arrow(&tpos);
 	can_cindent = TRUE;
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -2221,7 +2221,7 @@ getcmdline_int(
 	case K_HOR_SCROLLBAR:
 		if (msg_scrolled == 0)
 		{
-		    gui_do_horiz_scroll(scrollbar_value, FALSE);
+		    do_mousescroll_horiz(scrollbar_value);
 		    redrawcmd();
 		}
 		goto cmdline_not_changed;
--- a/src/gui.c
+++ b/src/gui.c
@@ -4105,14 +4105,14 @@ gui_drag_scrollbar(scrollbar_T *sb, long
 	scrollbar_value = value;
 
 	if (State & MODE_NORMAL)
-	    gui_do_horiz_scroll(scrollbar_value, FALSE);
+	    do_mousescroll_horiz(scrollbar_value);
 	else if (State & MODE_INSERT)
 	    ins_horscroll();
 	else if (State & MODE_CMDLINE)
 	{
 	    if (msg_scrolled == 0)
 	    {
-		gui_do_horiz_scroll(scrollbar_value, FALSE);
+		do_mousescroll_horiz(scrollbar_value);
 		redrawcmdline();
 	    }
 	}
@@ -4504,88 +4504,13 @@ gui_do_scroll(void)
     return (wp == curwin && !EQUAL_POS(curwin->w_cursor, old_cursor));
 }
 
-
 /*
  * Horizontal scrollbar stuff:
  */
-
-/*
- * Return length of line "lnum" for horizontal scrolling.
- */
-    static colnr_T
-scroll_line_len(linenr_T lnum)
-{
-    char_u	*p;
-    colnr_T	col;
-    int		w;
-
-    p = ml_get(lnum);
-    col = 0;
-    if (*p != NUL)
-	for (;;)
-	{
-	    w = chartabsize(p, col);
-	    MB_PTR_ADV(p);
-	    if (*p == NUL)		// don't count the last character
-		break;
-	    col += w;
-	}
-    return col;
-}
-
-// Remember which line is currently the longest, so that we don't have to
-// search for it when scrolling horizontally.
-static linenr_T longest_lnum = 0;
-
-/*
- * Find longest visible line number.  If this is not possible (or not desired,
- * by setting 'h' in "guioptions") then the current line number is returned.
- */
-    static linenr_T
-gui_find_longest_lnum(void)
-{
-    linenr_T ret = 0;
-
-    // Calculate maximum for horizontal scrollbar.  Check for reasonable
-    // line numbers, topline and botline can be invalid when displaying is
-    // postponed.
-    if (vim_strchr(p_go, GO_HORSCROLL) == NULL
-	    && curwin->w_topline <= curwin->w_cursor.lnum
-	    && curwin->w_botline > curwin->w_cursor.lnum
-	    && curwin->w_botline <= curbuf->b_ml.ml_line_count + 1)
-    {
-	linenr_T    lnum;
-	colnr_T	    n;
-	long	    max = 0;
-
-	// Use maximum of all visible lines.  Remember the lnum of the
-	// longest line, closest to the cursor line.  Used when scrolling
-	// below.
-	for (lnum = curwin->w_topline; lnum < curwin->w_botline; ++lnum)
-	{
-	    n = scroll_line_len(lnum);
-	    if (n > (colnr_T)max)
-	    {
-		max = n;
-		ret = lnum;
-	    }
-	    else if (n == (colnr_T)max
-		    && abs((int)(lnum - curwin->w_cursor.lnum))
-		       < abs((int)(ret - curwin->w_cursor.lnum)))
-		ret = lnum;
-	}
-    }
-    else
-	// Use cursor line only.
-	ret = curwin->w_cursor.lnum;
-
-    return ret;
-}
-
     static void
 gui_update_horiz_scrollbar(int force)
 {
-    long	value, size, max;	// need 32 bit ints here
+    long	value, size, max;
 
     if (!gui.which_scrollbars[SBAR_BOTTOM])
 	return;
@@ -4619,9 +4544,7 @@ gui_update_horiz_scrollbar(int force)
     else
     {
 	value = curwin->w_leftcol;
-
-	longest_lnum = gui_find_longest_lnum();
-	max = scroll_line_len(longest_lnum);
+	max = scroll_line_len(ui_find_longest_lnum());
 
 	if (virtual_active())
 	{
@@ -4670,44 +4593,6 @@ gui_update_horiz_scrollbar(int force)
 }
 
 /*
- * Do a horizontal scroll.  Return TRUE if the cursor moved, FALSE otherwise.
- */
-    int
-gui_do_horiz_scroll(long_u leftcol, int compute_longest_lnum)
-{
-    // no wrapping, no scrolling
-    if (curwin->w_p_wrap)
-	return FALSE;
-
-    if (curwin->w_leftcol == (colnr_T)leftcol)
-	return FALSE;
-
-    curwin->w_leftcol = (colnr_T)leftcol;
-
-    // When the line of the cursor is too short, move the cursor to the
-    // longest visible line.
-    if (vim_strchr(p_go, GO_HORSCROLL) == NULL
-	    && !virtual_active()
-	    && (colnr_T)leftcol > scroll_line_len(curwin->w_cursor.lnum))
-    {
-	if (compute_longest_lnum)
-	{
-	    curwin->w_cursor.lnum = gui_find_longest_lnum();
-	    curwin->w_cursor.col = 0;
-	}
-	// Do a sanity check on "longest_lnum", just in case.
-	else if (longest_lnum >= curwin->w_topline
-		&& longest_lnum < curwin->w_botline)
-	{
-	    curwin->w_cursor.lnum = longest_lnum;
-	    curwin->w_cursor.col = 0;
-	}
-    }
-
-    return leftcol_changed();
-}
-
-/*
  * Check that none of the colors are the same as the background color
  */
     void
--- a/src/mouse.c
+++ b/src/mouse.c
@@ -1101,89 +1101,39 @@ ins_mouse(int c)
     redraw_statuslines();
 }
 
+/*
+ * Implementation for scrolling in direction "dir", which is one of the MSCR_
+ * values.
+ */
     void
 ins_mousescroll(int dir)
 {
-    pos_T	tpos;
-    win_T	*old_curwin = curwin, *wp;
-    int		did_scroll = FALSE;
-
-    tpos = curwin->w_cursor;
-
-    if (mouse_row >= 0 && mouse_col >= 0)
-    {
-	int row, col;
-
-	row = mouse_row;
-	col = mouse_col;
+    cmdarg_T cap;
+    CLEAR_FIELD(cap);
 
-	// find the window at the pointer coordinates
-	wp = mouse_find_win(&row, &col, FIND_POPUP);
-	if (wp == NULL)
-	    return;
-	curwin = wp;
-	curbuf = curwin->w_buffer;
-    }
-    if (curwin == old_curwin)
-	undisplay_dollar();
-
-    // Don't scroll the window in which completion is being done.
-    if (!pum_visible() || curwin != old_curwin)
-    {
-	long step;
+    oparg_T oa;
+    clear_oparg(&oa);
+    cap.oap = &oa;
 
-	if (dir == MSCR_DOWN || dir == MSCR_UP)
-	{
-	    if (mouse_vert_step < 0
-		    || mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
-		step = (long)(curwin->w_botline - curwin->w_topline);
-	    else
-		step = mouse_vert_step;
-	    scroll_redraw(dir, step);
-# ifdef FEAT_PROP_POPUP
-	if (WIN_IS_POPUP(curwin))
-	    popup_set_firstline(curwin);
-# endif
-	}
-#ifdef FEAT_GUI
-	else
-	{
-	    int val;
-
-	    if (mouse_hor_step < 0
-		    || mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
-		step = curwin->w_width;
-	    else
-		step = mouse_hor_step;
-	    val = curwin->w_leftcol + (dir == MSCR_RIGHT ? -step : step);
-	    if (val < 0)
-		val = 0;
-	    gui_do_horiz_scroll(val, TRUE);
-	}
-#endif
-	did_scroll = TRUE;
-	may_trigger_winscrolled();
+    cap.arg = dir;
+    switch (dir)
+    {
+	case MSCR_UP:
+	    cap.cmdchar = K_MOUSEUP;
+	    break;
+	case MSCR_DOWN:
+	    cap.cmdchar = K_MOUSEDOWN;
+	    break;
+	case MSCR_LEFT:
+	    cap.cmdchar = K_MOUSELEFT;
+	    break;
+	case MSCR_RIGHT:
+	    cap.cmdchar = K_MOUSERIGHT;
+	    break;
+	default:
+	    siemsg("Invalid ins_mousescroll() argument: %d", dir);
     }
-
-    curwin->w_redr_status = TRUE;
-
-    curwin = old_curwin;
-    curbuf = curwin->w_buffer;
-
-    // The popup menu may overlay the window, need to redraw it.
-    // TODO: Would be more efficient to only redraw the windows that are
-    // overlapped by the popup menu.
-    if (pum_visible() && did_scroll)
-    {
-	redraw_all_later(UPD_NOT_VALID);
-	ins_compl_show_pum();
-    }
-
-    if (!EQUAL_POS(curwin->w_cursor, tpos))
-    {
-	start_arrow(&tpos);
-	set_can_cindent(TRUE);
-    }
+    do_mousescroll(MODE_INSERT, &cap);
 }
 
 /*
@@ -2073,16 +2023,52 @@ retnomove:
 }
 
 /*
+ * Make a horizontal scroll to "leftcol".
+ * Return TRUE if the cursor moved, FALSE otherwise.
+ */
+    int
+do_mousescroll_horiz(long_u leftcol)
+{
+    if (curwin->w_p_wrap)
+	return FALSE;  // no wrapping, no scrolling
+
+    if (curwin->w_leftcol == (colnr_T)leftcol)
+	return FALSE;  // already there
+
+    curwin->w_leftcol = (colnr_T)leftcol;
+
+    // When the line of the cursor is too short, move the cursor to the
+    // longest visible line.
+    if (
+#ifdef FEAT_GUI
+	    (!gui.in_use || vim_strchr(p_go, GO_HORSCROLL) == NULL) &&
+#endif
+		    !virtual_active()
+	    && (long)leftcol > scroll_line_len(curwin->w_cursor.lnum))
+    {
+	curwin->w_cursor.lnum = ui_find_longest_lnum();
+	curwin->w_cursor.col = 0;
+    }
+
+    return leftcol_changed();
+}
+
+/*
  * Mouse scroll wheel: Default action is to scroll mouse_vert_step lines (or
- * mouse_hor_step, depending on the scroll direction), or one page when Shift or
- * Ctrl is used.
- * K_MOUSEUP (cap->arg == 1) or K_MOUSEDOWN (cap->arg == 0) or
- * K_MOUSELEFT (cap->arg == -1) or K_MOUSERIGHT (cap->arg == -2)
+ * mouse_hor_step, depending on the scroll direction), or one page when Shift
+ * or Ctrl is used.
+ * Direction is indicated by "cap->arg":
+ *    K_MOUSEUP    - MSCR_UP
+ *    K_MOUSEDOWN  - MSCR_DOWN
+ *    K_MOUSELEFT  - MSCR_LEFT
+ *    K_MOUSERIGHT - MSCR_RIGHT
  */
     void
-nv_mousescroll(cmdarg_T *cap)
+do_mousescroll(int mode, cmdarg_T *cap)
 {
-    win_T *old_curwin = curwin, *wp;
+    win_T   *old_curwin = curwin, *wp;
+    int	    did_ins_scroll = FALSE;
+    pos_T   tpos = curwin->w_cursor;
 
     if (mouse_row >= 0 && mouse_col >= 0)
     {
@@ -2102,61 +2088,80 @@ nv_mousescroll(cmdarg_T *cap)
 	curwin = wp;
 	curbuf = curwin->w_buffer;
     }
-    if (cap->arg == MSCR_UP || cap->arg == MSCR_DOWN)
-    {
+    if (mode == MODE_INSERT && curwin == old_curwin)
+	undisplay_dollar();
+
 # ifdef FEAT_TERMINAL
-	if (term_use_loop())
-	    // This window is a terminal window, send the mouse event there.
-	    // Set "typed" to FALSE to avoid an endless loop.
-	    send_keys_to_term(curbuf->b_term, cap->cmdchar, mod_mask, FALSE);
-	else
+    if (term_use_loop())
+	// This window is a terminal window, send the mouse event there.
+	// Set "typed" to FALSE to avoid an endless loop.
+	send_keys_to_term(curbuf->b_term, cap->cmdchar, mod_mask, FALSE);
+    else
 # endif
-	if (mouse_vert_step < 0 || mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
+    // For insert mode, don't scroll the window in which completion is being
+    // done.
+    if (mode == MODE_NORMAL || !pum_visible() || curwin != old_curwin)
+    {
+	if (cap->arg == MSCR_UP || cap->arg == MSCR_DOWN)
 	{
-	    (void)onepage(cap->arg ? FORWARD : BACKWARD, 1L);
+	    if (mouse_vert_step < 0
+		    || mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
+	    {
+		if (mode == MODE_INSERT)
+		{
+		    long step = (long)(curwin->w_botline - curwin->w_topline);
+		    scroll_redraw(cap->arg, step);
+		}
+		else
+		{
+		    did_ins_scroll = onepage(cap->arg ? FORWARD : BACKWARD, 1L);
+		}
+	    }
+	    else
+	    {
+		if (mode == MODE_INSERT)
+		{
+		    scroll_redraw(cap->arg, mouse_vert_step);
+		}
+		else
+		{
+		    // Don't scroll more than half the window height.
+		    if (curwin->w_height < mouse_vert_step * 2)
+		    {
+			cap->count1 = curwin->w_height / 2;
+			if (cap->count1 == 0)
+			    cap->count1 = 1;
+		    }
+		    else
+		    {
+			cap->count1 = mouse_vert_step;
+		    }
+		    cap->count0 = cap->count1;
+		    nv_scroll_line(cap);
+		}
+	    }
+
+#ifdef FEAT_PROP_POPUP
+	    if (WIN_IS_POPUP(curwin))
+		popup_set_firstline(curwin);
+#endif
 	}
 	else
 	{
-	    // Don't scroll more than half the window height.
-	    if (curwin->w_height < mouse_vert_step * 2)
-	    {
-		cap->count1 = curwin->w_height / 2;
-		if (cap->count1 == 0)
-		    cap->count1 = 1;
-	    }
-	    else
-		cap->count1 = mouse_vert_step;
-	    cap->count0 = cap->count1;
-	    nv_scroll_line(cap);
-	}
-#ifdef FEAT_PROP_POPUP
-	if (WIN_IS_POPUP(curwin))
-	    popup_set_firstline(curwin);
-#endif
-    }
-# ifdef FEAT_GUI
-    else
-    {
-	// Horizontal scroll - only allowed when 'wrap' is disabled
-	if (!curwin->w_p_wrap)
-	{
-	    int val, step;
+	    long step = (mouse_hor_step < 0
+			      || (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)))
+		    ? curwin->w_width : mouse_hor_step;
+	    long leftcol = curwin->w_leftcol
+				     + (cap->arg == MSCR_RIGHT ? -step : step);
+	    if (leftcol < 0)
+		leftcol = 0;
 
-	    if (mouse_hor_step < 0
-		    || mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
-		step = curwin->w_width;
-	    else
-		step = mouse_hor_step;
-	    val = curwin->w_leftcol + (cap->arg == MSCR_RIGHT ? -step : +step);
-	    if (val < 0)
-		val = 0;
-
-	    gui_do_horiz_scroll(val, TRUE);
+	    did_ins_scroll = do_mousescroll_horiz((long_u)leftcol);
 	}
     }
-# endif
+
 # ifdef FEAT_SYN_HL
-    if (curwin != old_curwin && curwin->w_p_cul)
+    if (mode == MODE_NORMAL && curwin != old_curwin && curwin->w_p_cul)
 	redraw_for_cursorline(curwin);
 # endif
     may_trigger_winscrolled();
@@ -2165,6 +2170,29 @@ nv_mousescroll(cmdarg_T *cap)
 
     curwin = old_curwin;
     curbuf = curwin->w_buffer;
+
+    if (mode == MODE_INSERT)
+    {
+	// The popup menu may overlay the window, need to redraw it.
+	// TODO: Would be more efficient to only redraw the windows that are
+	// overlapped by the popup menu.
+	if (pum_visible() && did_ins_scroll)
+	{
+	    redraw_all_later(UPD_NOT_VALID);
+	    ins_compl_show_pum();
+	}
+	if (!EQUAL_POS(curwin->w_cursor, tpos))
+	{
+	    start_arrow(&tpos);
+	    set_can_cindent(TRUE);
+	}
+    }
+}
+
+    void
+nv_mousescroll(cmdarg_T *cap)
+{
+    do_mousescroll(MODE_NORMAL, cap);
 }
 
 /*
--- a/src/normal.c
+++ b/src/normal.c
@@ -3047,7 +3047,7 @@ nv_hor_scrollbar(cmdarg_T *cap)
 	clearopbeep(cap->oap);
 
     // Even if an operator was pending, we still want to scroll
-    gui_do_horiz_scroll(scrollbar_value, FALSE);
+    do_mousescroll_horiz(scrollbar_value);
 }
 #endif
 
--- a/src/proto/gui.pro
+++ b/src/proto/gui.pro
@@ -45,7 +45,6 @@ void gui_drag_scrollbar(scrollbar_T *sb,
 void gui_may_update_scrollbars(void);
 void gui_update_scrollbars(int force);
 int gui_do_scroll(void);
-int gui_do_horiz_scroll(long_u leftcol, int compute_longest_lnum);
 void gui_check_colors(void);
 guicolor_T gui_get_color(char_u *name);
 int gui_get_lightness(guicolor_T pixel);
--- a/src/proto/mouse.pro
+++ b/src/proto/mouse.pro
@@ -14,6 +14,8 @@ int mouse_has(int c);
 int mouse_model_popup(void);
 void reset_dragwin(void);
 int jump_to_mouse(int flags, int *inclusive, int which_button);
+int do_mousescroll_horiz(long_u leftcol);
+void do_mousescroll(int mode, cmdarg_T *cap);
 void nv_mousescroll(cmdarg_T *cap);
 void nv_mouse(cmdarg_T *cap);
 void reset_held_button(void);
--- a/src/proto/ui.pro
+++ b/src/proto/ui.pro
@@ -30,6 +30,8 @@ void ui_cursor_shape_forced(int forced);
 void ui_cursor_shape(void);
 int check_col(int col);
 int check_row(int row);
+long scroll_line_len(linenr_T lnum);
+linenr_T ui_find_longest_lnum(void);
 void ui_focus_change(int in_focus);
 void im_save_status(long *psave);
 /* vim: set ft=c : */
--- a/src/ui.c
+++ b/src/ui.c
@@ -1126,6 +1126,75 @@ check_row(int row)
 }
 
 /*
+ * Return length of line "lnum" in screen cells for horizontal scrolling.
+ */
+    long
+scroll_line_len(linenr_T lnum)
+{
+    char_u	*p = ml_get(lnum);
+    colnr_T	col = 0;
+
+    if (*p != NUL)
+	for (;;)
+	{
+	    int	    w = chartabsize(p, col);
+	    MB_PTR_ADV(p);
+	    if (*p == NUL)		// don't count the last character
+		break;
+	    col += w;
+	}
+    return col;
+}
+
+/*
+ * Find the longest visible line number.  This is used for horizontal
+ * scrolling.  If this is not possible (or not desired, by setting 'h' in
+ * "guioptions") then the current line number is returned.
+ */
+    linenr_T
+ui_find_longest_lnum(void)
+{
+    linenr_T ret = 0;
+
+    // Calculate maximum for horizontal scrollbar.  Check for reasonable
+    // line numbers, topline and botline can be invalid when displaying is
+    // postponed.
+    if (
+# ifdef FEAT_GUI
+	    (!gui.in_use || vim_strchr(p_go, GO_HORSCROLL) == NULL) &&
+# endif
+	    curwin->w_topline <= curwin->w_cursor.lnum
+	    && curwin->w_botline > curwin->w_cursor.lnum
+	    && curwin->w_botline <= curbuf->b_ml.ml_line_count + 1)
+    {
+	linenr_T    lnum;
+	long	    n;
+	long	    max = 0;
+
+	// Use maximum of all visible lines.  Remember the lnum of the
+	// longest line, closest to the cursor line.  Used when scrolling
+	// below.
+	for (lnum = curwin->w_topline; lnum < curwin->w_botline; ++lnum)
+	{
+	    n = scroll_line_len(lnum);
+	    if (n > max)
+	    {
+		max = n;
+		ret = lnum;
+	    }
+	    else if (n == max && abs((int)(lnum - curwin->w_cursor.lnum))
+				     < abs((int)(ret - curwin->w_cursor.lnum)))
+		ret = lnum;
+	}
+    }
+    else
+	// Use cursor line only.
+	ret = curwin->w_cursor.lnum;
+
+    return ret;
+}
+
+/*
  * Called when focus changed.  Used for the GUI or for systems where this can
  * be done in the console (Win32).
  */
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    886,
+/**/
     885,
 /**/
     884,