4 * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
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.
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.
19 #include <sys/types.h>
31 * Split a window (add a new pane).
34 #define SPLIT_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}"
36 static enum cmd_retval
cmd_split_window_exec(struct cmd
*,
39 const struct cmd_entry cmd_split_window_entry
= {
40 .name
= "split-window",
43 .args
= { "bc:de:fF:hIl:p:Pt:vZ", 0, -1, NULL
},
44 .usage
= "[-bdefhIPvZ] [-c start-directory] [-e environment] "
45 "[-F format] [-l size] " CMD_TARGET_PANE_USAGE
48 .target
= { 't', CMD_FIND_PANE
, 0 },
51 .exec
= cmd_split_window_exec
54 static enum cmd_retval
55 cmd_split_window_exec(struct cmd
*self
, struct cmdq_item
*item
)
57 struct args
*args
= cmd_get_args(self
);
58 struct cmd_find_state
*current
= cmdq_get_current(item
);
59 struct cmd_find_state
*target
= cmdq_get_target(item
);
60 struct spawn_context sc
= { 0 };
61 struct client
*tc
= cmdq_get_target_client(item
);
62 struct session
*s
= target
->s
;
63 struct winlink
*wl
= target
->wl
;
64 struct window
*w
= wl
->window
;
65 struct window_pane
*wp
= target
->wp
, *new_wp
;
66 enum layout_type type
;
67 struct layout_cell
*lc
;
68 struct cmd_find_state fs
;
69 int size
, percentage
, flags
, input
;
70 const char *template, *errstr
, *p
;
71 char *cause
, *cp
, *copy
;
73 struct args_value
*av
;
74 u_int count
= args_count(args
);
76 if (args_has(args
, 'h'))
77 type
= LAYOUT_LEFTRIGHT
;
79 type
= LAYOUT_TOPBOTTOM
;
80 if ((p
= args_get(args
, 'l')) != NULL
) {
82 if (p
[plen
- 1] == '%') {
84 copy
[plen
- 1] = '\0';
85 percentage
= strtonum(copy
, 0, INT_MAX
, &errstr
);
88 cmdq_error(item
, "percentage %s", errstr
);
89 return (CMD_RETURN_ERROR
);
91 if (args_has(args
, 'f')) {
92 if (type
== LAYOUT_TOPBOTTOM
)
93 size
= (w
->sy
* percentage
) / 100;
95 size
= (w
->sx
* percentage
) / 100;
97 if (type
== LAYOUT_TOPBOTTOM
)
98 size
= (wp
->sy
* percentage
) / 100;
100 size
= (wp
->sx
* percentage
) / 100;
103 size
= args_strtonum(args
, 'l', 0, INT_MAX
, &cause
);
105 cmdq_error(item
, "lines %s", cause
);
107 return (CMD_RETURN_ERROR
);
110 } else if (args_has(args
, 'p')) {
111 percentage
= args_strtonum(args
, 'p', 0, INT_MAX
, &cause
);
113 cmdq_error(item
, "create pane failed: -p %s", cause
);
115 return (CMD_RETURN_ERROR
);
117 if (args_has(args
, 'f')) {
118 if (type
== LAYOUT_TOPBOTTOM
)
119 size
= (w
->sy
* percentage
) / 100;
121 size
= (w
->sx
* percentage
) / 100;
123 if (type
== LAYOUT_TOPBOTTOM
)
124 size
= (wp
->sy
* percentage
) / 100;
126 size
= (wp
->sx
* percentage
) / 100;
131 window_push_zoom(wp
->window
, 1, args_has(args
, 'Z'));
132 input
= (args_has(args
, 'I') && count
== 0);
135 if (args_has(args
, 'b'))
136 flags
|= SPAWN_BEFORE
;
137 if (args_has(args
, 'f'))
138 flags
|= SPAWN_FULLSIZE
;
139 if (input
|| (count
== 1 && *args_string(args
, 0) == '\0'))
140 flags
|= SPAWN_EMPTY
;
142 lc
= layout_split_pane(wp
, type
, size
, flags
);
144 cmdq_error(item
, "no space for new pane");
145 return (CMD_RETURN_ERROR
);
155 args_to_vector(args
, &sc
.argc
, &sc
.argv
);
156 sc
.environ
= environ_create();
158 av
= args_first_value(args
, 'e');
160 environ_put(sc
.environ
, av
->string
, 0);
161 av
= args_next_value(av
);
165 sc
.cwd
= args_get(args
, 'c');
168 if (args_has(args
, 'd'))
169 sc
.flags
|= SPAWN_DETACHED
;
170 if (args_has(args
, 'Z'))
171 sc
.flags
|= SPAWN_ZOOM
;
173 if ((new_wp
= spawn_pane(&sc
, &cause
)) == NULL
) {
174 cmdq_error(item
, "create pane failed: %s", cause
);
177 cmd_free_argv(sc
.argc
, sc
.argv
);
178 environ_free(sc
.environ
);
179 return (CMD_RETURN_ERROR
);
182 switch (window_pane_start_input(new_wp
, item
, &cause
)) {
184 server_client_remove_pane(new_wp
);
185 layout_close_pane(new_wp
);
186 window_remove_pane(wp
->window
, new_wp
);
187 cmdq_error(item
, "%s", cause
);
190 cmd_free_argv(sc
.argc
, sc
.argv
);
191 environ_free(sc
.environ
);
192 return (CMD_RETURN_ERROR
);
198 if (!args_has(args
, 'd'))
199 cmd_find_from_winlink_pane(current
, wl
, new_wp
, 0);
200 window_pop_zoom(wp
->window
);
201 server_redraw_window(wp
->window
);
202 server_status_session(s
);
204 if (args_has(args
, 'P')) {
205 if ((template = args_get(args
, 'F')) == NULL
)
206 template = SPLIT_WINDOW_TEMPLATE
;
207 cp
= format_single(item
, template, tc
, s
, wl
, new_wp
);
208 cmdq_print(item
, "%s", cp
);
212 cmd_find_from_winlink_pane(&fs
, wl
, new_wp
, 0);
213 cmdq_insert_hook(s
, item
, &fs
, "after-split-window");
216 cmd_free_argv(sc
.argc
, sc
.argv
);
217 environ_free(sc
.environ
);
219 return (CMD_RETURN_WAIT
);
220 return (CMD_RETURN_NORMAL
);