1 /* $OpenBSD: cmd-choose-tree.c,v 1.5 2012/07/12 13:03:42 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2012 Thomas Adam <thomas@xteddy.org> 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 <stdlib.h> 23 24 #include <string.h> 25 26 #include "tmux.h" 27 28 #define CMD_CHOOSE_TREE_WINDOW_ACTION "select-window -t '%%'" 29 #define CMD_CHOOSE_TREE_SESSION_ACTION "switch-client -t '%%'" 30 #define CMD_CHOOSE_TREE_WINDOW_TEMPLATE \ 31 DEFAULT_WINDOW_TEMPLATE " \"#{pane_title}\"" 32 33 /* 34 * Enter choice mode to choose a session and/or window. 35 */ 36 37 int cmd_choose_tree_exec(struct cmd *, struct cmd_ctx *); 38 39 void cmd_choose_tree_callback(struct window_choose_data *); 40 void cmd_choose_tree_free(struct window_choose_data *); 41 42 const struct cmd_entry cmd_choose_tree_entry = { 43 "choose-tree", NULL, 44 "S:W:swb:c:t:", 0, 1, 45 "[-sw] [-b session-template] [-c window template] [-S format] " \ 46 "[-W format] " CMD_TARGET_WINDOW_USAGE, 47 0, 48 NULL, 49 NULL, 50 cmd_choose_tree_exec 51 }; 52 53 const struct cmd_entry cmd_choose_session_entry = { 54 "choose-session", NULL, 55 "F:t:", 0, 1, 56 CMD_TARGET_WINDOW_USAGE " [-F format] [template]", 57 0, 58 NULL, 59 NULL, 60 cmd_choose_tree_exec 61 }; 62 63 const struct cmd_entry cmd_choose_window_entry = { 64 "choose-window", NULL, 65 "F:t:", 0, 1, 66 CMD_TARGET_WINDOW_USAGE "[-F format] [template]", 67 0, 68 NULL, 69 NULL, 70 cmd_choose_tree_exec 71 }; 72 73 enum cmd_retval 74 cmd_choose_tree_exec(struct cmd *self, struct cmd_ctx *ctx) 75 { 76 struct args *args = self->args; 77 struct winlink *wl, *wm; 78 struct session *s, *s2; 79 struct window_choose_data *wcd = NULL; 80 const char *ses_template, *win_template; 81 char *final_win_action, *final_win_template; 82 const char *ses_action, *win_action; 83 u_int cur_win, idx_ses, win_ses; 84 u_int wflag, sflag; 85 86 ses_template = win_template = NULL; 87 ses_action = win_action = NULL; 88 89 if (ctx->curclient == NULL) { 90 ctx->error(ctx, "must be run interactively"); 91 return (CMD_RETURN_ERROR); 92 } 93 94 s = ctx->curclient->session; 95 96 if ((wl = cmd_find_window(ctx, args_get(args, 't'), NULL)) == NULL) 97 return (CMD_RETURN_ERROR); 98 99 if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0) 100 return (CMD_RETURN_NORMAL); 101 102 /* Sort out which command this is. */ 103 wflag = sflag = 0; 104 if (self->entry == &cmd_choose_session_entry) { 105 sflag = 1; 106 if ((ses_template = args_get(args, 'F')) == NULL) 107 ses_template = DEFAULT_SESSION_TEMPLATE; 108 109 if (args->argc != 0) 110 ses_action = args->argv[0]; 111 else 112 ses_action = CMD_CHOOSE_TREE_SESSION_ACTION; 113 } else if (self->entry == &cmd_choose_window_entry) { 114 wflag = 1; 115 if ((win_template = args_get(args, 'F')) == NULL) 116 win_template = CMD_CHOOSE_TREE_WINDOW_TEMPLATE; 117 118 if (args->argc != 0) 119 win_action = args->argv[0]; 120 else 121 win_action = CMD_CHOOSE_TREE_WINDOW_ACTION; 122 } else { 123 wflag = args_has(args, 'w'); 124 sflag = args_has(args, 's'); 125 126 if ((ses_action = args_get(args, 'b')) == NULL) 127 ses_action = CMD_CHOOSE_TREE_SESSION_ACTION; 128 129 if ((win_action = args_get(args, 'c')) == NULL) 130 win_action = CMD_CHOOSE_TREE_WINDOW_ACTION; 131 132 if ((ses_template = args_get(args, 'S')) == NULL) 133 ses_template = DEFAULT_SESSION_TEMPLATE; 134 135 if ((win_template = args_get(args, 'W')) == NULL) 136 win_template = CMD_CHOOSE_TREE_WINDOW_TEMPLATE; 137 } 138 139 /* 140 * If not asking for windows and sessions, assume no "-ws" given and 141 * hence display the entire tree outright. 142 */ 143 if (!wflag && !sflag) 144 wflag = sflag = 1; 145 146 /* 147 * If we're drawing in tree mode, including sessions, then pad the 148 * window template, otherwise just render the windows as a flat list 149 * without any padding. 150 */ 151 if (wflag && sflag) 152 xasprintf(&final_win_template, " --> %s", win_template); 153 else if (wflag) 154 final_win_template = xstrdup(win_template); 155 else 156 final_win_template = NULL; 157 158 idx_ses = cur_win = -1; 159 RB_FOREACH(s2, sessions, &sessions) { 160 idx_ses++; 161 162 /* 163 * If we're just choosing windows, jump straight there. Note 164 * that this implies the current session, so only choose 165 * windows when the session matches this one. 166 */ 167 if (wflag && !sflag) { 168 if (s != s2) 169 continue; 170 goto windows_only; 171 } 172 173 wcd = window_choose_add_session(wl->window->active, 174 ctx, s2, ses_template, (char *)ses_action, idx_ses); 175 176 /* If we're just choosing sessions, skip choosing windows. */ 177 if (sflag && !wflag) { 178 if (s == s2) 179 cur_win = idx_ses; 180 continue; 181 } 182 windows_only: 183 win_ses = -1; 184 RB_FOREACH(wm, winlinks, &s2->windows) { 185 win_ses++; 186 if (sflag && wflag) 187 idx_ses++; 188 189 if (wm == s2->curw && s == s2) { 190 if (wflag && !sflag) { 191 /* 192 * Then we're only counting windows. 193 * So remember which is the current 194 * window in the list. 195 */ 196 cur_win = win_ses; 197 } else 198 cur_win = idx_ses; 199 } 200 201 xasprintf(&final_win_action, "%s ; %s", win_action, 202 wcd ? wcd->command : ""); 203 204 window_choose_add_window(wl->window->active, 205 ctx, s2, wm, final_win_template, 206 final_win_action, idx_ses); 207 208 free(final_win_action); 209 } 210 /* 211 * If we're just drawing windows, don't consider moving on to 212 * other sessions as we only list windows in this session. 213 */ 214 if (wflag && !sflag) 215 break; 216 } 217 free(final_win_template); 218 219 window_choose_ready(wl->window->active, cur_win, 220 cmd_choose_tree_callback, cmd_choose_tree_free); 221 222 return (CMD_RETURN_NORMAL); 223 } 224 225 void 226 cmd_choose_tree_callback(struct window_choose_data *cdata) 227 { 228 if (cdata == NULL) 229 return; 230 231 if (cdata->client->flags & CLIENT_DEAD) 232 return; 233 234 window_choose_ctx(cdata); 235 } 236 237 void 238 cmd_choose_tree_free(struct window_choose_data *cdata) 239 { 240 cdata->session->references--; 241 cdata->client->references--; 242 243 free(cdata->ft_template); 244 free(cdata->command); 245 format_free(cdata->ft); 246 free(cdata); 247 248 } 249