To: vim_dev@googlegroups.com Subject: Patch 9.0.0886 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.0886 Problem: Horizontal mouse scroll only works in the GUI. Solution: Make horizontal mouse scroll also work in a terminal. (Christopher Plewright, closes #11448) Files: src/edit.c, src/ex_getln.c, src/gui.c, src/proto/gui.pro, src/mouse.c, src/proto/mouse.pro, src/normal.c, src/ui.c, src/proto/ui.pro *** ../vim-9.0.0885/src/edit.c 2022-10-14 20:09:00.895207512 +0100 --- src/edit.c 2022-11-15 17:03:43.364670773 +0000 *************** *** 4499,4505 **** undisplay_dollar(); tpos = curwin->w_cursor; ! if (gui_do_horiz_scroll(scrollbar_value, FALSE)) { start_arrow(&tpos); can_cindent = TRUE; --- 4499,4505 ---- undisplay_dollar(); tpos = curwin->w_cursor; ! if (do_mousescroll_horiz(scrollbar_value)) { start_arrow(&tpos); can_cindent = TRUE; *** ../vim-9.0.0885/src/ex_getln.c 2022-10-04 16:23:39.014042183 +0100 --- src/ex_getln.c 2022-11-15 17:04:05.740682564 +0000 *************** *** 2221,2227 **** case K_HOR_SCROLLBAR: if (msg_scrolled == 0) { ! gui_do_horiz_scroll(scrollbar_value, FALSE); redrawcmd(); } goto cmdline_not_changed; --- 2221,2227 ---- case K_HOR_SCROLLBAR: if (msg_scrolled == 0) { ! do_mousescroll_horiz(scrollbar_value); redrawcmd(); } goto cmdline_not_changed; *** ../vim-9.0.0885/src/gui.c 2022-11-14 15:31:04.041587447 +0000 --- src/gui.c 2022-11-15 17:18:30.097158161 +0000 *************** *** 4105,4118 **** scrollbar_value = value; if (State & MODE_NORMAL) ! gui_do_horiz_scroll(scrollbar_value, FALSE); else if (State & MODE_INSERT) ins_horscroll(); else if (State & MODE_CMDLINE) { if (msg_scrolled == 0) { ! gui_do_horiz_scroll(scrollbar_value, FALSE); redrawcmdline(); } } --- 4105,4118 ---- scrollbar_value = value; if (State & MODE_NORMAL) ! do_mousescroll_horiz(scrollbar_value); else if (State & MODE_INSERT) ins_horscroll(); else if (State & MODE_CMDLINE) { if (msg_scrolled == 0) { ! do_mousescroll_horiz(scrollbar_value); redrawcmdline(); } } *************** *** 4504,4591 **** 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 if (!gui.which_scrollbars[SBAR_BOTTOM]) return; --- 4504,4516 ---- return (wp == curwin && !EQUAL_POS(curwin->w_cursor, old_cursor)); } /* * Horizontal scrollbar stuff: */ static void gui_update_horiz_scrollbar(int force) { ! long value, size, max; if (!gui.which_scrollbars[SBAR_BOTTOM]) return; *************** *** 4619,4627 **** else { value = curwin->w_leftcol; ! ! longest_lnum = gui_find_longest_lnum(); ! max = scroll_line_len(longest_lnum); if (virtual_active()) { --- 4544,4550 ---- else { value = curwin->w_leftcol; ! max = scroll_line_len(ui_find_longest_lnum()); if (virtual_active()) { *************** *** 4670,4713 **** } /* - * 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 --- 4593,4598 ---- *** ../vim-9.0.0885/src/proto/gui.pro 2022-06-29 12:54:48.064572066 +0100 --- src/proto/gui.pro 2022-11-15 17:24:06.441386208 +0000 *************** *** 45,51 **** 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); --- 45,50 ---- *** ../vim-9.0.0885/src/mouse.c 2022-11-01 18:34:02.783964409 +0000 --- src/mouse.c 2022-11-15 17:22:13.993304937 +0000 *************** *** 1101,1189 **** redraw_statuslines(); } 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; ! ! // 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; ! ! 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(); ! } ! 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); } } /* --- 1101,1139 ---- redraw_statuslines(); } + /* + * Implementation for scrolling in direction "dir", which is one of the MSCR_ + * values. + */ void ins_mousescroll(int dir) { ! cmdarg_T cap; ! CLEAR_FIELD(cap); ! oparg_T oa; ! clear_oparg(&oa); ! cap.oap = &oa; ! 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); } + do_mousescroll(MODE_INSERT, &cap); } /* *************** *** 2073,2088 **** } /* * 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) */ void ! nv_mousescroll(cmdarg_T *cap) { ! win_T *old_curwin = curwin, *wp; if (mouse_row >= 0 && mouse_col >= 0) { --- 2023,2074 ---- } /* + * 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. ! * Direction is indicated by "cap->arg": ! * K_MOUSEUP - MSCR_UP ! * K_MOUSEDOWN - MSCR_DOWN ! * K_MOUSELEFT - MSCR_LEFT ! * K_MOUSERIGHT - MSCR_RIGHT */ void ! do_mousescroll(int mode, cmdarg_T *cap) { ! 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,2162 **** curwin = wp; curbuf = curwin->w_buffer; } ! if (cap->arg == MSCR_UP || cap->arg == MSCR_DOWN) ! { # 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 # endif ! if (mouse_vert_step < 0 || mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) ! { ! (void)onepage(cap->arg ? FORWARD : BACKWARD, 1L); ! } ! 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; ! ! 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); } } ! # endif # ifdef FEAT_SYN_HL ! if (curwin != old_curwin && curwin->w_p_cul) redraw_for_cursorline(curwin); # endif may_trigger_winscrolled(); --- 2088,2167 ---- curwin = wp; curbuf = curwin->w_buffer; } ! 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 # endif ! // 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) { ! 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 { ! 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; ! did_ins_scroll = do_mousescroll_horiz((long_u)leftcol); } } ! # ifdef FEAT_SYN_HL ! if (mode == MODE_NORMAL && curwin != old_curwin && curwin->w_p_cul) redraw_for_cursorline(curwin); # endif may_trigger_winscrolled(); *************** *** 2165,2170 **** --- 2170,2198 ---- 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); } /* *** ../vim-9.0.0885/src/proto/mouse.pro 2022-11-01 18:34:02.783964409 +0000 --- src/proto/mouse.pro 2022-11-15 17:24:13.265391047 +0000 *************** *** 14,19 **** --- 14,21 ---- 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); *** ../vim-9.0.0885/src/normal.c 2022-10-14 20:09:00.895207512 +0100 --- src/normal.c 2022-11-15 17:04:41.080701273 +0000 *************** *** 3047,3053 **** clearopbeep(cap->oap); // Even if an operator was pending, we still want to scroll ! gui_do_horiz_scroll(scrollbar_value, FALSE); } #endif --- 3047,3053 ---- clearopbeep(cap->oap); // Even if an operator was pending, we still want to scroll ! do_mousescroll_horiz(scrollbar_value); } #endif *** ../vim-9.0.0885/src/ui.c 2022-10-08 13:49:41.893378443 +0100 --- src/ui.c 2022-11-15 17:18:04.629143824 +0000 *************** *** 1126,1131 **** --- 1126,1200 ---- } /* + * 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). */ *** ../vim-9.0.0885/src/proto/ui.pro 2022-06-27 23:15:27.000000000 +0100 --- src/proto/ui.pro 2022-11-15 17:24:17.917394342 +0000 *************** *** 30,35 **** --- 30,37 ---- 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 : */ *** ../vim-9.0.0885/src/version.c 2022-11-15 13:57:35.122066675 +0000 --- src/version.c 2022-11-15 15:24:41.840859316 +0000 *************** *** 697,698 **** --- 697,700 ---- { /* Add new patch number below this line */ + /**/ + 886, /**/ -- hundred-and-one symptoms of being an internet addict: 77. The phone company asks you to test drive their new PBX system /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///