xref: /openbsd-src/usr.bin/tmux/cmd-command-prompt.c (revision 10e0aa77e9eb034f8a687e6dffc2e4e944ed30df)
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