0
0
mirror of https://github.com/vim/vim.git synced 2025-07-24 10:45:12 -04:00

Merge bc8b161ddc8814beffd5edf38ebc6a06ba3e4f93 into a494ce1c64a2637719a5c1339abf19ec7c48089c

This commit is contained in:
glepnir 2025-07-04 10:24:00 +02:00 committed by GitHub
commit c905f41961
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 241 additions and 15 deletions

View File

@ -4583,7 +4583,8 @@ A jump table for the options with a short description can be found at |Q_op|.
A:DiffAdd,C:DiffChange,D:DiffDelete, A:DiffAdd,C:DiffChange,D:DiffDelete,
T:DiffText,E:DiffTextAdd,>:SignColumn, T:DiffText,E:DiffTextAdd,>:SignColumn,
-:Conceal,B:SpellBad,P:SpellCap, -:Conceal,B:SpellBad,P:SpellCap,
R:SpellRare, L:SpellLocal,+:Pmenu, R:SpellRare, L:SpellLocal,
+:Pmenu,I:PmenuBorder,
=:PmenuSel, k:PmenuMatch,<:PmenuMatchSel, =:PmenuSel, k:PmenuMatch,<:PmenuMatchSel,
[:PmenuKind,]:PmenuKindSel, [:PmenuKind,]:PmenuKindSel,
{:PmenuExtra,}:PmenuExtraSel, {:PmenuExtra,}:PmenuExtraSel,
@ -6674,6 +6675,29 @@ A jump table for the options with a short description can be found at |Q_op|.
global global
When on a ":" prompt is used in Ex mode. When on a ":" prompt is used in Ex mode.
*'pumborder'* *'pbr'*
'pumborder' 'pbr' string (default "")
global
When non-empty, specifies the border style used for the
|ins-completion-menu| during completion. This affects how the border
around the popup menu is drawn.
Possible values are:
"single" a single-line border
"double" a double-line border
"rounded" a rounded border using box-drawing characters
"solid" a solid block-style border
"shadow" a shadow-like border style
Alternatively, a custom border style can be defined by specifying
a comma-separated list of eight border characters. The expected
order is as follows:
Top-left corner, Top border, Top-right corner, Right border
Bot-right corner, Bot border, Bot-left corner, Left border
Example: >
:set pumborder=rounded
:set pumborder=+,-,+,\|,+,-,+,\|
<
*'pumheight'* *'ph'* *'pumheight'* *'ph'*
'pumheight' 'ph' number (default 0) 'pumheight' 'ph' number (default 0)
global global

View File

@ -5915,6 +5915,8 @@ NonText '@' at the end of the window, "<<<" at the start of the window
Normal Normal text. Normal Normal text.
*hl-Pmenu* *hl-Pmenu*
Pmenu Popup menu: Normal item. Pmenu Popup menu: Normal item.
*hl-PmenuBorder*
PmenuBorder Popup menu: Border character.
*hl-PmenuSel* *hl-PmenuSel*
PmenuSel Popup menu: Selected item. PmenuSel Popup menu: Selected item.
*hl-PmenuKind* *hl-PmenuKind*

View File

