xref: /openbsd-src/usr.bin/tmux/cmd-command-prompt.c (revision a410d86c73a5d0d40951c44cf9e9b6e84ad8c623)
1 /* $OpenBSD: cmd-command-prompt.c,v 1.15 2011/01/05 22:38:28 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_key_binding(struct cmd *, int);
31 int	cmd_command_prompt_check(struct args *);
32 int	cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *);
33 
34 int	cmd_command_prompt_callback(void *, const char *);
35 void	cmd_command_prompt_free(void *);
36 
37 const struct cmd_entry cmd_command_prompt_entry = {
38 	"command-prompt", NULL,
39 	"p:t:", 0, 1,
40 	CMD_TARGET_CLIENT_USAGE " [-p prompts] [template]",
41 	0,
42 	cmd_command_prompt_key_binding,
43 	NULL,
44 	cmd_command_prompt_exec
45 };
46 
47 struct cmd_command_prompt_cdata {
48 	struct client	*c;
49 	char		*next_prompt;
50 	char		*prompts;
51 	char		*template;
52 	int		 idx;
53 };
54 
55 void
56 cmd_command_prompt_key_binding(struct cmd *self, int key)
57 {
58 	switch (key) {
59 	case ',':
60 		self->args = args_create(1, "rename-window '%%'");
61 		break;
62 	case '.':
63 		self->args = args_create(1, "move-window -t '%%'");
64 		break;
65 	case 'f':
66 		self->args = args_create(1, "find-window '%%'");
67 		break;
68 	case '\'':
69 		self->args = args_create(1, "select-window -t ':%%'");
70 		args_set(self->args, 'p', "index");
71 		break;
72 	default:
73 		self->args = args_create(0);
74 		break;
75 	}
76 }
77 
78 int
79 cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
80 {
81 	struct args			*args = self->args;
82 	const char			*prompts;
83 	struct cmd_command_prompt_cdata	*cdata;
84 	struct client			*c;
85 	char				*prompt, *ptr;
86 	size_t				 n;
87 
88 	if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
89 		return (-1);
90 
91 	if (c->prompt_string != NULL)
92 		return (0);
93 
94 	cdata = xmalloc(sizeof *cdata);
95 	cdata->c = c;
96 	cdata->idx = 1;
97 	cdata->next_prompt = NULL;
98 	cdata->prompts = NULL;
99 	cdata->template = NULL;
100 
101 	if (args->argc != 0)
102 		cdata->template = xstrdup(args->argv[0]);
103 	else
104 		cdata->template = xstrdup("%1");
105 
106 	prompts = args_get(args, 'p');
107 	if (prompts != NULL)
108 		cdata->prompts = xstrdup(prompts);
109 	else if (args->argc != 0) {
110 		n = strcspn(cdata->template, " ,");
111 		xasprintf(&cdata->prompts, "(%.*s) ", (int) n, cdata->template);
112 	} else
113 		cdata->prompts = xstrdup(":");
114 
115 	cdata->next_prompt = cdata->prompts;
116 	ptr = strsep(&cdata->next_prompt, ",");
117 	if (prompts == NULL)
118 		prompt = xstrdup(ptr);
119 	else
120 		xasprintf(&prompt, "%s ", ptr);
121 	status_prompt_set(c, prompt, cmd_command_prompt_callback,
122 	    cmd_command_prompt_free, cdata, 0);
123 	xfree(prompt);
124 
125 	return (0);
126 }
127 
128 int
129 cmd_command_prompt_callback(void *data, const char *s)
130 {
131 	struct cmd_command_prompt_cdata	*cdata = data;
132 	struct client			*c = cdata->c;
133 	struct cmd_list			*cmdlist;
134 	struct cmd_ctx			 ctx;
135 	char				*cause, *newtempl, *prompt, *ptr;
136 
137 	if (s == NULL)
138 		return (0);
139 
140 	newtempl = cmd_template_replace(cdata->template, s, cdata->idx);
141 	xfree(cdata->template);
142 	cdata->template = newtempl;
143 
144 	if ((ptr = strsep(&cdata->next_prompt, ",")) != NULL) {
145 		xasprintf(&prompt, "%s ", ptr);
146 		status_prompt_update(c, prompt);
147 		xfree(prompt);
148 		cdata->idx++;
149 		return (1);
150 	}
151 
152 	if (cmd_string_parse(newtempl, &cmdlist, &cause) != 0) {
153 		if (cause != NULL) {
154 			*cause = toupper((u_char) *cause);
155 			status_message_set(c, "%s", cause);
156 			xfree(cause);
157 		}
158 		return (0);
159 	}
160 
161 	ctx.msgdata = NULL;
162 	ctx.curclient = c;
163 
164 	ctx.error = key_bindings_error;
165 	ctx.print = key_bindings_print;
166 	ctx.info = key_bindings_info;
167 
168 	ctx.cmdclient = NULL;
169 
170 	cmd_list_exec(cmdlist, &ctx);
171 	cmd_list_free(cmdlist);
172 
173 	if (c->prompt_callbackfn != (void *) &cmd_command_prompt_callback)
174 		return (1);
175 	return (0);
176 }
177 
178 void
179 cmd_command_prompt_free(void *data)
180 {
181 	struct cmd_command_prompt_cdata	*cdata = data;
182 
183 	if (cdata->prompts != NULL)
184 		xfree(cdata->prompts);
185 	if (cdata->template != NULL)
186 		xfree(cdata->template);
187 	xfree(cdata);
188 }
189