1 1.1.1.5 christos /* $OpenBSD$ */ 2 1.1 jmmv 3 1.1 jmmv /* 4 1.1.1.6 christos * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott (at) gmail.com> 5 1.1 jmmv * 6 1.1 jmmv * Permission to use, copy, modify, and distribute this software for any 7 1.1 jmmv * purpose with or without fee is hereby granted, provided that the above 8 1.1 jmmv * copyright notice and this permission notice appear in all copies. 9 1.1 jmmv * 10 1.1 jmmv * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 1.1 jmmv * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 1.1 jmmv * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 1.1 jmmv * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 1.1 jmmv * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 1.1 jmmv * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 1.1 jmmv * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 1.1 jmmv */ 18 1.1 jmmv 19 1.1 jmmv #include <sys/types.h> 20 1.1 jmmv 21 1.1 jmmv #include <ctype.h> 22 1.1.1.3 christos #include <stdlib.h> 23 1.1 jmmv #include <string.h> 24 1.1.1.2 jmmv #include <time.h> 25 1.1 jmmv 26 1.1 jmmv #include "tmux.h" 27 1.1 jmmv 28 1.1 jmmv /* 29 1.1 jmmv * Prompt for command in client. 30 1.1 jmmv */ 31 1.1 jmmv 32 1.1.1.12 wiz static enum args_parse_type cmd_command_prompt_args_parse(struct args *, 33 1.1.1.12 wiz u_int, char **); 34 1.1.1.12 wiz static enum cmd_retval cmd_command_prompt_exec(struct cmd *, 35 1.1.1.12 wiz struct cmdq_item *); 36 1.1 jmmv 37 1.1.1.8 christos static int cmd_command_prompt_callback(struct client *, void *, 38 1.1.1.8 christos const char *, int); 39 1.1.1.7 christos static void cmd_command_prompt_free(void *); 40 1.1 jmmv 41 1.1 jmmv const struct cmd_entry cmd_command_prompt_entry = { 42 1.1.1.6 christos .name = "command-prompt", 43 1.1.1.6 christos .alias = NULL, 44 1.1.1.6 christos 45 1.1.1.15 wiz .args = { "1bFkliI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse }, 46 1.1.1.15 wiz .usage = "[-1bFkliN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE 47 1.1.1.15 wiz " [-T prompt-type] [template]", 48 1.1.1.6 christos 49 1.1.1.11 christos .flags = CMD_CLIENT_TFLAG, 50 1.1.1.6 christos .exec = cmd_command_prompt_exec 51 1.1 jmmv }; 52 1.1 jmmv 53 1.1.1.12 wiz struct cmd_command_prompt_prompt { 54 1.1.1.12 wiz char *input; 55 1.1.1.12 wiz char *prompt; 56 1.1.1.12 wiz }; 57 1.1.1.12 wiz 58 1.1 jmmv struct cmd_command_prompt_cdata { 59 1.1.1.12 wiz struct cmdq_item *item; 60 1.1.1.12 wiz struct args_command_state *state; 61 1.1.1.7 christos 62 1.1.1.12 wiz int flags; 63 1.1.1.12 wiz enum prompt_type prompt_type; 64 1.1.1.7 christos 65 1.1.1.12 wiz struct cmd_command_prompt_prompt *prompts; 66 1.1.1.12 wiz u_int count; 67 1.1.1.12 wiz u_int current; 68 1.1.1.7 christos 69 1.1.1.12 wiz int argc; 70 1.1.1.12 wiz char **argv; 71 1.1 jmmv }; 72 1.1 jmmv 73 1.1.1.12 wiz static enum args_parse_type 74 1.1.1.12 wiz cmd_command_prompt_args_parse(__unused struct args *args, __unused u_int idx, 75 1.1.1.12 wiz __unused char **cause) 76 1.1.1.12 wiz { 77 1.1.1.12 wiz return (ARGS_PARSE_COMMANDS_OR_STRING); 78 1.1.1.12 wiz } 79 1.1.1.12 wiz 80 1.1.1.7 christos static enum cmd_retval 81 1.1.1.7 christos cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item) 82 1.1 jmmv { 83 1.1.1.11 christos struct args *args = cmd_get_args(self); 84 1.1.1.11 christos struct client *tc = cmdq_get_target_client(item); 85 1.1.1.11 christos struct cmd_find_state *target = cmdq_get_target(item); 86 1.1.1.12 wiz const char *type, *s, *input; 87 1.1 jmmv struct cmd_command_prompt_cdata *cdata; 88 1.1.1.12 wiz char *tmp, *prompts, *prompt, *next_prompt; 89 1.1.1.12 wiz char *inputs = NULL, *next_input; 90 1.1.1.12 wiz u_int count = args_count(args); 91 1.1.1.12 wiz int wait = !args_has(args, 'b'), space = 1; 92 1.1 jmmv 93 1.1.1.11 christos if (tc->prompt_string != NULL) 94 1.1.1.3 christos return (CMD_RETURN_NORMAL); 95 1.1.1.12 wiz if (args_has(args, 'i')) 96 1.1.1.12 wiz wait = 0; 97 1.1 jmmv 98 1.1.1.7 christos cdata = xcalloc(1, sizeof *cdata); 99 1.1.1.12 wiz if (wait) 100 1.1.1.12 wiz cdata->item = item; 101 1.1.1.12 wiz cdata->state = args_make_commands_prepare(self, item, 0, "%1", wait, 102 1.1.1.12 wiz args_has(args, 'F')); 103 1.1.1.12 wiz 104 1.1.1.12 wiz if ((s = args_get(args, 'p')) == NULL) { 105 1.1.1.12 wiz if (count != 0) { 106 1.1.1.12 wiz tmp = args_make_commands_get_command(cdata->state); 107 1.1.1.12 wiz xasprintf(&prompts, "(%s)", tmp); 108 1.1.1.12 wiz free(tmp); 109 1.1.1.12 wiz } else { 110 1.1.1.12 wiz prompts = xstrdup(":"); 111 1.1.1.12 wiz space = 0; 112 1.1.1.12 wiz } 113 1.1.1.12 wiz next_prompt = prompts; 114 1.1 jmmv } else 115 1.1.1.12 wiz next_prompt = prompts = xstrdup(s); 116 1.1.1.12 wiz if ((s = args_get(args, 'I')) != NULL) 117 1.1.1.12 wiz next_input = inputs = xstrdup(s); 118 1.1 jmmv else 119 1.1.1.12 wiz next_input = NULL; 120 1.1.1.15 wiz if (args_has(args, 'l')) { 121 1.1.1.15 wiz cdata->prompts = xcalloc(1, sizeof *cdata->prompts); 122 1.1.1.15 wiz cdata->prompts[0].prompt = prompts; 123 1.1.1.15 wiz cdata->prompts[0].input = inputs; 124 1.1.1.15 wiz cdata->count = 1; 125 1.1.1.15 wiz } else { 126 1.1.1.15 wiz while ((prompt = strsep(&next_prompt, ",")) != NULL) { 127 1.1.1.15 wiz cdata->prompts = xreallocarray(cdata->prompts, 128 1.1.1.15 wiz cdata->count + 1, sizeof *cdata->prompts); 129 1.1.1.15 wiz if (!space) 130 1.1.1.15 wiz tmp = xstrdup(prompt); 131 1.1.1.15 wiz else 132 1.1.1.15 wiz xasprintf(&tmp, "%s ", prompt); 133 1.1.1.15 wiz cdata->prompts[cdata->count].prompt = tmp; 134 1.1.1.15 wiz 135 1.1.1.15 wiz if (next_input != NULL) { 136 1.1.1.15 wiz input = strsep(&next_input, ","); 137 1.1.1.15 wiz if (input == NULL) 138 1.1.1.15 wiz input = ""; 139 1.1.1.15 wiz } else 140 1.1.1.12 wiz input = ""; 141 1.1.1.15 wiz cdata->prompts[cdata->count].input = xstrdup(input); 142 1.1.1.15 wiz cdata->count++; 143 1.1.1.15 wiz } 144 1.1.1.15 wiz free(inputs); 145 1.1.1.15 wiz free(prompts); 146 1.1.1.2 jmmv } 147 1.1.1.12 wiz 148 1.1.1.12 wiz if ((type = args_get(args, 'T')) != NULL) { 149 1.1.1.12 wiz cdata->prompt_type = status_prompt_type(type); 150 1.1.1.12 wiz if (cdata->prompt_type == PROMPT_TYPE_INVALID) { 151 1.1.1.12 wiz cmdq_error(item, "unknown type: %s", type); 152 1.1.1.14 wiz cmd_command_prompt_free(cdata); 153 1.1.1.12 wiz return (CMD_RETURN_ERROR); 154 1.1.1.12 wiz } 155 1.1.1.12 wiz } else 156 1.1.1.12 wiz cdata->prompt_type = PROMPT_TYPE_COMMAND; 157 1.1 jmmv 158 1.1.1.7 christos if (args_has(args, '1')) 159 1.1.1.7 christos cdata->flags |= PROMPT_SINGLE; 160 1.1.1.7 christos else if (args_has(args, 'N')) 161 1.1.1.7 christos cdata->flags |= PROMPT_NUMERIC; 162 1.1.1.7 christos else if (args_has(args, 'i')) 163 1.1.1.7 christos cdata->flags |= PROMPT_INCREMENTAL; 164 1.1.1.10 christos else if (args_has(args, 'k')) 165 1.1.1.10 christos cdata->flags |= PROMPT_KEY; 166 1.1.1.12 wiz status_prompt_set(tc, target, cdata->prompts[0].prompt, 167 1.1.1.12 wiz cdata->prompts[0].input, cmd_command_prompt_callback, 168 1.1.1.12 wiz cmd_command_prompt_free, cdata, cdata->flags, cdata->prompt_type); 169 1.1 jmmv 170 1.1.1.12 wiz if (!wait) 171 1.1.1.12 wiz return (CMD_RETURN_NORMAL); 172 1.1.1.12 wiz return (CMD_RETURN_WAIT); 173 1.1 jmmv } 174 1.1 jmmv 175 1.1.1.7 christos static int 176 1.1.1.8 christos cmd_command_prompt_callback(struct client *c, void *data, const char *s, 177 1.1.1.8 christos int done) 178 1.1 jmmv { 179 1.1.1.12 wiz struct cmd_command_prompt_cdata *cdata = data; 180 1.1.1.12 wiz char *error; 181 1.1.1.12 wiz struct cmdq_item *item = cdata->item, *new_item; 182 1.1.1.12 wiz struct cmd_list *cmdlist; 183 1.1.1.12 wiz struct cmd_command_prompt_prompt *prompt; 184 1.1.1.12 wiz int argc = 0; 185 1.1.1.12 wiz char **argv = NULL; 186 1.1 jmmv 187 1.1 jmmv if (s == NULL) 188 1.1.1.12 wiz goto out; 189 1.1.1.13 wiz 190 1.1.1.7 christos if (done) { 191 1.1.1.12 wiz if (cdata->flags & PROMPT_INCREMENTAL) 192 1.1.1.12 wiz goto out; 193 1.1.1.12 wiz cmd_append_argv(&cdata->argc, &cdata->argv, s); 194 1.1.1.12 wiz if (++cdata->current != cdata->count) { 195 1.1.1.12 wiz prompt = &cdata->prompts[cdata->current]; 196 1.1.1.12 wiz status_prompt_update(c, prompt->prompt, prompt->input); 197 1.1.1.12 wiz return (1); 198 1.1.1.12 wiz } 199 1.1.1.12 wiz } 200 1.1.1.2 jmmv 201 1.1.1.12 wiz argc = cdata->argc; 202 1.1.1.12 wiz argv = cmd_copy_argv(cdata->argc, cdata->argv); 203 1.1.1.13 wiz if (!done) 204 1.1.1.13 wiz cmd_append_argv(&argc, &argv, s); 205 1.1.1.13 wiz 206 1.1.1.12 wiz if (done) { 207 1.1.1.13 wiz cmd_free_argv(cdata->argc, cdata->argv); 208 1.1.1.12 wiz cdata->argc = argc; 209 1.1.1.12 wiz cdata->argv = cmd_copy_argv(argc, argv); 210 1.1 jmmv } 211 1.1 jmmv 212 1.1.1.12 wiz cmdlist = args_make_commands(cdata->state, argc, argv, &error); 213 1.1.1.12 wiz if (cmdlist == NULL) { 214 1.1.1.11 christos cmdq_append(c, cmdq_get_error(error)); 215 1.1.1.11 christos free(error); 216 1.1.1.12 wiz } else if (item == NULL) { 217 1.1.1.12 wiz new_item = cmdq_get_command(cmdlist, NULL); 218 1.1.1.12 wiz cmdq_append(c, new_item); 219 1.1.1.12 wiz } else { 220 1.1.1.12 wiz new_item = cmdq_get_command(cmdlist, cmdq_get_state(item)); 221 1.1.1.12 wiz cmdq_insert_after(item, new_item); 222 1.1.1.9 christos } 223 1.1.1.12 wiz cmd_free_argv(argc, argv); 224 1.1 jmmv 225 1.1.1.8 christos if (c->prompt_inputcb != cmd_command_prompt_callback) 226 1.1 jmmv return (1); 227 1.1.1.12 wiz 228 1.1.1.12 wiz out: 229 1.1.1.12 wiz if (item != NULL) 230 1.1.1.12 wiz cmdq_continue(item); 231 1.1 jmmv return (0); 232 1.1 jmmv } 233 1.1 jmmv 234 1.1.1.7 christos static void 235 1.1.1.2 jmmv cmd_command_prompt_free(void *data) 236 1.1 jmmv { 237 1.1 jmmv struct cmd_command_prompt_cdata *cdata = data; 238 1.1.1.12 wiz u_int i; 239 1.1 jmmv 240 1.1.1.12 wiz for (i = 0; i < cdata->count; i++) { 241 1.1.1.12 wiz free(cdata->prompts[i].prompt); 242 1.1.1.12 wiz free(cdata->prompts[i].input); 243 1.1.1.12 wiz } 244 1.1.1.3 christos free(cdata->prompts); 245 1.1.1.12 wiz cmd_free_argv(cdata->argc, cdata->argv); 246 1.1.1.12 wiz args_make_commands_free(cdata->state); 247 1.1.1.3 christos free(cdata); 248 1.1 jmmv } 249