xref: /openbsd-src/usr.bin/tmux/cmd-new-window.c (revision 5054e3e78af0749a9bb00ba9a024b3ee2d90290f)
1 /* $OpenBSD: cmd-new-window.c,v 1.9 2009/11/13 19:53:29 nicm 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_detached;
40 	int	 flag_kill;
41 };
42 
43 const struct cmd_entry cmd_new_window_entry = {
44 	"new-window", "neww",
45 	"[-dk] [-n window-name] [-t target-window] [command]",
46 	0, "",
47 	cmd_new_window_init,
48 	cmd_new_window_parse,
49 	cmd_new_window_exec,
50 	cmd_new_window_free,
51 	cmd_new_window_print
52 };
53 
54 void
55 cmd_new_window_init(struct cmd *self, unused int arg)
56 {
57 	struct cmd_new_window_data	 *data;
58 
59 	self->data = data = xmalloc(sizeof *data);
60 	data->target = NULL;
61 	data->name = NULL;
62 	data->cmd = NULL;
63 	data->flag_detached = 0;
64 	data->flag_kill = 0;
65 }
66 
67 int
68 cmd_new_window_parse(struct cmd *self, int argc, char **argv, char **cause)
69 {
70 	struct cmd_new_window_data	*data;
71 	int				 opt;
72 
73 	self->entry->init(self, KEYC_NONE);
74 	data = self->data;
75 
76 	while ((opt = getopt(argc, argv, "dkt:n:")) != -1) {
77 		switch (opt) {
78 		case 'd':
79 			data->flag_detached = 1;
80 			break;
81 		case 'k':
82 			data->flag_kill = 1;
83 			break;
84 		case 't':
85 			if (data->target == NULL)
86 				data->target = xstrdup(optarg);
87 			break;
88 		case 'n':
89 			if (data->name == NULL)
90 				data->name = xstrdup(optarg);
91 			break;
92 		default:
93 			goto usage;
94 		}
95 	}
96 	argc -= optind;
97 	argv += optind;
98 	if (argc != 0 && argc != 1)
99 		goto usage;
100 
101 	if (argc == 1)
102 		data->cmd = xstrdup(argv[0]);
103 
104 	return (0);
105 
106 usage:
107 	xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
108 
109 	self->entry->free(self);
110 	return (-1);
111 }
112 
113 int
114 cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
115 {
116 	struct cmd_new_window_data	*data = self->data;
117 	struct session			*s;
118 	struct winlink			*wl;
119 	char				*cmd, *cwd, *cause;
120 	int				 idx;
121 
122 	if (data == NULL)
123 		return (0);
124 
125 	if ((idx = cmd_find_index(ctx, data->target, &s)) == -2)
126 		return (-1);
127 
128 	wl = NULL;
129 	if (idx != -1)
130 		wl = winlink_find_by_index(&s->windows, idx);
131 	if (wl != NULL) {
132 		if (data->flag_kill) {
133 			/*
134 			 * Can't use session_detach as it will destroy session
135 			 * if this makes it empty.
136 			 */
137 			session_alert_cancel(s, wl);
138 			winlink_stack_remove(&s->lastw, wl);
139 			winlink_remove(&s->windows, wl);
140 
141 			/* Force select/redraw if current. */
142 			if (wl == s->curw) {
143 				data->flag_detached = 0;
144 				s->curw = NULL;
145 			}
146 		}
147 	}
148 
149 	cmd = data->cmd;
150 	if (cmd == NULL)
151 		cmd = options_get_string(&s->options, "default-command");
152 	if (ctx->cmdclient == NULL || ctx->cmdclient->cwd == NULL)
153 		cwd = options_get_string(&s->options, "default-path");
154 	else
155 		cwd = ctx->cmdclient->cwd;
156 
157 	if (idx == -1)
158 		idx = -1 - options_get_number(&s->options, "base-index");
159 	wl = session_new(s, data->name, cmd, cwd, idx, &cause);
160 	if (wl == NULL) {
161 		ctx->error(ctx, "create window failed: %s", cause);
162 		xfree(cause);
163 		return (-1);
164 	}
165 	if (!data->flag_detached) {
166 		session_select(s, wl->idx);
167 		server_redraw_session_group(s);
168 	} else
169 		server_status_session_group(s);
170 
171 	return (0);
172 }
173 
174 void
175 cmd_new_window_free(struct cmd *self)
176 {
177 	struct cmd_new_window_data	*data = self->data;
178 
179 	if (data->target != NULL)
180 		xfree(data->target);
181 	if (data->name != NULL)
182 		xfree(data->name);
183 	if (data->cmd != NULL)
184 		xfree(data->cmd);
185 	xfree(data);
186 }
187 
188 size_t
189 cmd_new_window_print(struct cmd *self, char *buf, size_t len)
190 {
191 	struct cmd_new_window_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->flag_detached)
198 		off += xsnprintf(buf + off, len - off, " -d");
199 	if (off < len && data->target != NULL)
200 		off += cmd_prarg(buf + off, len - off, " -t ", data->target);
201 	if (off < len && data->name != NULL)
202 		off += cmd_prarg(buf + off, len - off, " -n ", data->name);
203 	if (off < len && data->cmd != NULL)
204 		off += cmd_prarg(buf + off, len - off, " ", data->cmd);
205 	return (off);
206 }
207