1 /* $OpenBSD: cmd-command-prompt.c,v 1.11 2009/09/21 15:32:06 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 21 #include <ctype.h> 22 #include <string.h> 23 24 #include "tmux.h" 25 26 /* 27 * Prompt for command in client. 28 */ 29 30 void cmd_command_prompt_init(struct cmd *, int); 31 int cmd_command_prompt_parse(struct cmd *, int, char **, char **); 32 int cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *); 33 void cmd_command_prompt_free(struct cmd *); 34 size_t cmd_command_prompt_print(struct cmd *, char *, size_t); 35 36 int cmd_command_prompt_callback(void *, const char *); 37 void cmd_command_prompt_cfree(void *); 38 39 const struct cmd_entry cmd_command_prompt_entry = { 40 "command-prompt", NULL, 41 CMD_TARGET_CLIENT_USAGE " [-p prompts] [template]", 42 0, 0, 43 cmd_command_prompt_init, 44 cmd_command_prompt_parse, 45 cmd_command_prompt_exec, 46 cmd_command_prompt_free, 47 cmd_command_prompt_print 48 }; 49 50 struct cmd_command_prompt_data { 51 char *prompts; 52 char *target; 53 char *template; 54 }; 55 56 struct cmd_command_prompt_cdata { 57 struct client *c; 58 char *next_prompt; 59 char *prompts; 60 char *template; 61 int idx; 62 }; 63 64 void 65 cmd_command_prompt_init(struct cmd *self, int key) 66 { 67 struct cmd_command_prompt_data *data; 68 69 self->data = data = xmalloc(sizeof *data); 70 data->prompts = NULL; 71 data->target = NULL; 72 data->template = NULL; 73 74 switch (key) { 75 case ',': 76 data->template = xstrdup("rename-window '%%'"); 77 break; 78 case '.': 79 data->template = xstrdup("move-window -t '%%'"); 80 break; 81 case 'f': 82 data->template = xstrdup("find-window '%%'"); 83 break; 84 } 85 } 86 87 int 88 cmd_command_prompt_parse(struct cmd *self, int argc, char **argv, char **cause) 89 { 90 struct cmd_command_prompt_data *data; 91 int opt; 92 93 self->entry->init(self, KEYC_NONE); 94 data = self->data; 95 96 while ((opt = getopt(argc, argv, "p:t:")) != -1) { 97 switch (opt) { 98 case 'p': 99 if (data->prompts == NULL) 100 data->prompts = xstrdup(optarg); 101 break; 102 case 't': 103 if (data->target == NULL) 104 data->target = xstrdup(optarg); 105 break; 106 default: 107 goto usage; 108 } 109 } 110 argc -= optind; 111 argv += optind; 112 if (argc != 0 && argc != 1) 113 goto usage; 114 115 if (argc == 1) 116 data->template = xstrdup(argv[0]); 117 118 return (0); 119 120 usage: 121 xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage); 122 123 self->entry->free(self); 124 return (-1); 125 } 126 127 int 128 cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx) 129 { 130 struct cmd_command_prompt_data *data = self->data; 131 struct cmd_command_prompt_cdata *cdata; 132 struct client *c; 133 char *prompt, *ptr; 134 size_t n; 135 136 if ((c = cmd_find_client(ctx, data->target)) == NULL) 137 return (-1); 138 139 if (c->prompt_string != NULL) 140 return (0); 141 142 cdata = xmalloc(sizeof *cdata); 143 cdata->c = c; 144 cdata->idx = 1; 145 cdata->next_prompt = NULL; 146 cdata->prompts = NULL; 147 cdata->template = NULL; 148 149 if (data->template != NULL) 150 cdata->template = xstrdup(data->template); 151 else 152 cdata->template = xstrdup("%1"); 153 if (data->prompts != NULL) 154 cdata->prompts = xstrdup(data->prompts); 155 else if (data->template != NULL) { 156 n = strcspn(data->template, " ,"); 157 xasprintf(&cdata->prompts, "(%.*s) ", (int) n, data->template); 158 } else 159 cdata->prompts = xstrdup(":"); 160 161 cdata->next_prompt = cdata->prompts; 162 ptr = strsep(&cdata->next_prompt, ","); 163 if (data->prompts == NULL) 164 prompt = xstrdup(ptr); 165 else 166 xasprintf(&prompt, "%s ", ptr); 167 status_prompt_set(c, prompt, cmd_command_prompt_callback, 168 cmd_command_prompt_cfree, cdata, 0); 169 xfree(prompt); 170 171 return (0); 172 } 173 174 void 175 cmd_command_prompt_free(struct cmd *self) 176 { 177 struct cmd_command_prompt_data *data = self->data; 178 179 if (data->prompts != NULL) 180 xfree(data->prompts); 181 if (data->target != NULL) 182 xfree(data->target); 183 if (data->template != NULL) 184 xfree(data->template); 185 xfree(data); 186 } 187 188 size_t 189 cmd_command_prompt_print(struct cmd *self, char *buf, size_t len) 190 { 191 struct cmd_command_prompt_data *data = self->data; 192 size_t off = 0; 193 194 off += xsnprintf(buf, len, "%s", self->entry->name); 195 if (data == NULL) 196 return (off); 197 if (off < len && data->prompts != NULL) 198 off += cmd_prarg(buf + off, len - off, " -p ", data->prompts); 199 if (off < len && data->target != NULL) 200 off += cmd_prarg(buf + off, len - off, " -t ", data->target); 201 if (off < len && data->template != NULL) 202 off += cmd_prarg(buf + off, len - off, " ", data->template); 203 return (off); 204 } 205 206 int 207 cmd_command_prompt_callback(void *data, const char *s) 208 { 209 struct cmd_command_prompt_cdata *cdata = data; 210 struct client *c = cdata->c; 211 struct cmd_list *cmdlist; 212 struct cmd_ctx ctx; 213 char *cause, *newtempl, *prompt, *ptr; 214 215 if (s == NULL) 216 return (0); 217 218 newtempl = cmd_template_replace(cdata->template, s, cdata->idx); 219 xfree(cdata->template); 220 cdata->template = newtempl; 221 222 if ((ptr = strsep(&cdata->next_prompt, ",")) != NULL) { 223 xasprintf(&prompt, "%s ", ptr); 224 status_prompt_update(c, prompt); 225 xfree(prompt); 226 cdata->idx++; 227 return (1); 228 } 229 230 if (cmd_string_parse(newtempl, &cmdlist, &cause) != 0) { 231 if (cause != NULL) { 232 *cause = toupper((u_char) *cause); 233 status_message_set(c, "%s", cause); 234 xfree(cause); 235 } 236 return (0); 237 } 238 239 ctx.msgdata = NULL; 240 ctx.curclient = c; 241 242 ctx.error = key_bindings_error; 243 ctx.print = key_bindings_print; 244 ctx.info = key_bindings_info; 245 246 ctx.cmdclient = NULL; 247 248 cmd_list_exec(cmdlist, &ctx); 249 cmd_list_free(cmdlist); 250 251 if (c->prompt_callbackfn != (void *) &cmd_command_prompt_callback) 252 return (1); 253 return (0); 254 } 255 256 void 257 cmd_command_prompt_cfree(void *data) 258 { 259 struct cmd_command_prompt_cdata *cdata = data; 260 261 if (cdata->prompts != NULL) 262 xfree(cdata->prompts); 263 if (cdata->template != NULL) 264 xfree(cdata->template); 265 xfree(cdata); 266 } 267