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:
Tiago Cunha 2009-08-20 11:51:20 +00:00
parent 4631c07483
commit 1292540bb5
4 changed files with 243 additions and 82 deletions

View File

@ -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> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@ -28,55 +28,111 @@
*/ */
void cmd_command_prompt_init(struct cmd *, int); 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 *); 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 *); int cmd_command_prompt_callback(void *, const char *);
void cmd_command_prompt_free(void *); void cmd_command_prompt_cfree(void *);
char *cmd_command_prompt_replace(char *, const char *, int);
const struct cmd_entry cmd_command_prompt_entry = { const struct cmd_entry cmd_command_prompt_entry = {
"command-prompt", NULL, "command-prompt", NULL,
CMD_TARGET_CLIENT_USAGE " [template]", CMD_TARGET_CLIENT_USAGE " [-p prompts] [template]",
CMD_ARG01, 0, 0, 0,
cmd_command_prompt_init, cmd_command_prompt_init,
cmd_target_parse, cmd_command_prompt_parse,
cmd_command_prompt_exec, cmd_command_prompt_exec,
cmd_target_free, cmd_command_prompt_free,
cmd_target_print cmd_command_prompt_print
}; };
struct cmd_command_prompt_data { struct cmd_command_prompt_data {
struct client *c; char *prompts;
char *target;
char *template; char *template;
}; };
struct cmd_command_prompt_cdata {
struct client *c;
char *next_prompt;
char *prompts;
char *template;
int idx;
};
void void
cmd_command_prompt_init(struct cmd *self, int key) 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); self->data = data = xmalloc(sizeof *data);
data = self->data; data->prompts = NULL;
data->target = NULL;
data->template = NULL;
switch (key) { switch (key) {
case ',': case ',':
data->arg = xstrdup("rename-window '%%'"); data->template = xstrdup("rename-window '%%'");
break; break;
case '.': case '.':
data->arg = xstrdup("move-window -t '%%'"); data->template = xstrdup("move-window -t '%%'");
break; break;
case 'f': case 'f':
data->arg = xstrdup("find-window '%%'"); data->template = xstrdup("find-window '%%'");
break; 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 int
cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
{ {
struct cmd_target_data *data = self->data; struct cmd_command_prompt_data *data = self->data;
struct cmd_command_prompt_data *cdata; struct cmd_command_prompt_cdata *cdata;
struct client *c; struct client *c;
char *hdr, *ptr; char *prompt, *ptr;
size_t n;
if ((c = cmd_find_client(ctx, data->target)) == NULL) if ((c = cmd_find_client(ctx, data->target)) == NULL)
return (-1); return (-1);
@ -86,76 +142,100 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
cdata = xmalloc(sizeof *cdata); cdata = xmalloc(sizeof *cdata);
cdata->c = c; cdata->c = c;
if (data->arg != NULL) { cdata->idx = 1;
cdata->template = xstrdup(data->arg); cdata->next_prompt = NULL;
if ((ptr = strchr(data->arg, ' ')) == NULL) cdata->prompts = NULL;
ptr = strchr(data->arg, '\0');
xasprintf(&hdr, "(%.*s) ", (int) (ptr - data->arg), data->arg);
} else {
cdata->template = NULL; cdata->template = NULL;
hdr = xstrdup(":");
} if (data->template != NULL)
status_prompt_set(c, hdr, cdata->template = xstrdup(data->template);
cmd_command_prompt_callback, cmd_command_prompt_free, cdata, 0); else
xfree(hdr); 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); 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 int
cmd_command_prompt_callback(void *data, const char *s) 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 client *c = cdata->c;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
struct cmd_ctx ctx; struct cmd_ctx ctx;
char *cause, *ptr, *buf, ch; char *cause, *newtempl, *prompt, *ptr;
size_t len, slen;
if (s == NULL || *s == '\0') if (s == NULL)
return (0); return (0);
slen = strlen(s);
len = 0; newtempl = cmd_command_prompt_replace(cdata->template, s, cdata->idx);
buf = NULL; xfree(cdata->template);
if (cdata->template != NULL) { cdata->template = newtempl;
ptr = cdata->template;
while (*ptr != '\0') {
switch (ch = *ptr++) {
case '%':
if (*ptr != '%')
break;
ptr++;
buf = xrealloc(buf, 1, len + slen + 1); if ((ptr = strsep(&cdata->next_prompt, ",")) != NULL) {
memcpy(buf + len, s, slen); xasprintf(&prompt, "%s ", ptr);
len += slen; status_prompt_update(c, prompt);
break; xfree(prompt);
default: cdata->idx++;
buf = xrealloc(buf, 1, len + 2); return (1);
buf[len++] = ch;
break;
}
} }
if (buf == NULL) if (cmd_string_parse(newtempl, &cmdlist, &cause) != 0) {
return (0); if (cause != NULL) {
buf[len] = '\0';
s = buf;
}
if (cmd_string_parse(s, &cmdlist, &cause) != 0) {
if (cause == NULL)
return (0);
*cause = toupper((u_char) *cause); *cause = toupper((u_char) *cause);
status_message_set(c, "%s", cause); status_message_set(c, "%s", cause);
xfree(cause); xfree(cause);
cmdlist = NULL;
} }
if (buf != NULL)
xfree(buf);
if (cmdlist == NULL)
return (0); return (0);
}
ctx.msgdata = NULL; ctx.msgdata = NULL;
ctx.cursession = c->session; ctx.cursession = c->session;
@ -176,11 +256,53 @@ cmd_command_prompt_callback(void *data, const char *s)
} }
void 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) if (cdata->template != NULL)
xfree(cdata->template); xfree(cdata->template);
xfree(cdata); 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);
}

