Add options and flags for menu styles similar to those existing for
authornicm <nicm@openbsd.org>
Tue, 8 Aug 2023 08:08:47 +0000 (08:08 +0000)
committernicm <nicm@openbsd.org>
Tue, 8 Aug 2023 08:08:47 +0000 (08:08 +0000)
popups, from Alexis Hildebrandt. GitHub issue 3650.

usr.bin/tmux/cmd-display-menu.c
usr.bin/tmux/menu.c
usr.bin/tmux/mode-tree.c
usr.bin/tmux/options-table.c
usr.bin/tmux/popup.c
usr.bin/tmux/screen-write.c
usr.bin/tmux/status.c
usr.bin/tmux/tmux.1
usr.bin/tmux/tmux.h

index 712524c..d616d0c 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-display-menu.c,v 1.40 2023/08/07 10:52:00 nicm Exp $ */
+/* $OpenBSD: cmd-display-menu.c,v 1.41 2023/08/08 08:08:47 nicm Exp $ */
 
 /*
  * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -39,10 +39,11 @@ const struct cmd_entry cmd_display_menu_entry = {
        .name = "display-menu",
        .alias = "menu",
 
-       .args = { "c:t:S:OT:x:y:", 1, -1, cmd_display_menu_args_parse },
-       .usage = "[-O] [-c target-client] [-S starting-choice] "
-                CMD_TARGET_PANE_USAGE " [-T title] [-x position] "
-                "[-y position] name key command ...",
+       .args = { "b:c:C:t:s:S:OT:x:y:", 1, -1, cmd_display_menu_args_parse },
+       .usage = "[-O] [-b border-lines] [-c target-client] "
+                "[-C starting-choice] [-s style] [-S border-style] "
+                CMD_TARGET_PANE_USAGE "[-T title] [-x position] [-y position] "
+                "name key command ...",
 
        .target = { 't', CMD_FIND_PANE, 0 },
 
@@ -289,19 +290,25 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
        struct client           *tc = cmdq_get_target_client(item);
        struct menu             *menu = NULL;
        struct menu_item         menu_item;
-       const char              *key, *name;
+       const char              *key, *name, *value;
+       const char              *style = args_get(args, 's');
+       const char              *border_style = args_get(args, 'S');
+       enum box_lines           lines = BOX_LINES_DEFAULT;
        char                    *title, *cause;
        int                      flags = 0, starting_choice = 0;
        u_int                    px, py, i, count = args_count(args);
+       struct options          *o = target->s->curw->window->options;
+       struct options_entry    *oe;
+
 
        if (tc->overlay_draw != NULL)
                return (CMD_RETURN_NORMAL);
 
-       if (args_has(args, 'S')) {
-               if (strcmp(args_get(args, 'S'), "-") == 0)
+       if (args_has(args, 'C')) {
+               if (strcmp(args_get(args, 'C'), "-") == 0)
                        starting_choice = -1;
                else {
-                       starting_choice = args_strtonum(args, 'S', 0, UINT_MAX,
+                       starting_choice = args_strtonum(args, 'C', 0, UINT_MAX,
                            &cause);
                        if (cause != NULL) {
                                cmdq_error(item, "starting choice %s", cause);
@@ -352,12 +359,24 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
                return (CMD_RETURN_NORMAL);
        }
 
+       value = args_get(args, 'b');
+       if (value != NULL) {
+               oe = options_get(o, "menu-border-lines");
+               lines = options_find_choice(options_table_entry(oe), value,
+                   &cause);
+               if (lines == -1) {
+                       cmdq_error(item, "menu-border-lines %s", cause);
+                       free(cause);
+                       return (CMD_RETURN_ERROR);
+               }
+       }
+
        if (args_has(args, 'O'))
                flags |= MENU_STAYOPEN;
        if (!event->m.valid)
                flags |= MENU_NOMOUSE;
-       if (menu_display(menu, flags, starting_choice, item, px, py, tc, target,
-           NULL, NULL) != 0)
+       if (menu_display(menu, flags, starting_choice, item, px, py, tc, lines,
+           style, border_style, target, NULL, NULL) != 0)
                return (CMD_RETURN_NORMAL);
        return (CMD_RETURN_WAIT);
 }
index 4c72a49..4b06220 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: menu.c,v 1.50 2023/08/08 07:41:04 nicm Exp $ */
+/* $OpenBSD: menu.c,v 1.51 2023/08/08 08:08:47 nicm Exp $ */
 
 /*
  * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -27,6 +27,10 @@ struct menu_data {
        struct cmdq_item        *item;
        int                      flags;
 
+       struct grid_cell         style;
+       struct grid_cell         border_style;
+       enum box_lines           border_lines;
+
        struct cmd_find_state    fs;
        struct screen            s;
 
@@ -199,12 +203,17 @@ menu_draw_cb(struct client *c, void *data,
        u_int                    i, px = md->px, py = md->py;
        struct grid_cell         gc;
 
-       style_apply(&gc, c->session->curw->window->options, "mode-style", NULL);
-
        screen_write_start(&ctx, s);
        screen_write_clearscreen(&ctx, 8);
-       screen_write_menu(&ctx, menu, md->choice, BOX_LINES_DEFAULT,
-           &grid_default_cell, &grid_default_cell, &gc);
+
+       if (md->border_lines != BOX_LINES_NONE) {
+               screen_write_box(&ctx, menu->width + 4, menu->count + 2,
+                   md->border_lines, &md->border_style, menu->title);
+       }
+       style_apply(&gc, c->session->curw->window->options, "mode-style", NULL);
+
+       screen_write_menu(&ctx, menu, md->choice, md->border_lines,
+           &md->style, &md->border_style, &gc);
        screen_write_stop(&ctx);
 
        for (i = 0; i < screen_size_y(&md->s); i++) {
@@ -432,11 +441,14 @@ chosen:
 struct menu_data *
 menu_prepare(struct menu *menu, int flags, int starting_choice,
     struct cmdq_item *item, u_int px, u_int py, struct client *c,
+    enum box_lines lines, const char *style, const char *border_style,
     struct cmd_find_state *fs, menu_choice_cb cb, void *data)
 {
        struct menu_data        *md;
        int                      choice;
        const char              *name;
+       struct style             sytmp;
+       struct options          *o = c->session->curw->window->options;
 
        if (c->tty.sx < menu->width + 4 || c->tty.sy < menu->count + 2)
                return (NULL);
@@ -445,9 +457,35 @@ menu_prepare(struct menu *menu, int flags, int starting_choice,
        if (py + menu->count + 2 > c->tty.sy)
                py = c->tty.sy - menu->count - 2;
 
+       if (lines == BOX_LINES_DEFAULT)
+               lines = options_get_number(o, "menu-border-lines");
+
        md = xcalloc(1, sizeof *md);
        md->item = item;
        md->flags = flags;
+       md->border_lines = lines;
+
+       memcpy(&md->style, &grid_default_cell, sizeof md->style);
+       style_apply(&md->style, o, "menu-style", NULL);
+       if (style != NULL) {
+               style_set(&sytmp, &grid_default_cell);
+               if (style_parse(&sytmp, &md->style, style) == 0) {
+                       md->style.fg = sytmp.gc.fg;
+                       md->style.bg = sytmp.gc.bg;
+               }
+       }
+       md->style.attr = 0;
+
+       memcpy(&md->border_style, &grid_default_cell, sizeof md->border_style);
+       style_apply(&md->border_style, o, "menu-border-style", NULL);
+       if (border_style != NULL) {
+               style_set(&sytmp, &grid_default_cell);
+               if (style_parse(&sytmp, &md->border_style, border_style) == 0) {
+                       md->border_style.fg = sytmp.gc.fg;
+                       md->border_style.bg = sytmp.gc.bg;
+               }
+       }
+       md->border_style.attr = 0;
 
        if (fs != NULL)
                cmd_find_copy_state(&md->fs, fs);
@@ -501,12 +539,13 @@ menu_prepare(struct menu *menu, int flags, int starting_choice,
 int
 menu_display(struct menu *menu, int flags, int starting_choice,
     struct cmdq_item *item, u_int px, u_int py, struct client *c,
+    enum box_lines lines, const char *style, const char *border_style,
     struct cmd_find_state *fs, menu_choice_cb cb, void *data)
 {
        struct menu_data        *md;
 
-       md = menu_prepare(menu, flags, starting_choice, item, px, py, c, fs, cb,
-           data);
+       md = menu_prepare(menu, flags, starting_choice, item, px, py, c, lines,
+           style, border_style, fs, cb, data);
        if (md == NULL)
                return (-1);
        server_client_set_overlay(c, 0, NULL, menu_mode_cb, menu_draw_cb,
index b90980f..08a5c29 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: mode-tree.c,v 1.63 2023/01/20 21:36:00 nicm Exp $ */
+/* $OpenBSD: mode-tree.c,v 1.64 2023/08/08 08:08:47 nicm Exp $ */
 
 /*
  * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -962,8 +962,8 @@ mode_tree_display_menu(struct mode_tree_data *mtd, struct client *c, u_int x,
                x -= (menu->width + 4) / 2;
        else
                x = 0;
-       if (menu_display(menu, 0, 0, NULL, x, y, c, NULL,
-           mode_tree_menu_callback, mtm) != 0)
+       if (menu_display(menu, 0, 0, NULL, x, y, c, BOX_LINES_DEFAULT, NULL,
+           NULL, NULL, mode_tree_menu_callback, mtm) != 0)
                menu_free(menu);
 }
 
index d7757f7..211257f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: options-table.c,v 1.165 2022/09/09 11:02:23 nicm Exp $ */
+/* $OpenBSD: options-table.c,v 1.166 2023/08/08 08:08:47 nicm Exp $ */
 
 /*
  * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -327,6 +327,33 @@ const struct options_table_entry options_table[] = {
                  "Empty does not write a history file."
        },
 
+       { .name = "menu-style",
+         .type = OPTIONS_TABLE_STRING,
+         .scope = OPTIONS_TABLE_WINDOW,
+         .flags = OPTIONS_TABLE_IS_STYLE,
+         .default_str = "default",
+         .separator = ",",
+         .text = "Default style of menu."
+       },
+
+       { .name = "menu-border-style",
+         .type = OPTIONS_TABLE_STRING,
+         .scope = OPTIONS_TABLE_WINDOW,
+         .default_str = "default",
+         .flags = OPTIONS_TABLE_IS_STYLE,
+         .separator = ",",
+         .text = "Default style of menu borders."
+       },
+
+       { .name = "menu-border-lines",
+         .type = OPTIONS_TABLE_CHOICE,
+         .scope = OPTIONS_TABLE_WINDOW,
+         .choices = options_table_popup_border_lines_list,
+         .default_num = BOX_LINES_SINGLE,
+         .text = "Type of characters used to draw menu border lines. Some of "
+                 "these are only supported on terminals with UTF-8 support."
+       },
+
        { .name = "message-limit",
          .type = OPTIONS_TABLE_NUMBER,
          .scope = OPTIONS_TABLE_SERVER,
index b172f40..35adb1b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: popup.c,v 1.50 2023/06/21 06:28:18 nicm Exp $ */
+/* $OpenBSD: popup.c,v 1.51 2023/08/08 08:08:47 nicm Exp $ */
 
 /*
  * Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -575,8 +575,8 @@ menu:
                x = m->x - (pd->menu->width + 4) / 2;
        else
                x = 0;
-       pd->md = menu_prepare(pd->menu, 0, 0, NULL, x, m->y, c, NULL,
-           popup_menu_done, pd);
+       pd->md = menu_prepare(pd->menu, 0, 0, NULL, x, m->y, c,
+           BOX_LINES_DEFAULT, NULL, NULL, NULL, popup_menu_done, pd);
        c->flags |= CLIENT_REDRAWOVERLAY;
 
 out:
index 9f57565..8d98e0e 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: screen-write.c,v 1.216 2023/08/08 07:41:04 nicm Exp $ */
+/* $OpenBSD: screen-write.c,v 1.217 2023/08/08 08:08:47 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -713,15 +713,16 @@ screen_write_menu(struct screen_write_ctx *ctx, struct menu *menu, int choice,
                name = menu->items[i].name;
                if (name == NULL) {
                        screen_write_cursormove(ctx, cx, cy + 1 + i, 0);
-                       screen_write_hline(ctx, width + 4, 1, 1, lines, gc);
+                       screen_write_hline(ctx, width + 4, 1, 1, lines,
+                           border_gc);
                        continue;
                }
 
                if (choice >= 0 && i == (u_int)choice && *name != '-')
                        gc = choice_gc;
 
-               screen_write_cursormove(ctx, cx + 2, cy + 1 + i, 0);
-               for (j = 0; j < width; j++)
+               screen_write_cursormove(ctx, cx + 1, cy + 1 + i, 0);
+               for (j = 0; j < width + 2; j++)
                        screen_write_putc(ctx, gc, ' ');
 
                screen_write_cursormove(ctx, cx + 2, cy + 1 + i, 0);
index d562ea4..ce8c9f7 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: status.c,v 1.238 2023/04/17 18:22:24 nicm Exp $ */
+/* $OpenBSD: status.c,v 1.239 2023/08/08 08:08:47 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1764,8 +1764,9 @@ status_prompt_complete_list_menu(struct client *c, char **list, u_int size,
        else
                offset = 0;
 
-       if (menu_display(menu, MENU_NOMOUSE|MENU_TAB, 0, NULL, offset,
-           py, c, NULL, status_prompt_menu_callback, spm) != 0) {
+       if (menu_display(menu, MENU_NOMOUSE|MENU_TAB, 0, NULL, offset, py, c,
+           BOX_LINES_DEFAULT, NULL, NULL, NULL, status_prompt_menu_callback,
+           spm) != 0) {
                menu_free(menu);
                free(spm);
                return (0);
@@ -1857,8 +1858,9 @@ status_prompt_complete_window_menu(struct client *c, struct session *s,
        else
                offset = 0;
 
-       if (menu_display(menu, MENU_NOMOUSE|MENU_TAB, 0, NULL, offset,
-           py, c, NULL, status_prompt_menu_callback, spm) != 0) {
+       if (menu_display(menu, MENU_NOMOUSE|MENU_TAB, 0, NULL, offset, py, c,
+           BOX_LINES_DEFAULT, NULL, NULL, NULL, status_prompt_menu_callback,
+           spm) != 0) {
                menu_free(menu);
                free(spm);
                return (NULL);
index cf0f9fd..35c6a11 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.924 2023/07/11 16:09:09 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.925 2023/08/08 08:08:47 nicm Exp $
 .\"
 .\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
 .\"
@@ -14,7 +14,7 @@
 .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 .\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: July 11 2023 $
+.Dd $Mdocdate: August 8 2023 $
 .Dt TMUX 1
 .Os
 .Sh NAME
@@ -4073,6 +4073,26 @@ The default is to run
 .Xr lock 1
 with
 .Fl np .
+.It Ic menu-style Ar style
+Set the menu style.
+See the
+.Sx STYLES
+section on how to specify
+.Ar style .
+Attributes are ignored.
+.It Ic menu-border-style Ar style
+Set the menu border style.
+See the
+.Sx STYLES
+section on how to specify
+.Ar style .
+Attributes are ignored.
+.It Ic menu-border-lines Ar type
+Set the type of characters used for drawing menu borders.
+See
+.Ic popup-border-lines
+for possible values for
+.Ar type .
 .It Ic message-command-style Ar style
 Set status line message command style.
 This is used for the command prompt with
@@ -4540,20 +4560,18 @@ Attributes are ignored.
 .Pp
 .It Ic popup-style Ar style
 Set the popup style.
-For how to specify
-.Ar style ,
-see the
+See the
 .Sx STYLES
-section.
+section on how to specify
+.Ar style .
 Attributes are ignored.
 .Pp
 .It Ic popup-border-style Ar style
 Set the popup border style.
-For how to specify
-.Ar style ,
-see the
+See the
 .Sx STYLES
-section.
+section on how to specify
+.Ar style .
 Attributes are ignored.
 .Pp
 .It Ic popup-border-lines Ar type
@@ -6028,9 +6046,12 @@ the default is
 .Tg menu
 .It Xo Ic display-menu
 .Op Fl O
+.Op Fl b Ar border-lines
 .Op Fl c Ar target-client
+.Op Fl s Ar style
+.Op Fl S Ar border-style
 .Op Fl t Ar target-pane
-.Op Fl S Ar starting-choice
+.Op Fl C Ar starting-choice
 .Op Fl T Ar title
 .Op Fl x Ar position
 .Op Fl y Ar position
@@ -6057,10 +6078,24 @@ may not be chosen.
 The name may be empty for a separator line, in which case both the key and
 command should be omitted.
 .Pp
+.Fl b
+sets the type of characters used for drawing menu borders.
+See
+.Ic popup-border-lines
+for possible values for
+.Ar border-lines .
+.Pp
+.Fl s
+sets the style for the menu and
+.Fl S
+sets the style for the menu border (see
+.Sx STYLES ) .
+.Pp
 .Fl T
 is a format for the menu title (see
 .Sx FORMATS ) .
-.Fl S
+.Pp
+.Fl C
 sets the menu item selected by default, if the menu is not bound to a mouse key
 binding.
 .Pp
@@ -6175,8 +6210,8 @@ forwards any input read from stdin to the empty pane given by
 .Op Fl d Ar start-directory
 .Op Fl e Ar environment
 .Op Fl h Ar height
-.Op Fl s Ar style
-.Op Fl S Ar border-style
+.Op Fl s Ar border-style
+.Op Fl S Ar style
 .Op Fl t Ar target-pane
 .Op Fl T Ar title
 .Op Fl w Ar width
@@ -6219,7 +6254,7 @@ If omitted, half of the terminal size is used.
 does not surround the popup by a border.
 .Pp
 .Fl b
-sets the type of border line for the popup.
+sets the type of characters used for drawing popup borders.
 When
 .Fl B
 is specified, the
@@ -6233,12 +6268,8 @@ for possible values for
 .Fl s
 sets the style for the popup and
 .Fl S
-sets the style for the popup border.
-For how to specify
-.Ar style ,
-see the
-.Sx STYLES
-section.
+sets the style for the popup border (see
+.Sx STYLES ) .
 .Pp
 .Fl e
 takes the form
index 1b994db..b2616b6 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.1202 2023/08/08 07:41:04 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.1203 2023/08/08 08:08:47 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -3306,11 +3306,13 @@ void             menu_add_item(struct menu *, const struct menu_item *,
                    struct cmd_find_state *);
 void            menu_free(struct menu *);
 struct menu_data *menu_prepare(struct menu *, int, int, struct cmdq_item *,
-                   u_int, u_int, struct client *, struct cmd_find_state *,
-                   menu_choice_cb, void *);
+                   u_int, u_int, struct client *, enum box_lines, const char *,
+                   const char *, struct cmd_find_state *, menu_choice_cb,
+                   void *);
 int             menu_display(struct menu *, int, int, struct cmdq_item *,
-                   u_int, u_int, struct client *, struct cmd_find_state *,
-                   menu_choice_cb, void *);
+                   u_int, u_int, struct client *, enum box_lines, const char *,
+                   const char *, struct cmd_find_state *, menu_choice_cb,
+                   void *);
 struct screen  *menu_mode_cb(struct client *, void *, u_int *, u_int *);
 void            menu_check_cb(struct client *, void *, u_int, u_int, u_int,
                    struct overlay_ranges *);