changeset 31065:50405a481037 v9.0.0867

patch 9.0.0867: wildmenu redrawing code is spread out Commit: https://github.com/vim/vim/commit/d6e91385f0f7256aec8f70373c9e3399770d22e5 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Nov 12 17:44:13 2022 +0000 patch 9.0.0867: wildmenu redrawing code is spread out Problem: Wildmenu redrawing code is spread out. Solution: Refactor to move code together. (closes https://github.com/vim/vim/issues/11528)
author Bram Moolenaar <Bram@vim.org>
date Sat, 12 Nov 2022 18:45:04 +0100
parents 00510bf4c61b
children dc81d69818ef
files src/cmdexpand.c src/proto/cmdexpand.pro src/proto/screen.pro src/screen.c src/version.c
diffstat 5 files changed, 275 insertions(+), 276 deletions(-) [+]
line wrap: on
line diff
--- a/src/cmdexpand.c
+++ b/src/cmdexpand.c
@@ -19,6 +19,7 @@ static int      ExpandGeneric(char_u *pa
 			      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,7 +35,7 @@ static int compl_match_arraysize;
 static int compl_startcol;
 static int compl_selected;
 
-#define SHOW_FILE_TEXT(m) (showtail ? sm_gettail(matches[m]) : matches[m])
+#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,7 +335,7 @@ cmdline_pum_create(
     columns = vim_strsize(xp->xp_pattern);
     if (showtail)
     {
-	columns += vim_strsize(sm_gettail(matches[0]));
+	columns += vim_strsize(showmatches_gettail(matches[0]));
 	columns -= vim_strsize(matches[0]);
     }
     if (columns >= compl_startcol)
@@ -403,6 +404,272 @@ int cmdline_compl_startcol(void)
 }
 
 /*
+ * 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,11 +1246,11 @@ showmatches(expand_T *xp, int wildmenu U
 }
 
 /*
- * Private gettail for showmatches() (and win_redr_status_matches()):
- * Find tail of file name path, but ignore trailing "/".
+ * gettail() version for showmatches() and win_redr_status_matches():
+ * Return the tail of file name path "s", ignoring a trailing "/".
  */
-    char_u *
-sm_gettail(char_u *s)
+    static char_u *
+showmatches_gettail(char_u *s)
 {
     char_u	*p;
     char_u	*t = s;
--- a/src/proto/cmdexpand.pro
+++ b/src/proto/cmdexpand.pro
@@ -10,7 +10,6 @@ char_u *ExpandOne(expand_T *xp, char_u *
 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);
--- a/src/proto/screen.pro
+++ b/src/proto/screen.pro
@@ -10,7 +10,6 @@ void reset_screen_attr(void);
 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);
--- a/src/screen.c
+++ b/src/screen.c
@@ -916,274 +916,6 @@ draw_vsep_win(win_T *wp, int row)
     }
 }
 
-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.
--- 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 */
 /**/
+    867,
+/**/
     866,
 /**/
     865,