1*10e0aa77Snicm /* $OpenBSD: cmd-command-prompt.c,v 1.67 2024/04/15 08:19:55 nicm Exp $ */
2311827fbSnicm
3311827fbSnicm /*
498ca8272Snicm * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
5311827fbSnicm *
6311827fbSnicm * Permission to use, copy, modify, and distribute this software for any
7311827fbSnicm * purpose with or without fee is hereby granted, provided that the above
8311827fbSnicm * copyright notice and this permission notice appear in all copies.
9311827fbSnicm *
10311827fbSnicm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11311827fbSnicm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12311827fbSnicm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13311827fbSnicm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14311827fbSnicm * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15311827fbSnicm * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16311827fbSnicm * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17311827fbSnicm */
18311827fbSnicm
19311827fbSnicm #include <sys/types.h>
20311827fbSnicm
21311827fbSnicm #include <ctype.h>
227d053cf9Snicm #include <stdlib.h>
23311827fbSnicm #include <string.h>
24b3a5ab26Snicm #include <time.h>
25311827fbSnicm
26311827fbSnicm #include "tmux.h"
27311827fbSnicm
28311827fbSnicm /*
29311827fbSnicm * Prompt for command in client.
30311827fbSnicm */
31311827fbSnicm
32e4c0b811Snicm static enum args_parse_type cmd_command_prompt_args_parse(struct args *,
33e4c0b811Snicm u_int, char **);
3468e0a7f2Snicm static enum cmd_retval cmd_command_prompt_exec(struct cmd *,
3568e0a7f2Snicm struct cmdq_item *);
36311827fbSnicm
373bf5ffecSnicm static int cmd_command_prompt_callback(struct client *, void *,
383bf5ffecSnicm const char *, int);
39dc1f0f5fSnicm static void cmd_command_prompt_free(void *);
40311827fbSnicm
41311827fbSnicm const struct cmd_entry cmd_command_prompt_entry = {
42c057646bSnicm .name = "command-prompt",
43c057646bSnicm .alias = NULL,
44c057646bSnicm
45e4c0b811Snicm .args = { "1bFkiI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse },
46d530b597Snicm .usage = "[-1bFkiN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
47bc5a8fc2Snicm " [-T type] [template]",
48c057646bSnicm
49035dc73dSnicm .flags = CMD_CLIENT_TFLAG,
50c057646bSnicm .exec = cmd_command_prompt_exec
51311827fbSnicm };
52311827fbSnicm
532db6a388Snicm struct cmd_command_prompt_prompt {
542db6a388Snicm char *input;
552db6a388Snicm char *prompt;
562db6a388Snicm };
572db6a388Snicm
583a89195fSnicm struct cmd_command_prompt_cdata {
59d530b597Snicm struct cmdq_item *item;
602db6a388Snicm struct args_command_state *state;
61d530b597Snicm
62edd3b079Snicm int flags;
63bc5a8fc2Snicm enum prompt_type prompt_type;
64edd3b079Snicm
652db6a388Snicm struct cmd_command_prompt_prompt *prompts;
662db6a388Snicm u_int count;
672db6a388Snicm u_int current;
68edd3b079Snicm
692db6a388Snicm int argc;
702db6a388Snicm char **argv;
713a89195fSnicm };
723a89195fSnicm
73e4c0b811Snicm static enum args_parse_type
cmd_command_prompt_args_parse(__unused struct args * args,__unused u_int idx,__unused char ** cause)74e4c0b811Snicm cmd_command_prompt_args_parse(__unused struct args *args, __unused u_int idx,
75e4c0b811Snicm __unused char **cause)
76e4c0b811Snicm {
77e4c0b811Snicm return (ARGS_PARSE_COMMANDS_OR_STRING);
78e4c0b811Snicm }
79e4c0b811Snicm
80dc1f0f5fSnicm static enum cmd_retval
cmd_command_prompt_exec(struct cmd * self,struct cmdq_item * item)8168e0a7f2Snicm cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
82311827fbSnicm {
8390d7ba38Snicm struct args *args = cmd_get_args(self);
84035dc73dSnicm struct client *tc = cmdq_get_target_client(item);
8594adf770Snicm struct cmd_find_state *target = cmdq_get_target(item);
862db6a388Snicm const char *type, *s, *input;
873a89195fSnicm struct cmd_command_prompt_cdata *cdata;
882db6a388Snicm char *tmp, *prompts, *prompt, *next_prompt;
8904c8d165Snicm char *inputs = NULL, *next_input;
901693b10bSnicm u_int count = args_count(args);
912db6a388Snicm int wait = !args_has(args, 'b'), space = 1;
92311827fbSnicm
93035dc73dSnicm if (tc->prompt_string != NULL)
94a224d0d3Snicm return (CMD_RETURN_NORMAL);
953e68b6f4Snicm if (args_has(args, 'i'))
963e68b6f4Snicm wait = 0;
97311827fbSnicm
98edd3b079Snicm cdata = xcalloc(1, sizeof *cdata);
99d530b597Snicm if (wait)
100d530b597Snicm cdata->item = item;
1012db6a388Snicm cdata->state = args_make_commands_prepare(self, item, 0, "%1", wait,
1022db6a388Snicm args_has(args, 'F'));
103d530b597Snicm
1042db6a388Snicm if ((s = args_get(args, 'p')) == NULL) {
1051693b10bSnicm if (count != 0) {
1062db6a388Snicm tmp = args_make_commands_get_command(cdata->state);
1072db6a388Snicm xasprintf(&prompts, "(%s)", tmp);
1082db6a388Snicm free(tmp);
1092db6a388Snicm } else {
1102db6a388Snicm prompts = xstrdup(":");
1112db6a388Snicm space = 0;
112b3a5ab26Snicm }
1132db6a388Snicm next_prompt = prompts;
1142db6a388Snicm } else
1152db6a388Snicm next_prompt = prompts = xstrdup(s);
1162db6a388Snicm if ((s = args_get(args, 'I')) != NULL)
1172db6a388Snicm next_input = inputs = xstrdup(s);
1182db6a388Snicm else
1192db6a388Snicm next_input = NULL;
1202db6a388Snicm while ((prompt = strsep(&next_prompt, ",")) != NULL) {
1212db6a388Snicm cdata->prompts = xreallocarray(cdata->prompts, cdata->count + 1,
1222db6a388Snicm sizeof *cdata->prompts);
1232db6a388Snicm if (!space)
1242db6a388Snicm tmp = xstrdup(prompt);
1252db6a388Snicm else
1262db6a388Snicm xasprintf(&tmp, "%s ", prompt);
1272db6a388Snicm cdata->prompts[cdata->count].prompt = tmp;
128b3a5ab26Snicm
1292db6a388Snicm if (next_input != NULL) {
1302db6a388Snicm input = strsep(&next_input, ",");
1312db6a388Snicm if (input == NULL)
1322db6a388Snicm input = "";
1332db6a388Snicm } else
1342db6a388Snicm input = "";
1352db6a388Snicm cdata->prompts[cdata->count].input = xstrdup(input);
1362db6a388Snicm
1372db6a388Snicm cdata->count++;
1382db6a388Snicm }
1392db6a388Snicm free(inputs);
1402db6a388Snicm free(prompts);
1412db6a388Snicm
142bc5a8fc2Snicm if ((type = args_get(args, 'T')) != NULL) {
143bc5a8fc2Snicm cdata->prompt_type = status_prompt_type(type);
144bc5a8fc2Snicm if (cdata->prompt_type == PROMPT_TYPE_INVALID) {
145bc5a8fc2Snicm cmdq_error(item, "unknown type: %s", type);
146*10e0aa77Snicm cmd_command_prompt_free(cdata);
147bc5a8fc2Snicm return (CMD_RETURN_ERROR);
148bc5a8fc2Snicm }
149bc5a8fc2Snicm } else
150bc5a8fc2Snicm cdata->prompt_type = PROMPT_TYPE_COMMAND;
151bc5a8fc2Snicm
152576538d5Snicm if (args_has(args, '1'))
153edd3b079Snicm cdata->flags |= PROMPT_SINGLE;
154a3806a61Snicm else if (args_has(args, 'N'))
155edd3b079Snicm cdata->flags |= PROMPT_NUMERIC;
156edd3b079Snicm else if (args_has(args, 'i'))
157edd3b079Snicm cdata->flags |= PROMPT_INCREMENTAL;
158c8877404Snicm else if (args_has(args, 'k'))
159c8877404Snicm cdata->flags |= PROMPT_KEY;
1602db6a388Snicm status_prompt_set(tc, target, cdata->prompts[0].prompt,
1612db6a388Snicm cdata->prompts[0].input, cmd_command_prompt_callback,
1622db6a388Snicm cmd_command_prompt_free, cdata, cdata->flags, cdata->prompt_type);
163311827fbSnicm
164d530b597Snicm if (!wait)
165a224d0d3Snicm return (CMD_RETURN_NORMAL);
166d530b597Snicm return (CMD_RETURN_WAIT);
167311827fbSnicm }
168311827fbSnicm
169dc1f0f5fSnicm static int
cmd_command_prompt_callback(struct client * c,void * data,const char * s,int done)1703bf5ffecSnicm cmd_command_prompt_callback(struct client *c, void *data, const char *s,
1713bf5ffecSnicm int done)
172311827fbSnicm {
1733a89195fSnicm struct cmd_command_prompt_cdata *cdata = data;
1742db6a388Snicm char *error;
1752db6a388Snicm struct cmdq_item *item = cdata->item, *new_item;
1762db6a388Snicm struct cmd_list *cmdlist;
1772db6a388Snicm struct cmd_command_prompt_prompt *prompt;
178d8b32369Snicm int argc = 0;
179d8b32369Snicm char **argv = NULL;
180311827fbSnicm
1813a89195fSnicm if (s == NULL)
182d530b597Snicm goto out;
183a01f743bSnicm
1842db6a388Snicm if (done) {
1852db6a388Snicm if (cdata->flags & PROMPT_INCREMENTAL)
186d530b597Snicm goto out;
187d520327dSnicm cmd_append_argv(&cdata->argc, &cdata->argv, s);
1882db6a388Snicm if (++cdata->current != cdata->count) {
1892db6a388Snicm prompt = &cdata->prompts[cdata->current];
1902db6a388Snicm status_prompt_update(c, prompt->prompt, prompt->input);
1913a89195fSnicm return (1);
192311827fbSnicm }
193d530b597Snicm }
1942db6a388Snicm
195d8b32369Snicm argc = cdata->argc;
196d8b32369Snicm argv = cmd_copy_argv(cdata->argc, cdata->argv);
197a01f743bSnicm if (!done)
198d8b32369Snicm cmd_append_argv(&argc, &argv, s);
199a01f743bSnicm
200d8b32369Snicm if (done) {
201a01f743bSnicm cmd_free_argv(cdata->argc, cdata->argv);
202d8b32369Snicm cdata->argc = argc;
203d8b32369Snicm cdata->argv = cmd_copy_argv(argc, argv);
204d8b32369Snicm }
205d8b32369Snicm
206d8b32369Snicm cmdlist = args_make_commands(cdata->state, argc, argv, &error);
2072db6a388Snicm if (cmdlist == NULL) {
2081c43462cSnicm cmdq_append(c, cmdq_get_error(error));
2091c43462cSnicm free(error);
2102db6a388Snicm } else if (item == NULL) {
2112db6a388Snicm new_item = cmdq_get_command(cmdlist, NULL);
2122db6a388Snicm cmdq_append(c, new_item);
2132db6a388Snicm } else {
2142db6a388Snicm new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
2152db6a388Snicm cmdq_insert_after(item, new_item);
216df6ab229Snicm }
217d8b32369Snicm cmd_free_argv(argc, argv);
218311827fbSnicm
2193bf5ffecSnicm if (c->prompt_inputcb != cmd_command_prompt_callback)
220311827fbSnicm return (1);
221d530b597Snicm
222d530b597Snicm out:
223d530b597Snicm if (item != NULL)
224d530b597Snicm cmdq_continue(item);
225311827fbSnicm return (0);
226311827fbSnicm }
227e468f8d3Snicm
228dc1f0f5fSnicm static void
cmd_command_prompt_free(void * data)229ca7befccSnicm cmd_command_prompt_free(void *data)
230e468f8d3Snicm {
2313a89195fSnicm struct cmd_command_prompt_cdata *cdata = data;
2322db6a388Snicm u_int i;
233e468f8d3Snicm
2342db6a388Snicm for (i = 0; i < cdata->count; i++) {
2352db6a388Snicm free(cdata->prompts[i].prompt);
2362db6a388Snicm free(cdata->prompts[i].input);
2372db6a388Snicm }
2387d053cf9Snicm free(cdata->prompts);
2392db6a388Snicm cmd_free_argv(cdata->argc, cdata->argv);
2402db6a388Snicm args_make_commands_free(cdata->state);
2417d053cf9Snicm free(cdata);
242e468f8d3Snicm }
243