# HG changeset patch # User Bram Moolenaar # Date 1668534303 -3600 # Node ID 33ca088dbd3e00d1bf2925daab27568c6890e763 # Parent 71da2abdd899dc9f1e9535a28e45d78949478396 patch 9.0.0886: horizontal mouse scroll only works in the GUI Commit: https://github.com/vim/vim/commit/44c2209352d56d70b1fc0215e81f1822d55aa563 Author: Christopher Plewright 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) diff --git a/src/edit.c b/src/edit.c --- 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; diff --git a/src/ex_getln.c b/src/ex_getln.c --- 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; diff --git a/src/gui.c b/src/gui.c --- 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 diff --git a/src/mouse.c b/src/mouse.c --- 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); } /* diff --git a/src/normal.c b/src/normal.c --- 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 diff --git a/src/proto/gui.pro b/src/proto/gui.pro --- 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); diff --git a/src/proto/mouse.pro b/src/proto/mouse.pro --- 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); diff --git a/src/proto/ui.pro b/src/proto/ui.pro --- 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 : */ diff --git a/src/ui.c b/src/ui.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). */ diff --git a/src/version.c b/src/version.c --- 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,