@ -841,6 +841,7 @@ $quote eval.txt /*$quote*
'patchexpr' options.txt /*'patchexpr'* 'patchexpr' options.txt /*'patchexpr'*
'patchmode' options.txt /*'patchmode'* 'patchmode' options.txt /*'patchmode'*
'path' options.txt /*'path'* 'path' options.txt /*'path'*
'pbr' options.txt /*'pbr'*
'pdev' options.txt /*'pdev'* 'pdev' options.txt /*'pdev'*
'penc' options.txt /*'penc'* 'penc' options.txt /*'penc'*
'perldll' options.txt /*'perldll'* 'perldll' options.txt /*'perldll'*
@ -870,6 +871,7 @@ $quote eval.txt /*$quote*
'printoptions' options.txt /*'printoptions'* 'printoptions' options.txt /*'printoptions'*
'prompt' options.txt /*'prompt'* 'prompt' options.txt /*'prompt'*
'pt' options.txt /*'pt'* 'pt' options.txt /*'pt'*
'pumborder' options.txt /*'pumborder'*
'pumheight' options.txt /*'pumheight'* 'pumheight' options.txt /*'pumheight'*
'pummaxwidth' options.txt /*'pummaxwidth'* 'pummaxwidth' options.txt /*'pummaxwidth'*
'pumwidth' options.txt /*'pumwidth'* 'pumwidth' options.txt /*'pumwidth'*
@ -8280,6 +8282,7 @@ hl-MsgArea syntax.txt /*hl-MsgArea*
hl-NonText syntax.txt /*hl-NonText* hl-NonText syntax.txt /*hl-NonText*
hl-Normal syntax.txt /*hl-Normal* hl-Normal syntax.txt /*hl-Normal*
hl-Pmenu syntax.txt /*hl-Pmenu* hl-Pmenu syntax.txt /*hl-Pmenu*
hl-PmenuBorder syntax.txt /*hl-PmenuBorder*
hl-PmenuExtra syntax.txt /*hl-PmenuExtra* hl-PmenuExtra syntax.txt /*hl-PmenuExtra*
hl-PmenuExtraSel syntax.txt /*hl-PmenuExtraSel* hl-PmenuExtraSel syntax.txt /*hl-PmenuExtraSel*
hl-PmenuKind syntax.txt /*hl-PmenuKind* hl-PmenuKind syntax.txt /*hl-PmenuKind*

View File

@ -260,6 +260,7 @@ static char *(highlight_init_both[]) = {
"default link CursorLineSign SignColumn", "default link CursorLineSign SignColumn",
"default link CursorLineFold FoldColumn", "default link CursorLineFold FoldColumn",
"default link CurSearch Search", "default link CurSearch Search",
"default link PmenuBorder Pmenu",
"default link PmenuKind Pmenu", "default link PmenuKind Pmenu",
"default link PmenuKindSel PmenuSel", "default link PmenuKindSel PmenuSel",
"default link PmenuMatch Pmenu", "default link PmenuMatch Pmenu",

View File

@ -521,6 +521,7 @@ EXTERN unsigned cfc_flags; // flags from "completefuzzycollect"
EXTERN char_u *p_cia; // 'completeitemalign' EXTERN char_u *p_cia; // 'completeitemalign'
EXTERN unsigned cia_flags; // order flags of 'completeitemalign' EXTERN unsigned cia_flags; // order flags of 'completeitemalign'
EXTERN char_u *p_cot; // 'completeopt' EXTERN char_u *p_cot; // 'completeopt'
EXTERN char_u *p_pbr; // 'pumborder'
EXTERN unsigned cot_flags; // flags from 'completeopt' EXTERN unsigned cot_flags; // flags from 'completeopt'
// Keep in sync with p_cot_values in optionstr.c // Keep in sync with p_cot_values in optionstr.c
#define COT_MENU 0x001 #define COT_MENU 0x001

View File

@ -2058,6 +2058,9 @@ static struct vimoption options[] =
{"prompt", NULL, P_BOOL|P_VI_DEF, {"prompt", NULL, P_BOOL|P_VI_DEF,
(char_u *)&p_prompt, PV_NONE, NULL, NULL, (char_u *)&p_prompt, PV_NONE, NULL, NULL,
{(char_u *)TRUE, (char_u *)0L} SCTX_INIT}, {(char_u *)TRUE, (char_u *)0L} SCTX_INIT},
{"pumborder", "pbr", P_STRING|P_VI_DEF,
(char_u *)&p_pbr, PV_NONE, did_set_pumborder, NULL,
{(char_u *)"", (char_u *)0L} SCTX_INIT},
{"pumheight", "ph", P_NUM|P_VI_DEF, {"pumheight", "ph", P_NUM|P_VI_DEF,
(char_u *)&p_ph, PV_NONE, NULL, NULL, (char_u *)&p_ph, PV_NONE, NULL, NULL,
{(char_u *)0L, (char_u *)0L} SCTX_INIT}, {(char_u *)0L, (char_u *)0L} SCTX_INIT},

View File

@ -3338,6 +3338,17 @@ did_set_optexpr(optset_T *args)
} }
#endif #endif
/*
* The 'pumborder' option is changed
*/
char *
did_set_pumborder(optset_T *args UNUSED)
{
if (!pum_parse_border())
return e_invalid_argument;
return NULL;
}
/* /*
* The 'pastetoggle' option is changed. * The 'pastetoggle' option is changed.
*/ */

View File

