mirror of
https://github.com/tmux/tmux.git
synced 2025-01-12 19:39:04 +00:00
Sync OpenBSD patchset 276:
Extend command-prompt with a -p option which is a comma-separated list of one or more prompts to present in order. The responses to the prompt are replaced in the template string: %% are replaced in order, so the first prompt replaces the first %%, the second replaces the second, and so on. In addition, %1 up to %9 are replaced with the responses to the first the ninth prompts The default template is "%1" so the response to the first prompt is processed as a command. Note that this changes the behaviour for %% so if there is only one prompt, only the first %% will be replaced. Templates such as "neww -n '%%' 'ssh %%'" should be changed to "neww -n '%1' 'ssh %1'". From Tiago Cunha.
This commit is contained in:
parent
4631c07483
commit
1292540bb5
@ -1,4 +1,4 @@
|
||||
/* $Id: cmd-command-prompt.c,v 1.22 2009-08-16 19:29:24 tcunha Exp $ */
|
||||
/* $Id: cmd-command-prompt.c,v 1.23 2009-08-20 11:51:20 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@ -27,56 +27,112 @@
|
||||
* Prompt for command in client.
|
||||
*/
|
||||
|
||||
void cmd_command_prompt_init(struct cmd *, int);
|
||||
int cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *);
|
||||
void cmd_command_prompt_init(struct cmd *, int);
|
||||
int cmd_command_prompt_parse(struct cmd *, int, char **, char **);
|
||||
int cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *);
|
||||
void cmd_command_prompt_free(struct cmd *);
|
||||
size_t cmd_command_prompt_print(struct cmd *, char *, size_t);
|
||||
|
||||
int cmd_command_prompt_callback(void *, const char *);
|
||||
void cmd_command_prompt_free(void *);
|
||||
int cmd_command_prompt_callback(void *, const char *);
|
||||
void cmd_command_prompt_cfree(void *);
|
||||
char *cmd_command_prompt_replace(char *, const char *, int);
|
||||
|
||||
const struct cmd_entry cmd_command_prompt_entry = {
|
||||
"command-prompt", NULL,
|
||||
CMD_TARGET_CLIENT_USAGE " [template]",
|
||||
CMD_ARG01, 0,
|
||||
CMD_TARGET_CLIENT_USAGE " [-p prompts] [template]",
|
||||
0, 0,
|
||||
cmd_command_prompt_init,
|
||||
cmd_target_parse,
|
||||
cmd_command_prompt_parse,
|
||||
cmd_command_prompt_exec,
|
||||
cmd_target_free,
|
||||
cmd_target_print
|
||||
cmd_command_prompt_free,
|
||||
cmd_command_prompt_print
|
||||
};
|
||||
|
||||
struct cmd_command_prompt_data {
|
||||
char *prompts;
|
||||
char *target;
|
||||
char *template;
|
||||
};
|
||||
|
||||
struct cmd_command_prompt_cdata {
|
||||
struct client *c;
|
||||
char *next_prompt;
|
||||
char *prompts;
|
||||
char *template;
|
||||
int idx;
|
||||
};
|
||||
|
||||
void
|
||||
cmd_command_prompt_init(struct cmd *self, int key)
|
||||
{
|
||||
struct cmd_target_data *data;
|
||||
struct cmd_command_prompt_data *data;
|
||||
|
||||
cmd_target_init(self, key);
|
||||
data = self->data;
|
||||
self->data = data = xmalloc(sizeof *data);
|
||||
data->prompts = NULL;
|
||||
data->target = NULL;
|
||||
data->template = NULL;
|
||||
|
||||
switch (key) {
|
||||
case ',':
|
||||
data->arg = xstrdup("rename-window '%%'");
|
||||
data->template = xstrdup("rename-window '%%'");
|
||||
break;
|
||||
case '.':
|
||||
data->arg = xstrdup("move-window -t '%%'");
|
||||
data->template = xstrdup("move-window -t '%%'");
|
||||
break;
|
||||
case 'f':
|
||||
data->arg = xstrdup("find-window '%%'");
|
||||
data->template = xstrdup("find-window '%%'");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
cmd_command_prompt_parse(struct cmd *self, int argc, char **argv, char **cause)
|
||||
{
|
||||
struct cmd_command_prompt_data *data;
|
||||
int opt;
|
||||
|
||||
self->entry->init(self, 0);
|
||||
data = self->data;
|
||||
|
||||
while ((opt = getopt(argc, argv, "p:t:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'p':
|
||||
if (data->prompts == NULL)
|
||||
data->prompts = xstrdup(optarg);
|
||||
break;
|
||||
case 't':
|
||||
if (data->target == NULL)
|
||||
data->target = xstrdup(optarg);
|
||||
break;
|
||||
default:
|
||||
goto usage;
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if (argc != 0 && argc != 1)
|
||||
goto usage;
|
||||
|
||||
if (argc == 1)
|
||||
data->template = xstrdup(argv[0]);
|
||||
|
||||
return (0);
|
||||
|
||||
usage:
|
||||
xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
|
||||
|
||||
self->entry->free(self);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int
|
||||
cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
{
|
||||
struct cmd_target_data *data = self->data;
|
||||
struct cmd_command_prompt_data *cdata;
|
||||
struct cmd_command_prompt_data *data = self->data;
|
||||
struct cmd_command_prompt_cdata *cdata;
|
||||
struct client *c;
|
||||
char *hdr, *ptr;
|
||||
char *prompt, *ptr;
|
||||
size_t n;
|
||||
|
||||
if ((c = cmd_find_client(ctx, data->target)) == NULL)
|
||||
return (-1);
|
||||
@ -86,76 +142,100 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
|
||||
cdata = xmalloc(sizeof *cdata);
|
||||
cdata->c = c;
|
||||
if (data->arg != NULL) {
|
||||
cdata->template = xstrdup(data->arg);
|
||||
if ((ptr = strchr(data->arg, ' ')) == NULL)
|
||||
ptr = strchr(data->arg, '\0');
|
||||
xasprintf(&hdr, "(%.*s) ", (int) (ptr - data->arg), data->arg);
|
||||
} else {
|
||||
cdata->template = NULL;
|
||||
hdr = xstrdup(":");
|
||||
}
|
||||
status_prompt_set(c, hdr,
|
||||
cmd_command_prompt_callback, cmd_command_prompt_free, cdata, 0);
|
||||
xfree(hdr);
|
||||
cdata->idx = 1;
|
||||
cdata->next_prompt = NULL;
|
||||
cdata->prompts = NULL;
|
||||
cdata->template = NULL;
|
||||
|
||||
if (data->template != NULL)
|
||||
cdata->template = xstrdup(data->template);
|
||||
else
|
||||
cdata->template = xstrdup("%1");
|
||||
if (data->prompts != NULL)
|
||||
cdata->prompts = xstrdup(data->prompts);
|
||||
else if (data->template != NULL) {
|
||||
n = strcspn(data->template, " ,");
|
||||
xasprintf(&cdata->prompts, "(%.*s) ", (int) n, data->template);
|
||||
} else
|
||||
cdata->prompts = xstrdup(":");
|
||||
|
||||
cdata->next_prompt = cdata->prompts;
|
||||
ptr = strsep(&cdata->next_prompt, ",");
|
||||
if (data->prompts == NULL)
|
||||
prompt = xstrdup(ptr);
|
||||
else
|
||||
xasprintf(&prompt, "%s ", ptr);
|
||||
status_prompt_set(c, prompt, cmd_command_prompt_callback,
|
||||
cmd_command_prompt_cfree, cdata, 0);
|
||||
xfree(prompt);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_command_prompt_free(struct cmd *self)
|
||||
{
|
||||
struct cmd_command_prompt_data *data = self->data;
|
||||
|
||||
if (data->prompts != NULL)
|
||||
xfree(data->prompts);
|
||||
if (data->target != NULL)
|
||||
xfree(data->target);
|
||||
if (data->template != NULL)
|
||||
xfree(data->template);
|
||||
xfree(data);
|
||||
}
|
||||
|
||||
size_t
|
||||
cmd_command_prompt_print(struct cmd *self, char *buf, size_t len)
|
||||
{
|
||||
struct cmd_command_prompt_data *data = self->data;
|
||||
size_t off = 0;
|
||||
|
||||
off += xsnprintf(buf, len, "%s", self->entry->name);
|
||||
if (data == NULL)
|
||||
return (off);
|
||||
if (off < len && data->prompts != NULL)
|
||||
off += cmd_prarg(buf + off, len - off, " -p ", data->prompts);
|
||||
if (off < len && data->target != NULL)
|
||||
off += cmd_prarg(buf + off, len - off, " -t ", data->target);
|
||||
if (off < len && data->template != NULL)
|
||||
off += cmd_prarg(buf + off, len - off, " ", data->template);
|
||||
return (off);
|
||||
}
|
||||
|
||||
int
|
||||
cmd_command_prompt_callback(void *data, const char *s)
|
||||
{
|
||||
struct cmd_command_prompt_data *cdata = data;
|
||||
struct cmd_command_prompt_cdata *cdata = data;
|
||||
struct client *c = cdata->c;
|
||||
struct cmd_list *cmdlist;
|
||||
struct cmd_ctx ctx;
|
||||
char *cause, *ptr, *buf, ch;
|
||||
size_t len, slen;
|
||||
struct cmd_ctx ctx;
|
||||
char *cause, *newtempl, *prompt, *ptr;
|
||||
|
||||
if (s == NULL || *s == '\0')
|
||||
if (s == NULL)
|
||||
return (0);
|
||||
slen = strlen(s);
|
||||
|
||||
len = 0;
|
||||
buf = NULL;
|
||||
if (cdata->template != NULL) {
|
||||
ptr = cdata->template;
|
||||
while (*ptr != '\0') {
|
||||
switch (ch = *ptr++) {
|
||||
case '%':
|
||||
if (*ptr != '%')
|
||||
break;
|
||||
ptr++;
|
||||
newtempl = cmd_command_prompt_replace(cdata->template, s, cdata->idx);
|
||||
xfree(cdata->template);
|
||||
cdata->template = newtempl;
|
||||
|
||||
buf = xrealloc(buf, 1, len + slen + 1);
|
||||
memcpy(buf + len, s, slen);
|
||||
len += slen;
|
||||
break;
|
||||
default:
|
||||
buf = xrealloc(buf, 1, len + 2);
|
||||
buf[len++] = ch;
|
||||
break;
|
||||
}
|
||||
if ((ptr = strsep(&cdata->next_prompt, ",")) != NULL) {
|
||||
xasprintf(&prompt, "%s ", ptr);
|
||||
status_prompt_update(c, prompt);
|
||||
xfree(prompt);
|
||||
cdata->idx++;
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (cmd_string_parse(newtempl, &cmdlist, &cause) != 0) {
|
||||
if (cause != NULL) {
|
||||
*cause = toupper((u_char) *cause);
|
||||
status_message_set(c, "%s", cause);
|
||||
xfree(cause);
|
||||
}
|
||||
|
||||
if (buf == NULL)
|
||||
return (0);
|
||||
buf[len] = '\0';
|
||||
s = buf;
|
||||
}
|
||||
|
||||
if (cmd_string_parse(s, &cmdlist, &cause) != 0) {
|
||||
if (cause == NULL)
|
||||
return (0);
|
||||
*cause = toupper((u_char) *cause);
|
||||
status_message_set(c, "%s", cause);
|
||||
xfree(cause);
|
||||
cmdlist = NULL;
|
||||
}
|
||||
if (buf != NULL)
|
||||
xfree(buf);
|
||||
if (cmdlist == NULL)
|
||||
return (0);
|
||||
}
|
||||
|
||||
ctx.msgdata = NULL;
|
||||
ctx.cursession = c->session;
|
||||
@ -176,11 +256,53 @@ cmd_command_prompt_callback(void *data, const char *s)
|
||||
}
|
||||
|
||||
void
|
||||
cmd_command_prompt_free(void *data)
|
||||
cmd_command_prompt_cfree(void *data)
|
||||
{
|
||||
struct cmd_command_prompt_data *cdata = data;
|
||||
struct cmd_command_prompt_cdata *cdata = data;
|
||||
|
||||
if (cdata->prompts != NULL)
|
||||
xfree(cdata->prompts);
|
||||
if (cdata->template != NULL)
|
||||
xfree(cdata->template);
|
||||
xfree(cdata);
|
||||
}
|
||||
|
||||
char *
|
||||
cmd_command_prompt_replace(char *template, const char *s, int idx)
|
||||
{
|
||||
char ch;
|
||||
char *buf, *ptr;
|
||||
int replaced;
|
||||
size_t len;
|
||||
|
||||
if (strstr(template, "%") == NULL)
|
||||
return (xstrdup(template));
|
||||
|
||||
buf = xmalloc(1);
|
||||
*buf = '\0';
|
||||
len = 0;
|
||||
replaced = 0;
|
||||
|
||||
ptr = template;
|
||||
while (*ptr != '\0') {
|
||||
switch (ch = *ptr++) {
|
||||
case '%':
|
||||
if (*ptr < '1' || *ptr > '9' || *ptr - '0' != idx) {
|
||||
if (*ptr != '%' || replaced)
|
||||
break;
|
||||
replaced = 1;
|
||||
}
|
||||
ptr++;
|
||||
|
||||
len += strlen(s);
|
||||
buf = xrealloc(buf, 1, len + 1);
|
||||
strlcat(buf, s, len + 1);
|
||||
continue;
|
||||
}
|
||||
buf = xrealloc(buf, 1, len + 2);
|
||||
buf[len++] = ch;
|
||||
buf[len] = '\0';
|
||||
}
|
||||
|
||||
return (buf);
|
||||
}
|
||||
|
16
status.c
16
status.c
@ -1,4 +1,4 @@
|
||||
/* $Id: status.c,v 1.111 2009-08-20 11:22:47 tcunha Exp $ */
|
||||
/* $Id: status.c,v 1.112 2009-08-20 11:51:20 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@ -668,6 +668,20 @@ status_prompt_clear(struct client *c)
|
||||
screen_reinit(&c->status);
|
||||
}
|
||||
|
||||
void
|
||||
status_prompt_update(struct client *c, const char *msg)
|
||||
{
|
||||
xfree(c->prompt_string);
|
||||
c->prompt_string = xstrdup(msg);
|
||||
|
||||
*c->prompt_buffer = '\0';
|
||||
c->prompt_index = 0;
|
||||
|
||||
c->prompt_hindex = 0;
|
||||
|
||||
c->flags |= CLIENT_STATUS;
|
||||
}
|
||||
|
||||
/* Draw client prompt on status line of present else on last line. */
|
||||
int
|
||||
status_prompt_redraw(struct client *c)
|
||||
|
32
tmux.1
32
tmux.1
@ -1,4 +1,4 @@
|
||||
.\" $Id: tmux.1,v 1.154 2009-08-20 11:37:46 tcunha Exp $
|
||||
.\" $Id: tmux.1,v 1.155 2009-08-20 11:51:20 tcunha Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
.\"
|
||||
@ -14,7 +14,7 @@
|
||||
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd $Mdocdate: August 18 2009 $
|
||||
.Dd $Mdocdate: August 19 2009 $
|
||||
.Dt TMUX 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -1662,6 +1662,7 @@ session option.
|
||||
Commands related to the status line are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Xo Ic command-prompt
|
||||
.Op Fl p Ar prompts
|
||||
.Op Fl t Ar target-client
|
||||
.Op Ar template
|
||||
.Xc
|
||||
@ -1671,8 +1672,30 @@ This may be used from inside
|
||||
to execute commands interactively.
|
||||
If
|
||||
.Ar template
|
||||
is specified, it is used as the command; any %% in the template will be
|
||||
replaced by what is entered at the prompt.
|
||||
is specified, it is used as the command.
|
||||
If
|
||||
.Fl p
|
||||
is given,
|
||||
.Ar prompts
|
||||
is a comma-separated list of prompts which are displayed in order; otherwise
|
||||
a single prompt is displayed, constructed from
|
||||
.Ar template
|
||||
if it is present, or
|
||||
.Ql \&:
|
||||
if not.
|
||||
Before the command is executed, the first occurrence of the string
|
||||
.Ql %%
|
||||
and all occurences of
|
||||
.Ql %1
|
||||
are replaced by the response to the first prompt, the second
|
||||
.Ql %%
|
||||
and all
|
||||
.Ql %2
|
||||
are replaced with the response to the second prompt, and so on for further
|
||||
prompts. Up to nine prompt responses may be replaced
|
||||
.Ns ( Ql %1
|
||||
to
|
||||
.Ns Ql %9 ) .
|
||||
.It Xo Ic confirm-before
|
||||
.Op Fl t Ar target-client
|
||||
.Ar command
|
||||
@ -1926,6 +1949,7 @@ Creating new key bindings:
|
||||
.Bd -literal -offset indent
|
||||
bind-key b set-option status
|
||||
bind-key / command-prompt "split-window 'exec man %%'"
|
||||
bind-key S command-prompt "new-window -n %1 'ssh %1'"
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr pty 4
|
||||
|
3
tmux.h
3
tmux.h
@ -1,4 +1,4 @@
|
||||
/* $Id: tmux.h,v 1.424 2009-08-20 11:48:01 tcunha Exp $ */
|
||||
/* $Id: tmux.h,v 1.425 2009-08-20 11:51:20 tcunha Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
@ -1438,6 +1438,7 @@ void status_prompt_set(struct client *, const char *,
|
||||
void status_prompt_clear(struct client *);
|
||||
int status_prompt_redraw(struct client *);
|
||||
void status_prompt_key(struct client *, int);
|
||||
void status_prompt_update(struct client *, const char *);
|
||||
|
||||
/* resize.c */
|
||||
void recalculate_sizes(void);
|
||||
|
Loading…
Reference in New Issue
Block a user