From 50a77f4417976915cf54bdfed7c9beb0d37f600d Mon Sep 17 00:00:00 2001 From: kn Date: Fri, 8 Oct 2021 06:37:39 +0000 Subject: Add tags for command aliases Make ":tnew" work, i.e. bring the reader to the definition of the full "new-window" command aliased as "new" just like ":tnew-window" would. OK nicm --- tmux.1 | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/tmux.1 b/tmux.1 index daa2b316..054aca32 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1027,6 +1027,7 @@ section. .Pp The following commands are available to manage clients and sessions: .Bl -tag -width Ds +.Tg attach .It Xo Ic attach-session .Op Fl dErx .Op Fl c Ar working-directory @@ -1113,6 +1114,7 @@ If is used, the .Ic update-environment option will not be applied. +.Tg detach .It Xo Ic detach-client .Op Fl aP .Op Fl E Ar shell-command @@ -1139,6 +1141,7 @@ With run .Ar shell-command to replace the client. +.Tg has .It Ic has-session Op Fl t Ar target-session .D1 (alias: Ic has ) Report an error and exit with 1 if the specified session does not exist. @@ -1160,6 +1163,7 @@ The .Fl C flag clears alerts (bell, activity, or silence) in all windows linked to the session. +.Tg lsc .It Xo Ic list-clients .Op Fl F Ar format .Op Fl t Ar target-session @@ -1174,6 +1178,7 @@ section. If .Ar target-session is specified, list only clients connected to that session. +.Tg lscm .It Xo Ic list-commands .Op Fl F Ar format .Op Ar command @@ -1183,6 +1188,7 @@ List the syntax of .Ar command or - if omitted - of all commands supported by .Nm . +.Tg ls .It Xo Ic list-sessions .Op Fl F Ar format .Op Fl f Ar filter @@ -1197,6 +1203,7 @@ Only sessions for which the filter is true are shown. See the .Sx FORMATS section. +.Tg lockc .It Ic lock-client Op Fl t Ar target-client .D1 (alias: Ic lockc ) Lock @@ -1204,10 +1211,12 @@ Lock see the .Ic lock-server command. +.Tg locks .It Ic lock-session Op Fl t Ar target-session .D1 (alias: Ic locks ) Lock all clients attached to .Ar target-session . +.Tg new .It Xo Ic new-session .Op Fl AdDEPX .Op Fl c Ar start-directory @@ -1327,6 +1336,7 @@ takes the form .Ql VARIABLE=value and sets an environment variable for the newly created session; it may be specified multiple times. +.Tg refresh .It Xo Ic refresh-client .Op Fl cDlLRSU .Op Fl A Ar pane:state @@ -1462,6 +1472,7 @@ resets so that the position follows the cursor. See the .Ic window-size option. +.Tg rename .It Xo Ic rename-session .Op Fl t Ar target-session .Ar new-name @@ -1469,6 +1480,7 @@ option. .D1 (alias: Ic rename ) Rename the session to .Ar new-name . +.Tg showmsgs .It Xo Ic show-messages .Op Fl JT .Op Fl t Ar target-client @@ -1482,6 +1494,7 @@ server option. and .Fl T show debugging information about jobs and terminals. +.Tg source .It Xo Ic source-file .Op Fl Fnqv .Ar path @@ -1508,6 +1521,7 @@ With the file is parsed but no commands are executed. .Fl v shows the parsed commands and line numbers if possible. +.Tg start .It Ic start-server .D1 (alias: Ic start ) Start the @@ -1524,6 +1538,7 @@ For example: .Bd -literal -offset indent $ tmux start \\; show -g .Ed +.Tg suspendc .It Xo Ic suspend-client .Op Fl t Ar target-client .Xc @@ -1531,6 +1546,7 @@ $ tmux start \\; show -g Suspend a client by sending .Dv SIGTSTP (tty stop). +.Tg switchc .It Xo Ic switch-client .Op Fl ElnprZ .Op Fl c Ar target-client @@ -1921,6 +1937,7 @@ from which the layout was originally defined. .Pp Commands related to windows and panes are as follows: .Bl -tag -width Ds +.Tg breakp .It Xo Ic break-pane .Op Fl abdP .Op Fl F Ar format @@ -1949,6 +1966,7 @@ By default, it uses the format .Ql #{session_name}:#{window_index}.#{pane_index} but a different format may be specified with .Fl F . +.Tg capturep .It Xo Ic capture-pane .Op Fl aepPqCJN .Op Fl b Ar buffer-name @@ -2201,6 +2219,7 @@ specifies the format for each item in the tree. starts without the option information. This command works only if at least one client is attached. .It Xo +.Tg displayp .Ic display-panes .Op Fl bN .Op Fl d Ar duration @@ -2241,6 +2260,7 @@ is "select-pane -t '%%'". With .Fl b , other commands are not blocked from running until the indicator is closed. +.Tg findw .It Xo Ic find-window .Op Fl iCNrTZ .Op Fl t Ar target-pane @@ -2269,6 +2289,7 @@ The default is zooms the pane. .Pp This command works only if at least one client is attached. +.Tg joinp .It Xo Ic join-pane .Op Fl bdfhv .Op Fl l Ar size @@ -2298,6 +2319,7 @@ is omitted and a marked pane is present (see .Ic select-pane .Fl m ) , the marked pane is used rather than the current pane. +.Tg killp .It Xo Ic kill-pane .Op Fl a .Op Fl t Ar target-pane @@ -2309,6 +2331,7 @@ The .Fl a option kills all but the pane given with .Fl t . +.Tg killw .It Xo Ic kill-window .Op Fl a .Op Fl t Ar target-window @@ -2321,6 +2344,7 @@ The .Fl a option kills all but the window given with .Fl t . +.Tg lastp .It Xo Ic last-pane .Op Fl deZ .Op Fl t Ar target-window @@ -2333,12 +2357,14 @@ keeps the window zoomed if it was zoomed. enables or .Fl d disables input to the pane. +.Tg last .It Ic last-window Op Fl t Ar target-session .D1 (alias: Ic last ) Select the last (previously selected) window. If no .Ar target-session is specified, select the last window of the current session. +.Tg link .It Xo Ic link-window .Op Fl abdk .Op Fl s Ar src-window @@ -2369,6 +2395,7 @@ exists, it is killed, otherwise an error is generated. If .Fl d is given, the newly linked window is not selected. +.Tg lsp .It Xo Ic list-panes .Op Fl as .Op Fl F Ar format @@ -2397,6 +2424,7 @@ Only panes for which the filter is true are shown. See the .Sx FORMATS section. +.Tg lsw .It Xo Ic list-windows .Op Fl a .Op Fl F Ar format @@ -2417,6 +2445,7 @@ Only windows for which the filter is true are shown. See the .Sx FORMATS section. +.Tg movep .It Xo Ic move-pane .Op Fl bdfhv .Op Fl l Ar size @@ -2426,6 +2455,7 @@ section. .D1 (alias: Ic movep ) Does the same as .Ic join-pane . +.Tg movew .It Xo Ic move-window .Op Fl abrdk .Op Fl s Ar src-window @@ -2444,6 +2474,7 @@ all windows in the session are renumbered in sequential order, respecting the .Ic base-index option. +.Tg neww .It Xo Ic new-window .Op Fl abdkPS .Op Fl c Ar start-directory @@ -2526,9 +2557,11 @@ By default, it uses the format .Ql #{session_name}:#{window_index} but a different format may be specified with .Fl F . +.Tg nextl .It Ic next-layout Op Fl t Ar target-window .D1 (alias: Ic nextl ) Move a window to the next layout and rearrange the panes to fit. +.Tg next .It Xo Ic next-window .Op Fl a .Op Fl t Ar target-session @@ -2538,6 +2571,7 @@ Move to the next window in the session. If .Fl a is used, move to the next window with an alert. +.Tg pipep .It Xo Ic pipe-pane .Op Fl IOo .Op Fl t Ar target-pane @@ -2586,11 +2620,13 @@ be toggled with a single key, for example: .Bd -literal -offset indent bind-key C-p pipe-pane -o 'cat >>~/output.#I-#P' .Ed +.Tg prevl .It Xo Ic previous-layout .Op Fl t Ar target-window .Xc .D1 (alias: Ic prevl ) Move to the previous layout in the session. +.Tg prev .It Xo Ic previous-window .Op Fl a .Op Fl t Ar target-session @@ -2600,6 +2636,7 @@ Move to the previous window in the session. With .Fl a , move to the previous window with an alert. +.Tg renamew .It Xo Ic rename-window .Op Fl t Ar target-window .Ar new-name @@ -2609,6 +2646,7 @@ Rename the current window, or the window at .Ar target-window if specified, to .Ar new-name . +.Tg resizep .It Xo Ic resize-pane .Op Fl DLMRTUZ .Op Fl t Ar target-pane @@ -2653,6 +2691,7 @@ begins mouse resizing (only valid if bound to a mouse key binding, see .Fl T trims all lines below the current cursor position and moves lines out of the history to replace them. +.Tg resizew .It Xo Ic resize-window .Op Fl aADLRU .Op Fl t Ar target-window @@ -2685,6 +2724,7 @@ the size of the smallest. This command will automatically set .Ic window-size to manual in the window options. +.Tg respawnp .It Xo Ic respawn-pane .Op Fl k .Op Fl c Ar start-directory @@ -2710,6 +2750,7 @@ The option has the same meaning as for the .Ic new-window command. +.Tg respawnw .It Xo Ic respawn-window .Op Fl k .Op Fl c Ar start-directory @@ -2735,6 +2776,7 @@ The option has the same meaning as for the .Ic new-window command. +.Tg rotatew .It Xo Ic rotate-window .Op Fl DUZ .Op Fl t Ar target-window @@ -2746,6 +2788,7 @@ lower) with or downward (numerically higher). .Fl Z keeps the window zoomed if it was zoomed. +.Tg selectl .It Xo Ic select-layout .Op Fl Enop .Op Fl t Ar target-pane @@ -2768,6 +2811,7 @@ commands. applies the last set layout if possible (undoes the most recent layout change). .Fl E spreads the current pane and any panes next to it out evenly. +.Tg selectp .It Xo Ic select-pane .Op Fl DdeLlMmRUZ .Op Fl T Ar title @@ -2812,6 +2856,7 @@ to .Ic swap-pane and .Ic swap-window . +.Tg selectw .It Xo Ic select-window .Op Fl lnpT .Op Fl t Ar target-window @@ -2834,6 +2879,7 @@ If is given and the selected window is already the current window, the command behaves like .Ic last-window . +.Tg splitw .It Xo Ic split-window .Op Fl bdfhIvPZ .Op Fl c Ar start-directory @@ -2894,6 +2940,7 @@ $ make 2>&1|tmux splitw -dI & All other options have the same meaning as for the .Ic new-window command. +.Tg swapp .It Xo Ic swap-pane .Op Fl dDUZ .Op Fl s Ar src-pane @@ -2922,6 +2969,7 @@ is omitted and a marked pane is present (see .Ic select-pane .Fl m ) , the marked pane is used rather than the current pane. +.Tg swapw .It Xo Ic swap-window .Op Fl d .Op Fl s Ar src-window @@ -2943,6 +2991,7 @@ is omitted and a marked pane is present (see .Ic select-pane .Fl m ) , the window containing the marked pane is used rather than the current window. +.Tg unlinkw .It Xo Ic unlink-window .Op Fl k .Op Fl t Ar target-window @@ -3013,6 +3062,7 @@ key will execute for all keys which do not have a more specific binding. .Pp Commands related to key bindings are as follows: .Bl -tag -width Ds +.Tg bind .It Xo Ic bind-key .Op Fl nr .Op Fl N Ar note @@ -3071,6 +3121,7 @@ attaches a note to the key (shown with To view the default bindings and possible commands, see the .Ic list-keys command. +.Tg lsk .It Xo Ic list-keys .Op Fl 1aN .Op Fl P Ar prefix-string Fl T Ar key-table @@ -3106,6 +3157,7 @@ specifies a prefix to print before each key and lists only the first matching key. .Fl a lists the command for keys that do not have a note rather than skipping them. +.Tg send .It Xo Ic send-keys .Op Fl FHlMRX .Op Fl N Ar repeat-count @@ -3157,6 +3209,7 @@ expands formats in arguments where appropriate. Send the prefix key, or with .Fl 2 the secondary prefix key, to a window as if it was pressed. +.Tg unbind .It Xo Ic unbind-key .Op Fl anq .Op Fl T Ar key-table @@ -3252,6 +3305,7 @@ abc123 .Pp Commands which set options are as follows: .Bl -tag -width Ds +.Tg set .It Xo Ic set-option .Op Fl aFgopqsuUw .Op Fl t Ar target-pane @@ -3326,6 +3380,7 @@ blue foreground. Without .Fl a , the result would be the default background and a blue foreground. +.Tg show .It Xo Ic show-options .Op Fl AgHpqsvw .Op Fl t Ar target-pane @@ -5303,6 +5358,7 @@ section). .Pp Commands to alter and view the environment are: .Bl -tag -width Ds +.Tg setenv .It Xo Ic set-environment .Op Fl Fhgru .Op Fl t Ar target-session @@ -5328,6 +5384,7 @@ indicates the variable is to be removed from the environment before starting a new process. .Fl h marks the variable as hidden. +.Tg showenv .It Xo Ic show-environment .Op Fl hgs .Op Fl t Ar target-session @@ -5412,6 +5469,7 @@ session option. .Pp Commands related to the status line are as follows: .Bl -tag -width Ds +.Tg clrphist .It Xo Ic clear-prompt-history .Op Fl T Ar prompt-type .Xc @@ -5534,6 +5592,7 @@ With .Fl b , the prompt is shown in the background and the invoking client does not exit until it is dismissed. +.Tg confirm .It Xo Ic confirm-before .Op Fl b .Op Fl p Ar prompt @@ -5556,6 +5615,7 @@ With .Fl b , the prompt is shown in the background and the invoking client does not exit until it is dismissed. +.Tg menu .It Xo Ic display-menu .Op Fl O .Op Fl c Ar target-client @@ -5647,6 +5707,7 @@ The following keys are also available: .It Li "Down" Ta "Select next item" .It Li "q" Ta "Exit menu" .El +.Tg display .It Xo Ic display-message .Op Fl aINpv .Op Fl c Ar target-client @@ -5688,6 +5749,7 @@ lists the format variables and their values. .Fl I forwards any input read from stdin to the empty pane given by .Ar target-pane . +.Tg popup .It Xo Ic display-popup .Op Fl BCE .Op Fl c Ar target-client @@ -5735,6 +5797,7 @@ does not surround the popup by a border. The .Fl C flag closes any popup on the client. +.Tg showphist .It Xo Ic show-prompt-history .Op Fl T Ar prompt-type .Xc @@ -5864,14 +5927,17 @@ a format for each shortcut key; both are evaluated once for each line. .Fl N starts without the preview. This command works only if at least one client is attached. +.Tg clearhist .It Ic clear-history Op Fl t Ar target-pane .D1 (alias: Ic clearhist ) Remove and free the history for the specified pane. +.Tg deleteb .It Ic delete-buffer Op Fl b Ar buffer-name .D1 (alias: Ic deleteb ) Delete the buffer named .Ar buffer-name , or the most recently added automatically named buffer if not specified. +.Tg lsb .It Xo Ic list-buffers .Op Fl F Ar format .Op Fl f Ar filter @@ -5892,6 +5958,7 @@ section. .Op Fl t Ar target-client .Ar path .Xc +.Tg loadb .D1 (alias: Ic loadb ) Load the contents of the specified paste buffer from .Ar path . @@ -5902,6 +5969,7 @@ is given, the buffer is also sent to the clipboard for using the .Xr xterm 1 escape sequence, if possible. +.Tg pasteb .It Xo Ic paste-buffer .Op Fl dpr .Op Fl b Ar buffer-name @@ -5926,6 +5994,7 @@ If .Fl p is specified, paste bracket control codes are inserted around the buffer if the application has requested bracketed paste mode. +.Tg saveb .It Xo Ic save-buffer .Op Fl a .Op Fl b Ar buffer-name @@ -5941,6 +6010,7 @@ option appends to rather than overwriting the file. .Op Fl aw .Op Fl b Ar buffer-name .Op Fl t Ar target-client +.Tg setb .Op Fl n Ar new-buffer-name .Ar data .Xc @@ -5961,6 +6031,7 @@ The .Fl n option renames the buffer to .Ar new-buffer-name . +.Tg showb .It Xo Ic show-buffer .Op Fl b Ar buffer-name .Xc @@ -5972,6 +6043,7 @@ Miscellaneous commands are as follows: .Bl -tag -width Ds .It Ic clock-mode Op Fl t Ar target-pane Display a large clock. +.Tg if .It Xo Ic if-shell .Op Fl bF .Op Fl t Ar target-pane @@ -6003,11 +6075,13 @@ is given, .Ar shell-command is not executed but considered success if neither empty nor zero (after formats are expanded). +.Tg lock .It Ic lock-server .D1 (alias: Ic lock ) Lock each client individually by running the command specified by the .Ic lock-command option. +.Tg run .It Xo Ic run-shell .Op Fl bC .Op Fl d Ar delay @@ -6041,6 +6115,7 @@ specified by .Fl t or the current pane if omitted) after the command finishes. If the command fails, the exit status is also displayed. +.Tg wait .It Xo Ic wait-for .Op Fl L | S | U .Ar channel -- cgit v1.2.3 From 7800a431ea63f3be4f0763df3f3a2fae44aeac58 Mon Sep 17 00:00:00 2001 From: jmc Date: Fri, 8 Oct 2021 14:14:31 +0000 Subject: remove extra .El; --- tmux.1 | 1 - 1 file changed, 1 deletion(-) diff --git a/tmux.1 b/tmux.1 index 054aca32..027db664 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4412,7 +4412,6 @@ see the .Sx STYLES section. .El -.El .Sh HOOKS .Nm allows commands to run on various triggers, called -- cgit v1.2.3 From 759efe1b3327a7244c03ecc7b90e0e3c49712d06 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 11 Oct 2021 10:55:30 +0000 Subject: Add -e flag to set environment for popup, from Alexis Hildebrandt in GitHub issue 2924. --- cmd-display-menu.c | 27 +++++++++++++++++++++------ cmd-if-shell.c | 2 +- cmd-run-shell.c | 2 +- format.c | 2 +- job.c | 5 ++++- popup.c | 9 +++++---- tmux.1 | 7 +++++++ tmux.h | 11 ++++++----- window-copy.c | 4 ++-- 9 files changed, 48 insertions(+), 21 deletions(-) diff --git a/cmd-display-menu.c b/cmd-display-menu.c index 5df01c7a..87871f68 100644 --- a/cmd-display-menu.c +++ b/cmd-display-menu.c @@ -53,10 +53,10 @@ const struct cmd_entry cmd_display_popup_entry = { .name = "display-popup", .alias = "popup", - .args = { "BCc:d:Eh:t:w:x:y:", 0, -1, NULL }, - .usage = "[-BCE] [-c target-client] [-d start-directory] [-h height] " - CMD_TARGET_PANE_USAGE " [-w width] " - "[-x position] [-y position] [shell-command]", + .args = { "BCc:d:e:Eh:t:w:x:y:", 0, -1, NULL }, + .usage = "[-BCE] [-c target-client] [-d start-directory] " + "[-e environment] [-h height] " CMD_TARGET_PANE_USAGE " " + "[-w width] [-x position] [-y position] [shell-command]", .target = { 't', CMD_FIND_PANE, 0 }, @@ -357,6 +357,8 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item) char *cwd, *cause, **argv = NULL; int flags = 0, argc = 0; u_int px, py, w, h, count = args_count(args); + struct args_value *av; + struct environ *env = NULL; if (args_has(args, 'C')) { server_client_clear_overlay(tc); @@ -410,17 +412,30 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item) } else args_to_vector(args, &argc, &argv); + if (args_has(args, 'e') >= 1) { + env = environ_create(); + av = args_first_value(args, 'e'); + while (av != NULL) { + environ_put(env, av->string, 0); + av = args_next_value(av); + } + } + if (args_has(args, 'E') > 1) flags |= POPUP_CLOSEEXITZERO; else if (args_has(args, 'E')) flags |= POPUP_CLOSEEXIT; if (args_has(args, 'B')) flags |= POPUP_NOBORDER; - if (popup_display(flags, item, px, py, w, h, shellcmd, argc, argv, cwd, - tc, s, NULL, NULL) != 0) { + if (popup_display(flags, item, px, py, w, h, env, shellcmd, argc, argv, + cwd, tc, s, NULL, NULL) != 0) { cmd_free_argv(argc, argv); + if (env != NULL) + environ_free(env); return (CMD_RETURN_NORMAL); } + if (env != NULL) + environ_free(env); cmd_free_argv(argc, argv); return (CMD_RETURN_WAIT); } diff --git a/cmd-if-shell.c b/cmd-if-shell.c index 211e08d6..205a8ce1 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -118,7 +118,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item) if (cdata->client != NULL) cdata->client->references++; - if (job_run(shellcmd, 0, NULL, s, + if (job_run(shellcmd, 0, NULL, NULL, s, server_client_get_cwd(cmdq_get_client(item), s), NULL, cmd_if_shell_callback, cmd_if_shell_free, cdata, 0, -1, -1) == NULL) { diff --git a/cmd-run-shell.c b/cmd-run-shell.c index bf43d313..5e914e65 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -188,7 +188,7 @@ cmd_run_shell_timer(__unused int fd, __unused short events, void* arg) cmd_run_shell_free(cdata); return; } - if (job_run(cmd, 0, NULL, cdata->s, cdata->cwd, NULL, + if (job_run(cmd, 0, NULL, NULL, cdata->s, cdata->cwd, NULL, cmd_run_shell_callback, cmd_run_shell_free, cdata, cdata->flags, -1, -1) == NULL) cmd_run_shell_free(cdata); diff --git a/format.c b/format.c index 37b9123b..f5d2c5f6 100644 --- a/format.c +++ b/format.c @@ -390,7 +390,7 @@ format_job_get(struct format_expand_state *es, const char *cmd) if (force && fj->job != NULL) job_free(fj->job); if (force || (fj->job == NULL && fj->last != t)) { - fj->job = job_run(expanded, 0, NULL, NULL, + fj->job = job_run(expanded, 0, NULL, NULL, NULL, server_client_get_cwd(ft->client, NULL), format_job_update, format_job_complete, NULL, fj, JOB_NOWAIT, -1, -1); if (fj->job == NULL) { diff --git a/job.c b/job.c index 66a25557..4c13f943 100644 --- a/job.c +++ b/job.c @@ -71,7 +71,7 @@ static LIST_HEAD(joblist, job) all_jobs = LIST_HEAD_INITIALIZER(all_jobs); /* Start a job running. */ struct job * -job_run(const char *cmd, int argc, char **argv, struct session *s, +job_run(const char *cmd, int argc, char **argv, struct environ *e, struct session *s, const char *cwd, job_update_cb updatecb, job_complete_cb completecb, job_free_cb freecb, void *data, int flags, int sx, int sy) { @@ -89,6 +89,9 @@ job_run(const char *cmd, int argc, char **argv, struct session *s, * if-shell to decide on default-terminal based on outside TERM. */ env = environ_for_session(s, !cfg_finished); + if (e != NULL) { + environ_copy(e, env); + } sigfillset(&set); sigprocmask(SIG_BLOCK, &set, &oldset); diff --git a/popup.c b/popup.c index d4fc3833..635559fa 100644 --- a/popup.c +++ b/popup.c @@ -590,8 +590,9 @@ popup_job_complete_cb(struct job *job) int popup_display(int flags, struct cmdq_item *item, u_int px, u_int py, u_int sx, - u_int sy, const char *shellcmd, int argc, char **argv, const char *cwd, - struct client *c, struct session *s, popup_close_cb cb, void *arg) + u_int sy, struct environ *env, const char *shellcmd, int argc, char **argv, + const char *cwd, struct client *c, struct session *s, popup_close_cb cb, + void *arg) { struct popup_data *pd; u_int jx, jy; @@ -635,7 +636,7 @@ popup_display(int flags, struct cmdq_item *item, u_int px, u_int py, u_int sx, pd->psx = sx; pd->psy = sy; - pd->job = job_run(shellcmd, argc, argv, s, cwd, + pd->job = job_run(shellcmd, argc, argv, env, s, cwd, popup_job_update_cb, popup_job_complete_cb, NULL, pd, JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE, jx, jy); pd->ictx = input_init(NULL, job_get_event(pd->job), &pd->palette); @@ -725,7 +726,7 @@ popup_editor(struct client *c, const char *buf, size_t len, xasprintf(&cmd, "%s %s", editor, path); if (popup_display(POPUP_INTERNAL|POPUP_CLOSEEXIT, NULL, px, py, sx, sy, - cmd, 0, NULL, _PATH_TMP, c, NULL, popup_editor_close_cb, pe) != 0) { + NULL, cmd, 0, NULL, _PATH_TMP, c, NULL, popup_editor_close_cb, pe) != 0) { popup_editor_free(pe); free(cmd); return (-1); diff --git a/tmux.1 b/tmux.1 index 027db664..14556ba3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -5753,6 +5753,7 @@ forwards any input read from stdin to the empty pane given by .Op Fl BCE .Op Fl c Ar target-client .Op Fl d Ar start-directory +.Op Fl e Ar environment .Op Fl h Ar height .Op Fl t Ar target-pane .Op Fl w Ar width @@ -5793,6 +5794,12 @@ If omitted, half of the terminal size is used. .Fl B does not surround the popup by a border. .Pp +.Fl e +takes the form +.Ql VARIABLE=value +and sets an environment variable for the popup; it may be specified multiple +times. +.Pp The .Fl C flag closes any popup on the client. diff --git a/tmux.h b/tmux.h index 29a532aa..57d3c909 100644 --- a/tmux.h +++ b/tmux.h @@ -2073,9 +2073,9 @@ typedef void (*job_free_cb) (void *); #define JOB_NOWAIT 0x1 #define JOB_KEEPWRITE 0x2 #define JOB_PTY 0x4 -struct job *job_run(const char *, int, char **, struct session *, - const char *, job_update_cb, job_complete_cb, job_free_cb, - void *, int, int, int); +struct job *job_run(const char *, int, char **, struct environ *, + struct session *, const char *, job_update_cb, + job_complete_cb, job_free_cb, void *, int, int, int); void job_free(struct job *); int job_transfer(struct job *, pid_t *, char *, size_t); void job_resize(struct job *, u_int, u_int); @@ -3105,8 +3105,9 @@ int menu_key_cb(struct client *, void *, struct key_event *); typedef void (*popup_close_cb)(int, void *); typedef void (*popup_finish_edit_cb)(char *, size_t, void *); int popup_display(int, struct cmdq_item *, u_int, u_int, u_int, - u_int, const char *, int, char **, const char *, - struct client *, struct session *, popup_close_cb, void *); + u_int, struct environ *, const char *, int, char **, + const char *, struct client *, struct session *, + popup_close_cb, void *); int popup_editor(struct client *, const char *, size_t, popup_finish_edit_cb, void *); diff --git a/window-copy.c b/window-copy.c index c1a31b48..ec6a2f4e 100644 --- a/window-copy.c +++ b/window-copy.c @@ -4531,8 +4531,8 @@ window_copy_pipe_run(struct window_mode_entry *wme, struct session *s, if (cmd == NULL || *cmd == '\0') cmd = options_get_string(global_options, "copy-command"); if (cmd != NULL && *cmd != '\0') { - job = job_run(cmd, 0, NULL, s, NULL, NULL, NULL, NULL, NULL, - JOB_NOWAIT, -1, -1); + job = job_run(cmd, 0, NULL, NULL, s, NULL, NULL, NULL, NULL, + NULL, JOB_NOWAIT, -1, -1); bufferevent_write(job_get_event(job), buf, *len); } return (buf); -- cgit v1.2.3 From b8581ec80e5339be5e2c08cfec70a77f21ba06b2 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 11 Oct 2021 13:27:50 +0000 Subject: Make positions hidden by overlays range-based rather than character-based, from Anindya Mukherjee. --- menu.c | 13 +++--- popup.c | 49 +++++++++++++++++---- screen-redraw.c | 13 +++--- server-client.c | 48 +++++++++++++++++++++ tmux.h | 15 ++++++- tty.c | 131 +++++++++++++++++++++++++++++++++++--------------------- 6 files changed, 196 insertions(+), 73 deletions(-) diff --git a/menu.c b/menu.c index 043dafdd..4c6403a0 100644 --- a/menu.c +++ b/menu.c @@ -140,17 +140,16 @@ menu_mode_cb(__unused struct client *c, void *data, __unused u_int *cx, return (&md->s); } -int -menu_check_cb(__unused struct client *c, void *data, u_int px, u_int py) +/* Return parts of the input range which are not obstructed by the menu. */ +void +menu_check_cb(__unused struct client *c, void *data, u_int px, u_int py, + u_int nx, struct overlay_ranges *r) { struct menu_data *md = data; struct menu *menu = md->menu; - if (px < md->px || px > md->px + menu->width + 3) - return (1); - if (py < md->py || py > md->py + menu->count + 1) - return (1); - return (0); + server_client_overlay_range(md->px, md->py, menu->width + 4, + menu->count + 2, px, py, nx, r); } void diff --git a/popup.c b/popup.c index 635559fa..106e4ee5 100644 --- a/popup.c +++ b/popup.c @@ -157,18 +157,49 @@ popup_mode_cb(__unused struct client *c, void *data, u_int *cx, u_int *cy) return (&pd->s); } -static int -popup_check_cb(struct client *c, void *data, u_int px, u_int py) +/* Return parts of the input range which are not obstructed by the popup. */ +static void +popup_check_cb(struct client* c, void *data, u_int px, u_int py, u_int nx, + struct overlay_ranges *r) { struct popup_data *pd = data; + struct overlay_ranges or[2]; + u_int i, j, k = 0; - if (pd->md != NULL && menu_check_cb(c, pd->md, px, py) == 0) - return (0); - if (px < pd->px || px > pd->px + pd->sx - 1) - return (1); - if (py < pd->py || py > pd->py + pd->sy - 1) - return (1); - return (0); + if (pd->md != NULL) { + /* Check each returned range for the menu against the popup. */ + menu_check_cb(c, pd->md, px, py, nx, r); + for (i = 0; i < 2; i++) { + server_client_overlay_range(pd->px, pd->py, pd->sx, + pd->sy, r->px[i], py, r->nx[i], &or[i]); + } + + /* + * or has up to OVERLAY_MAX_RANGES non-overlapping ranges, + * ordered from left to right. Collect them in the output. + */ + for (i = 0; i < 2; i++) { + /* Each or[i] only has 2 ranges. */ + for (j = 0; j < 2; j++) { + if (or[i].nx[j] > 0) { + r->px[k] = or[i].px[j]; + r->nx[k] = or[i].nx[j]; + k++; + } + } + } + + /* Zero remaining ranges if any. */ + for (i = k; i < OVERLAY_MAX_RANGES; i++) { + r->px[i] = 0; + r->nx[i] = 0; + } + + return; + } + + server_client_overlay_range(pd->px, pd->py, pd->sx, pd->sy, px, py, nx, + r); } static void diff --git a/screen-redraw.c b/screen-redraw.c index 82e390cd..1d736531 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -685,14 +685,17 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j) struct tty *tty = &c->tty; struct format_tree *ft; struct window_pane *wp; - u_int cell_type, x = ctx->ox + i, y = ctx->oy + j; - int pane_status = ctx->pane_status, isolates; struct grid_cell gc; const struct grid_cell *tmp; + struct overlay_ranges r; + u_int cell_type, x = ctx->ox + i, y = ctx->oy + j; + int pane_status = ctx->pane_status, isolates; - if (c->overlay_check != NULL && - !c->overlay_check(c, c->overlay_data, x, y)) - return; + if (c->overlay_check != NULL) { + c->overlay_check(c, c->overlay_data, x, y, 1, &r); + if (r.nx[0] + r.nx[1] == 0) + return; + } cell_type = screen_redraw_check_cell(c, x, y, pane_status, &wp); if (cell_type == CELL_INSIDE) diff --git a/server-client.c b/server-client.c index 51988799..dc5074e7 100644 --- a/server-client.c +++ b/server-client.c @@ -147,6 +147,54 @@ server_client_clear_overlay(struct client *c) server_redraw_client(c); } +/* + * Given overlay position and dimensions, return parts of the input range which + * are visible. + */ +void +server_client_overlay_range(u_int x, u_int y, u_int sx, u_int sy, u_int px, + u_int py, u_int nx, struct overlay_ranges *r) +{ + u_int ox, onx; + + /* Return up to 2 ranges. */ + r->px[2] = 0; + r->nx[2] = 0; + + /* Trivial case of no overlap in the y direction. */ + if (py < y || py > y + sy - 1) { + r->px[0] = px; + r->nx[0] = nx; + r->px[1] = 0; + r->nx[1] = 0; + return; + } + + /* Visible bit to the left of the popup. */ + if (px < x) { + r->px[0] = px; + r->nx[0] = x - px; + if (r->nx[0] > nx) + r->nx[0] = nx; + } else { + r->px[0] = 0; + r->nx[0] = 0; + } + + /* Visible bit to the right of the popup. */ + ox = x + sx; + if (px > ox) + ox = px; + onx = px + nx; + if (onx > ox) { + r->px[1] = ox; + r->nx[1] = onx - ox; + } else { + r->px[1] = 0; + r->nx[1] = 0; + } +} + /* Check if this client is inside this server. */ int server_client_check_nested(struct client *c) diff --git a/tmux.h b/tmux.h index 57d3c909..f4083a71 100644 --- a/tmux.h +++ b/tmux.h @@ -1567,10 +1567,18 @@ struct client_window { }; RB_HEAD(client_windows, client_window); +/* Visible areas not obstructed by overlays. */ +#define OVERLAY_MAX_RANGES 3 +struct overlay_ranges { + u_int px[OVERLAY_MAX_RANGES]; + u_int nx[OVERLAY_MAX_RANGES]; +}; + /* Client connection. */ typedef int (*prompt_input_cb)(struct client *, void *, const char *, int); typedef void (*prompt_free_cb)(void *); -typedef int (*overlay_check_cb)(struct client *, void *, u_int, u_int); +typedef void (*overlay_check_cb)(struct client*, void *, u_int, u_int, u_int, + struct overlay_ranges *); typedef struct screen *(*overlay_mode_cb)(struct client *, void *, u_int *, u_int *); typedef void (*overlay_draw_cb)(struct client *, void *, @@ -2462,6 +2470,8 @@ void server_client_set_overlay(struct client *, u_int, overlay_check_cb, overlay_mode_cb, overlay_draw_cb, overlay_key_cb, overlay_free_cb, overlay_resize_cb, void *); void server_client_clear_overlay(struct client *); +void server_client_overlay_range(u_int, u_int, u_int, u_int, u_int, u_int, + u_int, struct overlay_ranges *); void server_client_set_key_table(struct client *, const char *); const char *server_client_get_key_table(struct client *); int server_client_check_nested(struct client *); @@ -3091,7 +3101,8 @@ int menu_display(struct menu *, int, struct cmdq_item *, u_int, u_int, struct client *, struct cmd_find_state *, menu_choice_cb, void *); struct screen *menu_mode_cb(struct client *, void *, u_int *, u_int *); -int menu_check_cb(struct client *, void *, u_int, u_int); +void menu_check_cb(struct client *, void *, u_int, u_int, u_int, + struct overlay_ranges *); void menu_draw_cb(struct client *, void *, struct screen_redraw_ctx *); void menu_free_cb(struct client *, void *); diff --git a/tty.c b/tty.c index 0f295f6c..9a8265ef 100644 --- a/tty.c +++ b/tty.c @@ -71,6 +71,8 @@ static void tty_draw_pane(struct tty *, const struct tty_ctx *, u_int); static void tty_default_attributes(struct tty *, const struct grid_cell *, struct colour_palette *, u_int); static int tty_check_overlay(struct tty *, u_int, u_int); +static void tty_check_overlay_range(struct tty *, u_int, u_int, u_int, + struct overlay_ranges *); #define tty_use_margin(tty) \ (tty->term->flags & TERM_DECSLRM) @@ -1046,8 +1048,9 @@ static void tty_clear_line(struct tty *tty, const struct grid_cell *defaults, u_int py, u_int px, u_int nx, u_int bg) { - struct client *c = tty->client; - u_int i; + struct client *c = tty->client; + struct overlay_ranges r; + u_int i; log_debug("%s: %s, %u at %u,%u", __func__, c->name, nx, px, py); @@ -1083,18 +1086,13 @@ tty_clear_line(struct tty *tty, const struct grid_cell *defaults, u_int py, * Couldn't use an escape sequence, use spaces. Clear only the visible * bit if there is an overlay. */ - for (i = 0; i < nx; i++) { - if (!tty_check_overlay(tty, px + i, py)) - break; - } - tty_cursor(tty, px, py); - tty_repeat_space(tty, i); - for (; i < nx; i++) { - if (tty_check_overlay(tty, px + i, py)) - break; + tty_check_overlay_range(tty, px, py, nx, &r); + for (i = 0; i < OVERLAY_MAX_RANGES; i++) { + if (r.nx[i] == 0) + continue; + tty_cursor(tty, r.px[i], py); + tty_repeat_space(tty, r.nx[i]); } - tty_cursor(tty, px + i, py); - tty_repeat_space(tty, nx - i); } /* Clear a line, adjusting to visible part of pane. */ @@ -1306,14 +1304,44 @@ tty_check_codeset(struct tty *tty, const struct grid_cell *gc) return (&new); } +/* + * Check if a single character is obstructed by the overlay and return a + * boolean. + */ static int tty_check_overlay(struct tty *tty, u_int px, u_int py) +{ + struct overlay_ranges r; + + /* + * A unit width range will always return nx[2] == 0 from a check, even + * with multiple overlays, so it's sufficient to check just the first + * two entries. + */ + tty_check_overlay_range(tty, px, py, 1, &r); + if (r.nx[0] + r.nx[1] == 0) + return (0); + return (1); +} + +/* Return parts of the input range which are visible. */ +static void +tty_check_overlay_range(struct tty *tty, u_int px, u_int py, u_int nx, + struct overlay_ranges *r) { struct client *c = tty->client; - if (c->overlay_check == NULL) - return (1); - return (c->overlay_check(c, c->overlay_data, px, py)); + if (c->overlay_check == NULL) { + r->px[0] = px; + r->nx[0] = nx; + r->px[1] = 0; + r->nx[1] = 0; + r->px[2] = 0; + r->nx[2] = 0; + return; + } + + c->overlay_check(c, c->overlay_data, px, py, nx, r); } void @@ -1326,11 +1354,12 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, const struct grid_cell *gcp; struct grid_line *gl; struct client *c = tty->client; - u_int i, j, ux, sx, width, hidden; + struct overlay_ranges r; + u_int i, j, ux, sx, width, hidden, eux, nxx; + u_int cellsize; int flags, cleared = 0, wrapped = 0; char buf[512]; size_t len; - u_int cellsize; log_debug("%s: px=%u py=%u nx=%u atx=%u aty=%u", __func__, px, py, nx, atx, aty); @@ -1430,29 +1459,31 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, else memcpy(&last, gcp, sizeof last); + tty_check_overlay_range(tty, atx + ux, aty, gcp->data.width, + &r); hidden = 0; - for (j = 0; j < gcp->data.width; j++) { - if (!tty_check_overlay(tty, atx + ux + j, aty)) - hidden++; - } + for (j = 0; j < OVERLAY_MAX_RANGES; j++) + hidden += r.nx[j]; + hidden = gcp->data.width - hidden; if (hidden != 0 && hidden == gcp->data.width) { if (~gcp->flags & GRID_FLAG_PADDING) ux += gcp->data.width; } else if (hidden != 0 || ux + gcp->data.width > nx) { if (~gcp->flags & GRID_FLAG_PADDING) { tty_attributes(tty, &last, defaults, palette); - tty_cursor(tty, atx + ux, aty); - for (j = 0; j < gcp->data.width; j++) { - if (ux > nx) - break; - if (tty_check_overlay(tty, atx + ux, - aty)) - tty_putc(tty, ' '); - else { - tty_cursor(tty, atx + ux + 1, - aty); + for (j = 0; j < OVERLAY_MAX_RANGES; j++) { + if (r.nx[j] == 0) + continue; + /* Effective width drawn so far. */ + eux = r.px[j] - atx; + if (eux < nx) { + tty_cursor(tty, r.px[j], aty); + nxx = nx - eux; + if (r.nx[j] > nxx) + r.nx[j] = nxx; + tty_repeat_space(tty, r.nx[j]); + ux = eux + r.nx[j]; } - ux++; } } } else if (gcp->attr & GRID_ATTR_CHARSET) { @@ -1926,7 +1957,8 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) { const struct grid_cell *gcp = ctx->cell; struct screen *s = ctx->s; - u_int i, px, py; + struct overlay_ranges r; + u_int px, py, i, vis = 0; px = ctx->xoff + ctx->ocx - ctx->wox; py = ctx->yoff + ctx->ocy - ctx->woy; @@ -1936,13 +1968,14 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) /* Handle partially obstructed wide characters. */ if (gcp->data.width > 1) { - for (i = 0; i < gcp->data.width; i++) { - if (!tty_check_overlay(tty, px + i, py)) { - tty_draw_line(tty, s, s->cx, s->cy, + tty_check_overlay_range(tty, px, py, gcp->data.width, &r); + for (i = 0; i < OVERLAY_MAX_RANGES; i++) + vis += r.nx[i]; + if (vis < gcp->data.width) { + tty_draw_line(tty, s, s->cx, s->cy, gcp->data.width, px, py, &ctx->defaults, ctx->palette); return; - } } } @@ -1960,7 +1993,8 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx) { - u_int i, hide = 0; + struct overlay_ranges r; + u_int i, px; if (!tty_is_visible(tty, ctx, ctx->ocx, ctx->ocy, ctx->num, 1)) return; @@ -1985,18 +2019,15 @@ tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx) tty_cursor_pane_unless_wrap(tty, ctx, ctx->ocx, ctx->ocy); tty_attributes(tty, ctx->cell, &ctx->defaults, ctx->palette); - for (i = 0; i < ctx->num; i++) { - if (!tty_check_overlay(tty, tty->cx + i, tty->cy)) - break; - } - tty_putn(tty, ctx->ptr, i, i); - for (; i < ctx->num; i++) { - if (tty_check_overlay(tty, tty->cx + hide, tty->cy)) - break; - hide++; + px = tty->cx; + tty_check_overlay_range(tty, px, tty->cy, ctx->num, &r); + for (i = 0; i < OVERLAY_MAX_RANGES; i++) { + if (r.nx[i] == 0) + continue; + tty_cursor(tty, r.px[i], tty->cy); + tty_putn(tty, (char *)ctx->ptr + r.px[i] - px, r.nx[i], + r.nx[i]); } - tty_cursor(tty, tty->cx + hide, tty->cy); - tty_putn(tty, (char *)ctx->ptr + i, ctx->num - i, ctx->num - i); } void -- cgit v1.2.3 From 837ca176d1874273f3de615c75b506e1b1787a1b Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 13 Oct 2021 09:28:36 +0000 Subject: Add popup-style and popup-border-style options, from Alexis Hildebrandt in GitHub issue 2927. --- mode-tree.c | 2 +- options-table.c | 18 ++++++++++++++++++ popup.c | 14 +++++++++++--- screen-write.c | 12 ++++++++---- tmux.1 | 18 ++++++++++++++++++ tmux.h | 3 ++- window-tree.c | 2 +- 7 files changed, 59 insertions(+), 10 deletions(-) diff --git a/mode-tree.c b/mode-tree.c index c92f7cff..2d2d8d5c 100644 --- a/mode-tree.c +++ b/mode-tree.c @@ -747,7 +747,7 @@ mode_tree_draw(struct mode_tree_data *mtd) mti = mti->parent; screen_write_cursormove(&ctx, 0, h, 0); - screen_write_box(&ctx, w, sy - h); + screen_write_box(&ctx, w, sy - h, NULL); if (mtd->sort_list != NULL) { xasprintf(&text, " %s (sort: %s%s)", mti->name, diff --git a/options-table.c b/options-table.c index 607a90b6..e728dbe9 100644 --- a/options-table.c +++ b/options-table.c @@ -982,6 +982,24 @@ const struct options_table_entry options_table[] = { .text = "The default colour palette for colours zero to 255." }, + { .name = "popup-style", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_WINDOW, + .default_str = "default", + .flags = OPTIONS_TABLE_IS_STYLE, + .separator = ",", + .text = "Default style of popups." + }, + + { .name = "popup-border-style", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_WINDOW, + .default_str = "default", + .flags = OPTIONS_TABLE_IS_STYLE, + .separator = ",", + .text = "Default style of popup borders." + }, + { .name = "remain-on-exit", .type = OPTIONS_TABLE_CHOICE, .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, diff --git a/popup.c b/popup.c index 106e4ee5..5eea46ef 100644 --- a/popup.c +++ b/popup.c @@ -212,16 +212,22 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx) u_int i, px = pd->px, py = pd->py; struct colour_palette *palette = &pd->palette; struct grid_cell gc; + struct grid_cell bgc; + struct options *o = c->session->curw->window->options; screen_init(&s, pd->sx, pd->sy, 0); screen_write_start(&ctx, &s); screen_write_clearscreen(&ctx, 8); + memcpy(&bgc, &grid_default_cell, sizeof bgc); + style_apply(&bgc, o, "popup-border-style", NULL); + bgc.attr = 0; + if (pd->flags & POPUP_NOBORDER) { screen_write_cursormove(&ctx, 0, 0, 0); screen_write_fast_copy(&ctx, &pd->s, 0, 0, pd->sx, pd->sy); } else if (pd->sx > 2 && pd->sy > 2) { - screen_write_box(&ctx, pd->sx, pd->sy); + screen_write_box(&ctx, pd->sx, pd->sy, &bgc); screen_write_cursormove(&ctx, 1, 1, 0); screen_write_fast_copy(&ctx, &pd->s, 0, 0, pd->sx - 2, pd->sy - 2); @@ -229,8 +235,10 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx) screen_write_stop(&ctx); memcpy(&gc, &grid_default_cell, sizeof gc); - gc.fg = pd->palette.fg; - gc.bg = pd->palette.bg; + style_apply(&gc, o, "popup-style", NULL); + gc.attr = 0; + palette->fg = gc.fg; + palette->bg = gc.bg; if (pd->md != NULL) { c->overlay_check = menu_check_cb; diff --git a/screen-write.c b/screen-write.c index c09d09ab..e3b2b977 100644 --- a/screen-write.c +++ b/screen-write.c @@ -645,7 +645,7 @@ screen_write_menu(struct screen_write_ctx *ctx, struct menu *menu, memcpy(&default_gc, &grid_default_cell, sizeof default_gc); - screen_write_box(ctx, menu->width + 4, menu->count + 2); + screen_write_box(ctx, menu->width + 4, menu->count + 2, NULL); screen_write_cursormove(ctx, cx + 2, cy, 0); format_draw(ctx, &default_gc, menu->width, menu->title, NULL); @@ -677,16 +677,20 @@ screen_write_menu(struct screen_write_ctx *ctx, struct menu *menu, /* Draw a box on screen. */ void -screen_write_box(struct screen_write_ctx *ctx, u_int nx, u_int ny) +screen_write_box(struct screen_write_ctx *ctx, u_int nx, u_int ny, + const struct grid_cell *gcp) { struct screen *s = ctx->s; - struct grid_cell gc; + struct grid_cell gc; u_int cx, cy, i; cx = s->cx; cy = s->cy; - memcpy(&gc, &grid_default_cell, sizeof gc); + if (gcp != NULL) + memcpy(&gc, gcp, sizeof gc); + else + memcpy(&gc, &grid_default_cell, sizeof gc); gc.attr |= GRID_ATTR_CHARSET; gc.flags |= GRID_FLAG_NOPALETTE; diff --git a/tmux.1 b/tmux.1 index 14556ba3..f222e907 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4258,6 +4258,24 @@ see the section. Attributes are ignored. .Pp +.It Ic popup-style Ar style +Set the popup style. +For how to specify +.Ar style , +see the +.Sx STYLES +section. +Attributes are ignored. +.Pp +.It Ic popup-border-style Ar style +Set the popup border style. +For how to specify +.Ar style , +see the +.Sx STYLES +section. +Attributes are ignored. +.Pp .It Ic window-status-activity-style Ar style Set status line style for windows with an activity alert. For how to specify diff --git a/tmux.h b/tmux.h index f4083a71..885093e0 100644 --- a/tmux.h +++ b/tmux.h @@ -2699,7 +2699,8 @@ void screen_write_hline(struct screen_write_ctx *, u_int, int, int); void screen_write_vline(struct screen_write_ctx *, u_int, int, int); void screen_write_menu(struct screen_write_ctx *, struct menu *, int, const struct grid_cell *); -void screen_write_box(struct screen_write_ctx *, u_int, u_int); +void screen_write_box(struct screen_write_ctx *, u_int, u_int, + const struct grid_cell *gc); void screen_write_preview(struct screen_write_ctx *, struct screen *, u_int, u_int); void screen_write_backspace(struct screen_write_ctx *); diff --git a/window-tree.c b/window-tree.c index e7029d33..a721f1b5 100644 --- a/window-tree.c +++ b/window-tree.c @@ -519,7 +519,7 @@ window_tree_draw_label(struct screen_write_ctx *ctx, u_int px, u_int py, if (ox > 1 && ox + len < sx - 1 && sy >= 3) { screen_write_cursormove(ctx, px + ox - 1, py + oy - 1, 0); - screen_write_box(ctx, len + 2, 3); + screen_write_box(ctx, len + 2, 3, NULL); } screen_write_cursormove(ctx, px + ox, py + oy, 0); screen_write_puts(ctx, gc, "%s", label); -- cgit v1.2.3 From d0ab1a837a0ab3e26fe7195f14672f6feb43c4c4 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 14 Oct 2021 09:54:51 +0000 Subject: When checking ranges in tty_cmd_cells, cannot use the tty cursor position and tty_cursor because it may be at the final invisible cursor position on automargin terminals. The text to be drawn is confined to the pane, so use the pane cursor position for the checks instead. Fix from Anindya Mukherjee, redraw problem reported by naddy@. --- tty.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tty.c b/tty.c index 9a8265ef..809289e0 100644 --- a/tty.c +++ b/tty.c @@ -1993,8 +1993,9 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) void tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx) { - struct overlay_ranges r; - u_int i, px; + struct overlay_ranges r; + u_int i, px, py, cx; + char *cp = ctx->ptr; if (!tty_is_visible(tty, ctx, ctx->ocx, ctx->ocy, ctx->num, 1)) return; @@ -2017,16 +2018,20 @@ tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx) tty_margin_off(tty); tty_cursor_pane_unless_wrap(tty, ctx, ctx->ocx, ctx->ocy); - tty_attributes(tty, ctx->cell, &ctx->defaults, ctx->palette); - px = tty->cx; - tty_check_overlay_range(tty, px, tty->cy, ctx->num, &r); + + /* Get tty position from pane position for overlay check. */ + px = ctx->xoff + ctx->ocx - ctx->wox; + py = ctx->yoff + ctx->ocy - ctx->woy; + + tty_check_overlay_range(tty, px, py, ctx->num, &r); for (i = 0; i < OVERLAY_MAX_RANGES; i++) { if (r.nx[i] == 0) continue; - tty_cursor(tty, r.px[i], tty->cy); - tty_putn(tty, (char *)ctx->ptr + r.px[i] - px, r.nx[i], - r.nx[i]); + /* Convert back to pane position for printing. */ + cx = r.px[i] - ctx->xoff + ctx->wox; + tty_cursor_pane_unless_wrap(tty, ctx, cx, ctx->ocy); + tty_putn(tty, cp + r.px[i] - px, r.nx[i], r.nx[i]); } } -- cgit v1.2.3 From add20637f256c0118d3c687d5d1446612d14389a Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 14 Oct 2021 13:19:01 +0000 Subject: Add popup-border-lines option to set popup line style, from Alexis Hildebrandt, GitHub issue 2930. --- cmd-display-menu.c | 32 ++++++++++++++++++------ mode-tree.c | 2 +- options-table.c | 16 ++++++++++-- options.c | 33 ++++++++++++++++--------- popup.c | 44 +++++++++++++++++++++------------ screen-redraw.c | 71 +++++++++-------------------------------------------- screen-write.c | 70 +++++++++++++++++++++++++++++++++++++++++++--------- tmux.1 | 58 +++++++++++++++++++++++++++++++++++++++++++ tmux.h | 64 +++++++++++++++++++++++++++++++++++++----------- tty-acs.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ window-tree.c | 2 +- 11 files changed, 340 insertions(+), 124 deletions(-) diff --git a/cmd-display-menu.c b/cmd-display-menu.c index 87871f68..f6531ede 100644 --- a/cmd-display-menu.c +++ b/cmd-display-menu.c @@ -53,9 +53,10 @@ const struct cmd_entry cmd_display_popup_entry = { .name = "display-popup", .alias = "popup", - .args = { "BCc:d:e:Eh:t:w:x:y:", 0, -1, NULL }, - .usage = "[-BCE] [-c target-client] [-d start-directory] " - "[-e environment] [-h height] " CMD_TARGET_PANE_USAGE " " + .args = { "Bb:Cc:d:e:Eh:t:w:x:y:", 0, -1, NULL }, + .usage = "[-BCE] [-b border-lines] [-c target-client] " + "[-d start-directory] [-e environment] [-h height] " + CMD_TARGET_PANE_USAGE " " "[-w width] [-x position] [-y position] [shell-command]", .target = { 't', CMD_FIND_PANE, 0 }, @@ -354,11 +355,14 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item) struct client *tc = cmdq_get_target_client(item); struct tty *tty = &tc->tty; const char *value, *shell, *shellcmd = NULL; - char *cwd, *cause, **argv = NULL; + char *cwd, *cause = NULL, **argv = NULL; int flags = 0, argc = 0; + enum box_lines lines = BOX_LINES_DEFAULT; u_int px, py, w, h, count = args_count(args); struct args_value *av; struct environ *env = NULL; + struct options *o = s->curw->window->options; + struct options_entry *oe; if (args_has(args, 'C')) { server_client_clear_overlay(tc); @@ -394,6 +398,20 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item) if (!cmd_display_menu_get_position(tc, item, args, &px, &py, w, h)) return (CMD_RETURN_NORMAL); + value = args_get(args, 'b'); + if (args_has(args, 'B')) + lines = BOX_LINES_NONE; + else if (value != NULL) { + oe = options_get(o, "popup-border-lines"); + lines = options_find_choice(options_table_entry(oe), value, + &cause); + if (cause != NULL) { + cmdq_error(item, "popup-border-lines %s", cause); + free(cause); + return (CMD_RETURN_ERROR); + } + } + value = args_get(args, 'd'); if (value != NULL) cwd = format_single_from_target(item, value); @@ -425,10 +443,8 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item) flags |= POPUP_CLOSEEXITZERO; else if (args_has(args, 'E')) flags |= POPUP_CLOSEEXIT; - if (args_has(args, 'B')) - flags |= POPUP_NOBORDER; - if (popup_display(flags, item, px, py, w, h, env, shellcmd, argc, argv, - cwd, tc, s, NULL, NULL) != 0) { + if (popup_display(flags, lines, item, px, py, w, h, env, shellcmd, argc, + argv, cwd, tc, s, NULL, NULL) != 0) { cmd_free_argv(argc, argv); if (env != NULL) environ_free(env); diff --git a/mode-tree.c b/mode-tree.c index 2d2d8d5c..2e029691 100644 --- a/mode-tree.c +++ b/mode-tree.c @@ -747,7 +747,7 @@ mode_tree_draw(struct mode_tree_data *mtd) mti = mti->parent; screen_write_cursormove(&ctx, 0, h, 0); - screen_write_box(&ctx, w, sy - h, NULL); + screen_write_box(&ctx, w, sy - h, BOX_LINES_DEFAULT, NULL); if (mtd->sort_list != NULL) { xasprintf(&text, " %s (sort: %s%s)", mti->name, diff --git a/options-table.c b/options-table.c index e728dbe9..6c57e3ff 100644 --- a/options-table.c +++ b/options-table.c @@ -60,9 +60,12 @@ static const char *options_table_visual_bell_list[] = { static const char *options_table_pane_status_list[] = { "off", "top", "bottom", NULL }; -static const char *options_table_pane_lines_list[] = { +static const char *options_table_pane_border_lines_list[] = { "single", "double", "heavy", "simple", "number", NULL }; +static const char *options_table_popup_border_lines_list[] = { + "single", "double", "heavy", "simple", "rounded", "padded", "none", NULL +}; static const char *options_table_set_clipboard_list[] = { "off", "external", "on", NULL }; @@ -951,7 +954,7 @@ const struct options_table_entry options_table[] = { { .name = "pane-border-lines", .type = OPTIONS_TABLE_CHOICE, .scope = OPTIONS_TABLE_WINDOW, - .choices = options_table_pane_lines_list, + .choices = options_table_pane_border_lines_list, .default_num = PANE_LINES_SINGLE, .text = "Type of characters used to draw pane border lines. Some of " "these are only supported on terminals with UTF-8 support." @@ -1000,6 +1003,15 @@ const struct options_table_entry options_table[] = { .text = "Default style of popup borders." }, + { .name = "popup-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 popup border lines. Some of " + "these are only supported on terminals with UTF-8 support." + }, + { .name = "remain-on-exit", .type = OPTIONS_TABLE_CHOICE, .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, diff --git a/options.c b/options.c index e32db774..65263fd0 100644 --- a/options.c +++ b/options.c @@ -989,28 +989,39 @@ options_from_string_flag(struct options *oo, const char *name, return (0); } +int +options_find_choice(const struct options_table_entry *oe, const char *value, + char **cause) +{ + const char **cp; + int n = 0, choice = -1; + + for (cp = oe->choices; *cp != NULL; cp++) { + if (strcmp(*cp, value) == 0) + choice = n; + n++; + } + if (choice == -1) { + xasprintf(cause, "unknown value: %s", value); + return (-1); + } + return (choice); +} + static int options_from_string_choice(const struct options_table_entry *oe, struct options *oo, const char *name, const char *value, char **cause) { - const char **cp; - int n, choice = -1; + int choice = -1; if (value == NULL) { choice = options_get_number(oo, name); if (choice < 2) choice = !choice; } else { - n = 0; - for (cp = oe->choices; *cp != NULL; cp++) { - if (strcmp(*cp, value) == 0) - choice = n; - n++; - } - if (choice == -1) { - xasprintf(cause, "unknown value: %s", value); + choice = options_find_choice(oe, value, cause); + if (choice < 0) return (-1); - } } options_set_number(oo, name, choice); return (0); diff --git a/popup.c b/popup.c index 5eea46ef..328deba6 100644 --- a/popup.c +++ b/popup.c @@ -31,6 +31,7 @@ struct popup_data { struct client *c; struct cmdq_item *item; int flags; + enum box_lines lines; struct screen s; struct colour_palette palette; @@ -117,7 +118,7 @@ popup_set_client_cb(struct tty_ctx *ttyctx, struct client *c) ttyctx->wsx = c->tty.sx; ttyctx->wsy = c->tty.sy; - if (pd->flags & POPUP_NOBORDER) { + if (pd->lines == BOX_LINES_NONE) { ttyctx->xoff = ttyctx->rxoff = pd->px; ttyctx->yoff = ttyctx->ryoff = pd->py; } else { @@ -147,7 +148,7 @@ popup_mode_cb(__unused struct client *c, void *data, u_int *cx, u_int *cy) if (pd->md != NULL) return (menu_mode_cb(c, pd->md, cx, cy)); - if (pd->flags & POPUP_NOBORDER) { + if (pd->lines == BOX_LINES_NONE) { *cx = pd->px + pd->s.cx; *cy = pd->py + pd->s.cy; } else { @@ -220,14 +221,15 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx) screen_write_clearscreen(&ctx, 8); memcpy(&bgc, &grid_default_cell, sizeof bgc); + bgc.attr = 0; style_apply(&bgc, o, "popup-border-style", NULL); bgc.attr = 0; - if (pd->flags & POPUP_NOBORDER) { + if (pd->lines == BOX_LINES_NONE) { screen_write_cursormove(&ctx, 0, 0, 0); screen_write_fast_copy(&ctx, &pd->s, 0, 0, pd->sx, pd->sy); } else if (pd->sx > 2 && pd->sy > 2) { - screen_write_box(&ctx, pd->sx, pd->sy, &bgc); + screen_write_box(&ctx, pd->sx, pd->sy, pd->lines, &bgc); screen_write_cursormove(&ctx, 1, 1, 0); screen_write_fast_copy(&ctx, &pd->s, 0, 0, pd->sx - 2, pd->sy - 2); @@ -318,7 +320,7 @@ popup_resize_cb(__unused struct client *c, void *data) pd->px = pd->ppx; /* Avoid zero size screens. */ - if (pd->flags & POPUP_NOBORDER) { + if (pd->lines == BOX_LINES_NONE) { screen_resize(&pd->s, pd->sx, pd->sy, 0); if (pd->job != NULL) job_resize(pd->job, pd->sx, pd->sy ); @@ -444,7 +446,7 @@ popup_handle_drag(struct client *c, struct popup_data *pd, pd->ppy = py; server_redraw_client(c); } else if (pd->dragging == SIZE) { - if (pd->flags & POPUP_NOBORDER) { + if (pd->lines == BOX_LINES_NONE) { if (m->x < pd->px + 1) return; if (m->y < pd->py + 1) @@ -460,7 +462,7 @@ popup_handle_drag(struct client *c, struct popup_data *pd, pd->psx = pd->sx; pd->psy = pd->sy; - if (pd->flags & POPUP_NOBORDER) { + if (pd->lines == BOX_LINES_NONE) { screen_resize(&pd->s, pd->sx, pd->sy, 0); if (pd->job != NULL) job_resize(pd->job, pd->sx, pd->sy); @@ -508,7 +510,7 @@ popup_key_cb(struct client *c, void *data, struct key_event *event) goto menu; return (0); } - if (~pd->flags & POPUP_NOBORDER) { + if (pd->lines != BOX_LINES_NONE) { if (m->x == pd->px) border = LEFT; else if (m->x == pd->px + pd->sx - 1) @@ -542,7 +544,7 @@ popup_key_cb(struct client *c, void *data, struct key_event *event) if (pd->job != NULL) { if (KEYC_IS_MOUSE(event->key)) { /* Must be inside, checked already. */ - if (pd->flags & POPUP_NOBORDER) { + if (pd->lines == BOX_LINES_NONE) { px = m->x - pd->px; py = m->y - pd->py; } else { @@ -628,15 +630,23 @@ popup_job_complete_cb(struct job *job) } int -popup_display(int flags, struct cmdq_item *item, u_int px, u_int py, u_int sx, - u_int sy, struct environ *env, const char *shellcmd, int argc, char **argv, - const char *cwd, struct client *c, struct session *s, popup_close_cb cb, - void *arg) +popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px, + u_int py, u_int sx, u_int sy, struct environ *env, const char *shellcmd, + int argc, char **argv, const char *cwd, struct client *c, struct session *s, + popup_close_cb cb, void *arg) { struct popup_data *pd; u_int jx, jy; + struct options *o; - if (flags & POPUP_NOBORDER) { + if (lines == BOX_LINES_DEFAULT) { + if (s != NULL) + o = s->curw->window->options; + else + o = c->session->curw->window->options; + lines = options_get_number(o, "popup-border-lines"); + } + if (lines == BOX_LINES_NONE) { if (sx < 1 || sy < 1) return (-1); jx = sx; @@ -653,6 +663,7 @@ popup_display(int flags, struct cmdq_item *item, u_int px, u_int py, u_int sx, pd = xcalloc(1, sizeof *pd); pd->item = item; pd->flags = flags; + pd->lines = lines; pd->c = c; pd->c->references++; @@ -764,8 +775,9 @@ popup_editor(struct client *c, const char *buf, size_t len, py = (c->tty.sy / 2) - (sy / 2); xasprintf(&cmd, "%s %s", editor, path); - if (popup_display(POPUP_INTERNAL|POPUP_CLOSEEXIT, NULL, px, py, sx, sy, - NULL, cmd, 0, NULL, _PATH_TMP, c, NULL, popup_editor_close_cb, pe) != 0) { + if (popup_display(POPUP_INTERNAL|POPUP_CLOSEEXIT, BOX_LINES_DEFAULT, + NULL, px, py, sx, sy, NULL, cmd, 0, NULL, _PATH_TMP, c, NULL, + popup_editor_close_cb, pe) != 0) { popup_editor_free(pe); free(cmd); return (-1); diff --git a/screen-redraw.c b/screen-redraw.c index 1d736531..11900b4f 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -31,57 +31,9 @@ static void screen_redraw_draw_pane(struct screen_redraw_ctx *, static void screen_redraw_set_context(struct client *, struct screen_redraw_ctx *); -#define CELL_INSIDE 0 -#define CELL_TOPBOTTOM 1 -#define CELL_LEFTRIGHT 2 -#define CELL_TOPLEFT 3 -#define CELL_TOPRIGHT 4 -#define CELL_BOTTOMLEFT 5 -#define CELL_BOTTOMRIGHT 6 -#define CELL_TOPJOIN 7 -#define CELL_BOTTOMJOIN 8 -#define CELL_LEFTJOIN 9 -#define CELL_RIGHTJOIN 10 -#define CELL_JOIN 11 -#define CELL_OUTSIDE 12 - -#define CELL_BORDERS " xqlkmjwvtun~" - #define START_ISOLATE "\342\201\246" #define END_ISOLATE "\342\201\251" -static const struct utf8_data screen_redraw_double_borders[] = { - { "", 0, 0, 0 }, - { "\342\225\221", 0, 3, 1 }, /* U+2551 */ - { "\342\225\220", 0, 3, 1 }, /* U+2550 */ - { "\342\225\224", 0, 3, 1 }, /* U+2554 */ - { "\342\225\227", 0, 3, 1 }, /* U+2557 */ - { "\342\225\232", 0, 3, 1 }, /* U+255A */ - { "\342\225\235", 0, 3, 1 }, /* U+255D */ - { "\342\225\246", 0, 3, 1 }, /* U+2566 */ - { "\342\225\251", 0, 3, 1 }, /* U+2569 */ - { "\342\225\240", 0, 3, 1 }, /* U+2560 */ - { "\342\225\243", 0, 3, 1 }, /* U+2563 */ - { "\342\225\254", 0, 3, 1 }, /* U+256C */ - { "\302\267", 0, 2, 1 } /* U+00B7 */ -}; - -static const struct utf8_data screen_redraw_heavy_borders[] = { - { "", 0, 0, 0 }, - { "\342\224\203", 0, 3, 1 }, /* U+2503 */ - { "\342\224\201", 0, 3, 1 }, /* U+2501 */ - { "\342\224\223", 0, 3, 1 }, /* U+2513 */ - { "\342\224\217", 0, 3, 1 }, /* U+250F */ - { "\342\224\227", 0, 3, 1 }, /* U+2517 */ - { "\342\224\233", 0, 3, 1 }, /* U+251B */ - { "\342\224\263", 0, 3, 1 }, /* U+2533 */ - { "\342\224\273", 0, 3, 1 }, /* U+253B */ - { "\342\224\243", 0, 3, 1 }, /* U+2523 */ - { "\342\224\253", 0, 3, 1 }, /* U+252B */ - { "\342\225\213", 0, 3, 1 }, /* U+254B */ - { "\302\267", 0, 2, 1 } /* U+00B7 */ -}; - enum screen_redraw_border_type { SCREEN_REDRAW_OUTSIDE, SCREEN_REDRAW_INSIDE, @@ -90,8 +42,8 @@ enum screen_redraw_border_type { /* Get cell border character. */ static void -screen_redraw_border_set(struct window_pane *wp, int pane_lines, int cell_type, - struct grid_cell *gc) +screen_redraw_border_set(struct window_pane *wp, enum pane_lines pane_lines, + int cell_type, struct grid_cell *gc) { u_int idx; @@ -110,15 +62,15 @@ screen_redraw_border_set(struct window_pane *wp, int pane_lines, int cell_type, break; case PANE_LINES_DOUBLE: gc->attr &= ~GRID_ATTR_CHARSET; - utf8_copy(&gc->data, &screen_redraw_double_borders[cell_type]); + utf8_copy(&gc->data, tty_acs_double_borders(cell_type)); break; case PANE_LINES_HEAVY: gc->attr &= ~GRID_ATTR_CHARSET; - utf8_copy(&gc->data, &screen_redraw_heavy_borders[cell_type]); + utf8_copy(&gc->data, tty_acs_heavy_borders(cell_type)); break; case PANE_LINES_SIMPLE: gc->attr &= ~GRID_ATTR_CHARSET; - utf8_set(&gc->data, " |-+++++++++."[cell_type]); + utf8_set(&gc->data, SIMPLE_BORDERS[cell_type]); break; default: gc->attr |= GRID_ATTR_CHARSET; @@ -402,7 +354,7 @@ screen_redraw_check_is(u_int px, u_int py, int pane_status, /* Update pane status. */ static int screen_redraw_make_pane_status(struct client *c, struct window_pane *wp, - struct screen_redraw_ctx *rctx, int pane_lines) + struct screen_redraw_ctx *rctx, enum pane_lines pane_lines) { struct window *w = wp->window; struct grid_cell gc; @@ -527,11 +479,12 @@ screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx) static int screen_redraw_update(struct client *c, int flags) { - struct window *w = c->session->curw->window; - struct window_pane *wp; - struct options *wo = w->options; - int redraw, lines; - struct screen_redraw_ctx ctx; + struct window *w = c->session->curw->window; + struct window_pane *wp; + struct options *wo = w->options; + int redraw; + enum pane_lines lines; + struct screen_redraw_ctx ctx; if (c->message_string != NULL) redraw = status_message_redraw(c); diff --git a/screen-write.c b/screen-write.c index e3b2b977..3cd0fb55 100644 --- a/screen-write.c +++ b/screen-write.c @@ -645,7 +645,8 @@ screen_write_menu(struct screen_write_ctx *ctx, struct menu *menu, memcpy(&default_gc, &grid_default_cell, sizeof default_gc); - screen_write_box(ctx, menu->width + 4, menu->count + 2, NULL); + screen_write_box(ctx, menu->width + 4, menu->count + 2, + BOX_LINES_DEFAULT, NULL); screen_write_cursormove(ctx, cx + 2, cy, 0); format_draw(ctx, &default_gc, menu->width, menu->title, NULL); @@ -675,10 +676,45 @@ screen_write_menu(struct screen_write_ctx *ctx, struct menu *menu, screen_write_set_cursor(ctx, cx, cy); } +static void +screen_write_box_border_set(enum box_lines box_lines, int cell_type, + struct grid_cell *gc) +{ + switch (box_lines) { + case BOX_LINES_NONE: + break; + case BOX_LINES_DOUBLE: + gc->attr &= ~GRID_ATTR_CHARSET; + utf8_copy(&gc->data, tty_acs_double_borders(cell_type)); + break; + case BOX_LINES_HEAVY: + gc->attr &= ~GRID_ATTR_CHARSET; + utf8_copy(&gc->data, tty_acs_heavy_borders(cell_type)); + break; + case BOX_LINES_ROUNDED: + gc->attr &= ~GRID_ATTR_CHARSET; + utf8_copy(&gc->data, tty_acs_rounded_borders(cell_type)); + break; + case BOX_LINES_SIMPLE: + gc->attr &= ~GRID_ATTR_CHARSET; + utf8_set(&gc->data, SIMPLE_BORDERS[cell_type]); + break; + case BOX_LINES_PADDED: + gc->attr &= ~GRID_ATTR_CHARSET; + utf8_set(&gc->data, PADDED_BORDERS[cell_type]); + break; + case BOX_LINES_SINGLE: + case BOX_LINES_DEFAULT: + gc->attr |= GRID_ATTR_CHARSET; + utf8_set(&gc->data, CELL_BORDERS[cell_type]); + break; + } +} + /* Draw a box on screen. */ void screen_write_box(struct screen_write_ctx *ctx, u_int nx, u_int ny, - const struct grid_cell *gcp) + enum box_lines l, const struct grid_cell *gcp) { struct screen *s = ctx->s; struct grid_cell gc; @@ -694,24 +730,34 @@ screen_write_box(struct screen_write_ctx *ctx, u_int nx, u_int ny, gc.attr |= GRID_ATTR_CHARSET; gc.flags |= GRID_FLAG_NOPALETTE; - screen_write_putc(ctx, &gc, 'l'); + /* Draw top border */ + screen_write_box_border_set(l, CELL_TOPLEFT, &gc); + screen_write_cell(ctx, &gc); + screen_write_box_b