@ -39,6 +39,8 @@ static int pum_win_height;
static int pum_win_col; static int pum_win_col;
static int pum_win_wcol; static int pum_win_wcol;
static int pum_win_width; static int pum_win_width;
static int pum_border_chars[8];
static int pum_has_border = FALSE;
// Some parts are not updated when a popup menu is visible. Setting this flag // Some parts are not updated when a popup menu is visible. Setting this flag
// makes pum_visible() return FALSE even when there is a popup menu. // makes pum_visible() return FALSE even when there is a popup menu.
@ -104,6 +106,7 @@ pum_display(
int content_width; int content_width;
int right_edge_col; int right_edge_col;
int redo_count = 0; int redo_count = 0;
int border_cells = pum_has_border ? 2 : 0;
#if defined(FEAT_QUICKFIX) #if defined(FEAT_QUICKFIX)
win_T *pvwin; win_T *pvwin;
#endif #endif
@ -161,7 +164,7 @@ pum_display(
// Put the pum below "pum_win_row" if possible. If there are few lines // Put the pum below "pum_win_row" if possible. If there are few lines
// decide on where there is more room. // decide on where there is more room.
if (pum_win_row + 2 >= below_row - pum_height if (pum_win_row + 2 + border_cells >= below_row - pum_height
&& pum_win_row - above_row > (below_row - above_row) / 2) && pum_win_row - above_row > (below_row - above_row) / 2)
{ {
// pum above "pum_win_row" // pum above "pum_win_row"
@ -187,6 +190,14 @@ pum_display(
pum_row += pum_height - p_ph; pum_row += pum_height - p_ph;
pum_height = p_ph; pum_height = p_ph;
} }
if (pum_has_border && border_cells + pum_row + pum_height > pum_win_row)
{
if (pum_row < 2)
pum_height -= border_cells;
else
pum_row -= border_cells;
}
} }
else else
{ {
@ -207,6 +218,10 @@ pum_display(
pum_height = MIN(below_row - pum_row, size); pum_height = MIN(below_row - pum_row, size);
if (p_ph > 0 && pum_height > p_ph) if (p_ph > 0 && pum_height > p_ph)
pum_height = p_ph; pum_height = p_ph;
if ((State == MODE_CMDLINE)
&& pum_row + pum_height + border_cells >= cmdline_row)
pum_height -= border_cells;
} }
// don't display when we only have room for one line // don't display when we only have room for one line
@ -375,6 +390,9 @@ pum_display(
pum_width = max_width - pum_scrollbar; pum_width = max_width - pum_scrollbar;
} }
if (pum_col + border_cells + pum_width > Columns)
pum_col -= border_cells;
// Set selected item and redraw. If the window size changed need to // Set selected item and redraw. If the window size changed need to
// redo the positioning. Limit this to two times, when there is not // redo the positioning. Limit this to two times, when there is not
// much room the window size will keep changing. // much room the window size will keep changing.
@ -872,6 +890,148 @@ pum_draw_scrollbar(
screen_putchar(' ', row, pum_col + pum_width, attr); screen_putchar(' ', row, pum_col + pum_width, attr);
} }
int
pum_parse_border(void)
{
int i;
char_u *p = p_pbr;
char_u *next = NULL;
int this_char;
int comb[MAX_MCO];
char_u buf[10];
int len;
int tmp[8];
struct {
char_u *name;
int c[8];
} defaults[] = {
{ (char_u *)"double", { 0x2554, 0x2550, 0x2557, 0x2551,
0x255D, 0x2550, 0x255A, 0x2551 } },
{ (char_u *)"single", { 0x250C, 0x2500, 0x2510, 0x2502,
0x2518, 0x2500, 0x2514, 0x2502 } },
{ (char_u *)"rounded", { 0x256D, 0x2500, 0x256E, 0x2502,
0x256F, 0x2500, 0x2570, 0x2502 } },
{ (char_u *)"bold", { 0x250F, 0x2501, 0x2513, 0x2503,
0x251B, 0x2501, 0x2517, 0x2503 } },
{ (char_u *)"solid", { 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20 } },
};
if (*p_pbr == NUL)
{
pum_has_border = FALSE;
return TRUE;
}
for (i = 0; i < 5; i++)
{
if (STRCMP(p_pbr, defaults[i].name) == 0)
{
memcpy(pum_border_chars, defaults[i].c, 8 * sizeof(int));
pum_has_border = TRUE;
return TRUE;
}
}
for (i = 0; i < 8; i++)
{
next = vim_strchr(p, ',');
if (next)
{
len = (int)(next - p);
if (len > 9)
len = 9;
vim_strncpy(buf, p, len);
buf[len] = NUL;
p = next + 1;
}
else
{
vim_strncpy(buf, p, 9);
buf[9] = NUL;
p += STRLEN(buf);
}
this_char = utfc_ptr2char(buf, comb);
if (!vim_isprintc(this_char))
{
pum_has_border = FALSE;
return FALSE;
}
tmp[i] = this_char;
}
if (*p != NUL)
{
pum_has_border = FALSE;
return FALSE;
}
memcpy(pum_border_chars, tmp, 8 * sizeof(int));
pum_has_border = TRUE;
return TRUE;
}
static void
pum_draw_border(int *border_char, int thumb_pos, int thumb_height)
{
int i;
int row = pum_row;
int col = pum_col;
int attr = syn_name2attr((char_u *)"PmenuBorder");
int width = pum_width - (State & MODE_CMDLINE ? 1 : 0);
int height = pum_height;
#ifdef FEAT_RIGHTLEFT
if (pum_rl)
{
// topright leftright botright botleft
screen_putchar(border_char[2], row, col + 1, attr);
screen_putchar(border_char[0], row, col - width, attr);
screen_putchar(border_char[4], row + height + 1, col + 1, attr);
screen_putchar(border_char[6], row + height + 1, col - width, attr);
// top bot
for (i = 0; i < width; i++)
{
screen_putchar(border_char[1], row, col - i, attr);
screen_putchar(border_char[5], row + height + 1, col - i, attr);
}
// left right
for (i = 1; i < height + 1; i++)
{
screen_putchar(border_char[3], row + i, col + 1, attr);
if (!pum_scrollbar || i < thumb_pos || i >= thumb_pos + thumb_height)
screen_putchar(border_char[7], row + i, col - width, attr);
}
}
else
#endif
{
// topleft topright botleft botright
screen_putchar(border_char[0], row, col, attr);
screen_putchar(border_char[2], row, col + width, attr);
screen_putchar(border_char[6], row + height + 1, col, attr);
screen_putchar(border_char[4], row + height + 1, col + width, attr);
// top bot
for (i = 1; i < width; i++)
{
screen_putchar(border_char[1], row, col + i, attr);
screen_putchar(border_char[5], row + height + 1, col + i, attr);
}
// left right
for (i = 1; i < height + 1; i++)
{
screen_putchar(border_char[7], row + i, col, attr);
if (!pum_scrollbar || i - 1 < thumb_pos || i - 1 >= thumb_pos + thumb_height)
screen_putchar(border_char[3], row + i, col + width, attr);
}
}
}
/* /*
* Redraw the popup menu, using "pum_first" and "pum_selected". * Redraw the popup menu, using "pum_first" and "pum_selected".
*/ */
@ -898,7 +1058,9 @@ pum_redraw(void)
int basic_width; // first item width int basic_width; // first item width
int last_isabbr = FALSE; int last_isabbr = FALSE;
int orig_attr = -1; int orig_attr = -1;
int scroll_range = pum_size - pum_height; int border_cells = pum_has_border ? 2 : 0;
int scroll_range = pum_size - pum_height + border_cells;
int col_off = pum_has_border > 0 ? 1 : 0;
hlf_T hlfsNorm[3]; hlf_T hlfsNorm[3];
hlf_T hlfsSel[3]; hlf_T hlfsSel[3];
@ -940,6 +1102,9 @@ pum_redraw(void)
screen_zindex = POPUPMENU_ZINDEX; screen_zindex = POPUPMENU_ZINDEX;
#endif #endif
if (pum_has_border > 0)
++row;
for (i = 0; i < pum_height; ++i) for (i = 0; i < pum_height; ++i)
{ {
idx = i + pum_first; idx = i + pum_first;
@ -947,21 +1112,31 @@ pum_redraw(void)
hlf = hlfs[0]; // start with "word" highlight hlf = hlfs[0]; // start with "word" highlight
attr = highlight_attr[hlf]; attr = highlight_attr[hlf];
// prepend a space if there is room if (!pum_has_border)
#ifdef FEAT_RIGHTLEFT
if (pum_rl)
{ {
if (pum_col < curwin->w_wincol + curwin->w_width - 1) // prepend a space if there is room
screen_putchar(' ', row, pum_col + 1, attr); #ifdef FEAT_RIGHTLEFT
} if (pum_rl)
else {
if (pum_col < curwin->w_wincol + curwin->w_width - 1)
screen_putchar(' ', row, pum_col + 1, attr);
}
else
#endif #endif
if (pum_col > 0) if (pum_col > 0)
screen_putchar(' ', row, pum_col - 1, attr); screen_putchar(' ', row, pum_col - 1, attr);
}
// Display each entry, use two spaces for a Tab. // Display each entry, use two spaces for a Tab.
// Do this 3 times and order from p_cia // Do this 3 times and order from p_cia
col = pum_col; col = pum_col;
if (pum_has_border > 0)
{
#ifdef FEAT_RIGHTLEFT
if (!pum_rl)
#endif
++col;
}
totwidth = 0; totwidth = 0;
pum_align_order(order); pum_align_order(order);
basic_width = items_width_array[order[0]]; basic_width = items_width_array[order[0]];
@ -1005,9 +1180,9 @@ pum_redraw(void)
else else
#endif #endif
{ {
screen_fill(row, row + 1, col, pum_col + basic_width + n, screen_fill(row, row + 1, col, pum_col + basic_width + n + col_off,
' ', ' ', orig_attr); ' ', ' ', orig_attr);
col = pum_col + basic_width + n; col = pum_col + basic_width + n + col_off;
} }
totwidth = basic_width + n; totwidth = basic_width + n;
} }
@ -1021,10 +1196,12 @@ pum_redraw(void)
screen_fill(row, row + 1, col, pum_col + pum_width, ' ', ' ', screen_fill(row, row + 1, col, pum_col + pum_width, ' ', ' ',
orig_attr); orig_attr);
pum_draw_scrollbar(row, i, thumb_pos, thumb_height); pum_draw_scrollbar(row, i, thumb_pos, thumb_height);
++row; ++row;
} }
if (pum_has_border && pum_window != NULL)
pum_draw_border(pum_border_chars, thumb_pos, thumb_height);
#ifdef FEAT_PROP_POPUP #ifdef FEAT_PROP_POPUP
screen_zindex = 0; screen_zindex = 0;
#endif #endif

