xref: /openbsd-src/usr.bin/tmux/cmd-new-window.c (revision ac9b4aacc1da35008afea06a5d23c2f2dea9b93e)
1 /* $OpenBSD: cmd-new-window.c,v 1.27 2012/08/14 08:51:53 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_exec(struct cmd *, struct cmd_ctx *);
30 
31 const struct cmd_entry cmd_new_window_entry = {
32 	"new-window", "neww",
33 	"ac:dF:kn:Pt:", 0, 1,
34 	"[-adkP] [-c start-directory] [-F format] [-n window-name] "
35 	"[-t target-window] [command]",
36 	0,
37 	NULL,
38 	NULL,
39 	cmd_new_window_exec
40 };
41 
42 enum cmd_retval
43 cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
44 {
45 	struct args		*args = self->args;
46 	struct session		*s;
47 	struct winlink		*wl;
48 	struct client		*c;
49 	const char		*cmd, *cwd;
50 	const char		*template;
51 	char			*cause;
52 	int			 idx, last, detached;
53 	struct format_tree	*ft;
54 	char			*cp;
55 
56 	if (args_has(args, 'a')) {
57 		wl = cmd_find_window(ctx, args_get(args, 't'), &s);
58 		if (wl == NULL)
59 			return (CMD_RETURN_ERROR);
60 		idx = wl->idx + 1;
61 
62 		/* Find the next free index. */
63 		for (last = idx; last < INT_MAX; last++) {
64 			if (winlink_find_by_index(&s->windows, last) == NULL)
65 				break;
66 		}
67 		if (last == INT_MAX) {
68 			ctx->error(ctx, "no free window indexes");
69 			return (CMD_RETURN_ERROR);
70 		}
71 
72 		/* Move everything from last - 1 to idx up a bit. */
73 		for (; last > idx; last--) {
74 			wl = winlink_find_by_index(&s->windows, last - 1);
75 			server_link_window(s, wl, s, last, 0, 0, NULL);
76 			server_unlink_window(s, wl);
77 		}
78 	} else {
79 		if ((idx = cmd_find_index(ctx, args_get(args, 't'), &s)) == -2)
80 			return (CMD_RETURN_ERROR);
81 	}
82 	detached = args_has(args, 'd');
83 
84 	wl = NULL;
85 	if (idx != -1)
86 		wl = winlink_find_by_index(&s->windows, idx);
87 	if (wl != NULL && args_has(args, 'k')) {
88 		/*
89 		 * Can't use session_detach as it will destroy session if this
90 		 * makes it empty.
91 		 */
92 		notify_window_unlinked(s, wl->window);
93 		wl->flags &= ~WINLINK_ALERTFLAGS;
94 		winlink_stack_remove(&s->lastw, wl);
95 		winlink_remove(&s->windows, wl);
96 
97 		/* Force select/redraw if current. */
98 		if (wl == s->curw) {
99 			detached = 0;
100 			s->curw = NULL;
101 		}
102 	}
103 
104 	if (args->argc == 0)
105 		cmd = options_get_string(&s->options, "default-command");
106 	else
107 		cmd = args->argv[0];
108 	cwd = cmd_get_default_path(ctx, args_get(args, 'c'));
109 
110 	if (idx == -1)
111 		idx = -1 - options_get_number(&s->options, "base-index");
112 	wl = session_new(s, args_get(args, 'n'), cmd, cwd, idx, &cause);
113 	if (wl == NULL) {
114 		ctx->error(ctx, "create window failed: %s", cause);
115 		free(cause);
116 		return (CMD_RETURN_ERROR);
117 	}
118 	if (!detached) {
119 		session_select(s, wl->idx);
120 		server_redraw_session_group(s);
121 	} else
122 		server_status_session_group(s);
123 
124 	if (args_has(args, 'P')) {
125 		if ((template = args_get(args, 'F')) == NULL)
126 			template = NEW_WINDOW_TEMPLATE;
127 
128 		ft = format_create();
129 		if ((c = cmd_find_client(ctx, NULL)) != NULL)
130 		    format_client(ft, c);
131 		format_session(ft, s);
132 		format_winlink(ft, s, wl);
133 		format_window_pane(ft, wl->window->active);
134 
135 		cp = format_expand(ft, template);
136 		ctx->print(ctx, "%s", cp);
137 		free(cp);
138 
139 		format_free(ft);
140 	}
141 
142 	return (CMD_RETURN_NORMAL);
143 }
144