View File

@ -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> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -668,6 +668,20 @@ status_prompt_clear(struct client *c)
screen_reinit(&c->status); 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. */ /* Draw client prompt on status line of present else on last line. */
int int
status_prompt_redraw(struct client *c) status_prompt_redraw(struct client *c)

32
tmux.1
View File

@ -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> .\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
.\" .\"
@ -14,7 +14,7 @@
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING .\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" 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 .Dt TMUX 1
.Os .Os
.Sh NAME .Sh NAME
@ -1662,6 +1662,7 @@ session option.
Commands related to the status line are as follows: Commands related to the status line are as follows:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Xo Ic command-prompt .It Xo Ic command-prompt
.Op Fl p Ar prompts
.Op Fl t Ar target-client .Op Fl t Ar target-client
.Op Ar template .Op Ar template
.Xc .Xc
@ -1671,8 +1672,30 @@ This may be used from inside
to execute commands interactively. to execute commands interactively.
If If
.Ar template .Ar template
is specified, it is used as the command; any %% in the template will be is specified, it is used as the command.
replaced by what is entered at the prompt. 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 .It Xo Ic confirm-before
.Op Fl t Ar target-client .Op Fl t Ar target-client
.Ar command .Ar command
@ -1926,6 +1949,7 @@ Creating new key bindings:
.Bd -literal -offset indent .Bd -literal -offset indent
bind-key b set-option status bind-key b set-option status
bind-key / command-prompt "split-window 'exec man %%'" bind-key / command-prompt "split-window 'exec man %%'"
bind-key S command-prompt "new-window -n %1 'ssh %1'"
.Ed .Ed
.Sh SEE ALSO .Sh SEE ALSO
.Xr pty 4 .Xr pty 4

3
tmux.h
View File

@ -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> * 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 *); void status_prompt_clear(struct client *);
int status_prompt_redraw(struct client *); int status_prompt_redraw(struct client *);
void status_prompt_key(struct client *, int); void status_prompt_key(struct client *, int);
void status_prompt_update(struct client *, const char *);
/* resize.c */ /* resize.c */
void recalculate_sizes(void); void recalculate_sizes(void);