View File

@ -208,4 +208,5 @@ int check_ff_value(char_u *p);
void save_clear_shm_value(void); void save_clear_shm_value(void);
void restore_shm_value(void); void restore_shm_value(void);
void export_myvimdir(void); void export_myvimdir(void);
char *did_set_pumborder(optset_T *args);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@ -17,4 +17,5 @@ void ui_post_balloon(char_u *mesg, list_T *list);
void ui_may_remove_balloon(void); void ui_may_remove_balloon(void);
void pum_show_popupmenu(vimmenu_T *menu); void pum_show_popupmenu(vimmenu_T *menu);
void pum_make_popup(char_u *path_name, int use_mouse_pos); void pum_make_popup(char_u *path_name, int use_mouse_pos);
int pum_parse_border(void);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@ -275,6 +275,8 @@ let test_values = {
\ ['xxx', 'xxx,c:yes', 'xxx:', 'xxx:,c:yes']], \ ['xxx', 'xxx,c:yes', 'xxx:', 'xxx:,c:yes']],
\ 'printoptions': [['', 'header:0', 'left:10pc,top:5pc'], \ 'printoptions': [['', 'header:0', 'left:10pc,top:5pc'],
\ ['xxx', 'header:-1']], \ ['xxx', 'header:-1']],
\ 'pumborder': [['', 'single', 'rounded', '+,-,+,\|,+,-,+,\|'],
\ ['xxx', '+,-,+,\|,+,-,+,']],
\ 'scrollopt': [['', 'ver', 'hor', 'jump', 'ver,hor'], ['xxx']], \ 'scrollopt': [['', 'ver', 'hor', 'jump', 'ver,hor'], ['xxx']],
\ 'renderoptions': [[''], ['xxx']], \ 'renderoptions': [[''], ['xxx']],
\ 'rightleftcmd': [['search'], ['xxx']], \ 'rightleftcmd': [['search'], ['xxx']],