From 50a77f4417976915cf54bdfed7c9beb0d37f600d Mon Sep 17 00:00:00 2001 From: kn Date: Fri, 8 Oct 2021 06:37:39 +0000 Subject: [PATCH 01/45] 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 From 7800a431ea63f3be4f0763df3f3a2fae44aeac58 Mon Sep 17 00:00:00 2001 From: jmc Date: Fri, 8 Oct 2021 14:14:31 +0000 Subject: [PATCH 02/45] 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 From 759efe1b3327a7244c03ecc7b90e0e3c49712d06 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 11 Oct 2021 10:55:30 +0000 Subject: [PATCH 03/45] 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); From b8581ec80e5339be5e2c08cfec70a77f21ba06b2 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 11 Oct 2021 13:27:50 +0000 Subject: [PATCH 04/45] 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_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, py); - tty_repeat_space(tty, i); - for (; i < nx; i++) { - if (tty_check_overlay(tty, px + i, py)) - break; - } - 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; + 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_putn(tty, ctx->ptr, i, i); - for (; i < ctx->num; i++) { - if (tty_check_overlay(tty, tty->cx + hide, tty->cy)) - break; - hide++; - } - tty_cursor(tty, tty->cx + hide, tty->cy); - tty_putn(tty, (char *)ctx->ptr + i, ctx->num - i, ctx->num - i); } void From 837ca176d1874273f3de615c75b506e1b1787a1b Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 13 Oct 2021 09:28:36 +0000 Subject: [PATCH 05/45] 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); From d0ab1a837a0ab3e26fe7195f14672f6feb43c4c4 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 14 Oct 2021 09:54:51 +0000 Subject: [PATCH 06/45] 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]); } } From add20637f256c0118d3c687d5d1446612d14389a Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 14 Oct 2021 13:19:01 +0000 Subject: [PATCH 07/45] 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_border_set(l, CELL_LEFTRIGHT, &gc); for (i = 1; i < nx - 1; i++) - screen_write_putc(ctx, &gc, 'q'); - screen_write_putc(ctx, &gc, 'k'); + screen_write_cell(ctx, &gc); + screen_write_box_border_set(l, CELL_TOPRIGHT, &gc); + screen_write_cell(ctx, &gc); + /* Draw bottom border */ screen_write_set_cursor(ctx, cx, cy + ny - 1); - screen_write_putc(ctx, &gc, 'm'); + screen_write_box_border_set(l, CELL_BOTTOMLEFT, &gc); + screen_write_cell(ctx, &gc); + screen_write_box_border_set(l, CELL_LEFTRIGHT, &gc); for (i = 1; i < nx - 1; i++) - screen_write_putc(ctx, &gc, 'q'); - screen_write_putc(ctx, &gc, 'j'); + screen_write_cell(ctx, &gc); + screen_write_box_border_set(l, CELL_BOTTOMRIGHT, &gc); + screen_write_cell(ctx, &gc); + /* Draw sides */ + screen_write_box_border_set(l, CELL_TOPBOTTOM, &gc); for (i = 1; i < ny - 1; i++) { + /* left side */ screen_write_set_cursor(ctx, cx, cy + i); - screen_write_putc(ctx, &gc, 'x'); - } - for (i = 1; i < ny - 1; i++) { + screen_write_cell(ctx, &gc); + /* right side */ screen_write_set_cursor(ctx, cx + nx - 1, cy + i); - screen_write_putc(ctx, &gc, 'x'); + screen_write_cell(ctx, &gc); } screen_write_set_cursor(ctx, cx, cy); diff --git a/tmux.1 b/tmux.1 index f222e907..cb930c9c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4276,6 +4276,50 @@ 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 popup-border-lines Ar type +Set the type of characters used for drawing popup borders. +.Ar type +may be one of: +.Bl -tag -width Ds +.It single +single lines using ACS or UTF-8 characters (default) +.It rounded +variation of single with rounded corners using UTF-8 characters +.It double +double lines using UTF-8 characters +.It heavy +heavy lines using UTF-8 characters +.It simple +simple ASCII characters +.It padded +simple ASCII space character +.It none +no border +.El +.Pp +.Ql double +and +.Ql heavy +will fall back to standard ACS line drawing when UTF-8 is not supported. +.Pp .It Ic window-status-activity-style Ar style Set status line style for windows with an activity alert. For how to specify @@ -5769,6 +5813,7 @@ forwards any input read from stdin to the empty pane given by .Tg popup .It Xo Ic display-popup .Op Fl BCE +.Op Fl b Ar border-lines .Op Fl c Ar target-client .Op Fl d Ar start-directory .Op Fl e Ar environment @@ -5809,9 +5854,22 @@ and give the width and height - both may be a percentage (followed by .Ql % ) . If omitted, half of the terminal size is used. +.Pp .Fl B does not surround the popup by a border. .Pp +.Fl b +sets the type of border line for the popup. +When +.Fl B +is specified the +.Fl b +option is ignored. +See +.Ic popup-border-lines +for possible values for +.Ar border-lines . +.Pp .Fl e takes the form .Ql VARIABLE=value diff --git a/tmux.h b/tmux.h index 885093e0..65a3a571 100644 --- a/tmux.h +++ b/tmux.h @@ -613,6 +613,24 @@ struct colour_palette { #define GRID_LINE_EXTENDED 0x2 #define GRID_LINE_DEAD 0x4 +#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 SIMPLE_BORDERS " |-+++++++++." +#define PADDED_BORDERS " " + /* Grid cell data. */ struct grid_cell { struct utf8_data data; @@ -799,6 +817,27 @@ struct screen_write_ctx { u_int bg; }; +/* Box border lines option. */ +enum box_lines { + BOX_LINES_DEFAULT = -1, + BOX_LINES_SINGLE, + BOX_LINES_DOUBLE, + BOX_LINES_HEAVY, + BOX_LINES_SIMPLE, + BOX_LINES_ROUNDED, + BOX_LINES_PADDED, + BOX_LINES_NONE +}; + +/* Pane border lines option. */ +enum pane_lines { + PANE_LINES_SINGLE, + PANE_LINES_DOUBLE, + PANE_LINES_HEAVY, + PANE_LINES_SIMPLE, + PANE_LINES_NUMBER +}; + /* Screen redraw context. */ struct screen_redraw_ctx { struct client *c; @@ -807,7 +846,7 @@ struct screen_redraw_ctx { int statustop; int pane_status; - int pane_lines; + enum pane_lines pane_lines; struct grid_cell no_pane_gc; int no_pane_gc_set; @@ -1061,13 +1100,6 @@ TAILQ_HEAD(winlink_stack, winlink); #define PANE_STATUS_TOP 1 #define PANE_STATUS_BOTTOM 2 -/* Pane border lines option. */ -#define PANE_LINES_SINGLE 0 -#define PANE_LINES_DOUBLE 1 -#define PANE_LINES_HEAVY 2 -#define PANE_LINES_SIMPLE 3 -#define PANE_LINES_NUMBER 4 - /* Layout direction. */ enum layout_type { LAYOUT_LEFTRIGHT, @@ -2066,6 +2098,8 @@ struct style *options_string_to_style(struct options *, const char *, int options_from_string(struct options *, const struct options_table_entry *, const char *, const char *, int, char **); +int options_find_choice(const struct options_table_entry *, + const char *, char **); void options_push_changes(const char *); int options_remove_or_default(struct options_entry *, int, char **); @@ -2216,6 +2250,9 @@ void tty_default_features(int *, const char *, u_int); int tty_acs_needed(struct tty *); const char *tty_acs_get(struct tty *, u_char); int tty_acs_reverse_get(struct tty *, const char *, size_t); +const struct utf8_data *tty_acs_double_borders(int); +const struct utf8_data *tty_acs_heavy_borders(int); +const struct utf8_data *tty_acs_rounded_borders(int); /* tty-keys.c */ void tty_keys_build(struct tty *); @@ -2699,8 +2736,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, - const struct grid_cell *gc); +void screen_write_box(struct screen_write_ctx *, u_int, u_int, int, + const struct grid_cell *); void screen_write_preview(struct screen_write_ctx *, struct screen *, u_int, u_int); void screen_write_backspace(struct screen_write_ctx *); @@ -3112,12 +3149,11 @@ int menu_key_cb(struct client *, void *, struct key_event *); /* popup.c */ #define POPUP_CLOSEEXIT 0x1 #define POPUP_CLOSEEXITZERO 0x2 -#define POPUP_NOBORDER 0x4 -#define POPUP_INTERNAL 0x8 +#define POPUP_INTERNAL 0x4 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, struct environ *, const char *, int, char **, +int popup_display(int, int, struct cmdq_item *, u_int, u_int, + u_int, 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, diff --git a/tty-acs.c b/tty-acs.c index 63eccb93..1a57826c 100644 --- a/tty-acs.c +++ b/tty-acs.c @@ -110,6 +110,78 @@ static const struct tty_acs_reverse_entry tty_acs_reverse3[] = { { "\342\225\254", 'n' }, }; +/* UTF-8 double borders. */ +static const struct utf8_data tty_acs_double_borders_list[] = { + { "", 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 */ +}; + +/* UTF-8 heavy borders. */ +static const struct utf8_data tty_acs_heavy_borders_list[] = { + { "", 0, 0, 0 }, + { "\342\224\203", 0, 3, 1 }, /* U+2503 */ + { "\342\224\201", 0, 3, 1 }, /* U+2501 */ + { "\342\224\217", 0, 3, 1 }, /* U+250F */ + { "\342\224\223", 0, 3, 1 }, /* U+2513 */ + { "\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 */ +}; + +/* UTF-8 rounded borders. */ +static const struct utf8_data tty_acs_rounded_borders_list[] = { + { "", 0, 0, 0 }, + { "\342\224\202", 0, 3, 1 }, /* U+2502 */ + { "\342\224\200", 0, 3, 1 }, /* U+2500 */ + { "\342\225\255", 0, 3, 1 }, /* U+256D */ + { "\342\225\256", 0, 3, 1 }, /* U+256E */ + { "\342\225\260", 0, 3, 1 }, /* U+2570 */ + { "\342\225\257", 0, 3, 1 }, /* U+256F */ + { "\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 */ +}; + +/* Get cell border character for double style. */ +const struct utf8_data * +tty_acs_double_borders(int cell_type) +{ + return (&tty_acs_double_borders_list[cell_type]); +} + +/* Get cell border character for heavy style. */ +const struct utf8_data * +tty_acs_heavy_borders(int cell_type) +{ + return (&tty_acs_heavy_borders_list[cell_type]); +} + +/* Get cell border character for rounded style. */ +const struct utf8_data * +tty_acs_rounded_borders(int cell_type) +{ + return (&tty_acs_rounded_borders_list[cell_type]); +} + static int tty_acs_cmp(const void *key, const void *value) { diff --git a/window-tree.c b/window-tree.c index a721f1b5..d22a2b58 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, NULL); + screen_write_box(ctx, len + 2, 3, BOX_LINES_DEFAULT, NULL); } screen_write_cursormove(ctx, px + ox, py + oy, 0); screen_write_puts(ctx, gc, "%s", label); From 537302f2c17849058cf6080f5735efe86d21a239 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 15 Oct 2021 10:39:22 +0000 Subject: [PATCH 08/45] Do not send any key if -N flag is given even if no other arguments, fixes problem with repeat in copy mode reported by tb@. --- cmd-send-keys.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd-send-keys.c b/cmd-send-keys.c index 47fa1caa..46cb37f0 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -203,6 +203,8 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item) } if (count == 0) { + if (args_has(args, 'N')) + return (CMD_RETURN_NORMAL); for (; np != 0; np--) cmd_send_keys_inject_key(item, NULL, event->key); return (CMD_RETURN_NORMAL); From cc27a43c402b412509f4bd63ecf4c263ea65ec81 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 18 Oct 2021 09:09:46 +0000 Subject: [PATCH 09/45] Remove duplicate options, spotted by Ricky Cintron. --- tmux.1 | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/tmux.1 b/tmux.1 index cb930c9c..ab92be2e 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4276,24 +4276,6 @@ 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 popup-border-lines Ar type Set the type of characters used for drawing popup borders. .Ar type From 2c188ee0c5dbe2633920b0c2a341264335734767 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 18 Oct 2021 09:15:56 +0000 Subject: [PATCH 10/45] Spacing fixes from Alexis Hildebrandt. --- tty-acs.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/tty-acs.c b/tty-acs.c index 1a57826c..64ba367e 100644 --- a/tty-acs.c +++ b/tty-acs.c @@ -25,7 +25,7 @@ /* Table mapping ACS entries to UTF-8. */ struct tty_acs_entry { - u_char key; + u_char key; const char *string; }; static const struct tty_acs_entry tty_acs_table[] = { @@ -61,7 +61,7 @@ static const struct tty_acs_entry tty_acs_table[] = { { 'x', "\342\224\202" }, /* vertical line */ { 'y', "\342\211\244" }, /* less-than-or-equal-to */ { 'z', "\342\211\245" }, /* greater-than-or-equal-to */ - { '{', "\317\200" }, /* greek pi */ + { '{', "\317\200" }, /* greek pi */ { '|', "\342\211\240" }, /* not-equal */ { '}', "\302\243" }, /* UK pound sign */ { '~', "\302\267" } /* bullet */ @@ -124,7 +124,7 @@ static const struct utf8_data tty_acs_double_borders_list[] = { { "\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 */ + { "\302\267", 0, 2, 1 } /* U+00B7 */ }; /* UTF-8 heavy borders. */ @@ -141,24 +141,24 @@ static const struct utf8_data tty_acs_heavy_borders_list[] = { { "\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 */ + { "\302\267", 0, 2, 1 } /* U+00B7 */ }; /* UTF-8 rounded borders. */ static const struct utf8_data tty_acs_rounded_borders_list[] = { - { "", 0, 0, 0 }, - { "\342\224\202", 0, 3, 1 }, /* U+2502 */ - { "\342\224\200", 0, 3, 1 }, /* U+2500 */ - { "\342\225\255", 0, 3, 1 }, /* U+256D */ - { "\342\225\256", 0, 3, 1 }, /* U+256E */ - { "\342\225\260", 0, 3, 1 }, /* U+2570 */ - { "\342\225\257", 0, 3, 1 }, /* U+256F */ - { "\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 */ + { "", 0, 0, 0 }, + { "\342\224\202", 0, 3, 1 }, /* U+2502 */ + { "\342\224\200", 0, 3, 1 }, /* U+2500 */ + { "\342\225\255", 0, 3, 1 }, /* U+256D */ + { "\342\225\256", 0, 3, 1 }, /* U+256E */ + { "\342\225\260", 0, 3, 1 }, /* U+2570 */ + { "\342\225\257", 0, 3, 1 }, /* U+256F */ + { "\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 */ }; /* Get cell border character for double style. */ From 51ff77d47be80d59b1e30e55bd75788fcc22e4bf Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 18 Oct 2021 09:48:35 +0000 Subject: [PATCH 11/45] Fix menu width containing disabled items, from Alexis Hildebrandt in GitHub issue 2935. --- menu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/menu.c b/menu.c index 4c6403a0..a1c81816 100644 --- a/menu.c +++ b/menu.c @@ -100,6 +100,8 @@ menu_add_item(struct menu *menu, const struct menu_item *item, new_item->key = item->key; width = format_width(new_item->name); + if (*new_item->name == '-') + width--; if (width > menu->width) menu->width = width; } From f26b8c57ffb253db08072629b7c969c021580492 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 19 Oct 2021 12:51:43 +0000 Subject: [PATCH 12/45] Same as -N, don't send if 0 arguments and -R. --- cmd-send-keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-send-keys.c b/cmd-send-keys.c index 46cb37f0..d6a95434 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -203,7 +203,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item) } if (count == 0) { - if (args_has(args, 'N')) + if (args_has(args, 'N') || args_has(args, 'R')) return (CMD_RETURN_NORMAL); for (; np != 0; np--) cmd_send_keys_inject_key(item, NULL, event->key); From 8a9bfd0cddd783436e842495fc3039aa56571ed1 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 20 Oct 2021 09:50:40 +0000 Subject: [PATCH 13/45] Add -T to set a popup title, from Alexis Hildebrandt in GitHub issue 2941. --- cmd-display-menu.c | 14 ++++++++++---- mode-tree.c | 2 +- screen-write.c | 27 ++++++++++++++++----------- tmux.1 | 5 +++++ tmux.h | 6 +++--- window-tree.c | 3 ++- 6 files changed, 37 insertions(+), 20 deletions(-) diff --git a/cmd-display-menu.c b/cmd-display-menu.c index f6531ede..b350ca15 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 = { "Bb:Cc:d:e:Eh:t:w:x:y:", 0, -1, NULL }, + .args = { "Bb:Cc:d:e:Eh:t: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 " " + CMD_TARGET_PANE_USAGE " [-T title] " "[-w width] [-x position] [-y position] [shell-command]", .target = { 't', CMD_FIND_PANE, 0 }, @@ -355,7 +355,7 @@ 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 = NULL, **argv = NULL; + char *cwd, *cause = NULL, **argv = NULL, *title; int flags = 0, argc = 0; enum box_lines lines = BOX_LINES_DEFAULT; u_int px, py, w, h, count = args_count(args); @@ -439,19 +439,25 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item) } } + if (args_has(args, 'T')) + title = format_single_from_target(item, args_get(args, 'T')); + else + title = xstrdup(""); if (args_has(args, 'E') > 1) flags |= POPUP_CLOSEEXITZERO; else if (args_has(args, 'E')) flags |= POPUP_CLOSEEXIT; if (popup_display(flags, lines, item, px, py, w, h, env, shellcmd, argc, - argv, cwd, tc, s, NULL, NULL) != 0) { + argv, cwd, title, tc, s, NULL, NULL) != 0) { cmd_free_argv(argc, argv); if (env != NULL) environ_free(env); + free(title); return (CMD_RETURN_NORMAL); } if (env != NULL) environ_free(env); + free(title); cmd_free_argv(argc, argv); return (CMD_RETURN_WAIT); } diff --git a/mode-tree.c b/mode-tree.c index 2e029691..d4e93208 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, BOX_LINES_DEFAULT, NULL); + screen_write_box(&ctx, w, sy - h, BOX_LINES_DEFAULT, NULL, NULL); if (mtd->sort_list != NULL) { xasprintf(&text, " %s (sort: %s%s)", mti->name, diff --git a/screen-write.c b/screen-write.c index 3cd0fb55..e2904ef6 100644 --- a/screen-write.c +++ b/screen-write.c @@ -646,9 +646,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, - BOX_LINES_DEFAULT, NULL); - screen_write_cursormove(ctx, cx + 2, cy, 0); - format_draw(ctx, &default_gc, menu->width, menu->title, NULL); + BOX_LINES_DEFAULT, &default_gc, menu->title); for (i = 0; i < menu->count; i++) { name = menu->items[i].name; @@ -714,7 +712,7 @@ screen_write_box_border_set(enum box_lines box_lines, int cell_type, /* Draw a box on screen. */ void screen_write_box(struct screen_write_ctx *ctx, u_int nx, u_int ny, - enum box_lines l, const struct grid_cell *gcp) + enum box_lines lines, const struct grid_cell *gcp, const char *title) { struct screen *s = ctx->s; struct grid_cell gc; @@ -727,30 +725,31 @@ screen_write_box(struct screen_write_ctx *ctx, u_int nx, u_int ny, memcpy(&gc, gcp, sizeof gc); else memcpy(&gc, &grid_default_cell, sizeof gc); + gc.attr |= GRID_ATTR_CHARSET; gc.flags |= GRID_FLAG_NOPALETTE; /* Draw top border */ - screen_write_box_border_set(l, CELL_TOPLEFT, &gc); + screen_write_box_border_set(lines, CELL_TOPLEFT, &gc); screen_write_cell(ctx, &gc); - screen_write_box_border_set(l, CELL_LEFTRIGHT, &gc); + screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc); for (i = 1; i < nx - 1; i++) screen_write_cell(ctx, &gc); - screen_write_box_border_set(l, CELL_TOPRIGHT, &gc); + screen_write_box_border_set(lines, CELL_TOPRIGHT, &gc); screen_write_cell(ctx, &gc); /* Draw bottom border */ screen_write_set_cursor(ctx, cx, cy + ny - 1); - screen_write_box_border_set(l, CELL_BOTTOMLEFT, &gc); + screen_write_box_border_set(lines, CELL_BOTTOMLEFT, &gc); screen_write_cell(ctx, &gc); - screen_write_box_border_set(l, CELL_LEFTRIGHT, &gc); + screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc); for (i = 1; i < nx - 1; i++) screen_write_cell(ctx, &gc); - screen_write_box_border_set(l, CELL_BOTTOMRIGHT, &gc); + screen_write_box_border_set(lines, CELL_BOTTOMRIGHT, &gc); screen_write_cell(ctx, &gc); /* Draw sides */ - screen_write_box_border_set(l, CELL_TOPBOTTOM, &gc); + screen_write_box_border_set(lines, CELL_TOPBOTTOM, &gc); for (i = 1; i < ny - 1; i++) { /* left side */ screen_write_set_cursor(ctx, cx, cy + i); @@ -760,6 +759,12 @@ screen_write_box(struct screen_write_ctx *ctx, u_int nx, u_int ny, screen_write_cell(ctx, &gc); } + if (title != NULL) { + gc.attr &= ~GRID_ATTR_CHARSET; + screen_write_cursormove(ctx, cx + 2, cy, 0); + format_draw(ctx, &gc, nx - 4, title, NULL); + } + screen_write_set_cursor(ctx, cx, cy); } diff --git a/tmux.1 b/tmux.1 index ab92be2e..bf615895 100644 --- a/tmux.1 +++ b/tmux.1 @@ -5801,6 +5801,7 @@ forwards any input read from stdin to the empty pane given by .Op Fl e Ar environment .Op Fl h Ar height .Op Fl t Ar target-pane +.Op Fl T Ar title .Op Fl w Ar width .Op Fl x Ar position .Op Fl y Ar position @@ -5858,6 +5859,10 @@ takes the form and sets an environment variable for the popup; it may be specified multiple times. .Pp +.Fl T +is a format for the popup title (see +.Sx FORMATS ) . +.Pp The .Fl C flag closes any popup on the client. diff --git a/tmux.h b/tmux.h index 65a3a571..fc4ad70d 100644 --- a/tmux.h +++ b/tmux.h @@ -2737,7 +2737,7 @@ 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, int, - const struct grid_cell *); + const struct grid_cell *, const char *); void screen_write_preview(struct screen_write_ctx *, struct screen *, u_int, u_int); void screen_write_backspace(struct screen_write_ctx *); @@ -3154,8 +3154,8 @@ typedef void (*popup_close_cb)(int, void *); typedef void (*popup_finish_edit_cb)(char *, size_t, void *); int popup_display(int, int, struct cmdq_item *, u_int, u_int, u_int, u_int, struct environ *, const char *, int, char **, - const char *, struct client *, struct session *, - popup_close_cb, void *); + const 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-tree.c b/window-tree.c index d22a2b58..b594edd9 100644 --- a/window-tree.c +++ b/window-tree.c @@ -519,7 +519,8 @@ 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, BOX_LINES_DEFAULT, NULL); + screen_write_box(ctx, len + 2, 3, BOX_LINES_DEFAULT, NULL, + NULL); } screen_write_cursormove(ctx, px + ox, py + oy, 0); screen_write_puts(ctx, gc, "%s", label); From acba07629ebf2dc2f0c316f110493e720b30757c Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 20 Oct 2021 09:52:27 +0000 Subject: [PATCH 14/45] Remove a TODO comment. --- popup.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/popup.c b/popup.c index 328deba6..549c26e1 100644 --- a/popup.c +++ b/popup.c @@ -32,6 +32,7 @@ struct popup_data { struct cmdq_item *item; int flags; enum box_lines lines; + char *title; struct screen s; struct colour_palette palette; @@ -229,7 +230,8 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx) 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, pd->lines, &bgc); + screen_write_box(&ctx, pd->sx, pd->sy, pd->lines, &bgc, + pd->title); screen_write_cursormove(&ctx, 1, 1, 0); screen_write_fast_copy(&ctx, &pd->s, 0, 0, pd->sx - 2, pd->sy - 2); @@ -287,6 +289,7 @@ popup_free_cb(struct client *c, void *data) screen_free(&pd->s); colour_palette_free(&pd->palette); + free(pd->title); free(pd); } @@ -632,8 +635,8 @@ popup_job_complete_cb(struct job *job) int 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) + int argc, char **argv, const char *cwd, const char *title, struct client *c, + struct session *s, popup_close_cb cb, void *arg) { struct popup_data *pd; u_int jx, jy; @@ -664,6 +667,7 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px, pd->item = item; pd->flags = flags; pd->lines = lines; + pd->title = xstrdup(title); pd->c = c; pd->c->references++; @@ -776,7 +780,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, BOX_LINES_DEFAULT, - NULL, px, py, sx, sy, NULL, cmd, 0, NULL, _PATH_TMP, c, NULL, + NULL, px, py, sx, sy, NULL, cmd, 0, NULL, _PATH_TMP, NULL, c, NULL, popup_editor_close_cb, pe) != 0) { popup_editor_free(pe); free(cmd); From 7bd9cdf6fcf43e0edc8ab3a4accf2009ca5aa35e Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 21 Oct 2021 08:23:48 +0000 Subject: [PATCH 15/45] Show error if user option doesn't exist, GitHub issue 2938. --- cmd-show-options.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cmd-show-options.c b/cmd-show-options.c index bdcd3e78..7ac7e455 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -127,6 +127,12 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item) parent = 0; if (o != NULL) cmd_show_options_print(self, item, o, idx, parent); + else if (*name == '@') { + if (args_has(args, 'q')) + goto fail; + cmdq_error(item, "invalid option: %s", argument); + goto fail; + } free(name); free(argument); From 289ac55ebde18df237ad21734ba4056896d11022 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 21 Oct 2021 08:36:51 +0000 Subject: [PATCH 16/45] Correctly adjust the end pointer for a two character terminator before decoding OSC 52 response, from Daniel Ekloef in GitHub issue 2942. --- tty-keys.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tty-keys.c b/tty-keys.c index 6dfa70f3..65b600c0 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1204,6 +1204,9 @@ tty_keys_clipboard(__unused struct tty *tty, const char *buf, size_t len, buf += 5; end -= 5; + /* Adjust end so that it points to the start of the terminator. */ + end -= terminator - 1; + /* Get the second argument. */ while (end != 0 && *buf != ';') { buf++; From 8235957eaae0aacb1ad0c9b145a1f9d3abc93dfd Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 22 Oct 2021 17:12:50 +0000 Subject: [PATCH 17/45] Remove key and trim text if menu cannot fit in available space, based on a change from Alexis Hildebrandt. --- menu.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/menu.c b/menu.c index a1c81816..45645147 100644 --- a/menu.c +++ b/menu.c @@ -55,10 +55,11 @@ menu_add_item(struct menu *menu, const struct menu_item *item, struct cmdq_item *qitem, struct client *c, struct cmd_find_state *fs) { struct menu_item *new_item; - const char *key, *cmd; + const char *key = NULL, *cmd, *suffix = ""; char *s, *name; - u_int width; + u_int width, max_width; int line; + size_t keylen, slen; line = (item == NULL || item->name == NULL || *item->name == '\0'); if (line && menu->count == 0) @@ -80,11 +81,30 @@ menu_add_item(struct menu *menu, const struct menu_item *item, menu->count--; return; } + max_width = c->tty.sx - 4; + + slen = strlen(s); if (*s != '-' && item->key != KEYC_UNKNOWN && item->key != KEYC_NONE) { key = key_string_lookup_key(item->key, 0); + keylen = strlen(key) + 3; /* 3 = space and two brackets */ + + /* + * Only add the key if there is space for the entire item text + * and the key. + */ + if (keylen >= max_width || slen >= max_width - keylen) + key = NULL; + } + + if (key != NULL) xasprintf(&name, "%s#[default] #[align=right](%s)", s, key); - } else - xasprintf(&name, "%s", s); + else { + if (slen > max_width) { + max_width--; + suffix = ">"; + } + xasprintf(&name, "%.*s%s", (int)max_width, s, suffix); + } new_item->name = name; free(s); From 9b4148b12ca631b9cb8f48a03adb1fad146ee53d Mon Sep 17 00:00:00 2001 From: deraadt Date: Sun, 24 Oct 2021 21:24:17 +0000 Subject: [PATCH 18/45] For open/openat, if the flags parameter does not contain O_CREAT, the 3rd (variadic) mode_t parameter is irrelevant. Many developers in the past have passed mode_t (0, 044, 0644, or such), which might lead future people to copy this broken idiom, and perhaps even believe this parameter has some meaning or implication or application. Delete them all. This comes out of a conversation where tb@ noticed that a strange (but intentional) pledge behaviour is to always knock-out high-bits from mode_t on a number of system calls as a safety factor, and his bewilderment that this appeared to be happening against valid modes (at least visually), but no sorry, they are all irrelevant junk. They could all be 0xdeafbeef. ok millert --- cmd-pipe-pane.c | 2 +- job.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd-pipe-pane.c b/cmd-pipe-pane.c index ed08e618..1a8c851b 100644 --- a/cmd-pipe-pane.c +++ b/cmd-pipe-pane.c @@ -131,7 +131,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item) sigprocmask(SIG_SETMASK, &oldset, NULL); close(pipe_fd[0]); - null_fd = open(_PATH_DEVNULL, O_WRONLY, 0); + null_fd = open(_PATH_DEVNULL, O_WRONLY); if (out) { if (dup2(pipe_fd[1], STDIN_FILENO) == -1) _exit(1); diff --git a/job.c b/job.c index 4c13f943..dad211f4 100644 --- a/job.c +++ b/job.c @@ -142,7 +142,7 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e, struct sessio close(out[1]); close(out[0]); - nullfd = open(_PATH_DEVNULL, O_RDWR, 0); + nullfd = open(_PATH_DEVNULL, O_RDWR); if (nullfd == -1) fatal("open failed"); if (dup2(nullfd, STDERR_FILENO) == -1) From 0cca695d6e75426e295e03668a4ed35ee62afe7c Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 25 Oct 2021 09:22:17 +0000 Subject: [PATCH 19/45] Instead of setting the popup default colours in the draw callback, set it up in popup_display and follow the same routine as panes in the draw and init_ctx callbacks - use the palette if the option value is default. Allows application-set fg and bg to work in panes again. --- popup.c | 74 ++++++++++++++++++++++++++++---------------------- screen-write.c | 6 ++-- tty.c | 7 ++--- 3 files changed, 48 insertions(+), 39 deletions(-) diff --git a/popup.c b/popup.c index 549c26e1..dd83d608 100644 --- a/popup.c +++ b/popup.c @@ -31,11 +31,15 @@ struct popup_data { struct client *c; struct cmdq_item *item; int flags; - enum box_lines lines; char *title; + struct grid_cell border_cell; + enum box_lines border_lines; + struct screen s; + struct grid_cell defaults; struct colour_palette palette; + struct job *job; struct input_ctx *ictx; int status; @@ -119,7 +123,7 @@ popup_set_client_cb(struct tty_ctx *ttyctx, struct client *c) ttyctx->wsx = c->tty.sx; ttyctx->wsy = c->tty.sy; - if (pd->lines == BOX_LINES_NONE) { + if (pd->border_lines == BOX_LINES_NONE) { ttyctx->xoff = ttyctx->rxoff = pd->px; ttyctx->yoff = ttyctx->ryoff = pd->py; } else { @@ -135,6 +139,7 @@ popup_init_ctx_cb(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx) { struct popup_data *pd = ctx->arg; + memcpy(&ttyctx->defaults, &pd->defaults, sizeof ttyctx->defaults); ttyctx->palette = &pd->palette; ttyctx->redraw_cb = popup_redraw_cb; ttyctx->set_client_cb = popup_set_client_cb; @@ -149,7 +154,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->lines == BOX_LINES_NONE) { + if (pd->border_lines == BOX_LINES_NONE) { *cx = pd->px + pd->s.cx; *cy = pd->py + pd->s.cy; } else { @@ -213,36 +218,29 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx) struct screen_write_ctx ctx; 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; + struct grid_cell defaults; 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); - bgc.attr = 0; - style_apply(&bgc, o, "popup-border-style", NULL); - bgc.attr = 0; - - if (pd->lines == BOX_LINES_NONE) { + if (pd->border_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, pd->lines, &bgc, - pd->title); + screen_write_box(&ctx, pd->sx, pd->sy, pd->border_lines, + &pd->border_cell, pd->title); screen_write_cursormove(&ctx, 1, 1, 0); screen_write_fast_copy(&ctx, &pd->s, 0, 0, pd->sx - 2, pd->sy - 2); } screen_write_stop(&ctx); - memcpy(&gc, &grid_default_cell, sizeof gc); - style_apply(&gc, o, "popup-style", NULL); - gc.attr = 0; - palette->fg = gc.fg; - palette->bg = gc.bg; + memcpy(&defaults, &pd->defaults, sizeof defaults); + if (COLOUR_DEFAULT(defaults.fg)) + defaults.fg = palette->fg; + if (COLOUR_DEFAULT(defaults.bg)) + defaults.bg = palette->bg; if (pd->md != NULL) { c->overlay_check = menu_check_cb; @@ -251,8 +249,10 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx) c->overlay_check = NULL; c->overlay_data = NULL; } - for (i = 0; i < pd->sy; i++) - tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i, &gc, palette); + for (i = 0; i < pd->sy; i++) { + tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i, &defaults, + palette); + } if (pd->md != NULL) { c->overlay_check = NULL; c->overlay_data = NULL; @@ -323,7 +323,7 @@ popup_resize_cb(__unused struct client *c, void *data) pd->px = pd->ppx; /* Avoid zero size screens. */ - if (pd->lines == BOX_LINES_NONE) { + if (pd->border_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 ); @@ -449,7 +449,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->lines == BOX_LINES_NONE) { + if (pd->border_lines == BOX_LINES_NONE) { if (m->x < pd->px + 1) return; if (m->y < pd->py + 1) @@ -465,7 +465,7 @@ popup_handle_drag(struct client *c, struct popup_data *pd, pd->psx = pd->sx; pd->psy = pd->sy; - if (pd->lines == BOX_LINES_NONE) { + if (pd->border_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); @@ -513,7 +513,7 @@ popup_key_cb(struct client *c, void *data, struct key_event *event) goto menu; return (0); } - if (pd->lines != BOX_LINES_NONE) { + if (pd->border_lines != BOX_LINES_NONE) { if (m->x == pd->px) border = LEFT; else if (m->x == pd->px + pd->sx - 1) @@ -547,7 +547,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->lines == BOX_LINES_NONE) { + if (pd->border_lines == BOX_LINES_NONE) { px = m->x - pd->px; py = m->y - pd->py; } else { @@ -642,13 +642,13 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px, u_int jx, jy; struct options *o; - if (lines == BOX_LINES_DEFAULT) { - if (s != NULL) - o = s->curw->window->options; - else - o = c->session->curw->window->options; + if (s != NULL) + o = s->curw->window->options; + else + o = c->session->curw->window->options; + + if (lines == BOX_LINES_DEFAULT) lines = options_get_number(o, "popup-border-lines"); - } if (lines == BOX_LINES_NONE) { if (sx < 1 || sy < 1) return (-1); @@ -666,7 +666,6 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px, pd = xcalloc(1, sizeof *pd); pd->item = item; pd->flags = flags; - pd->lines = lines; pd->title = xstrdup(title); pd->c = c; @@ -676,10 +675,19 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px, pd->arg = arg; pd->status = 128 + SIGHUP; + pd->border_lines = lines; + memcpy(&pd->border_cell, &grid_default_cell, sizeof pd->border_cell); + style_apply(&pd->border_cell, o, "popup-border-style", NULL); + pd->border_cell.attr = 0; + screen_init(&pd->s, sx - 2, sy - 2, 0); colour_palette_init(&pd->palette); colour_palette_from_option(&pd->palette, global_w_options); + memcpy(&pd->defaults, &grid_default_cell, sizeof pd->defaults); + style_apply(&pd->defaults, o, "popup-style", NULL); + pd->defaults.attr = 0; + pd->px = px; pd->py = py; pd->sx = sx; diff --git a/screen-write.c b/screen-write.c index e2904ef6..251ca823 100644 --- a/screen-write.c +++ b/screen-write.c @@ -184,8 +184,10 @@ screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, if (ctx->init_ctx_cb != NULL) { ctx->init_ctx_cb(ctx, ttyctx); if (ttyctx->palette != NULL) { - ttyctx->defaults.fg = ttyctx->palette->fg; - ttyctx->defaults.bg = ttyctx->palette->bg; + if (COLOUR_DEFAULT(ttyctx->defaults.fg)) + ttyctx->defaults.fg = ttyctx->palette->fg; + if (COLOUR_DEFAULT(ttyctx->defaults.bg)) + ttyctx->defaults.bg = ttyctx->palette->bg; } } else { ttyctx->redraw_cb = screen_write_redraw_cb; diff --git a/tty.c b/tty.c index 809289e0..243eae56 100644 --- a/tty.c +++ b/tty.c @@ -1972,10 +1972,9 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) 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; + tty_draw_line(tty, s, s->cx, s->cy, gcp->data.width, + px, py, &ctx->defaults, ctx->palette); + return; } } From ef46eb91a5e0b6e2b023544f45dbc98c8fe1377f Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 25 Oct 2021 09:38:36 +0000 Subject: [PATCH 20/45] Add -s and -S to display-popup to set popup and border style, from Alexis Hildebrandt in GitHub issue 2931. --- cmd-display-menu.c | 11 +++++++---- popup.c | 24 ++++++++++++++++++++---- screen-write.c | 4 ++-- tmux.1 | 12 ++++++++++++ tmux.h | 3 ++- 5 files changed, 43 insertions(+), 11 deletions(-) diff --git a/cmd-display-menu.c b/cmd-display-menu.c index b350ca15..6ecfad29 100644 --- a/cmd-display-menu.c +++ b/cmd-display-menu.c @@ -53,11 +53,12 @@ const struct cmd_entry cmd_display_popup_entry = { .name = "display-popup", .alias = "popup", - .args = { "Bb:Cc:d:e:Eh:t:T:w:x:y:", 0, -1, NULL }, + .args = { "Bb:Cc:d:e:Eh:s:S:t: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 " [-T title] " - "[-w width] [-x position] [-y position] [shell-command]", + "[-s style] [-S border-style] " CMD_TARGET_PANE_USAGE + "[-T title] [-w width] [-x position] [-y position] " + "[shell-command]", .target = { 't', CMD_FIND_PANE, 0 }, @@ -355,6 +356,8 @@ 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; + const char *style = args_get(args, 's'); + const char *border_style = args_get(args, 'S'); char *cwd, *cause = NULL, **argv = NULL, *title; int flags = 0, argc = 0; enum box_lines lines = BOX_LINES_DEFAULT; @@ -448,7 +451,7 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item) else if (args_has(args, 'E')) flags |= POPUP_CLOSEEXIT; if (popup_display(flags, lines, item, px, py, w, h, env, shellcmd, argc, - argv, cwd, title, tc, s, NULL, NULL) != 0) { + argv, cwd, title, tc, s, style, border_style, NULL, NULL) != 0) { cmd_free_argv(argc, argv); if (env != NULL) environ_free(env); diff --git a/popup.c b/popup.c index dd83d608..ed6a6bb9 100644 --- a/popup.c +++ b/popup.c @@ -237,9 +237,9 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx) screen_write_stop(&ctx); memcpy(&defaults, &pd->defaults, sizeof defaults); - if (COLOUR_DEFAULT(defaults.fg)) + if (defaults.fg == 8) defaults.fg = palette->fg; - if (COLOUR_DEFAULT(defaults.bg)) + if (defaults.bg == 8) defaults.bg = palette->bg; if (pd->md != NULL) { @@ -636,11 +636,13 @@ int 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, const char *title, struct client *c, - struct session *s, popup_close_cb cb, void *arg) + struct session *s, const char* style, const char* border_style, + popup_close_cb cb, void *arg) { struct popup_data *pd; u_int jx, jy; struct options *o; + struct style sytmp; if (s != NULL) o = s->curw->window->options; @@ -678,6 +680,13 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px, pd->border_lines = lines; memcpy(&pd->border_cell, &grid_default_cell, sizeof pd->border_cell); style_apply(&pd->border_cell, o, "popup-border-style", NULL); + if (border_style != NULL) { + style_set(&sytmp, &grid_default_cell); + if (style_parse(&sytmp, &pd->border_cell, border_style) == 0) { + pd->border_cell.fg = sytmp.gc.fg; + pd->border_cell.bg = sytmp.gc.bg; + } + } pd->border_cell.attr = 0; screen_init(&pd->s, sx - 2, sy - 2, 0); @@ -686,6 +695,13 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px, memcpy(&pd->defaults, &grid_default_cell, sizeof pd->defaults); style_apply(&pd->defaults, o, "popup-style", NULL); + if (style != NULL) { + style_set(&sytmp, &grid_default_cell); + if (style_parse(&sytmp, &pd->defaults, style) == 0) { + pd->defaults.fg = sytmp.gc.fg; + pd->defaults.bg = sytmp.gc.bg; + } + } pd->defaults.attr = 0; pd->px = px; @@ -789,7 +805,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, BOX_LINES_DEFAULT, NULL, px, py, sx, sy, NULL, cmd, 0, NULL, _PATH_TMP, NULL, c, NULL, - popup_editor_close_cb, pe) != 0) { + NULL, NULL, popup_editor_close_cb, pe) != 0) { popup_editor_free(pe); free(cmd); return (-1); diff --git a/screen-write.c b/screen-write.c index 251ca823..cead12d4 100644 --- a/screen-write.c +++ b/screen-write.c @@ -184,9 +184,9 @@ screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, if (ctx->init_ctx_cb != NULL) { ctx->init_ctx_cb(ctx, ttyctx); if (ttyctx->palette != NULL) { - if (COLOUR_DEFAULT(ttyctx->defaults.fg)) + if (ttyctx->defaults.fg == 8) ttyctx->defaults.fg = ttyctx->palette->fg; - if (COLOUR_DEFAULT(ttyctx->defaults.bg)) + if (ttyctx->defaults.bg == 8) ttyctx->defaults.bg = ttyctx->palette->bg; } } else { diff --git a/tmux.1 b/tmux.1 index bf615895..9bedb20b 100644 --- a/tmux.1 +++ b/tmux.1 @@ -5800,6 +5800,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 t Ar target-pane .Op Fl T Ar title .Op Fl w Ar width @@ -5853,6 +5855,16 @@ See for possible values for .Ar border-lines . .Pp +.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. +.Pp .Fl e takes the form .Ql VARIABLE=value diff --git a/tmux.h b/tmux.h index fc4ad70d..f2957de9 100644 --- a/tmux.h +++ b/tmux.h @@ -3155,7 +3155,8 @@ typedef void (*popup_finish_edit_cb)(char *, size_t, void *); int popup_display(int, int, struct cmdq_item *, u_int, u_int, u_int, u_int, struct environ *, const char *, int, char **, const char *, const char *, struct client *, - struct session *, popup_close_cb, void *); + struct session *, const char *, const char *, + popup_close_cb, void *); int popup_editor(struct client *, const char *, size_t, popup_finish_edit_cb, void *); From eb82ad5216f1538e13f4ad7c2d36f28fedd88310 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 25 Oct 2021 20:32:42 +0000 Subject: [PATCH 21/45] Missing Pp, from Alexis Hildebrandt. --- tmux.1 | 1 + 1 file changed, 1 insertion(+) diff --git a/tmux.1 b/tmux.1 index 9bedb20b..c270309f 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4214,6 +4214,7 @@ see the .Sx STYLES section. Attributes are ignored. +.Pp .It Ic pane-base-index Ar index Like .Ic base-index , From 197a116f5a2146309c4c6fecbd9d08d36f2be750 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 25 Oct 2021 21:21:16 +0000 Subject: [PATCH 22/45] Add a way to force a colour to RGB and a format to display it. --- colour.c | 15 +++++++++++++++ format.c | 24 ++++++++++++++++++++---- tmux.1 | 4 ++++ tmux.h | 1 + 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/colour.c b/colour.c index 9ac07415..92bbd71e 100644 --- a/colour.c +++ b/colour.c @@ -105,6 +105,21 @@ colour_split_rgb(int c, u_char *r, u_char *g, u_char *b) *b = c & 0xff; } +/* Force colour to RGB if not already. */ +int +colour_force_rgb(int c) +{ + if (c & COLOUR_FLAG_RGB) + return (c); + if (c & COLOUR_FLAG_256) + return (colour_256toRGB(c)); + if (c >= 0 && c <= 7) + return (colour_256toRGB(c)); + if (c >= 90 & c <= 97) + return (colour_256toRGB(8 + c - 90)); + return (-1); +} + /* Convert colour to a string. */ const char * colour_tostring(int c) diff --git a/format.c b/format.c index f5d2c5f6..b34fc341 100644 --- a/format.c +++ b/format.c @@ -101,6 +101,7 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2) #define FORMAT_WINDOW_NAME 0x4000 #define FORMAT_SESSION_NAME 0x8000 #define FORMAT_CHARACTER 0x10000 +#define FORMAT_COLOUR 0x20000 /* Limit on recursion. */ #define FORMAT_LOOP_LIMIT 100 @@ -3555,7 +3556,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s, /* * Modifiers are a ; separated list of the forms: - * l,m,C,a,b,d,n,t,w,q,E,T,S,W,P,<,> + * l,m,C,a,b,c,d,n,t,w,q,E,T,S,W,P,<,> * =a * =/a * =/a/ @@ -3572,7 +3573,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s, cp++; /* Check single character modifiers with no arguments. */ - if (strchr("labdnwETSWP<>", cp[0]) != NULL && + if (strchr("labcdnwETSWP<>", cp[0]) != NULL && format_is_end(cp[1])) { format_add_modifier(&list, count, cp, 1, NULL, 0); cp++; @@ -4052,10 +4053,10 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen, const char *errstr, *copy, *cp, *marker = NULL; const char *time_format = NULL; char *copy0, *condition, *found, *new; - char *value, *left, *right, c; + char *value, *left, *right; size_t valuelen; int modifiers = 0, limit = 0, width = 0; - int j; + int j, c; struct format_modifier *list, *cmp = NULL, *search = NULL; struct format_modifier **sub = NULL, *mexp = NULL, *fm; u_int i, count, nsub = 0; @@ -4126,6 +4127,9 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen, case 'b': modifiers |= FORMAT_BASENAME; break; + case 'c': + modifiers |= FORMAT_COLOUR; + break; case 'd': modifiers |= FORMAT_DIRNAME; break; @@ -4201,6 +4205,18 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen, goto done; } + /* Is this a colour? */ + if (modifiers & FORMAT_COLOUR) { + new = format_expand1(es, copy); + c = colour_fromstring(new); + if (c == -1 || (c = colour_force_rgb(c)) == -1) + value = xstrdup(""); + else + xasprintf(&value, "%06x", c & 0xffffff); + free(new); + goto done; + } + /* Is this a loop, comparison or condition? */ if (modifiers & FORMAT_SESSIONS) { value = format_loop_sessions(es, copy); diff --git a/tmux.1 b/tmux.1 index c270309f..35a87bd0 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4831,6 +4831,10 @@ replaces a numeric argument by its ASCII equivalent, so .Ql #{a:98} results in .Ql b . +.Ql c +replaces a +.Nm +colour by its six-digit hexadecimal RGB value. .Pp A limit may be placed on the length of the resultant string by prefixing it by an diff --git a/tmux.h b/tmux.h index f2957de9..e3896132 100644 --- a/tmux.h +++ b/tmux.h @@ -2616,6 +2616,7 @@ int input_key_get_mouse(struct screen *, struct mouse_event *, u_int, int colour_find_rgb(u_char, u_char, u_char); int colour_join_rgb(u_char, u_char, u_char); void colour_split_rgb(int, u_char *, u_char *, u_char *); +int colour_force_rgb(int); const char *colour_tostring(int); int colour_fromstring(const char *s); int colour_256toRGB(int); From 5745bd27fdfd0e806fb3f734966f66f302c76c48 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 26 Oct 2021 12:22:23 +0000 Subject: [PATCH 23/45] Do not allow inline styles to replace mode-style for the selected item, from Alexis Hildebrandt in GitHub issue 2946. --- format-draw.c | 7 ++++++- mode-tree.c | 4 ++-- screen-redraw.c | 2 +- screen-write.c | 8 +++++--- tmux.h | 2 +- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/format-draw.c b/format-draw.c index 6164cc44..1110535f 100644 --- a/format-draw.c +++ b/format-draw.c @@ -677,7 +677,8 @@ format_draw_many(struct screen_write_ctx *ctx, struct style *sy, char ch, /* Draw a format to a screen. */ void format_draw(struct screen_write_ctx *octx, const struct grid_cell *base, - u_int available, const char *expanded, struct style_ranges *srs) + u_int available, const char *expanded, struct style_ranges *srs, + int default_colours) { enum { LEFT, CENTRE, @@ -819,6 +820,10 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base, log_debug("%s: style '%s' -> '%s'", __func__, tmp, style_tostring(&sy)); free(tmp); + if (default_colours) { + sy.gc.bg = base->bg; + sy.gc.fg = base->fg; + } /* If this style has a fill colour, store it for later. */ if (sy.fill != 8) diff --git a/mode-tree.c b/mode-tree.c index d4e93208..85027caf 100644 --- a/mode-tree.c +++ b/mode-tree.c @@ -716,14 +716,14 @@ mode_tree_draw(struct mode_tree_data *mtd) screen_write_nputs(&ctx, w, &gc0, "%s", text); if (mti->text != NULL) { format_draw(&ctx, &gc0, w - width, mti->text, - NULL); + NULL, 0); } } else { screen_write_clearendofline(&ctx, gc.bg); screen_write_nputs(&ctx, w, &gc, "%s", text); if (mti->text != NULL) { format_draw(&ctx, &gc, w - width, mti->text, - NULL); + NULL, 0); } } free(text); diff --git a/screen-redraw.c b/screen-redraw.c index 11900b4f..0326c12d 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -400,7 +400,7 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp, gc.attr &= ~GRID_ATTR_CHARSET; screen_write_cursormove(&ctx, 0, 0, 0); - format_draw(&ctx, &gc, width, expanded, NULL); + format_draw(&ctx, &gc, width, expanded, NULL, 0); screen_write_stop(&ctx); free(expanded); diff --git a/screen-write.c b/screen-write.c index cead12d4..0d70f668 100644 --- a/screen-write.c +++ b/screen-write.c @@ -665,10 +665,12 @@ screen_write_menu(struct screen_write_ctx *ctx, struct menu *menu, if (*name == '-') { name++; default_gc.attr |= GRID_ATTR_DIM; - format_draw(ctx, gc, menu->width, name, NULL); + format_draw(ctx, gc, menu->width, name, NULL, + 0); default_gc.attr &= ~GRID_ATTR_DIM; } else - format_draw(ctx, gc, menu->width, name, NULL); + format_draw(ctx, gc, menu->width, name, NULL, + gc == choice_gc); gc = &default_gc; } } @@ -764,7 +766,7 @@ screen_write_box(struct screen_write_ctx *ctx, u_int nx, u_int ny, if (title != NULL) { gc.attr &= ~GRID_ATTR_CHARSET; screen_write_cursormove(ctx, cx + 2, cy, 0); - format_draw(ctx, &gc, nx - 4, title, NULL); + format_draw(ctx, &gc, nx - 4, title, NULL, 0); } screen_write_set_cursor(ctx, cx, cy); diff --git a/tmux.h b/tmux.h index e3896132..0d3c923f 100644 --- a/tmux.h +++ b/tmux.h @@ -2032,7 +2032,7 @@ char *format_grid_line(struct grid *, u_int); /* format-draw.c */ void format_draw(struct screen_write_ctx *, const struct grid_cell *, u_int, const char *, - struct style_ranges *); + struct style_ranges *, int); u_int format_width(const char *); char *format_trim_left(const char *, u_int); char *format_trim_right(const char *, u_int); From 9695114230613f57c11936ae0e1fe2cd6ba0a7b4 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 26 Oct 2021 12:29:41 +0000 Subject: [PATCH 24/45] Accept some emacs control keys in vi normal mode, from Alexis Hildebrandt in GitHub issue 2922. --- status.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/status.c b/status.c index b442e85d..65c81386 100644 --- a/status.c +++ b/status.c @@ -439,7 +439,8 @@ status_redraw(struct client *c) screen_write_cursormove(&ctx, 0, i, 0); status_free_ranges(&sle->ranges); - format_draw(&ctx, &gc, width, expanded, &sle->ranges); + format_draw(&ctx, &gc, width, expanded, &sle->ranges, + 0); free(sle->expanded); sle->expanded = expanded; @@ -562,7 +563,7 @@ status_message_redraw(struct client *c) if (c->message_ignore_styles) screen_write_nputs(&ctx, len, &gc, "%s", c->message_string); else - format_draw(&ctx, &gc, c->tty.sx, c->message_string, NULL); + format_draw(&ctx, &gc, c->tty.sx, c->message_string, NULL, 0); screen_write_stop(&ctx); if (grid_compare(sl->active->grid, old_screen.grid) == 0) { @@ -809,14 +810,23 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key) { if (c->prompt_mode == PROMPT_ENTRY) { switch (key) { + case '\001': /* C-a */ case '\003': /* C-c */ + case '\005': /* C-e */ case '\007': /* C-g */ case '\010': /* C-h */ case '\011': /* Tab */ + case '\013': /* C-k */ + case '\016': /* C-n */ + case '\020': /* C-p */ + case '\024': /* C-t */ case '\025': /* C-u */ case '\027': /* C-w */ + case '\031': /* C-y */ case '\n': case '\r': + case KEYC_LEFT|KEYC_CTRL: + case KEYC_RIGHT|KEYC_CTRL: case KEYC_BSPACE: case KEYC_DC: case KEYC_DOWN: @@ -837,6 +847,9 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key) } switch (key) { + case KEYC_BSPACE: + *new_key = KEYC_LEFT; + return (1); case 'A': case 'I': case 'C': @@ -882,7 +895,7 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key) *new_key = 'B'|KEYC_VI; return (1); case 'd': - *new_key = '\025'; + *new_key = '\025'; /* C-u */ return (1); case 'e': *new_key = 'e'|KEYC_VI; From 76f5d3364c8d822989adbf0d3f7bc7c27981110b Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 28 Oct 2021 18:39:15 +0000 Subject: [PATCH 25/45] Expand command as a format, GitHub issue 2920. --- cmd-confirm-before.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index 95841962..ce8c95e0 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -72,7 +72,7 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item) int wait = !args_has(args, 'b'); cdata = xcalloc(1, sizeof *cdata); - cdata->cmdlist = args_make_commands_now(self, item, 0, 0); + cdata->cmdlist = args_make_commands_now(self, item, 0, 1); if (cdata->cmdlist == NULL) return (CMD_RETURN_ERROR); From 49d33a4282dad9245cc644b9259b40ae94bc0063 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 28 Oct 2021 18:54:33 +0000 Subject: [PATCH 26/45] Allow detach even if suspend flag set, GitHub issue 2932. --- server-client.c | 2 +- tmux.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/server-client.c b/server-client.c index dc5074e7..7cea32c0 100644 --- a/server-client.c +++ b/server-client.c @@ -516,7 +516,7 @@ server_client_detach(struct client *c, enum msgtype msgtype) { struct session *s = c->session; - if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS)) + if (s == NULL || (c->flags & CLIENT_NODETACHFLAGS)) return; c->flags |= CLIENT_EXIT; diff --git a/tmux.h b/tmux.h index 0d3c923f..59e1687d 100644 --- a/tmux.h +++ b/tmux.h @@ -1710,6 +1710,9 @@ struct client { (CLIENT_DEAD| \ CLIENT_SUSPENDED| \ CLIENT_EXIT) +#define CLIENT_NODETACHFLAGS \ + (CLIENT_DEAD| \ + CLIENT_EXIT) #define CLIENT_NOSIZEFLAGS \ (CLIENT_DEAD| \ CLIENT_SUSPENDED| \ From 4acad43013b7bb5f91103a68cfce591b1980ae17 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 28 Oct 2021 18:57:06 +0000 Subject: [PATCH 27/45] Do not force the cursor to move if it is in the automargin space at EOL and that is where we want it to be, GitHub issue 2956. --- tty.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tty.c b/tty.c index 243eae56..62298a54 100644 --- a/tty.c +++ b/tty.c @@ -2278,17 +2278,25 @@ tty_cursor(struct tty *tty, u_int cx, u_int cy) if (tty->flags & TTY_BLOCK) return; - if (cx > tty->sx - 1) - cx = tty->sx - 1; - thisx = tty->cx; thisy = tty->cy; + /* + * If in the automargin space, and want to be there, do not move. + * Otherwise, force the cursor to be in range (and complain). + */ + if (cx == thisx && cy == thisy && cx == tty->sx) + return; + if (cx > tty->sx - 1) { + log_debug("%s: x too big %u > %u", __func__, cx, tty->sx - 1); + cx = tty->sx - 1; + } + /* No change. */ if (cx == thisx && cy == thisy) return; - /* Very end of the line, just use absolute movement. */ + /* Currently at the very end of the line - use absolute movement. */ if (thisx > tty->sx - 1) goto absolute; From c76904343a3ddfea3c58ec00d9904c16574a8af3 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Fri, 29 Oct 2021 08:36:40 +0100 Subject: [PATCH 28/45] Spelling, from someone in GitHub issue 2958. --- tools/ansicode.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ansicode.txt b/tools/ansicode.txt index 8767b9e7..5a9c79e0 100644 --- a/tools/ansicode.txt +++ b/tools/ansicode.txt @@ -184,7 +184,7 @@ Oct Hex Name * (* marks function used in DEC VT series or LA series terminals) 230 98 X Reserved for for future standard 231 99 Y Reserved 232 9A Z * Reserved, but causes DEC terminals to respond with DA codes -233 9B [ CSI * Control Sequence Introducer (described in a seperate table) +233 9B [ CSI * Control Sequence Introducer (described in a separate table) 234 9C \ ST * String Terminator (VT125 exits graphics) 235 9D ] OSC Operating System Command (reprograms intelligent terminal) 236 9E ^ PM Privacy Message (password verification), terminated by ST From 4fe5aa99fb203ddb25089955d8814e1065e11a60 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 1 Nov 2021 07:48:04 +0000 Subject: [PATCH 29/45] Fix a comparison, from Ben Boeckel, and a crash when opening completion menu, from Anindya Mukherjee. --- colour.c | 2 +- status.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/colour.c b/colour.c index 92bbd71e..6ede25da 100644 --- a/colour.c +++ b/colour.c @@ -115,7 +115,7 @@ colour_force_rgb(int c) return (colour_256toRGB(c)); if (c >= 0 && c <= 7) return (colour_256toRGB(c)); - if (c >= 90 & c <= 97) + if (c >= 90 && c <= 97) return (colour_256toRGB(8 + c - 90)); return (-1); } diff --git a/status.c b/status.c index 65c81386..d499eab8 100644 --- a/status.c +++ b/status.c @@ -1727,7 +1727,7 @@ status_prompt_complete_list_menu(struct client *c, char **list, u_int size, item.name = list[i]; item.key = '0' + (i - spm->start); item.command = NULL; - menu_add_item(menu, &item, NULL, NULL, NULL); + menu_add_item(menu, &item, NULL, c, NULL); } if (options_get_number(c->session->options, "status-position") == 0) From 8d2286b76917debc4f6c3b0903ad2807ae254bb5 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 1 Nov 2021 09:34:49 +0000 Subject: [PATCH 30/45] Add a cursor-colour option, from Alexis Hildebrandt in GitHub issue 2959. --- input.c | 47 +++++++++++++++++++++++++++++++++++++++++------ options-table.c | 8 ++++++++ options.c | 9 ++++++++- screen.c | 9 ++++----- tmux.1 | 3 +++ tmux.h | 7 ++++--- tty.c | 43 ++++++++++++++++++++++++++++--------------- 7 files changed, 96 insertions(+), 30 deletions(-) diff --git a/input.c b/input.c index 8a16281c..b2769e31 100644 --- a/input.c +++ b/input.c @@ -137,10 +137,12 @@ static void input_reset_cell(struct input_ctx *); static void input_osc_4(struct input_ctx *, const char *); static void input_osc_10(struct input_ctx *, const char *); static void input_osc_11(struct input_ctx *, const char *); +static void input_osc_12(struct input_ctx *, const char *); static void input_osc_52(struct input_ctx *, const char *); static void input_osc_104(struct input_ctx *, const char *); static void input_osc_110(struct input_ctx *, const char *); static void input_osc_111(struct input_ctx *, const char *); +static void input_osc_112(struct input_ctx *, const char *); /* Transition entry/exit handlers. */ static void input_clear(struct input_ctx *); @@ -2310,8 +2312,7 @@ input_exit_osc(struct input_ctx *ictx) input_osc_11(ictx, p); break; case 12: - if (utf8_isvalid(p) && *p != '?') /* ? is colour request */ - screen_set_cursor_colour(sctx->s, p); + input_osc_12(ictx, p); break; case 52: input_osc_52(ictx, p); @@ -2326,8 +2327,7 @@ input_exit_osc(struct input_ctx *ictx) input_osc_111(ictx, p); break; case 112: - if (*p == '\0') /* no arguments allowed */ - screen_set_cursor_colour(sctx->s, ""); + input_osc_112(ictx, p); break; default: log_debug("%s: unknown '%u'", __func__, option); @@ -2489,7 +2489,9 @@ input_osc_colour_reply(struct input_ctx *ictx, u_int n, int c) u_char r, g, b; const char *end; - if (c == 8 || (~c & COLOUR_FLAG_RGB)) + if (c != -1) + c = colour_force_rgb(c); + if (c == -1) return; colour_split_rgb(c, &r, &g, &b); @@ -2564,7 +2566,7 @@ input_osc_10(struct input_ctx *ictx, const char *p) } } -/* Handle the OSC 110 sequence for resetting background colour. */ +/* Handle the OSC 110 sequence for resetting foreground colour. */ static void input_osc_110(struct input_ctx *ictx, const char *p) { @@ -2624,6 +2626,39 @@ input_osc_111(struct input_ctx *ictx, const char *p) } } +/* Handle the OSC 12 sequence for setting and querying cursor colour. */ +static void +input_osc_12(struct input_ctx *ictx, const char *p) +{ + struct window_pane *wp = ictx->wp; + int c; + + if (strcmp(p, "?") == 0) { + if (wp != NULL) { + c = ictx->ctx.s->ccolour; + if (c == -1) + c = ictx->ctx.s->default_ccolour; + input_osc_colour_reply(ictx, 12, c); + } + return; + } + + if ((c = input_osc_parse_colour(p)) == -1) { + log_debug("bad OSC 12: %s", p); + return; + } + screen_set_cursor_colour(ictx->ctx.s, c); +} + +/* Handle the OSC 112 sequence for resetting cursor colour. */ +static void +input_osc_112(struct input_ctx *ictx, const char *p) +{ + if (*p == '\0') /* no arguments allowed */ + screen_set_cursor_colour(ictx->ctx.s, -1); +} + + /* Handle the OSC 52 sequence for setting the clipboard. */ static void input_osc_52(struct input_ctx *ictx, const char *p) diff --git a/options-table.c b/options-table.c index 6c57e3ff..d23f7d57 100644 --- a/options-table.c +++ b/options-table.c @@ -188,6 +188,7 @@ const struct options_name_map options_other_names[] = { { "display-panes-color", "display-panes-colour" }, { "display-panes-active-color", "display-panes-active-colour" }, { "clock-mode-color", "clock-mode-colour" }, + { "cursor-color", "cursor-colour" }, { "pane-colors", "pane-colours" }, { NULL, NULL } }; @@ -235,6 +236,13 @@ const struct options_table_entry options_table[] = { "If empty, no command is run." }, + { .name = "cursor-colour", + .type = OPTIONS_TABLE_COLOUR, + .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, + .default_num = -1, + .text = "Colour of the cursor." + }, + { .name = "default-terminal", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_SERVER, diff --git a/options.c b/options.c index 65263fd0..4da1c408 100644 --- a/options.c +++ b/options.c @@ -1106,15 +1106,22 @@ options_push_changes(const char *name) struct session *s; struct window *w; struct window_pane *wp; + int c; if (strcmp(name, "automatic-rename") == 0) { RB_FOREACH(w, windows, &windows) { if (w->active == NULL) continue; - if (options_get_number(w->options, "automatic-rename")) + if (options_get_number(w->options, name)) w->active->flags |= PANE_CHANGED; } } + if (strcmp(name, "cursor-colour") == 0) { + RB_FOREACH(wp, window_pane_tree, &all_window_panes) { + c = options_get_number(wp->options, name); + wp->screen->default_ccolour = c; + } + } if (strcmp(name, "key-table") == 0) { TAILQ_FOREACH(loop, &clients, entry) server_client_set_key_table(loop, NULL); diff --git a/screen.c b/screen.c index 4c13b693..bc95705a 100644 --- a/screen.c +++ b/screen.c @@ -82,7 +82,8 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit) s->path = NULL; s->cstyle = SCREEN_CURSOR_DEFAULT; - s->ccolour = xstrdup(""); + s->ccolour = -1; + s->default_ccolour = -1; s->tabs = NULL; s->sel = NULL; @@ -126,7 +127,6 @@ screen_free(struct screen *s) free(s->tabs); free(s->path); free(s->title); - free(s->ccolour); if (s->write_list != NULL) screen_write_free_list(s); @@ -190,10 +190,9 @@ screen_set_cursor_style(struct screen *s, u_int style) /* Set screen cursor colour. */ void -screen_set_cursor_colour(struct screen *s, const char *colour) +screen_set_cursor_colour(struct screen *s, int colour) { - free(s->ccolour); - s->ccolour = xstrdup(colour); + s->ccolour = colour; } /* Set screen title. */ diff --git a/tmux.1 b/tmux.1 index 35a87bd0..eb2340e3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4416,6 +4416,9 @@ The alternate screen feature preserves the contents of the window when an interactive application starts and restores it on exit, so that any output visible before the application starts reappears unchanged after it exits. .Pp +.It Ic cursor-colour Ar colour +Set the colour of the cursor. +.Pp .It Ic pane-colours[] Ar colour The default colour palette. Each entry in the array defines the colour diff --git a/tmux.h b/tmux.h index 59e1687d..62c84cc7 100644 --- a/tmux.h +++ b/tmux.h @@ -779,7 +779,8 @@ struct screen { u_int cy; /* cursor y */ enum screen_cursor_style cstyle; /* cursor style */ - char *ccolour; /* cursor colour */ + int ccolour; /* cursor colour */ + int default_ccolour; u_int rupper; /* scroll region top */ u_int rlower; /* scroll region bottom */ @@ -1276,7 +1277,7 @@ struct tty { u_int cx; u_int cy; enum screen_cursor_style cstyle; - char *ccolour; + int ccolour; int oflag; u_int oox; @@ -2793,7 +2794,7 @@ void screen_reinit(struct screen *); void screen_free(struct screen *); void screen_reset_tabs(struct screen *); void screen_set_cursor_style(struct screen *, u_int); -void screen_set_cursor_colour(struct screen *, const char *); +void screen_set_cursor_colour(struct screen *, int); int screen_set_title(struct screen *, const char *); void screen_set_path(struct screen *, const char *); void screen_push_title(struct screen *); diff --git a/tty.c b/tty.c index 62298a54..38a7a752 100644 --- a/tty.c +++ b/tty.c @@ -38,7 +38,7 @@ static int tty_client_ready(struct client *); static void tty_set_italics(struct tty *); static int tty_try_colour(struct tty *, int, const char *); -static void tty_force_cursor_colour(struct tty *, const char *); +static void tty_force_cursor_colour(struct tty *, int); static void tty_cursor_pane(struct tty *, const struct tty_ctx *, u_int, u_int); static void tty_cursor_pane_unless_wrap(struct tty *, @@ -105,7 +105,7 @@ tty_init(struct tty *tty, struct client *c) tty->client = c; tty->cstyle = SCREEN_CURSOR_DEFAULT; - tty->ccolour = xstrdup(""); + tty->ccolour = -1; if (tcgetattr(c->fd, &tty->tio) != 0) return (-1); @@ -341,8 +341,8 @@ tty_start_tty(struct tty *tty) tty->flags |= TTY_STARTED; tty_invalidate(tty); - if (*tty->ccolour != '\0') - tty_force_cursor_colour(tty, ""); + if (tty->ccolour != -1) + tty_force_cursor_colour(tty, -1); tty->mouse_drag_flag = 0; tty->mouse_drag_update = NULL; @@ -406,7 +406,7 @@ tty_stop_tty(struct tty *tty) } if (tty->mode & MODE_BRACKETPASTE) tty_raw(tty, tty_term_string(tty->term, TTYC_DSBP)); - if (*tty->ccolour != '\0') + if (tty->ccolour != -1) tty_raw(tty, tty_term_string(tty->term, TTYC_CR)); tty_raw(tty, tty_term_string(tty->term, TTYC_CNORM)); @@ -451,7 +451,6 @@ void tty_free(struct tty *tty) { tty_close(tty); - free(tty->ccolour); } void @@ -650,24 +649,38 @@ tty_set_title(struct tty *tty, const char *title) } static void -tty_force_cursor_colour(struct tty *tty, const char *ccolour) +tty_force_cursor_colour(struct tty *tty, int c) { - if (*ccolour == '\0') + u_char r, g, b; + char s[13] = ""; + + if (c != -1) + c = colour_force_rgb(c); + if (c == tty->ccolour) + return; + if (c == -1) tty_putcode(tty, TTYC_CR); - else - tty_putcode_ptr1(tty, TTYC_CS, ccolour); - free(tty->ccolour); - tty->ccolour = xstrdup(ccolour); + else { + colour_split_rgb(c, &r, &g, &b); + xsnprintf(s, sizeof s, "rgb:%02hhx/%02hhx/%02hhx", r, g, b); + tty_putcode_ptr1(tty, TTYC_CS, s); + } + tty->ccolour = c; } static void tty_update_cursor(struct tty *tty, int mode, int changed, struct screen *s) { - enum screen_cursor_style cstyle; + enum screen_cursor_style cstyle; + int ccolour; /* Set cursor colour if changed. */ - if (s != NULL && strcmp(s->ccolour, tty->ccolour) != 0) - tty_force_cursor_colour(tty, s->ccolour); + if (s != NULL) { + ccolour = s->ccolour; + if (s->ccolour == -1) + ccolour = s->default_ccolour; + tty_force_cursor_colour(tty, ccolour); + } /* If cursor is off, set as invisible. */ if (~mode & MODE_CURSOR) { From 200b6536e13b41a6fed72c0ca4f364f270bfe382 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 2 Nov 2021 10:57:04 +0000 Subject: [PATCH 31/45] fatalx on unknown enum members in a couple of places, from Ben Boeckel. --- arguments.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arguments.c b/arguments.c index 985aadc0..17bc12ec 100644 --- a/arguments.c +++ b/arguments.c @@ -108,6 +108,7 @@ args_value_as_string(struct args_value *value) case ARGS_STRING: return (value->string); } + fatalx("unexpected argument type"); } /* Create an empty arguments set. */ @@ -753,6 +754,7 @@ args_make_commands(struct args_command_state *state, int argc, char **argv, case CMD_PARSE_SUCCESS: return (pr->cmdlist); } + fatalx("invalid parse return state"); } /* Free commands state. */ From 57100376cc70739f53a1f8a4bacf192b8cdcd124 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 3 Nov 2021 13:37:17 +0000 Subject: [PATCH 32/45] Add a cursor-style option, from Alexis Hildebrandt in GitHub issue 2960. --- input.c | 4 +++- options-table.c | 12 +++++++++++ options.c | 8 ++++++++ screen.c | 34 ++++++++++++++++--------------- tmux.1 | 10 +++++++++ tmux.h | 5 ++++- tty.c | 54 ++++++++++++++++++++++++++++++++----------------- 7 files changed, 91 insertions(+), 36 deletions(-) diff --git a/input.c b/input.c index b2769e31..3626c4b2 100644 --- a/input.c +++ b/input.c @@ -1619,7 +1619,7 @@ input_csi_dispatch(struct input_ctx *ictx) case INPUT_CSI_DECSCUSR: n = input_get(ictx, 0, 0, 0); if (n != -1) - screen_set_cursor_style(s, n); + screen_set_cursor_style(n, &s->cstyle, &s->mode); break; case INPUT_CSI_XDA: n = input_get(ictx, 0, 0, 0); @@ -1685,6 +1685,7 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx) break; case 12: screen_write_mode_clear(sctx, MODE_CURSOR_BLINKING); + screen_write_mode_set(sctx, MODE_CURSOR_BLINKING_SET); break; case 25: /* TCEM */ screen_write_mode_clear(sctx, MODE_CURSOR); @@ -1774,6 +1775,7 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx) break; case 12: screen_write_mode_set(sctx, MODE_CURSOR_BLINKING); + screen_write_mode_set(sctx, MODE_CURSOR_BLINKING_SET); break; case 25: /* TCEM */ screen_write_mode_set(sctx, MODE_CURSOR); diff --git a/options-table.c b/options-table.c index d23f7d57..bad22bfb 100644 --- a/options-table.c +++ b/options-table.c @@ -57,6 +57,10 @@ static const char *options_table_bell_action_list[] = { static const char *options_table_visual_bell_list[] = { "off", "on", "both", NULL }; +static const char *options_table_cursor_style_list[] = { + "default", "blinking-block", "block", "blinking-underline", "underline", + "blinking-bar", "bar", NULL +}; static const char *options_table_pane_status_list[] = { "off", "top", "bottom", NULL }; @@ -243,6 +247,14 @@ const struct options_table_entry options_table[] = { .text = "Colour of the cursor." }, + { .name = "cursor-style", + .type = OPTIONS_TABLE_CHOICE, + .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, + .choices = options_table_cursor_style_list, + .default_num = 0, + .text = "Style of the cursor." + }, + { .name = "default-terminal", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_SERVER, diff --git a/options.c b/options.c index 4da1c408..865ab01f 100644 --- a/options.c +++ b/options.c @@ -1122,6 +1122,14 @@ options_push_changes(const char *name) wp->screen->default_ccolour = c; } } + if (strcmp(name, "cursor-style") == 0) { + RB_FOREACH(wp, window_pane_tree, &all_window_panes) { + wp->screen->default_mode = 0; + screen_set_cursor_style(options_get_number(wp->options, + name), &wp->screen->default_cstyle, + &wp->screen->default_mode); + } + } if (strcmp(name, "key-table") == 0) { TAILQ_FOREACH(loop, &clients, entry) server_client_set_key_table(loop, NULL); diff --git a/screen.c b/screen.c index bc95705a..da108866 100644 --- a/screen.c +++ b/screen.c @@ -82,6 +82,8 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit) s->path = NULL; s->cstyle = SCREEN_CURSOR_DEFAULT; + s->default_cstyle = SCREEN_CURSOR_DEFAULT; + s->default_mode = 0; s->ccolour = -1; s->default_ccolour = -1; s->tabs = NULL; @@ -152,38 +154,38 @@ screen_reset_tabs(struct screen *s) bit_set(s->tabs, i); } -/* Set screen cursor style. */ +/* Set screen cursor style and mode. */ void -screen_set_cursor_style(struct screen *s, u_int style) +screen_set_cursor_style(u_int style, enum screen_cursor_style *cstyle, + int *mode) { - log_debug("%s: new %u, was %u", __func__, style, s->cstyle); switch (style) { case 0: - s->cstyle = SCREEN_CURSOR_DEFAULT; + *cstyle = SCREEN_CURSOR_DEFAULT; break; case 1: - s->cstyle = SCREEN_CURSOR_BLOCK; - s->mode |= MODE_CURSOR_BLINKING; + *cstyle = SCREEN_CURSOR_BLOCK; + *mode |= MODE_CURSOR_BLINKING; break; case 2: - s->cstyle = SCREEN_CURSOR_BLOCK; - s->mode &= ~MODE_CURSOR_BLINKING; + *cstyle = SCREEN_CURSOR_BLOCK; + *mode &= ~MODE_CURSOR_BLINKING; break; case 3: - s->cstyle = SCREEN_CURSOR_UNDERLINE; - s->mode |= MODE_CURSOR_BLINKING; + *cstyle = SCREEN_CURSOR_UNDERLINE; + *mode |= MODE_CURSOR_BLINKING; break; case 4: - s->cstyle = SCREEN_CURSOR_UNDERLINE; - s->mode &= ~MODE_CURSOR_BLINKING; + *cstyle = SCREEN_CURSOR_UNDERLINE; + *mode &= ~MODE_CURSOR_BLINKING; break; case 5: - s->cstyle = SCREEN_CURSOR_BAR; - s->mode |= MODE_CURSOR_BLINKING; + *cstyle = SCREEN_CURSOR_BAR; + *mode |= MODE_CURSOR_BLINKING; break; case 6: - s->cstyle = SCREEN_CURSOR_BAR; - s->mode &= ~MODE_CURSOR_BLINKING; + *cstyle = SCREEN_CURSOR_BAR; + *mode &= ~MODE_CURSOR_BLINKING; break; } } diff --git a/tmux.1 b/tmux.1 index eb2340e3..4131719c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4426,6 +4426,16 @@ Each entry in the array defines the colour uses when the colour with that index is requested. The index may be from zero to 255. .Pp +.It Ic cursor-style Ar style +Set the style of the cursor. Available styles are: +.Ic default , +.Ic blinking-block , +.Ic block , +.Ic blinking-underline , +.Ic underline , +.Ic blinking-bar , +.Ic bar . +.Pp .It Xo Ic remain-on-exit .Op Ic on | off | failed .Xc diff --git a/tmux.h b/tmux.h index 62c84cc7..07e649f2 100644 --- a/tmux.h +++ b/tmux.h @@ -530,6 +530,7 @@ enum tty_code_code { #define MODE_CRLF 0x4000 #define MODE_KEXTENDED 0x8000 #define MODE_CURSOR_VERY_VISIBLE 0x10000 +#define MODE_CURSOR_BLINKING_SET 0x20000 #define ALL_MODES 0xffffff #define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL) @@ -779,6 +780,7 @@ struct screen { u_int cy; /* cursor y */ enum screen_cursor_style cstyle; /* cursor style */ + enum screen_cursor_style default_cstyle; int ccolour; /* cursor colour */ int default_ccolour; @@ -786,6 +788,7 @@ struct screen { u_int rlower; /* scroll region bottom */ int mode; + int default_mode; u_int saved_cx; u_int saved_cy; @@ -2793,7 +2796,7 @@ void screen_init(struct screen *, u_int, u_int, u_int); void screen_reinit(struct screen *); void screen_free(struct screen *); void screen_reset_tabs(struct screen *); -void screen_set_cursor_style(struct screen *, u_int); +void screen_set_cursor_style(u_int, enum screen_cursor_style *, int *); void screen_set_cursor_colour(struct screen *, int); int screen_set_title(struct screen *, const char *); void screen_set_path(struct screen *, const char *); diff --git a/tty.c b/tty.c index 38a7a752..70470a08 100644 --- a/tty.c +++ b/tty.c @@ -668,11 +668,11 @@ tty_force_cursor_colour(struct tty *tty, int c) tty->ccolour = c; } -static void -tty_update_cursor(struct tty *tty, int mode, int changed, struct screen *s) +static int +tty_update_cursor(struct tty *tty, int mode, struct screen *s) { enum screen_cursor_style cstyle; - int ccolour; + int ccolour, changed, cmode = mode; /* Set cursor colour if changed. */ if (s != NULL) { @@ -683,19 +683,32 @@ tty_update_cursor(struct tty *tty, int mode, int changed, struct screen *s) } /* If cursor is off, set as invisible. */ - if (~mode & MODE_CURSOR) { - if (changed & MODE_CURSOR) + if (~cmode & MODE_CURSOR) { + if (tty->mode & MODE_CURSOR) tty_putcode(tty, TTYC_CIVIS); - return; + return (cmode); } /* Check if blinking or very visible flag changed or style changed. */ if (s == NULL) cstyle = tty->cstyle; - else + else { cstyle = s->cstyle; + if (cstyle == SCREEN_CURSOR_DEFAULT) { + if (~cmode & MODE_CURSOR_BLINKING_SET) { + if (s->default_mode & MODE_CURSOR_BLINKING) + cmode |= MODE_CURSOR_BLINKING; + else + cmode &= ~MODE_CURSOR_BLINKING; + } + cstyle = s->default_cstyle; + } + } + + /* If nothing changed, do nothing. */ + changed = cmode ^ tty->mode; if ((changed & CURSOR_MODES) == 0 && cstyle == tty->cstyle) - return; + return (cmode); /* * Set cursor style. If an explicit style has been set with DECSCUSR, @@ -713,49 +726,56 @@ tty_update_cursor(struct tty *tty, int mode, int changed, struct screen *s) else tty_putcode1(tty, TTYC_SS, 0); } - if (mode & (MODE_CURSOR_BLINKING|MODE_CURSOR_VERY_VISIBLE)) + if (cmode & (MODE_CURSOR_BLINKING|MODE_CURSOR_VERY_VISIBLE)) tty_putcode(tty, TTYC_CVVIS); break; case SCREEN_CURSOR_BLOCK: if (tty_term_has(tty->term, TTYC_SS)) { - if (mode & MODE_CURSOR_BLINKING) + if (cmode & MODE_CURSOR_BLINKING) tty_putcode1(tty, TTYC_SS, 1); else tty_putcode1(tty, TTYC_SS, 2); - } else if (mode & MODE_CURSOR_BLINKING) + } else if (cmode & MODE_CURSOR_BLINKING) tty_putcode(tty, TTYC_CVVIS); break; case SCREEN_CURSOR_UNDERLINE: if (tty_term_has(tty->term, TTYC_SS)) { - if (mode & MODE_CURSOR_BLINKING) + if (cmode & MODE_CURSOR_BLINKING) tty_putcode1(tty, TTYC_SS, 3); else tty_putcode1(tty, TTYC_SS, 4); - } else if (mode & MODE_CURSOR_BLINKING) + } else if (cmode & MODE_CURSOR_BLINKING) tty_putcode(tty, TTYC_CVVIS); break; case SCREEN_CURSOR_BAR: if (tty_term_has(tty->term, TTYC_SS)) { - if (mode & MODE_CURSOR_BLINKING) + if (cmode & MODE_CURSOR_BLINKING) tty_putcode1(tty, TTYC_SS, 5); else tty_putcode1(tty, TTYC_SS, 6); - } else if (mode & MODE_CURSOR_BLINKING) + } else if (cmode & MODE_CURSOR_BLINKING) tty_putcode(tty, TTYC_CVVIS); break; } tty->cstyle = cstyle; + return (cmode); } void tty_update_mode(struct tty *tty, int mode, struct screen *s) { + struct tty_term *term = tty->term; struct client *c = tty->client; int changed; if (tty->flags & TTY_NOCURSOR) mode &= ~MODE_CURSOR; + if (tty_update_cursor(tty, mode, s) & MODE_CURSOR_BLINKING) + mode |= MODE_CURSOR_BLINKING; + else + mode &= ~MODE_CURSOR_BLINKING; + changed = mode ^ tty->mode; if (log_get_level() != 0 && changed != 0) { log_debug("%s: current mode %s", c->name, @@ -764,9 +784,7 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s) screen_mode_to_string(mode)); } - tty_update_cursor(tty, mode, changed, s); - if ((changed & ALL_MOUSE_MODES) && - tty_term_has(tty->term, TTYC_KMOUS)) { + if ((changed & ALL_MOUSE_MODES) && tty_term_has(term, TTYC_KMOUS)) { /* * If the mouse modes have changed, clear any that are set and * apply again. There are differences in how terminals track From 8f1cc0e9fa78a6200ba6bddf7c8958225d9fdd6d Mon Sep 17 00:00:00 2001 From: kn Date: Thu, 4 Nov 2021 13:15:13 +0000 Subject: [PATCH 33/45] Fix mandoc HTML rendering for command aliases Replace hand-rolled parentheses with the proper mdoc(7) macro, otherwise the closing ")" ends up inside the command description. Reported by Josh Rickmar, thanks! --- tmux.1 | 150 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/tmux.1 b/tmux.1 index 4131719c..20723308 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1034,7 +1034,7 @@ The following commands are available to manage clients and sessions: .Op Fl f Ar flags .Op Fl t Ar target-session .Xc -.D1 (alias: Ic attach ) +.D1 Pq alias: Ic attach If run from outside .Nm , create a new client in the current terminal and attach it to @@ -1121,7 +1121,7 @@ option will not be applied. .Op Fl s Ar target-session .Op Fl t Ar target-client .Xc -.D1 (alias: Ic detach ) +.D1 Pq alias: Ic detach Detach the current client if bound to a key, the client specified with .Fl t , or all clients currently attached to the session specified by @@ -1143,7 +1143,7 @@ run to replace the client. .Tg has .It Ic has-session Op Fl t Ar target-session -.D1 (alias: Ic has ) +.D1 Pq alias: Ic has Report an error and exit with 1 if the specified session does not exist. If it does exist, exit with 0. .It Ic kill-server @@ -1168,7 +1168,7 @@ session. .Op Fl F Ar format .Op Fl t Ar target-session .Xc -.D1 (alias: Ic lsc ) +.D1 Pq alias: Ic lsc List all clients attached to the server. For the meaning of the .Fl F @@ -1183,7 +1183,7 @@ is specified, list only clients connected to that session. .Op Fl F Ar format .Op Ar command .Xc -.D1 (alias: Ic lscm ) +.D1 Pq alias: Ic lscm List the syntax of .Ar command or - if omitted - of all commands supported by @@ -1193,7 +1193,7 @@ or - if omitted - of all commands supported by .Op Fl F Ar format .Op Fl f Ar filter .Xc -.D1 (alias: Ic ls ) +.D1 Pq alias: Ic ls List all sessions managed by the server. .Fl F specifies the format of each line and @@ -1205,7 +1205,7 @@ See the section. .Tg lockc .It Ic lock-client Op Fl t Ar target-client -.D1 (alias: Ic lockc ) +.D1 Pq alias: Ic lockc Lock .Ar target-client , see the @@ -1213,7 +1213,7 @@ see the command. .Tg locks .It Ic lock-session Op Fl t Ar target-session -.D1 (alias: Ic locks ) +.D1 Pq alias: Ic locks Lock all clients attached to .Ar target-session . .Tg new @@ -1230,7 +1230,7 @@ Lock all clients attached to .Op Fl y Ar height .Op Ar shell-command .Xc -.D1 (alias: Ic new ) +.D1 Pq alias: Ic new Create a new session with name .Ar session-name . .Pp @@ -1346,7 +1346,7 @@ specified multiple times. .Op Fl t Ar target-client .Op Ar adjustment .Xc -.D1 (alias: Ic refresh ) +.D1 Pq alias: Ic refresh Refresh the current client if bound to a key, or a single client if one is given with .Fl t . @@ -1477,7 +1477,7 @@ option. .Op Fl t Ar target-session .Ar new-name .Xc -.D1 (alias: Ic rename ) +.D1 Pq alias: Ic rename Rename the session to .Ar new-name . .Tg showmsgs @@ -1485,7 +1485,7 @@ Rename the session to .Op Fl JT .Op Fl t Ar target-client .Xc -.D1 (alias: Ic showmsgs ) +.D1 Pq alias: Ic showmsgs Show server messages or information. Messages are stored, up to a maximum of the limit set by the .Ar message-limit @@ -1500,7 +1500,7 @@ show debugging information about jobs and terminals. .Ar path .Ar ... .Xc -.D1 (alias: Ic source ) +.D1 Pq alias: Ic source Execute commands from one or more files specified by .Ar path (which may be @@ -1523,7 +1523,7 @@ the file is parsed but no commands are executed. shows the parsed commands and line numbers if possible. .Tg start .It Ic start-server -.D1 (alias: Ic start ) +.D1 Pq alias: Ic start Start the .Nm server, if not already running, without creating any sessions. @@ -1542,7 +1542,7 @@ $ tmux start \\; show -g .It Xo Ic suspend-client .Op Fl t Ar target-client .Xc -.D1 (alias: Ic suspendc ) +.D1 Pq alias: Ic suspendc Suspend a client by sending .Dv SIGTSTP (tty stop). @@ -1553,7 +1553,7 @@ Suspend a client by sending .Op Fl t Ar target-session .Op Fl T Ar key-table .Xc -.D1 (alias: Ic switchc ) +.D1 Pq alias: Ic switchc Switch the current session for client .Ar target-client to @@ -1945,7 +1945,7 @@ Commands related to windows and panes are as follows: .Op Fl s Ar src-pane .Op Fl t Ar dst-window .Xc -.D1 (alias: Ic breakp ) +.D1 Pq alias: Ic breakp Break .Ar src-pane off from its containing window to make it the only pane in @@ -1974,7 +1974,7 @@ but a different format may be specified with .Op Fl S Ar start-line .Op Fl t Ar target-pane .Xc -.D1 (alias: Ic capturep ) +.D1 Pq alias: Ic capturep Capture the contents of a pane. If .Fl p @@ -2226,7 +2226,7 @@ This command works only if at least one client is attached. .Op Fl t Ar target-client .Op Ar template .Xc -.D1 (alias: Ic displayp ) +.D1 Pq alias: Ic displayp Display a visible indicator of each pane shown by .Ar target-client . See the @@ -2266,7 +2266,7 @@ other commands are not blocked from running until the indicator is closed. .Op Fl t Ar target-pane .Ar match-string .Xc -.D1 (alias: Ic findw ) +.D1 Pq alias: Ic findw Search for a .Xr fnmatch 3 pattern or, with @@ -2296,7 +2296,7 @@ This command works only if at least one client is attached. .Op Fl s Ar src-pane .Op Fl t Ar dst-pane .Xc -.D1 (alias: Ic joinp ) +.D1 Pq alias: Ic joinp Like .Ic split-window , but instead of splitting @@ -2324,7 +2324,7 @@ the marked pane is used rather than the current pane. .Op Fl a .Op Fl t Ar target-pane .Xc -.D1 (alias: Ic killp ) +.D1 Pq alias: Ic killp Destroy the given pane. If no panes remain in the containing window, it is also destroyed. The @@ -2336,7 +2336,7 @@ option kills all but the pane given with .Op Fl a .Op Fl t Ar target-window .Xc -.D1 (alias: Ic killw ) +.D1 Pq alias: Ic killw Kill the current window or the window at .Ar target-window , removing it from any sessions to which it is linked. @@ -2349,7 +2349,7 @@ option kills all but the window given with .Op Fl deZ .Op Fl t Ar target-window .Xc -.D1 (alias: Ic lastp ) +.D1 Pq alias: Ic lastp Select the last (previously selected) pane. .Fl Z keeps the window zoomed if it was zoomed. @@ -2359,7 +2359,7 @@ enables or disables input to the pane. .Tg last .It Ic last-window Op Fl t Ar target-session -.D1 (alias: Ic last ) +.D1 Pq alias: Ic last Select the last (previously selected) window. If no .Ar target-session @@ -2370,7 +2370,7 @@ is specified, select the last window of the current session. .Op Fl s Ar src-window .Op Fl t Ar dst-window .Xc -.D1 (alias: Ic linkw ) +.D1 Pq alias: Ic linkw Link the window at .Ar src-window to the specified @@ -2402,7 +2402,7 @@ is given, the newly linked window is not selected. .Op Fl f Ar filter .Op Fl t Ar target .Xc -.D1 (alias: Ic lsp ) +.D1 Pq alias: Ic lsp If .Fl a is given, @@ -2431,7 +2431,7 @@ section. .Op Fl f Ar filter .Op Fl t Ar target-session .Xc -.D1 (alias: Ic lsw ) +.D1 Pq alias: Ic lsw If .Fl a is given, list all windows on the server. @@ -2452,7 +2452,7 @@ section. .Op Fl s Ar src-pane .Op Fl t Ar dst-pane .Xc -.D1 (alias: Ic movep ) +.D1 Pq alias: Ic movep Does the same as .Ic join-pane . .Tg movew @@ -2461,7 +2461,7 @@ Does the same as .Op Fl s Ar src-window .Op Fl t Ar dst-window .Xc -.D1 (alias: Ic movew ) +.D1 Pq alias: Ic movew This is similar to .Ic link-window , except the window at @@ -2484,7 +2484,7 @@ option. .Op Fl t Ar target-window .Op Ar shell-command .Xc -.D1 (alias: Ic neww ) +.D1 Pq alias: Ic neww Create a new window. With .Fl a @@ -2559,14 +2559,14 @@ 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 ) +.D1 Pq 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 .Xc -.D1 (alias: Ic next ) +.D1 Pq alias: Ic next Move to the next window in the session. If .Fl a @@ -2577,7 +2577,7 @@ is used, move to the next window with an alert. .Op Fl t Ar target-pane .Op Ar shell-command .Xc -.D1 (alias: Ic pipep ) +.D1 Pq alias: Ic pipep Pipe output sent by the program in .Ar target-pane to a shell command or vice versa. @@ -2624,14 +2624,14 @@ bind-key C-p pipe-pane -o 'cat >>~/output.#I-#P' .It Xo Ic previous-layout .Op Fl t Ar target-window .Xc -.D1 (alias: Ic prevl ) +.D1 Pq 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 .Xc -.D1 (alias: Ic prev ) +.D1 Pq alias: Ic prev Move to the previous window in the session. With .Fl a , @@ -2641,7 +2641,7 @@ move to the previous window with an alert. .Op Fl t Ar target-window .Ar new-name .Xc -.D1 (alias: Ic renamew ) +.D1 Pq alias: Ic renamew Rename the current window, or the window at .Ar target-window if specified, to @@ -2654,7 +2654,7 @@ if specified, to .Op Fl y Ar height .Op Ar adjustment .Xc -.D1 (alias: Ic resizep ) +.D1 Pq alias: Ic resizep Resize a pane, up, down, left or right by .Ar adjustment with @@ -2699,7 +2699,7 @@ history to replace them. .Op Fl y Ar height .Op Ar adjustment .Xc -.D1 (alias: Ic resizew ) +.D1 Pq alias: Ic resizew Resize a window, up, down, left or right by .Ar adjustment with @@ -2732,7 +2732,7 @@ to manual in the window options. .Op Fl t Ar target-pane .Op Ar shell-command .Xc -.D1 (alias: Ic respawnp ) +.D1 Pq alias: Ic respawnp Reactivate a pane in which the command has exited (see the .Ic remain-on-exit window option). @@ -2758,7 +2758,7 @@ command. .Op Fl t Ar target-window .Op Ar shell-command .Xc -.D1 (alias: Ic respawnw ) +.D1 Pq alias: Ic respawnw Reactivate a window in which the command has exited (see the .Ic remain-on-exit window option). @@ -2781,7 +2781,7 @@ command. .Op Fl DUZ .Op Fl t Ar target-window .Xc -.D1 (alias: Ic rotatew ) +.D1 Pq alias: Ic rotatew Rotate the positions of the panes within a window, either upward (numerically lower) with .Fl U @@ -2794,7 +2794,7 @@ keeps the window zoomed if it was zoomed. .Op Fl t Ar target-pane .Op Ar layout-name .Xc -.D1 (alias: Ic selectl ) +.D1 Pq alias: Ic selectl Choose a specific layout for a window. If .Ar layout-name @@ -2817,7 +2817,7 @@ spreads the current pane and any panes next to it out evenly. .Op Fl T Ar title .Op Fl t Ar target-pane .Xc -.D1 (alias: Ic selectp ) +.D1 Pq alias: Ic selectp Make pane .Ar target-pane the active pane in its window. @@ -2861,7 +2861,7 @@ and .Op Fl lnpT .Op Fl t Ar target-window .Xc -.D1 (alias: Ic selectw ) +.D1 Pq alias: Ic selectw Select the window at .Ar target-window . .Fl l , @@ -2889,7 +2889,7 @@ the command behaves like .Op Ar shell-command .Op Fl F Ar format .Xc -.D1 (alias: Ic splitw ) +.D1 Pq alias: Ic splitw Create a new pane by splitting .Ar target-pane : .Fl h @@ -2946,7 +2946,7 @@ command. .Op Fl s Ar src-pane .Op Fl t Ar dst-pane .Xc -.D1 (alias: Ic swapp ) +.D1 Pq alias: Ic swapp Swap two panes. If .Fl U @@ -2975,7 +2975,7 @@ the marked pane is used rather than the current pane. .Op Fl s Ar src-window .Op Fl t Ar dst-window .Xc -.D1 (alias: Ic swapw ) +.D1 Pq alias: Ic swapw This is similar to .Ic link-window , except the source and destination windows are swapped. @@ -2996,7 +2996,7 @@ the window containing the marked pane is used rather than the current window. .Op Fl k .Op Fl t Ar target-window .Xc -.D1 (alias: Ic unlinkw ) +.D1 Pq alias: Ic unlinkw Unlink .Ar target-window . Unless @@ -3069,7 +3069,7 @@ Commands related to key bindings are as follows: .Op Fl T Ar key-table .Ar key command Op Ar arguments .Xc -.D1 (alias: Ic bind ) +.D1 Pq alias: Ic bind Bind key .Ar key to @@ -3127,7 +3127,7 @@ command. .Op Fl P Ar prefix-string Fl T Ar key-table .Op Ar key .Xc -.D1 (alias: Ic lsk ) +.D1 Pq alias: Ic lsk List key bindings. There are two forms: the default lists keys as .Ic bind-key @@ -3164,7 +3164,7 @@ lists the command for keys that do not have a note rather than skipping them. .Op Fl t Ar target-pane .Ar key Ar ... .Xc -.D1 (alias: Ic send ) +.D1 Pq alias: Ic send Send a key or keys to a window. Each argument .Ar key @@ -3215,7 +3215,7 @@ the secondary prefix key, to a window as if it was pressed. .Op Fl T Ar key-table .Ar key .Xc -.D1 (alias: Ic unbind ) +.D1 Pq alias: Ic unbind Unbind the command bound to .Ar key . .Fl n @@ -3311,7 +3311,7 @@ Commands which set options are as follows: .Op Fl t Ar target-pane .Ar option Ar value .Xc -.D1 (alias: Ic set ) +.D1 Pq alias: Ic set Set a pane option with .Fl p , a window option with @@ -3386,7 +3386,7 @@ the result would be the default background and a blue foreground. .Op Fl t Ar target-pane .Op Ar option .Xc -.D1 (alias: Ic show ) +.D1 Pq alias: Ic show Show the pane options (or a single option if .Ar option is provided) with @@ -5425,7 +5425,7 @@ Commands to alter and view the environment are: .Op Fl t Ar target-session .Ar name Op Ar value .Xc -.D1 (alias: Ic setenv ) +.D1 Pq alias: Ic setenv Set or unset an environment variable. If .Fl g @@ -5451,7 +5451,7 @@ marks the variable as hidden. .Op Fl t Ar target-session .Op Ar variable .Xc -.D1 (alias: Ic showenv ) +.D1 Pq alias: Ic showenv Display the environment for .Ar target-session or the global environment with @@ -5534,7 +5534,7 @@ Commands related to the status line are as follows: .It Xo Ic clear-prompt-history .Op Fl T Ar prompt-type .Xc -.D1 (alias: Ic clrphist ) +.D1 Pq alias: Ic clrphist Clear status prompt history for prompt type .Ar prompt-type . If @@ -5660,7 +5660,7 @@ until it is dismissed. .Op Fl t Ar target-client .Ar command .Xc -.D1 (alias: Ic confirm ) +.D1 Pq alias: Ic confirm Ask for confirmation before executing .Ar command . If @@ -5689,7 +5689,7 @@ until it is dismissed. .Ar command .Ar ... .Xc -.D1 (alias: Ic menu ) +.D1 Pq alias: Ic menu Display a menu on .Ar target-client . .Ar target-pane @@ -5776,7 +5776,7 @@ The following keys are also available: .Op Fl t Ar target-pane .Op Ar message .Xc -.D1 (alias: Ic display ) +.D1 Pq alias: Ic display Display a message. If .Fl p @@ -5827,7 +5827,7 @@ forwards any input read from stdin to the empty pane given by .Op Fl y Ar position .Op Ar shell-command .Xc -.D1 (alias: Ic popup ) +.D1 Pq alias: Ic popup Display a popup running .Ar shell-command on @@ -5900,7 +5900,7 @@ flag closes any popup on the client. .It Xo Ic show-prompt-history .Op Fl T Ar prompt-type .Xc -.D1 (alias: Ic showphist ) +.D1 Pq alias: Ic showphist Display status prompt history for prompt type .Ar prompt-type . If @@ -6028,11 +6028,11 @@ 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 ) +.D1 Pq 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 ) +.D1 Pq alias: Ic deleteb Delete the buffer named .Ar buffer-name , or the most recently added automatically named buffer if not specified. @@ -6041,7 +6041,7 @@ or the most recently added automatically named buffer if not specified. .Op Fl F Ar format .Op Fl f Ar filter .Xc -.D1 (alias: Ic lsb ) +.D1 Pq alias: Ic lsb List the global buffers. .Fl F specifies the format of each line and @@ -6058,7 +6058,7 @@ section. .Ar path .Xc .Tg loadb -.D1 (alias: Ic loadb ) +.D1 Pq alias: Ic loadb Load the contents of the specified paste buffer from .Ar path . If @@ -6075,7 +6075,7 @@ escape sequence, if possible. .Op Fl s Ar separator .Op Fl t Ar target-pane .Xc -.D1 (alias: Ic pasteb ) +.D1 Pq alias: Ic pasteb Insert the contents of a paste buffer into the specified pane. If not specified, paste into the current one. With @@ -6099,7 +6099,7 @@ buffer if the application has requested bracketed paste mode. .Op Fl b Ar buffer-name .Ar path .Xc -.D1 (alias: Ic saveb ) +.D1 Pq alias: Ic saveb Save the contents of the specified paste buffer to .Ar path . The @@ -6113,7 +6113,7 @@ option appends to rather than overwriting the file. .Op Fl n Ar new-buffer-name .Ar data .Xc -.D1 (alias: Ic setb ) +.D1 Pq alias: Ic setb Set the contents of the specified buffer to .Ar data . If @@ -6134,7 +6134,7 @@ option renames the buffer to .It Xo Ic show-buffer .Op Fl b Ar buffer-name .Xc -.D1 (alias: Ic showb ) +.D1 Pq alias: Ic showb Display the contents of the specified buffer. .El .Sh MISCELLANEOUS @@ -6149,7 +6149,7 @@ Display a large clock. .Ar shell-command command .Op Ar command .Xc -.D1 (alias: Ic if ) +.D1 Pq alias: Ic if Execute the first .Ar command if @@ -6176,7 +6176,7 @@ 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 ) +.D1 Pq alias: Ic lock Lock each client individually by running the command specified by the .Ic lock-command option. @@ -6187,7 +6187,7 @@ option. .Op Fl t Ar target-pane .Op Ar shell-command .Xc -.D1 (alias: Ic run ) +.D1 Pq alias: Ic run Execute .Ar shell-command or (with @@ -6219,7 +6219,7 @@ If the command fails, the exit status is also displayed. .Op Fl L | S | U .Ar channel .Xc -.D1 (alias: Ic wait ) +.D1 Pq alias: Ic wait When used without options, prevents the client from exiting until woken using .Ic wait-for .Fl S From 10b3cd17fa94e3ac129080e68c69d2130b015fb2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 11 Nov 2021 09:18:04 +0000 Subject: [PATCH 34/45] OS X -> macOS, from J Lewis Muir. --- .github/CONTRIBUTING.md | 2 +- .github/README.md | 2 +- README | 2 +- README.ja | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 89c6549b..0c517a52 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -29,7 +29,7 @@ uname -sp && tmux -V && echo $TERM Also include: -- Your platform (Linux, OS X, or whatever). +- Your platform (Linux, macOS, or whatever). - A brief description of the problem with steps to reproduce. diff --git a/.github/README.md b/.github/README.md index 5590d0b2..353f10ec 100644 --- a/.github/README.md +++ b/.github/README.md @@ -4,7 +4,7 @@ tmux is a terminal multiplexer: it enables a number of terminals to be created, accessed, and controlled from a single screen. tmux may be detached from a screen and continue running in the background, then later reattached. -This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris. +This release runs on OpenBSD, FreeBSD, NetBSD, Linux, macOS and Solaris. ## Dependencies diff --git a/README b/README index 8732a027..57329629 100644 --- a/README +++ b/README @@ -4,7 +4,7 @@ tmux is a terminal multiplexer: it enables a number of terminals to be created, accessed, and controlled from a single screen. tmux may be detached from a screen and continue running in the background, then later reattached. -This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris. +This release runs on OpenBSD, FreeBSD, NetBSD, Linux, macOS and Solaris. * Dependencies diff --git a/README.ja b/README.ja index 1580df52..3c944738 100644 --- a/README.ja +++ b/README.ja @@ -3,7 +3,7 @@ tmuxへようこそ! tmuxはターミナルマルチプレクサーです。複数のターミナルを一つのスクリーン内に作成し、操作することができます。 バックグラウンドで処理を実行中に一度スクリーンから離れて後から復帰することも可能です。 -OpenBSD、FreeBSD、NetBSD、Linux、OS X、Solarisで実行できます。 +OpenBSD、FreeBSD、NetBSD、Linux、macOS、Solarisで実行できます。 tmuxはlibevent 2.x.に依存します。 下記からダウンロードしてください。 From 630c592ef8740a935ba6c12c957a359c94414219 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 11 Nov 2021 09:22:33 +0000 Subject: [PATCH 35/45] If trimming menu item text, show key if it would take up less than a quarter of the space; from Alexis Hildebrandt. Also new sentence, new line in tmux.1, from jmc. --- menu.c | 26 +++++++++++++++----------- tmux.1 | 3 ++- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/menu.c b/menu.c index 45645147..aaa1287e 100644 --- a/menu.c +++ b/menu.c @@ -89,22 +89,26 @@ menu_add_item(struct menu *menu, const struct menu_item *item, keylen = strlen(key) + 3; /* 3 = space and two brackets */ /* - * Only add the key if there is space for the entire item text - * and the key. + * Add the key if it is shorter than a quarter of the available + * space or there is space for the entire item text and the + * key. */ - if (keylen >= max_width || slen >= max_width - keylen) + if (keylen <= max_width / 4) + max_width -= keylen; + else if (keylen >= max_width || slen >= max_width - keylen) key = NULL; } - if (key != NULL) - xasprintf(&name, "%s#[default] #[align=right](%s)", s, key); - else { - if (slen > max_width) { - max_width--; - suffix = ">"; - } - xasprintf(&name, "%.*s%s", (int)max_width, s, suffix); + if (slen > max_width) { + max_width--; + suffix = ">"; } + if (key != NULL) + xasprintf(&name, "%.*s%s#[default] #[align=right](%s)", + (int)max_width, s, suffix, key); + else + xasprintf(&name, "%.*s%s", (int)max_width, s, suffix); + new_item->name = name; free(s); diff --git a/tmux.1 b/tmux.1 index 20723308..7d5c7357 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4427,7 +4427,8 @@ uses when the colour with that index is requested. The index may be from zero to 255. .Pp .It Ic cursor-style Ar style -Set the style of the cursor. Available styles are: +Set the style of the cursor. +Available styles are: .Ic default , .Ic blinking-block , .Ic block , From cb8a0d83fbaa2ae49c06105cb94d247ef20ed91e Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 11 Nov 2021 09:31:16 +0000 Subject: [PATCH 36/45] If automatic-rename is off, allow the escape sequence to set an empty window name, GitHub issue 2964. --- input.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/input.c b/input.c index 3626c4b2..73a58890 100644 --- a/input.c +++ b/input.c @@ -2382,6 +2382,7 @@ static void input_exit_rename(struct input_ctx *ictx) { struct window_pane *wp = ictx->wp; + struct window *w; struct options_entry *o; if (wp == NULL) @@ -2394,17 +2395,20 @@ input_exit_rename(struct input_ctx *ictx) if (!utf8_isvalid(ictx->input_buf)) return; + w = wp->window; if (ictx->input_len == 0) { - o = options_get_only(wp->window->options, "automatic-rename"); + o = options_get_only(w->options, "automatic-rename"); if (o != NULL) options_remove_or_default(o, -1, NULL); - return; + if (!options_get_number(w->options, "automatic-rename")) + window_set_name(w, ""); + } else { + options_set_number(w->options, "automatic-rename", 0); + window_set_name(w, ictx->input_buf); } - window_set_name(wp->window, ictx->input_buf); - options_set_number(wp->window->options, "automatic-rename", 0); - server_redraw_window_borders(wp->window); - server_status_window(wp->window); + server_redraw_window_borders(w); + server_status_window(w); } /* Open UTF-8 character. */ From b55f0ac6b94449b3372f0d1737fcf967f4fa13a2 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 15 Nov 2021 10:58:13 +0000 Subject: [PATCH 37/45] Leave the hardware cursor at the position of the selected line in choose modes and current editing position and at the command prompt. It is invisible but this is helpful for people using screen readers. GitHub issue 2970. --- mode-tree.c | 8 ++++---- server-client.c | 17 +++++++++++++++-- status.c | 1 + tmux.h | 1 + 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/mode-tree.c b/mode-tree.c index 85027caf..21a73ef2 100644 --- a/mode-tree.c +++ b/mode-tree.c @@ -736,10 +736,8 @@ mode_tree_draw(struct mode_tree_data *mtd) } sy = screen_size_y(s); - if (!mtd->preview || sy <= 4 || h <= 4 || sy - h <= 4 || w <= 4) { - screen_write_stop(&ctx); - return; - } + if (!mtd->preview || sy <= 4 || h <= 4 || sy - h <= 4 || w <= 4) + goto done; line = &mtd->line_list[mtd->current]; mti = line->item; @@ -783,6 +781,8 @@ mode_tree_draw(struct mode_tree_data *mtd) mtd->drawcb(mtd->modedata, mti->itemdata, &ctx, box_x, box_y); } +done: + screen_write_cursormove(&ctx, 0, mtd->current - mtd->offset, 0); screen_write_stop(&ctx); } diff --git a/server-client.c b/server-client.c index 7cea32c0..072c5589 100644 --- a/server-client.c +++ b/server-client.c @@ -1706,7 +1706,7 @@ server_client_reset_state(struct client *c) struct window_pane *wp = server_client_get_pane(c), *loop; struct screen *s = NULL; struct options *oo = c->session->options; - int mode = 0, cursor, flags; + int mode = 0, cursor, flags, n; u_int cx = 0, cy = 0, ox, oy, sx, sy; if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED)) @@ -1734,7 +1734,20 @@ server_client_reset_state(struct client *c) tty_margin_off(tty); /* Move cursor to pane cursor and offset. */ - if (c->overlay_draw == NULL) { + if (c->prompt_string != NULL) { + n = options_get_number(c->session->options, "status-position"); + if (n == 0) + cy = 0; + else { + n = status_line_size(c); + if (n == 0) + cy = tty->sy - 1; + else + cy = tty->sy - n; + } + cx = c->prompt_cursor; + mode &= ~MODE_CURSOR; + } else if (c->overlay_draw == NULL) { cursor = 0; tty_window_offset(tty, &ox, &oy, &sx, &sy); if (wp->xoff + s->cx >= ox && wp->xoff + s->cx <= ox + sx && diff --git a/status.c b/status.c index d499eab8..bb57b3d6 100644 --- a/status.c +++ b/status.c @@ -748,6 +748,7 @@ status_prompt_redraw(struct client *c) offset = 0; if (pwidth > left) pwidth = left; + c->prompt_cursor = start + c->prompt_index - offset; width = 0; for (i = 0; c->prompt_buffer[i].size != 0; i++) { diff --git a/tmux.h b/tmux.h index 07e649f2..dfea1583 100644 --- a/tmux.h +++ b/tmux.h @@ -1758,6 +1758,7 @@ struct client { #define PROMPT_KEY 0x10 int prompt_flags; enum prompt_type prompt_type; + int prompt_cursor; struct session *session; struct session *last_session; From add03dfb8dd4f2871b2cbc487ff5af95a63f48f4 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 29 Nov 2021 11:01:51 +0000 Subject: [PATCH 38/45] Fix user option lookup ordering. --- window-customize.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/window-customize.c b/window-customize.c index 0f09eba8..98387e50 100644 --- a/window-customize.c +++ b/window-customize.c @@ -398,11 +398,11 @@ window_customize_build_options(struct window_customize_modedata *data, for (i = 0; i < size; i++) { if (oo2 != NULL) - o = options_get(oo0, list[i]); + o = options_get(oo2, list[i]); if (o == NULL && oo1 != NULL) o = options_get(oo1, list[i]); if (o == NULL) - o = options_get(oo2, list[i]); + o = options_get(oo0, list[i]); if (options_owner(o) == oo2) scope = scope2; else if (options_owner(o) == oo1) From 333cf6429ae16da6fb3892978ea450bc62c3e873 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 29 Nov 2021 11:05:28 +0000 Subject: [PATCH 39/45] Bump response timer to three seconds, GitHub issue 2984. --- tty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tty.c b/tty.c index 70470a08..233d52a8 100644 --- a/tty.c +++ b/tty.c @@ -302,7 +302,7 @@ tty_start_tty(struct tty *tty) { struct client *c = tty->client; struct termios tio; - struct timeval tv = { .tv_sec = 1 }; + struct timeval tv = { .tv_sec = 3 }; setblocking(c->fd, 0); event_add(&tty->event_in, NULL); From 8fccbbb02673bed71676412f1a313093a39c48ff Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 6 Dec 2021 10:08:42 +0000 Subject: [PATCH 40/45] Do not dereference NULL window when resizing client, GitHub issue 2982. --- resize.c | 2 ++ tty.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/resize.c b/resize.c index 8416ad6a..175dd740 100644 --- a/resize.c +++ b/resize.c @@ -348,6 +348,8 @@ recalculate_size_skip_client(struct client *loop, __unused int type, * is not the current window - this is used for aggressive-resize. * Otherwise skip any session that doesn't contain the window. */ + if (loop->session->curw == NULL) + return (1); if (current) return (loop->session->curw->window != w); return (session_has(loop->session, w) == 0); diff --git a/tty.c b/tty.c index 233d52a8..a9678eaf 100644 --- a/tty.c +++ b/tty.c @@ -937,7 +937,9 @@ tty_update_window_offset(struct window *w) struct client *c; TAILQ_FOREACH(c, &clients, entry) { - if (c->session != NULL && c->session->curw->window == w) + if (c->session != NULL && + c->session->curw != NULL && + c->session->curw->window == w) tty_update_client_offset(c); } } From ecac73f66445311c58a28afc7d3f92c964eaae67 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 6 Dec 2021 10:10:52 +0000 Subject: [PATCH 41/45] Fix g/G keys to be in line with copy mode. --- mode-tree.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode-tree.c b/mode-tree.c index 21a73ef2..1eb496fe 100644 --- a/mode-tree.c +++ b/mode-tree.c @@ -1055,7 +1055,6 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, case '\016': /* C-n */ mode_tree_down(mtd, 1); break; - case 'g': case KEYC_PPAGE: case '\002': /* C-b */ for (i = 0; i < mtd->height; i++) { @@ -1064,7 +1063,6 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, mode_tree_up(mtd, 1); } break; - case 'G': case KEYC_NPAGE: case '\006': /* C-f */ for (i = 0; i < mtd->height; i++) { @@ -1073,10 +1071,12 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, mode_tree_down(mtd, 1); } break; + case 'g': case KEYC_HOME: mtd->current = 0; mtd->offset = 0; break; + case 'G': case KEYC_END: mtd->current = mtd->line_size - 1; if (mtd->current > mtd->height - 1) From ef676e1202a4d5c423d5bba2f8ecba1f768d8364 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 6 Dec 2021 10:17:34 +0000 Subject: [PATCH 42/45] Remove fallback for wcwidth failure, GitHub issue 3003. --- utf8.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/utf8.c b/utf8.c index 56f20cbb..df75a769 100644 --- a/utf8.c +++ b/utf8.c @@ -237,21 +237,6 @@ utf8_width(struct utf8_data *ud, int *width) if (*width >= 0 && *width <= 0xff) return (UTF8_DONE); log_debug("UTF-8 %.*s, wcwidth() %d", (int)ud->size, ud->data, *width); - -#ifndef __OpenBSD__ - /* - * Many platforms (particularly and inevitably OS X) have no width for - * relatively common characters (wcwidth() returns -1); assume width 1 - * in this case. This will be wrong for genuinely nonprintable - * characters, but they should be rare. We may pass through stuff that - * ideally we would block, but this is no worse than sending the same - * to the terminal without tmux. - */ - if (*width < 0) { - *width = 1; - return (UTF8_DONE); - } -#endif return (UTF8_ERROR); } From 71c3234dc78f6f59a66757a6e272e77823a820b3 Mon Sep 17 00:00:00 2001 From: deraadt Date: Tue, 7 Dec 2021 00:38:42 +0000 Subject: [PATCH 43/45] Use PATH_MAX (the standard name) rather than MAXPATHLEN (from BSD sys/param.h) --- procname.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/procname.c b/procname.c index 45e508ef..ac56bb48 100644 --- a/procname.c +++ b/procname.c @@ -138,7 +138,7 @@ char * get_proc_cwd(int fd) { int name[] = { CTL_KERN, KERN_PROC_CWD, 0 }; - static char path[MAXPATHLEN]; + static char path[PATH_MAX]; size_t pathlen = sizeof path; if ((name[2] = tcgetpgrp(fd)) == -1) From 7532a5cf9574f8c5e102383329477e934992d2ea Mon Sep 17 00:00:00 2001 From: deraadt Date: Tue, 7 Dec 2021 00:40:03 +0000 Subject: [PATCH 44/45] sys/signal.h (or some master include) must happen before sys/proc.h, which is not standalone. This problem is being hidden by a sys/param.h which cannot be deleted yet. --- procname.c | 1 + 1 file changed, 1 insertion(+) diff --git a/procname.c b/procname.c index ac56bb48..b2cba1c2 100644 --- a/procname.c +++ b/procname.c @@ -18,6 +18,7 @@ #include /* MAXCOMLEN */ #include +#include #include #include #include From d721fb2a9fd70c157abb8540d4c50fca654f9f4d Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 7 Dec 2021 07:28:44 +0000 Subject: [PATCH 45/45] Respond to OSC 4 query. --- input.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/input.c b/input.c index 73a58890..16f31ad7 100644 --- a/input.c +++ b/input.c @@ -2505,7 +2505,8 @@ input_osc_colour_reply(struct input_ctx *ictx, u_int n, int c) end = "\007"; else end = "\033\\"; - input_reply(ictx, "\033]%u;rgb:%02hhx/%02hhx/%02hhx%s", n, r, g, b, end); + input_reply(ictx, "\033]%u;rgb:%02hhx%02hhx/%02hhx%02hhx/%02hhx%02hhx%s", + n, r, r, g, g, b, b, end); } /* Handle the OSC 4 sequence for setting (multiple) palette entries. */ @@ -2529,6 +2530,12 @@ input_osc_4(struct input_ctx *ictx, const char *p) } s = strsep(&next, ";"); + if (strcmp(s, "?") == 0) { + c = colour_palette_get(ictx->palette, idx); + if (c != -1) + input_osc_colour_reply(ictx, 4, c); + continue; + } if ((c = input_osc_parse_colour(s)) == -1) { s = next; continue;