To: vim_dev@googlegroups.com Subject: Patch 9.0.0867 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.0867 Problem: Wildmenu redrawing code is spread out. Solution: Refactor to move code together. (closes #11528) Files: src/cmdexpand.c, src/proto/cmdexpand.pro, src/screen.c, src/proto/screen.pro *** ../vim-9.0.0866/src/cmdexpand.c 2022-09-18 13:06:36.461124371 +0100 --- src/cmdexpand.c 2022-11-12 17:42:15.944860523 +0000 *************** *** 19,24 **** --- 19,25 ---- char_u ***matches, int *numMatches, char_u *((*func)(expand_T *, int)), int escaped); static int ExpandFromContext(expand_T *xp, char_u *, char_u ***, int *, int); + static char_u *showmatches_gettail(char_u *s); static int expand_showtail(expand_T *xp); static int expand_shellcmd(char_u *filepat, char_u ***matches, int *numMatches, int flagsarg); #if defined(FEAT_EVAL) *************** *** 34,40 **** static int compl_startcol; static int compl_selected; ! #define SHOW_FILE_TEXT(m) (showtail ? sm_gettail(matches[m]) : matches[m]) /* * Returns TRUE if fuzzy completion is supported for a given cmdline completion --- 35,41 ---- static int compl_startcol; static int compl_selected; ! #define SHOW_FILE_TEXT(m) (showtail ? showmatches_gettail(matches[m]) : matches[m]) /* * Returns TRUE if fuzzy completion is supported for a given cmdline completion *************** *** 334,340 **** columns = vim_strsize(xp->xp_pattern); if (showtail) { ! columns += vim_strsize(sm_gettail(matches[0])); columns -= vim_strsize(matches[0]); } if (columns >= compl_startcol) --- 335,341 ---- columns = vim_strsize(xp->xp_pattern); if (showtail) { ! columns += vim_strsize(showmatches_gettail(matches[0])); columns -= vim_strsize(matches[0]); } if (columns >= compl_startcol) *************** *** 403,408 **** --- 404,675 ---- } /* + * Return the number of characters that should be skipped in a status match. + * These are backslashes used for escaping. Do show backslashes in help tags. + */ + static int + skip_status_match_char(expand_T *xp, char_u *s) + { + if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP) + #ifdef FEAT_MENU + || ((xp->xp_context == EXPAND_MENUS + || xp->xp_context == EXPAND_MENUNAMES) + && (s[0] == '\t' || (s[0] == '\\' && s[1] != NUL))) + #endif + ) + { + #ifndef BACKSLASH_IN_FILENAME + if (xp->xp_shell && csh_like_shell() && s[1] == '\\' && s[2] == '!') + return 2; + #endif + return 1; + } + return 0; + } + + /* + * Get the length of an item as it will be shown in the status line. + */ + static int + status_match_len(expand_T *xp, char_u *s) + { + int len = 0; + + #ifdef FEAT_MENU + int emenu = xp->xp_context == EXPAND_MENUS + || xp->xp_context == EXPAND_MENUNAMES; + + // Check for menu separators - replace with '|'. + if (emenu && menu_is_separator(s)) + return 1; + #endif + + while (*s != NUL) + { + s += skip_status_match_char(xp, s); + len += ptr2cells(s); + MB_PTR_ADV(s); + } + + return len; + } + + /* + * Show wildchar matches in the status line. + * Show at least the "match" item. + * We start at item 'first_match' in the list and show all matches that fit. + * + * If inversion is possible we use it. Else '=' characters are used. + */ + static void + win_redr_status_matches( + expand_T *xp, + int num_matches, + char_u **matches, // list of matches + int match, + int showtail) + { + #define L_MATCH(m) (showtail ? showmatches_gettail(matches[m]) : matches[m]) + int row; + char_u *buf; + int len; + int clen; // length in screen cells + int fillchar; + int attr; + int i; + int highlight = TRUE; + char_u *selstart = NULL; + int selstart_col = 0; + char_u *selend = NULL; + static int first_match = 0; + int add_left = FALSE; + char_u *s; + #ifdef FEAT_MENU + int emenu; + #endif + int l; + + if (matches == NULL) // interrupted completion? + return; + + if (has_mbyte) + buf = alloc(Columns * MB_MAXBYTES + 1); + else + buf = alloc(Columns + 1); + if (buf == NULL) + return; + + if (match == -1) // don't show match but original text + { + match = 0; + highlight = FALSE; + } + // count 1 for the ending ">" + clen = status_match_len(xp, L_MATCH(match)) + 3; + if (match == 0) + first_match = 0; + else if (match < first_match) + { + // jumping left, as far as we can go + first_match = match; + add_left = TRUE; + } + else + { + // check if match fits on the screen + for (i = first_match; i < match; ++i) + clen += status_match_len(xp, L_MATCH(i)) + 2; + if (first_match > 0) + clen += 2; + // jumping right, put match at the left + if ((long)clen > Columns) + { + first_match = match; + // if showing the last match, we can add some on the left + clen = 2; + for (i = match; i < num_matches; ++i) + { + clen += status_match_len(xp, L_MATCH(i)) + 2; + if ((long)clen >= Columns) + break; + } + if (i == num_matches) + add_left = TRUE; + } + } + if (add_left) + while (first_match > 0) + { + clen += status_match_len(xp, L_MATCH(first_match - 1)) + 2; + if ((long)clen >= Columns) + break; + --first_match; + } + + fillchar = fillchar_status(&attr, curwin); + + if (first_match == 0) + { + *buf = NUL; + len = 0; + } + else + { + STRCPY(buf, "< "); + len = 2; + } + clen = len; + + i = first_match; + while ((long)(clen + status_match_len(xp, L_MATCH(i)) + 2) < Columns) + { + if (i == match) + { + selstart = buf + len; + selstart_col = clen; + } + + s = L_MATCH(i); + // Check for menu separators - replace with '|' + #ifdef FEAT_MENU + emenu = (xp->xp_context == EXPAND_MENUS + || xp->xp_context == EXPAND_MENUNAMES); + if (emenu && menu_is_separator(s)) + { + STRCPY(buf + len, transchar('|')); + l = (int)STRLEN(buf + len); + len += l; + clen += l; + } + else + #endif + for ( ; *s != NUL; ++s) + { + s += skip_status_match_char(xp, s); + clen += ptr2cells(s); + if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1) + { + STRNCPY(buf + len, s, l); + s += l - 1; + len += l; + } + else + { + STRCPY(buf + len, transchar_byte(*s)); + len += (int)STRLEN(buf + len); + } + } + if (i == match) + selend = buf + len; + + *(buf + len++) = ' '; + *(buf + len++) = ' '; + clen += 2; + if (++i == num_matches) + break; + } + + if (i != num_matches) + { + *(buf + len++) = '>'; + ++clen; + } + + buf[len] = NUL; + + row = cmdline_row - 1; + if (row >= 0) + { + if (wild_menu_showing == 0) + { + if (msg_scrolled > 0) + { + // Put the wildmenu just above the command line. If there is + // no room, scroll the screen one line up. + if (cmdline_row == Rows - 1) + { + screen_del_lines(0, 0, 1, (int)Rows, TRUE, 0, NULL); + ++msg_scrolled; + } + else + { + ++cmdline_row; + ++row; + } + wild_menu_showing = WM_SCROLLED; + } + else + { + // Create status line if needed by setting 'laststatus' to 2. + // Set 'winminheight' to zero to avoid that the window is + // resized. + if (lastwin->w_status_height == 0) + { + save_p_ls = p_ls; + save_p_wmh = p_wmh; + p_ls = 2; + p_wmh = 0; + last_status(FALSE); + } + wild_menu_showing = WM_SHOWN; + } + } + + screen_puts(buf, row, 0, attr); + if (selstart != NULL && highlight) + { + *selend = NUL; + screen_puts(selstart, row, selstart_col, HL_ATTR(HLF_WM)); + } + + screen_fill(row, row + 1, clen, (int)Columns, fillchar, fillchar, attr); + } + + win_redraw_last_status(topframe); + vim_free(buf); + } + + /* * Get the next or prev cmdline completion match. The index of the match is set * in "p_findex" */ *************** *** 979,989 **** } /* ! * Private gettail for showmatches() (and win_redr_status_matches()): ! * Find tail of file name path, but ignore trailing "/". */ ! char_u * ! sm_gettail(char_u *s) { char_u *p; char_u *t = s; --- 1246,1256 ---- } /* ! * gettail() version for showmatches() and win_redr_status_matches(): ! * Return the tail of file name path "s", ignoring a trailing "/". */ ! static char_u * ! showmatches_gettail(char_u *s) { char_u *p; char_u *t = s; *** ../vim-9.0.0866/src/proto/cmdexpand.pro 2022-06-27 23:14:59.000000000 +0100 --- src/proto/cmdexpand.pro 2022-11-12 17:37:43.176872002 +0000 *************** *** 10,16 **** void ExpandInit(expand_T *xp); void ExpandCleanup(expand_T *xp); int showmatches(expand_T *xp, int wildmenu); - char_u *sm_gettail(char_u *s); char_u *addstar(char_u *fname, int len, int context); void set_expand_context(expand_T *xp); void set_cmd_context(expand_T *xp, char_u *str, int len, int col, int use_ccline); --- 10,15 ---- *** ../vim-9.0.0866/src/screen.c 2022-11-07 12:16:46.397761740 +0000 --- src/screen.c 2022-11-12 17:36:10.924827342 +0000 *************** *** 916,1189 **** } } - static int skip_status_match_char(expand_T *xp, char_u *s); - - /* - * Get the length of an item as it will be shown in the status line. - */ - static int - status_match_len(expand_T *xp, char_u *s) - { - int len = 0; - - #ifdef FEAT_MENU - int emenu = (xp->xp_context == EXPAND_MENUS - || xp->xp_context == EXPAND_MENUNAMES); - - // Check for menu separators - replace with '|'. - if (emenu && menu_is_separator(s)) - return 1; - #endif - - while (*s != NUL) - { - s += skip_status_match_char(xp, s); - len += ptr2cells(s); - MB_PTR_ADV(s); - } - - return len; - } - - /* - * Return the number of characters that should be skipped in a status match. - * These are backslashes used for escaping. Do show backslashes in help tags. - */ - static int - skip_status_match_char(expand_T *xp, char_u *s) - { - if ((rem_backslash(s) && xp->xp_context != EXPAND_HELP) - #ifdef FEAT_MENU - || ((xp->xp_context == EXPAND_MENUS - || xp->xp_context == EXPAND_MENUNAMES) - && (s[0] == '\t' || (s[0] == '\\' && s[1] != NUL))) - #endif - ) - { - #ifndef BACKSLASH_IN_FILENAME - if (xp->xp_shell && csh_like_shell() && s[1] == '\\' && s[2] == '!') - return 2; - #endif - return 1; - } - return 0; - } - - /* - * Show wildchar matches in the status line. - * Show at least the "match" item. - * We start at item 'first_match' in the list and show all matches that fit. - * - * If inversion is possible we use it. Else '=' characters are used. - */ - void - win_redr_status_matches( - expand_T *xp, - int num_matches, - char_u **matches, // list of matches - int match, - int showtail) - { - #define L_MATCH(m) (showtail ? sm_gettail(matches[m]) : matches[m]) - int row; - char_u *buf; - int len; - int clen; // length in screen cells - int fillchar; - int attr; - int i; - int highlight = TRUE; - char_u *selstart = NULL; - int selstart_col = 0; - char_u *selend = NULL; - static int first_match = 0; - int add_left = FALSE; - char_u *s; - #ifdef FEAT_MENU - int emenu; - #endif - int l; - - if (matches == NULL) // interrupted completion? - return; - - if (has_mbyte) - buf = alloc(Columns * MB_MAXBYTES + 1); - else - buf = alloc(Columns + 1); - if (buf == NULL) - return; - - if (match == -1) // don't show match but original text - { - match = 0; - highlight = FALSE; - } - // count 1 for the ending ">" - clen = status_match_len(xp, L_MATCH(match)) + 3; - if (match == 0) - first_match = 0; - else if (match < first_match) - { - // jumping left, as far as we can go - first_match = match; - add_left = TRUE; - } - else - { - // check if match fits on the screen - for (i = first_match; i < match; ++i) - clen += status_match_len(xp, L_MATCH(i)) + 2; - if (first_match > 0) - clen += 2; - // jumping right, put match at the left - if ((long)clen > Columns) - { - first_match = match; - // if showing the last match, we can add some on the left - clen = 2; - for (i = match; i < num_matches; ++i) - { - clen += status_match_len(xp, L_MATCH(i)) + 2; - if ((long)clen >= Columns) - break; - } - if (i == num_matches) - add_left = TRUE; - } - } - if (add_left) - while (first_match > 0) - { - clen += status_match_len(xp, L_MATCH(first_match - 1)) + 2; - if ((long)clen >= Columns) - break; - --first_match; - } - - fillchar = fillchar_status(&attr, curwin); - - if (first_match == 0) - { - *buf = NUL; - len = 0; - } - else - { - STRCPY(buf, "< "); - len = 2; - } - clen = len; - - i = first_match; - while ((long)(clen + status_match_len(xp, L_MATCH(i)) + 2) < Columns) - { - if (i == match) - { - selstart = buf + len; - selstart_col = clen; - } - - s = L_MATCH(i); - // Check for menu separators - replace with '|' - #ifdef FEAT_MENU - emenu = (xp->xp_context == EXPAND_MENUS - || xp->xp_context == EXPAND_MENUNAMES); - if (emenu && menu_is_separator(s)) - { - STRCPY(buf + len, transchar('|')); - l = (int)STRLEN(buf + len); - len += l; - clen += l; - } - else - #endif - for ( ; *s != NUL; ++s) - { - s += skip_status_match_char(xp, s); - clen += ptr2cells(s); - if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1) - { - STRNCPY(buf + len, s, l); - s += l - 1; - len += l; - } - else - { - STRCPY(buf + len, transchar_byte(*s)); - len += (int)STRLEN(buf + len); - } - } - if (i == match) - selend = buf + len; - - *(buf + len++) = ' '; - *(buf + len++) = ' '; - clen += 2; - if (++i == num_matches) - break; - } - - if (i != num_matches) - { - *(buf + len++) = '>'; - ++clen; - } - - buf[len] = NUL; - - row = cmdline_row - 1; - if (row >= 0) - { - if (wild_menu_showing == 0) - { - if (msg_scrolled > 0) - { - // Put the wildmenu just above the command line. If there is - // no room, scroll the screen one line up. - if (cmdline_row == Rows - 1) - { - screen_del_lines(0, 0, 1, (int)Rows, TRUE, 0, NULL); - ++msg_scrolled; - } - else - { - ++cmdline_row; - ++row; - } - wild_menu_showing = WM_SCROLLED; - } - else - { - // Create status line if needed by setting 'laststatus' to 2. - // Set 'winminheight' to zero to avoid that the window is - // resized. - if (lastwin->w_status_height == 0) - { - save_p_ls = p_ls; - save_p_wmh = p_wmh; - p_ls = 2; - p_wmh = 0; - last_status(FALSE); - } - wild_menu_showing = WM_SHOWN; - } - } - - screen_puts(buf, row, 0, attr); - if (selstart != NULL && highlight) - { - *selend = NUL; - screen_puts(selstart, row, selstart_col, HL_ATTR(HLF_WM)); - } - - screen_fill(row, row + 1, clen, (int)Columns, fillchar, fillchar, attr); - } - - win_redraw_last_status(topframe); - vim_free(buf); - } - /* * Return TRUE if the status line of window "wp" is connected to the status * line of the window right of it. If not, then it's a vertical separator. --- 916,921 ---- *** ../vim-9.0.0866/src/proto/screen.pro 2022-09-26 15:18:43.782952802 +0100 --- src/proto/screen.pro 2022-11-12 17:37:37.404869197 +0000 *************** *** 10,16 **** void screen_line(win_T *wp, int row, int coloff, int endcol, int clear_width, int flags); void rl_mirror(char_u *str); void draw_vsep_win(win_T *wp, int row); - void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, int match, int showtail); int stl_connected(win_T *wp); int get_keymap_str(win_T *wp, char_u *fmt, char_u *buf, int len); void win_redr_custom(win_T *wp, int draw_ruler); --- 10,15 ---- *** ../vim-9.0.0866/src/version.c 2022-11-12 17:30:21.788661869 +0000 --- src/version.c 2022-11-12 17:37:28.828865037 +0000 *************** *** 697,698 **** --- 697,700 ---- { /* Add new patch number below this line */ + /**/ + 867, /**/ -- hundred-and-one symptoms of being an internet addict: 48. You get a tatoo that says "This body best viewed with Netscape 3.1 or higher." /// 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 ///