15494e770Schristos /* $OpenBSD$ */ 2698d5317Sjmmv 3698d5317Sjmmv /* 4ed4e6cd4Schristos * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com> 5698d5317Sjmmv * 6698d5317Sjmmv * Permission to use, copy, modify, and distribute this software for any 7698d5317Sjmmv * purpose with or without fee is hereby granted, provided that the above 8698d5317Sjmmv * copyright notice and this permission notice appear in all copies. 9698d5317Sjmmv * 10698d5317Sjmmv * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11698d5317Sjmmv * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12698d5317Sjmmv * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13698d5317Sjmmv * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14698d5317Sjmmv * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15698d5317Sjmmv * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16698d5317Sjmmv * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17698d5317Sjmmv */ 18698d5317Sjmmv 19698d5317Sjmmv #include <sys/types.h> 20698d5317Sjmmv 21698d5317Sjmmv #include <ctype.h> 22928fc495Schristos #include <stdlib.h> 23698d5317Sjmmv #include <string.h> 24d530c4d0Sjmmv #include <time.h> 25698d5317Sjmmv 26698d5317Sjmmv #include "tmux.h" 27698d5317Sjmmv 28698d5317Sjmmv /* 29698d5317Sjmmv * Prompt for command in client. 30698d5317Sjmmv */ 31698d5317Sjmmv 326db26757Swiz static enum args_parse_type cmd_command_prompt_args_parse(struct args *, 336db26757Swiz u_int, char **); 344e179ddaSchristos static enum cmd_retval cmd_command_prompt_exec(struct cmd *, 354e179ddaSchristos struct cmdq_item *); 36698d5317Sjmmv 37c9ad075bSchristos static int cmd_command_prompt_callback(struct client *, void *, 38c9ad075bSchristos const char *, int); 394e179ddaSchristos static void cmd_command_prompt_free(void *); 40698d5317Sjmmv 41698d5317Sjmmv const struct cmd_entry cmd_command_prompt_entry = { 42ed4e6cd4Schristos .name = "command-prompt", 43ed4e6cd4Schristos .alias = NULL, 44ed4e6cd4Schristos 456db26757Swiz .args = { "1bFkiI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse }, 466db26757Swiz .usage = "[-1bFkiN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE 476db26757Swiz " [-T type] [template]", 48ed4e6cd4Schristos 499fb66d81Schristos .flags = CMD_CLIENT_TFLAG, 50ed4e6cd4Schristos .exec = cmd_command_prompt_exec 51698d5317Sjmmv }; 52698d5317Sjmmv 536db26757Swiz struct cmd_command_prompt_prompt { 546db26757Swiz char *input; 556db26757Swiz char *prompt; 56698d5317Sjmmv }; 57698d5317Sjmmv 586db26757Swiz struct cmd_command_prompt_cdata { 596db26757Swiz struct cmdq_item *item; 606db26757Swiz struct args_command_state *state; 616db26757Swiz 626db26757Swiz int flags; 636db26757Swiz enum prompt_type prompt_type; 646db26757Swiz 656db26757Swiz struct cmd_command_prompt_prompt *prompts; 666db26757Swiz u_int count; 676db26757Swiz u_int current; 686db26757Swiz 696db26757Swiz int argc; 706db26757Swiz char **argv; 716db26757Swiz }; 726db26757Swiz 736db26757Swiz static enum args_parse_type 746db26757Swiz cmd_command_prompt_args_parse(__unused struct args *args, __unused u_int idx, 756db26757Swiz __unused char **cause) 766db26757Swiz { 776db26757Swiz return (ARGS_PARSE_COMMANDS_OR_STRING); 786db26757Swiz } 796db26757Swiz 804e179ddaSchristos static enum cmd_retval 814e179ddaSchristos cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item) 82698d5317Sjmmv { 839fb66d81Schristos struct args *args = cmd_get_args(self); 849fb66d81Schristos struct client *tc = cmdq_get_target_client(item); 859fb66d81Schristos struct cmd_find_state *target = cmdq_get_target(item); 866db26757Swiz const char *type, *s, *input; 87698d5317Sjmmv struct cmd_command_prompt_cdata *cdata; 886db26757Swiz char *tmp, *prompts, *prompt, *next_prompt; 896db26757Swiz char *inputs = NULL, *next_input; 906db26757Swiz u_int count = args_count(args); 916db26757Swiz int wait = !args_has(args, 'b'), space = 1; 92698d5317Sjmmv 939fb66d81Schristos if (tc->prompt_string != NULL) 94928fc495Schristos return (CMD_RETURN_NORMAL); 956db26757Swiz if (args_has(args, 'i')) 966db26757Swiz wait = 0; 97698d5317Sjmmv 984e179ddaSchristos cdata = xcalloc(1, sizeof *cdata); 996db26757Swiz if (wait) 1006db26757Swiz cdata->item = item; 1016db26757Swiz cdata->state = args_make_commands_prepare(self, item, 0, "%1", wait, 1026db26757Swiz args_has(args, 'F')); 1034e179ddaSchristos 1046db26757Swiz if ((s = args_get(args, 'p')) == NULL) { 1056db26757Swiz if (count != 0) { 1066db26757Swiz tmp = args_make_commands_get_command(cdata->state); 1076db26757Swiz xasprintf(&prompts, "(%s)", tmp); 1086db26757Swiz free(tmp); 1096db26757Swiz } else { 1106db26757Swiz prompts = xstrdup(":"); 1116db26757Swiz space = 0; 112d530c4d0Sjmmv } 1136db26757Swiz next_prompt = prompts; 1146db26757Swiz } else 1156db26757Swiz next_prompt = prompts = xstrdup(s); 1166db26757Swiz if ((s = args_get(args, 'I')) != NULL) 1176db26757Swiz next_input = inputs = xstrdup(s); 1186db26757Swiz else 1196db26757Swiz next_input = NULL; 1206db26757Swiz while ((prompt = strsep(&next_prompt, ",")) != NULL) { 1216db26757Swiz cdata->prompts = xreallocarray(cdata->prompts, cdata->count + 1, 1226db26757Swiz sizeof *cdata->prompts); 1236db26757Swiz if (!space) 1246db26757Swiz tmp = xstrdup(prompt); 1256db26757Swiz else 1266db26757Swiz xasprintf(&tmp, "%s ", prompt); 1276db26757Swiz cdata->prompts[cdata->count].prompt = tmp; 1286db26757Swiz 1296db26757Swiz if (next_input != NULL) { 1306db26757Swiz input = strsep(&next_input, ","); 1316db26757Swiz if (input == NULL) 1326db26757Swiz input = ""; 1336db26757Swiz } else 1346db26757Swiz input = ""; 1356db26757Swiz cdata->prompts[cdata->count].input = xstrdup(input); 1366db26757Swiz 1376db26757Swiz cdata->count++; 1386db26757Swiz } 1396db26757Swiz free(inputs); 1406db26757Swiz free(prompts); 1416db26757Swiz 1426db26757Swiz if ((type = args_get(args, 'T')) != NULL) { 1436db26757Swiz cdata->prompt_type = status_prompt_type(type); 1446db26757Swiz if (cdata->prompt_type == PROMPT_TYPE_INVALID) { 1456db26757Swiz cmdq_error(item, "unknown type: %s", type); 146*f8cf1a91Swiz cmd_command_prompt_free(cdata); 1476db26757Swiz return (CMD_RETURN_ERROR); 1486db26757Swiz } 1496db26757Swiz } else 1506db26757Swiz cdata->prompt_type = PROMPT_TYPE_COMMAND; 151d530c4d0Sjmmv 1524e179ddaSchristos if (args_has(args, '1')) 1534e179ddaSchristos cdata->flags |= PROMPT_SINGLE; 1544e179ddaSchristos else if (args_has(args, 'N')) 1554e179ddaSchristos cdata->flags |= PROMPT_NUMERIC; 1564e179ddaSchristos else if (args_has(args, 'i')) 1574e179ddaSchristos cdata->flags |= PROMPT_INCREMENTAL; 158aa83ff61Schristos else if (args_has(args, 'k')) 159aa83ff61Schristos cdata->flags |= PROMPT_KEY; 1606db26757Swiz status_prompt_set(tc, target, cdata->prompts[0].prompt, 1616db26757Swiz cdata->prompts[0].input, cmd_command_prompt_callback, 1626db26757Swiz cmd_command_prompt_free, cdata, cdata->flags, cdata->prompt_type); 163698d5317Sjmmv 1646db26757Swiz if (!wait) 165928fc495Schristos return (CMD_RETURN_NORMAL); 1666db26757Swiz return (CMD_RETURN_WAIT); 167698d5317Sjmmv } 168698d5317Sjmmv 1694e179ddaSchristos static int 170c9ad075bSchristos cmd_command_prompt_callback(struct client *c, void *data, const char *s, 171c9ad075bSchristos int done) 172698d5317Sjmmv { 173698d5317Sjmmv struct cmd_command_prompt_cdata *cdata = data; 1746db26757Swiz char *error; 1756db26757Swiz struct cmdq_item *item = cdata->item, *new_item; 1766db26757Swiz struct cmd_list *cmdlist; 1776db26757Swiz struct cmd_command_prompt_prompt *prompt; 1786db26757Swiz int argc = 0; 1796db26757Swiz char **argv = NULL; 180698d5317Sjmmv 181698d5317Sjmmv if (s == NULL) 1826db26757Swiz goto out; 183c23f9150Swiz 1844e179ddaSchristos if (done) { 1856db26757Swiz if (cdata->flags & PROMPT_INCREMENTAL) 1866db26757Swiz goto out; 1876db26757Swiz cmd_append_argv(&cdata->argc, &cdata->argv, s); 1886db26757Swiz if (++cdata->current != cdata->count) { 1896db26757Swiz prompt = &cdata->prompts[cdata->current]; 1906db26757Swiz status_prompt_update(c, prompt->prompt, prompt->input); 191698d5317Sjmmv return (1); 192698d5317Sjmmv } 1936db26757Swiz } 194698d5317Sjmmv 1956db26757Swiz argc = cdata->argc; 1966db26757Swiz argv = cmd_copy_argv(cdata->argc, cdata->argv); 197c23f9150Swiz if (!done) 1986db26757Swiz cmd_append_argv(&argc, &argv, s); 199c23f9150Swiz 2006db26757Swiz if (done) { 201c23f9150Swiz cmd_free_argv(cdata->argc, cdata->argv); 2026db26757Swiz cdata->argc = argc; 2036db26757Swiz cdata->argv = cmd_copy_argv(argc, argv); 2046db26757Swiz } 2056db26757Swiz 2066db26757Swiz cmdlist = args_make_commands(cdata->state, argc, argv, &error); 2076db26757Swiz if (cmdlist == NULL) { 2089fb66d81Schristos cmdq_append(c, cmdq_get_error(error)); 2099fb66d81Schristos free(error); 2106db26757Swiz } else if (item == NULL) { 2116db26757Swiz new_item = cmdq_get_command(cmdlist, NULL); 2126db26757Swiz cmdq_append(c, new_item); 2136db26757Swiz } else { 2146db26757Swiz new_item = cmdq_get_command(cmdlist, cmdq_get_state(item)); 2156db26757Swiz cmdq_insert_after(item, new_item); 2166483eba0Schristos } 2176db26757Swiz cmd_free_argv(argc, argv); 2184e179ddaSchristos 219c9ad075bSchristos if (c->prompt_inputcb != cmd_command_prompt_callback) 220698d5317Sjmmv return (1); 2216db26757Swiz 2226db26757Swiz out: 2236db26757Swiz if (item != NULL) 2246db26757Swiz cmdq_continue(item); 225698d5317Sjmmv return (0); 226698d5317Sjmmv } 227698d5317Sjmmv 2284e179ddaSchristos static void 229d530c4d0Sjmmv cmd_command_prompt_free(void *data) 230698d5317Sjmmv { 231698d5317Sjmmv struct cmd_command_prompt_cdata *cdata = data; 2326db26757Swiz u_int i; 233698d5317Sjmmv 2346db26757Swiz for (i = 0; i < cdata->count; i++) { 2356db26757Swiz free(cdata->prompts[i].prompt); 2366db26757Swiz free(cdata->prompts[i].input); 2376db26757Swiz } 238928fc495Schristos free(cdata->prompts); 2396db26757Swiz cmd_free_argv(cdata->argc, cdata->argv); 2406db26757Swiz args_make_commands_free(cdata->state); 241928fc495Schristos free(cdata); 242698d5317Sjmmv } 243