xref: /netbsd-src/external/bsd/tmux/dist/cmd-new-window.c (revision 1b9578b8c2c1f848eeb16dabbfd7d1f0d9fdefbd)
1 /* $Id: cmd-new-window.c,v 1.1.1.1 2011/03/10 09:15:37 jmmv Exp $ */
2 
3 /*
4  * Copyright (c) 2007 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 <stdlib.h>
22 
23 #include "tmux.h"
24 
25 /*
26  * Create a new window.
27  */
28 
29 int	cmd_new_window_parse(struct cmd *, int, char **, char **);
30 int	cmd_new_window_exec(struct cmd *, struct cmd_ctx *);
31 void	cmd_new_window_free(struct cmd *);
32 void	cmd_new_window_init(struct cmd *, int);
33 size_t	cmd_new_window_print(struct cmd *, char *, size_t);
34 
35 struct cmd_new_window_data {
36 	char	*target;
37 	char	*name;
38 	char	*cmd;
39 	int	 flag_insert_after;
40 	int	 flag_detached;
41 	int	 flag_kill;
42 };
43 
44 const struct cmd_entry cmd_new_window_entry = {
45 	"new-window", "neww",
46 	"[-adk] [-n window-name] [-t target-window] [command]",
47 	0, "",
48 	cmd_new_window_init,
49 	cmd_new_window_parse,
50 	cmd_new_window_exec,
51 	cmd_new_window_free,
52 	cmd_new_window_print
53 };
54 
55 /* ARGSUSED */
56 void
57 cmd_new_window_init(struct cmd *self, unused int arg)
58 {
59 	struct cmd_new_window_data	 *data;
60 
61 	self->data = data = xmalloc(sizeof *data);
62 	data->target = NULL;
63 	data->name = NULL;
64 	data->cmd = NULL;
65 	data->flag_insert_after = 0;
66 	data->flag_detached = 0;
67 	data->flag_kill = 0;
68 }
69 
70 int
71 cmd_new_window_parse(struct cmd *self, int argc, char **argv, char **cause)
72 {
73 	struct cmd_new_window_data	*data;
74 	int				 opt;
75 
76 	self->entry->init(self, KEYC_NONE);
77 	data = self->data;
78 
79 	while ((opt = getopt(argc, argv, "adkt:n:")) != -1) {
80 		switch (opt) {
81 		case 'a':
82 			data->flag_insert_after = 1;
83 			break;
84 		case 'd':
85 			data->flag_detached = 1;
86 			break;
87 		case 'k':
88 			data->flag_kill = 1;
89 			break;
90 		case 't':
91 			if (data->target == NULL)
92 				data->target = xstrdup(optarg);
93 			break;
94 		case 'n':
95 			if (data->name == NULL)
96 				data->name = xstrdup(optarg);
97 			break;
98 		default:
99 			goto usage;
100 		}
101 	}
102 	argc -= optind;
103 	argv += optind;
104 	if (argc != 0 && argc != 1)
105 		goto usage;
106 
107 	if (argc == 1)
108 		data->cmd = xstrdup(argv[0]);
109 
110 	return (0);
111 
112 usage:
113 	xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
114 
115 	self->entry->free(self);
116 	return (-1);
117 }
118 
119 int
120 cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
121 {
122 	struct cmd_new_window_data	*data = self->data;
123 	struct session			*s;
124 	struct winlink			*wl;
125 	char				*cmd, *cwd, *cause;
126 	int				 idx, last;
127 
128 	if (data == NULL)
129 		return (0);
130 
131 	if (data->flag_insert_after) {
132 		if ((wl = cmd_find_window(ctx, data->target, &s)) == NULL)
133 			return (-1);
134 		idx = wl->idx + 1;
135 
136 		/* Find the next free index. */
137 		for (last = idx; last < INT_MAX; last++) {
138 			if (winlink_find_by_index(&s->windows, last) == NULL)
139 				break;
140 		}
141 		if (last == INT_MAX) {
142 			ctx->error(ctx, "no free window indexes");
143 			return (-1);
144 		}
145 
146 		/* Move everything from last - 1 to idx up a bit. */
147 		for (; last > idx; last--) {
148 			wl = winlink_find_by_index(&s->windows, last - 1);
149 			server_link_window(s, wl, s, last, 0, 0, NULL);
150 			server_unlink_window(s, wl);
151 		}
152 	} else {
153 		if ((idx = cmd_find_index(ctx, data->target, &s)) == -2)
154 			return (-1);
155 	}
156 
157 	wl = NULL;
158 	if (idx != -1)
159 		wl = winlink_find_by_index(&s->windows, idx);
160 	if (wl != NULL && data->flag_kill) {
161 		/*
162 		 * Can't use session_detach as it will destroy session if this
163 		 * makes it empty.
164 		 */
165 		wl->flags &= ~WINLINK_ALERTFLAGS;
166 		winlink_stack_remove(&s->lastw, wl);
167 		winlink_remove(&s->windows, wl);
168 
169 		/* Force select/redraw if current. */
170 		if (wl == s->curw) {
171 			data->flag_detached = 0;
172 			s->curw = NULL;
173 		}
174 	}
175 
176 	cmd = data->cmd;
177 	if (cmd == NULL)
178 		cmd = options_get_string(&s->options, "default-command");
179 	cwd = options_get_string(&s->options, "default-path");
180 	if (*cwd == '\0') {
181 		if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
182 			cwd = ctx->cmdclient->cwd;
183 		else
184 			cwd = s->cwd;
185 	}
186 
187 	if (idx == -1)
188 		idx = -1 - options_get_number(&s->options, "base-index");
189 	wl = session_new(s, data->name, cmd, cwd, idx, &cause);
190 	if (wl == NULL) {
191 		ctx->error(ctx, "create window failed: %s", cause);
192 		xfree(cause);
193 		return (-1);
194 	}
195 	if (!data->flag_detached) {
196 		session_select(s, wl->idx);
197 		server_redraw_session_group(s);
198 	} else
199 		server_status_session_group(s);
200 
201 	return (0);
202 }
203 
204 void
205 cmd_new_window_free(struct cmd *self)
206 {
207 	struct cmd_new_window_data	*data = self->data;
208 
209 	if (data->target != NULL)
210 		xfree(data->target);
211 	if (data->name != NULL)
212 		xfree(data->name);
213 	if (data->cmd != NULL)
214 		xfree(data->cmd);
215 	xfree(data);
216 }
217 
218 size_t
219 cmd_new_window_print(struct cmd *self, char *buf, size_t len)
220 {
221 	struct cmd_new_window_data	*data = self->data;
222 	size_t				 off = 0;
223 
224 	off += xsnprintf(buf, len, "%s", self->entry->name);
225 	if (data == NULL)
226 		return (off);
227 	if (off < len && data->flag_detached)
228 		off += xsnprintf(buf + off, len - off, " -d");
229 	if (off < len && data->target != NULL)
230 		off += cmd_prarg(buf + off, len - off, " -t ", data->target);
231 	if (off < len && data->name != NULL)
232 		off += cmd_prarg(buf + off, len - off, " -n ", data->name);
233 	if (off < len && data->cmd != NULL)
234 		off += cmd_prarg(buf + off, len - off, " ", data->cmd);
235 	return (off);
236 }
237