mirror of
https://github.com/tmux/tmux.git
synced 2025-01-13 03:48:51 +00:00
Merge branch 'obsd-master'
This commit is contained in:
commit
d4bf4bd7c7
@ -206,7 +206,7 @@ args_print(struct args *args)
|
|||||||
char *
|
char *
|
||||||
args_escape(const char *s)
|
args_escape(const char *s)
|
||||||
{
|
{
|
||||||
static const char quoted[] = " #\"';$";
|
static const char quoted[] = " #\"';${}";
|
||||||
char *escaped, *result;
|
char *escaped, *result;
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
|
@ -48,10 +48,12 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
key_code key;
|
key_code key;
|
||||||
const char *tablename;
|
const char *tablename;
|
||||||
struct cmd_parse_result *pr;
|
struct cmd_parse_result *pr;
|
||||||
|
char **argv = args->argv;
|
||||||
|
int argc = args->argc;
|
||||||
|
|
||||||
key = key_string_lookup_string(args->argv[0]);
|
key = key_string_lookup_string(argv[0]);
|
||||||
if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
|
if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
|
||||||
cmdq_error(item, "unknown key: %s", args->argv[0]);
|
cmdq_error(item, "unknown key: %s", argv[0]);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +64,10 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
else
|
else
|
||||||
tablename = "prefix";
|
tablename = "prefix";
|
||||||
|
|
||||||
pr = cmd_parse_from_arguments(args->argc - 1, args->argv + 1, NULL);
|
if (argc == 2)
|
||||||
|
pr = cmd_parse_from_string(argv[1], NULL);
|
||||||
|
else
|
||||||
|
pr = cmd_parse_from_arguments(argc - 1, argv + 1, NULL);
|
||||||
switch (pr->status) {
|
switch (pr->status) {
|
||||||
case CMD_PARSE_EMPTY:
|
case CMD_PARSE_EMPTY:
|
||||||
cmdq_error(item, "empty command");
|
cmdq_error(item, "empty command");
|
||||||
|
100
cmd-parse.y
100
cmd-parse.y
@ -1236,6 +1236,99 @@ yylex_token_tilde(char **buf, size_t *len)
|
|||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
yylex_token_brace(char **buf, size_t *len)
|
||||||
|
{
|
||||||
|
struct cmd_parse_state *ps = &parse_state;
|
||||||
|
int ch, nesting = 1, escape = 0, quote = '\0';
|
||||||
|
int lines = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract a string up to the matching unquoted '}', including newlines
|
||||||
|
* and handling nested braces.
|
||||||
|
*
|
||||||
|
* To detect the final and intermediate braces which affect the nesting
|
||||||
|
* depth, we scan the input as if it was a tmux config file, and ignore
|
||||||
|
* braces which would be considered quoted, escaped, or in a comment.
|
||||||
|
*
|
||||||
|
* The result is verbatim copy of the input excluding the final brace.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (ch = yylex_getc1(); ch != EOF; ch = yylex_getc1()) {
|
||||||
|
yylex_append1(buf, len, ch);
|
||||||
|
if (ch == '\n')
|
||||||
|
lines++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the previous character was a backslash (escape is set),
|
||||||
|
* escape anything if unquoted or in double quotes, otherwise
|
||||||
|
* escape only '\n' and '\\'.
|
||||||
|
*/
|
||||||
|
if (escape &&
|
||||||
|
(quote == '\0' ||
|
||||||
|
quote == '"' ||
|
||||||
|
ch == '\n' ||
|
||||||
|
ch == '\\')) {
|
||||||
|
escape = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The character is not escaped. If it is a backslash, set the
|
||||||
|
* escape flag.
|
||||||
|
*/
|
||||||
|
if (ch == '\\') {
|
||||||
|
escape = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
escape = 0;
|
||||||
|
|
||||||
|
/* A newline always resets to unquoted. */
|
||||||
|
if (ch == '\n') {
|
||||||
|
quote = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (quote) {
|
||||||
|
/*
|
||||||
|
* Inside quotes or comment. Check if this is the
|
||||||
|
* closing quote.
|
||||||
|
*/
|
||||||
|
if (ch == quote && quote != '#')
|
||||||
|
quote = 0;
|
||||||
|
} else {
|
||||||
|
/* Not inside quotes or comment. */
|
||||||
|
switch (ch) {
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
case '#':
|
||||||
|
/* Beginning of quote or comment. */
|
||||||
|
quote = ch;
|
||||||
|
break;
|
||||||
|
case '{':
|
||||||
|
nesting++;
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
nesting--;
|
||||||
|
if (nesting == 0) {
|
||||||
|
(*len)--; /* remove closing } */
|
||||||
|
ps->input->line += lines;
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update line count after error as reporting the opening line
|
||||||
|
* is more useful than EOF.
|
||||||
|
*/
|
||||||
|
yyerror("unterminated brace string");
|
||||||
|
ps->input->line += lines;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
yylex_token(int ch)
|
yylex_token(int ch)
|
||||||
{
|
{
|
||||||
@ -1282,6 +1375,13 @@ yylex_token(int ch)
|
|||||||
goto error;
|
goto error;
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
|
if (ch == '{' && state == NONE) {
|
||||||
|
if (!yylex_token_brace(&buf, &len))
|
||||||
|
goto error;
|
||||||
|
goto skip;
|
||||||
|
}
|
||||||
|
if (ch == '}' && state == NONE)
|
||||||
|
goto error; /* unmatched (matched ones were handled) */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ' and " starts or end quotes (and is consumed).
|
* ' and " starts or end quotes (and is consumed).
|
||||||
|
@ -242,8 +242,8 @@ key_bindings_init(void)
|
|||||||
"bind w choose-tree -Zw",
|
"bind w choose-tree -Zw",
|
||||||
"bind x confirm-before -p\"kill-pane #P? (y/n)\" kill-pane",
|
"bind x confirm-before -p\"kill-pane #P? (y/n)\" kill-pane",
|
||||||
"bind z resize-pane -Z",
|
"bind z resize-pane -Z",
|
||||||
"bind { swap-pane -U",
|
"bind '{' swap-pane -U",
|
||||||
"bind } swap-pane -D",
|
"bind '}' swap-pane -D",
|
||||||
"bind '~' show-messages",
|
"bind '~' show-messages",
|
||||||
"bind PPage copy-mode -u",
|
"bind PPage copy-mode -u",
|
||||||
"bind -r Up select-pane -U",
|
"bind -r Up select-pane -U",
|
||||||
@ -347,8 +347,8 @@ key_bindings_init(void)
|
|||||||
"bind -Tcopy-mode M-r send -X middle-line",
|
"bind -Tcopy-mode M-r send -X middle-line",
|
||||||
"bind -Tcopy-mode M-v send -X page-up",
|
"bind -Tcopy-mode M-v send -X page-up",
|
||||||
"bind -Tcopy-mode M-w send -X copy-selection-and-cancel",
|
"bind -Tcopy-mode M-w send -X copy-selection-and-cancel",
|
||||||
"bind -Tcopy-mode M-{ send -X previous-paragraph",
|
"bind -Tcopy-mode 'M-{' send -X previous-paragraph",
|
||||||
"bind -Tcopy-mode M-} send -X next-paragraph",
|
"bind -Tcopy-mode 'M-}' send -X next-paragraph",
|
||||||
"bind -Tcopy-mode M-Up send -X halfpage-up",
|
"bind -Tcopy-mode M-Up send -X halfpage-up",
|
||||||
"bind -Tcopy-mode M-Down send -X halfpage-down",
|
"bind -Tcopy-mode M-Down send -X halfpage-down",
|
||||||
"bind -Tcopy-mode C-Up send -X scroll-up",
|
"bind -Tcopy-mode C-Up send -X scroll-up",
|
||||||
@ -413,8 +413,8 @@ key_bindings_init(void)
|
|||||||
"bind -Tcopy-mode-vi t command-prompt -1p'(jump to forward)' 'send -X jump-to-forward \"%%%\"'",
|
"bind -Tcopy-mode-vi t command-prompt -1p'(jump to forward)' 'send -X jump-to-forward \"%%%\"'",
|
||||||
"bind -Tcopy-mode-vi v send -X rectangle-toggle",
|
"bind -Tcopy-mode-vi v send -X rectangle-toggle",
|
||||||
"bind -Tcopy-mode-vi w send -X next-word",
|
"bind -Tcopy-mode-vi w send -X next-word",
|
||||||
"bind -Tcopy-mode-vi { send -X previous-paragraph",
|
"bind -Tcopy-mode-vi '{' send -X previous-paragraph",
|
||||||
"bind -Tcopy-mode-vi } send -X next-paragraph",
|
"bind -Tcopy-mode-vi '}' send -X next-paragraph",
|
||||||
"bind -Tcopy-mode-vi % send -X next-matching-bracket",
|
"bind -Tcopy-mode-vi % send -X next-matching-bracket",
|
||||||
"bind -Tcopy-mode-vi MouseDown1Pane select-pane",
|
"bind -Tcopy-mode-vi MouseDown1Pane select-pane",
|
||||||
"bind -Tcopy-mode-vi MouseDrag1Pane select-pane\\; send -X begin-selection",
|
"bind -Tcopy-mode-vi MouseDrag1Pane select-pane\\; send -X begin-selection",
|
||||||
|
2
spawn.c
2
spawn.c
@ -159,6 +159,8 @@ spawn_window(struct spawn_context *sc, char **cause)
|
|||||||
xasprintf(cause, "couldn't create window %d", idx);
|
xasprintf(cause, "couldn't create window %d", idx);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
if (s->curw == NULL)
|
||||||
|
s->curw = sc->wl;
|
||||||
sc->wl->session = s;
|
sc->wl->session = s;
|
||||||
winlink_set_window(sc->wl, w);
|
winlink_set_window(sc->wl, w);
|
||||||
} else
|
} else
|
||||||
|
45
tmux.1
45
tmux.1
@ -495,11 +495,13 @@ line (the \e and the newline are completely removed).
|
|||||||
This is called line continuation and applies both inside and outside quoted
|
This is called line continuation and applies both inside and outside quoted
|
||||||
strings and in comments.
|
strings and in comments.
|
||||||
.Pp
|
.Pp
|
||||||
Command arguments may be specified as strings surrounded by either single (')
|
Command arguments may be specified as strings surrounded by single (') quotes,
|
||||||
or double quotes (").
|
double quotes (") or braces ({}).
|
||||||
.\" "
|
.\" "
|
||||||
This is required when the argument contains any special character.
|
This is required when the argument contains any special character.
|
||||||
Strings cannot span multiple lines except with line continuation.
|
Single and double quoted strings cannot span multiple lines except with line
|
||||||
|
continuation.
|
||||||
|
Braces can span multiple lines.
|
||||||
.Pp
|
.Pp
|
||||||
Outside of quotes and inside double quotes, these replacements are performed:
|
Outside of quotes and inside double quotes, these replacements are performed:
|
||||||
.Bl -dash -offset indent
|
.Bl -dash -offset indent
|
||||||
@ -525,6 +527,34 @@ is removed) and are not treated as having any special meaning - so for example
|
|||||||
variable.
|
variable.
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
|
Braces are similar to single quotes in that the text inside is taken literally
|
||||||
|
without replacements, but they can span multiple lines.
|
||||||
|
They are designed to avoid the need for additional escaping when passing a group
|
||||||
|
of
|
||||||
|
.Nm
|
||||||
|
or shell commands as an argument (for example to
|
||||||
|
.Ic if-shell
|
||||||
|
or
|
||||||
|
.Ic pipe-pane ) .
|
||||||
|
These two examples produce an identical command - note that no escaping is
|
||||||
|
needed when using {}:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
if-shell true {
|
||||||
|
display -p 'brace-dollar-foo: }$foo'
|
||||||
|
}
|
||||||
|
|
||||||
|
if-shell true "\en display -p 'brace-dollar-foo: }\e$foo'\en"
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Braces may be enclosed inside braces, for example:
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
bind x if-shell "true" {
|
||||||
|
if-shell "true" {
|
||||||
|
display "true!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
Environment variables may be set by using the syntax
|
Environment variables may be set by using the syntax
|
||||||
.Ql name=value ,
|
.Ql name=value ,
|
||||||
for example
|
for example
|
||||||
@ -825,15 +855,16 @@ directly without invoking the shell.
|
|||||||
.Op Ar arguments
|
.Op Ar arguments
|
||||||
refers to a
|
refers to a
|
||||||
.Nm
|
.Nm
|
||||||
command, passed with the command and arguments separately, for example:
|
command, either passed with the command and arguments separately, for example:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
bind-key F1 set-option status off
|
bind-key F1 set-option status off
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
Or if using
|
Or passed as a single string argument in
|
||||||
.Xr sh 1 :
|
.Pa .tmux.conf ,
|
||||||
|
for example:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
$ tmux bind-key F1 set-option status off
|
bind-key F1 { set-option status off }
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
Example
|
Example
|
||||||
|
Loading…
Reference in New Issue
Block a user