mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 09:26:05 +00:00 
			
		
		
		
	Add an additional {} syntax for defining strings in the configuration
file, making it much tidier to define commands that contain other tmux
or shell commands (like if-shell). Also tweak bind-key to expect a
string if it is only given one argument, so {} can be used with it as
well. From Avi Halachmi.
			
			
This commit is contained in:
		@@ -207,7 +207,7 @@ args_print(struct args *args)
 | 
			
		||||
char *
 | 
			
		||||
args_escape(const char *s)
 | 
			
		||||
{
 | 
			
		||||
	static const char	 quoted[] = " #\"';$";
 | 
			
		||||
	static const char	 quoted[] = " #\"';${}";
 | 
			
		||||
	char			*escaped, *result;
 | 
			
		||||
	int			 flags;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -44,14 +44,16 @@ const struct cmd_entry cmd_bind_key_entry = {
 | 
			
		||||
static enum cmd_retval
 | 
			
		||||
cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
 | 
			
		||||
{
 | 
			
		||||
	struct args		*args = self->args;
 | 
			
		||||
	key_code		 key;
 | 
			
		||||
	const char		*tablename;
 | 
			
		||||
	struct cmd_parse_result	*pr;
 | 
			
		||||
	struct args		 *args = self->args;
 | 
			
		||||
	key_code		  key;
 | 
			
		||||
	const char		 *tablename;
 | 
			
		||||
	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) {
 | 
			
		||||
		cmdq_error(item, "unknown key: %s", args->argv[0]);
 | 
			
		||||
		cmdq_error(item, "unknown key: %s", argv[0]);
 | 
			
		||||
		return (CMD_RETURN_ERROR);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -62,7 +64,10 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
 | 
			
		||||
	else
 | 
			
		||||
		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) {
 | 
			
		||||
	case CMD_PARSE_EMPTY:
 | 
			
		||||
		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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 *
 | 
			
		||||
yylex_token(int ch)
 | 
			
		||||
{
 | 
			
		||||
@@ -1282,6 +1375,13 @@ yylex_token(int ch)
 | 
			
		||||
				goto error;
 | 
			
		||||
			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).
 | 
			
		||||
 
 | 
			
		||||
@@ -242,8 +242,8 @@ key_bindings_init(void)
 | 
			
		||||
		"bind w choose-tree -Zw",
 | 
			
		||||
		"bind x confirm-before -p\"kill-pane #P? (y/n)\" kill-pane",
 | 
			
		||||
		"bind z resize-pane -Z",
 | 
			
		||||
		"bind { swap-pane -U",
 | 
			
		||||
		"bind } swap-pane -D",
 | 
			
		||||
		"bind '{' swap-pane -U",
 | 
			
		||||
		"bind '}' swap-pane -D",
 | 
			
		||||
		"bind '~' show-messages",
 | 
			
		||||
		"bind PPage copy-mode -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-v send -X page-up",
 | 
			
		||||
		"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 next-paragraph",
 | 
			
		||||
		"bind -Tcopy-mode 'M-{' send -X previous-paragraph",
 | 
			
		||||
		"bind -Tcopy-mode 'M-}' send -X next-paragraph",
 | 
			
		||||
		"bind -Tcopy-mode M-Up send -X halfpage-up",
 | 
			
		||||
		"bind -Tcopy-mode M-Down send -X halfpage-down",
 | 
			
		||||
		"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 v send -X rectangle-toggle",
 | 
			
		||||
		"bind -Tcopy-mode-vi w send -X next-word",
 | 
			
		||||
		"bind -Tcopy-mode-vi { send -X previous-paragraph",
 | 
			
		||||
		"bind -Tcopy-mode-vi } send -X next-paragraph",
 | 
			
		||||
		"bind -Tcopy-mode-vi '{' send -X previous-paragraph",
 | 
			
		||||
		"bind -Tcopy-mode-vi '}' send -X next-paragraph",
 | 
			
		||||
		"bind -Tcopy-mode-vi % send -X next-matching-bracket",
 | 
			
		||||
		"bind -Tcopy-mode-vi MouseDown1Pane select-pane",
 | 
			
		||||
		"bind -Tcopy-mode-vi MouseDrag1Pane select-pane\\; send -X begin-selection",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										45
									
								
								tmux.1
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								tmux.1
									
									
									
									
									
								
							@@ -490,11 +490,13 @@ line (the \e and the newline are completely removed).
 | 
			
		||||
This is called line continuation and applies both inside and outside quoted
 | 
			
		||||
strings and in comments.
 | 
			
		||||
.Pp
 | 
			
		||||
Command arguments may be specified as strings surrounded by either single (')
 | 
			
		||||
or double quotes (").
 | 
			
		||||
Command arguments may be specified as strings surrounded by single (') quotes,
 | 
			
		||||
double quotes (") or braces ({}).
 | 
			
		||||
.\" "
 | 
			
		||||
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
 | 
			
		||||
Outside of quotes and inside double quotes, these replacements are performed:
 | 
			
		||||
.Bl -dash -offset indent
 | 
			
		||||
@@ -520,6 +522,34 @@ is removed) and are not treated as having any special meaning - so for example
 | 
			
		||||
variable.
 | 
			
		||||
.El
 | 
			
		||||
.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
 | 
			
		||||
.Ql name=value ,
 | 
			
		||||
for example
 | 
			
		||||
@@ -820,15 +850,16 @@ directly without invoking the shell.
 | 
			
		||||
.Op Ar arguments
 | 
			
		||||
refers to a
 | 
			
		||||
.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
 | 
			
		||||
bind-key F1 set-option status off
 | 
			
		||||
.Ed
 | 
			
		||||
.Pp
 | 
			
		||||
Or if using
 | 
			
		||||
.Xr sh 1 :
 | 
			
		||||
Or passed as a single string argument in
 | 
			
		||||
.Pa .tmux.conf ,
 | 
			
		||||
for example:
 | 
			
		||||
.Bd -literal -offset indent
 | 
			
		||||
$ tmux bind-key F1 set-option status off
 | 
			
		||||
bind-key F1 { set-option status off }
 | 
			
		||||
.Ed
 | 
			
		||||
.Pp
 | 
			
		||||
Example
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user