summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2022-11-12 17:44:13 +0000
committerBram Moolenaar <Bram@vim.org>2022-11-12 17:44:13 +0000
commitd6e91385f0f7256aec8f70373c9e3399770d22e5 (patch)
treec88a8113c10548767da3106bb88bedfb7ca0ebab
parentf7570f2107d91f35dc67dd0e400fc638585b226c (diff)
patch 9.0.0867: wildmenu redrawing code is spread outv9.0.0867
Problem: Wildmenu redrawing code is spread out. Solution: Refactor to move code together. (closes #11528)
-rw-r--r--src/cmdexpand.c279
-rw-r--r--src/proto/cmdexpand.pro1
-rw-r--r--src/proto/screen.pro1
-rw-r--r--src/screen.c268
-rw-r--r--src/version.c2
5 files changed, 275 insertions, 276 deletions
diff --git a/src/cmdexpand.c b/src/cmdexpand.c
index e0ad1a77f2..2dbde4ef77 100644
--- a/src/cmdexpand.c
+++ b/src/cmdexpand.c
@@ -19,6 +19,7 @@ static int ExpandGeneric(char_u *pat, expand_T *xp, regmatch_T *regmatch,
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 UNUSED)
}
/*
- * 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;
diff --git a/src/proto/cmdexpand.pro b/src/proto/cmdexpand.pro
index e42ed6d423..2fb543ab43 100644
--- a/src/proto/cmdexpand.pro
+++ b/src/proto/cmdexpand.pro
@@ -10,7 +10,6 @@ char_u *ExpandOne(expand_T *xp, char_u *str, char_u *orig, int options, int mode
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);
diff --git a/src/proto/screen.pro b/src/proto/screen.pro
index d53955efc7..84f53e9244 100644
--- 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);
diff --git a/src/screen.c b/src/screen.c
index 15fbe598b3..5855b90080 100644
--- 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.
diff --git a/src/version.c b/src/version.c
index 02ffdeca2f..a7da3160e1 100644
--- 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,