cmd-choose-tree.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /* $OpenBSD$ */
  2. /*
  3. * Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
  14. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  15. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/types.h>
  18. #include <ctype.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include "tmux.h"
  22. #define CMD_CHOOSE_TREE_WINDOW_ACTION "select-window -t '%%'"
  23. #define CMD_CHOOSE_TREE_SESSION_ACTION "switch-client -t '%%'"
  24. /*
  25. * Enter choice mode to choose a session and/or window.
  26. */
  27. #define CHOOSE_TREE_SESSION_TEMPLATE \
  28. "#{session_name}: #{session_windows} windows" \
  29. "#{?session_grouped, (group ,}" \
  30. "#{session_group}#{?session_grouped,),}" \
  31. "#{?session_attached, (attached),}"
  32. #define CHOOSE_TREE_WINDOW_TEMPLATE \
  33. "#{window_index}: #{window_name}#{window_flags} " \
  34. "\"#{pane_title}\""
  35. enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmd_q *);
  36. const struct cmd_entry cmd_choose_tree_entry = {
  37. .name = "choose-tree",
  38. .alias = NULL,
  39. .args = { "S:W:swub:c:t:", 0, 1 },
  40. .usage = "[-suw] [-b session-template] [-c window template] "
  41. "[-S format] [-W format] " CMD_TARGET_WINDOW_USAGE,
  42. .tflag = CMD_WINDOW,
  43. .flags = 0,
  44. .exec = cmd_choose_tree_exec
  45. };
  46. const struct cmd_entry cmd_choose_session_entry = {
  47. .name = "choose-session",
  48. .alias = NULL,
  49. .args = { "F:t:", 0, 1 },
  50. .usage = CMD_TARGET_WINDOW_USAGE " [-F format] [template]",
  51. .tflag = CMD_WINDOW,
  52. .flags = 0,
  53. .exec = cmd_choose_tree_exec
  54. };
  55. const struct cmd_entry cmd_choose_window_entry = {
  56. .name = "choose-window",
  57. .alias = NULL,
  58. .args = { "F:t:", 0, 1 },
  59. .usage = CMD_TARGET_WINDOW_USAGE "[-F format] [template]",
  60. .tflag = CMD_WINDOW,
  61. .flags = 0,
  62. .exec = cmd_choose_tree_exec
  63. };
  64. enum cmd_retval
  65. cmd_choose_tree_exec(struct cmd *self, struct cmd_q *cmdq)
  66. {
  67. struct args *args = self->args;
  68. struct client *c = cmdq->state.c;
  69. struct winlink *wl = cmdq->state.tflag.wl, *wm;
  70. struct session *s = cmdq->state.tflag.s, *s2;
  71. struct window_choose_data *wcd = NULL;
  72. const char *ses_template, *win_template;
  73. char *final_win_action, *cur_win_template;
  74. char *final_win_template_middle;
  75. char *final_win_template_last;
  76. const char *ses_action, *win_action;
  77. u_int cur_win, idx_ses, win_ses, win_max;
  78. u_int wflag, sflag;
  79. ses_template = win_template = NULL;
  80. ses_action = win_action = NULL;
  81. if (c == NULL) {
  82. cmdq_error(cmdq, "no client available");
  83. return (CMD_RETURN_ERROR);
  84. }
  85. if (window_pane_set_mode(wl->window->active, &window_choose_mode) != 0)
  86. return (CMD_RETURN_NORMAL);
  87. /* Sort out which command this is. */
  88. wflag = sflag = 0;
  89. if (self->entry == &cmd_choose_session_entry) {
  90. sflag = 1;
  91. if ((ses_template = args_get(args, 'F')) == NULL)
  92. ses_template = CHOOSE_TREE_SESSION_TEMPLATE;
  93. if (args->argc != 0)
  94. ses_action = args->argv[0];
  95. else
  96. ses_action = CMD_CHOOSE_TREE_SESSION_ACTION;
  97. } else if (self->entry == &cmd_choose_window_entry) {
  98. wflag = 1;
  99. if ((win_template = args_get(args, 'F')) == NULL)
  100. win_template = CHOOSE_TREE_WINDOW_TEMPLATE;
  101. if (args->argc != 0)
  102. win_action = args->argv[0];
  103. else
  104. win_action = CMD_CHOOSE_TREE_WINDOW_ACTION;
  105. } else {
  106. wflag = args_has(args, 'w');
  107. sflag = args_has(args, 's');
  108. if ((ses_action = args_get(args, 'b')) == NULL)
  109. ses_action = CMD_CHOOSE_TREE_SESSION_ACTION;
  110. if ((win_action = args_get(args, 'c')) == NULL)
  111. win_action = CMD_CHOOSE_TREE_WINDOW_ACTION;
  112. if ((ses_template = args_get(args, 'S')) == NULL)
  113. ses_template = CHOOSE_TREE_SESSION_TEMPLATE;
  114. if ((win_template = args_get(args, 'W')) == NULL)
  115. win_template = CHOOSE_TREE_WINDOW_TEMPLATE;
  116. }
  117. /*
  118. * If not asking for windows and sessions, assume no "-ws" given and
  119. * hence display the entire tree outright.
  120. */
  121. if (!wflag && !sflag)
  122. wflag = sflag = 1;
  123. /*
  124. * If we're drawing in tree mode, including sessions, then pad the
  125. * window template, otherwise just render the windows as a flat list
  126. * without any padding.
  127. */
  128. if (wflag && sflag) {
  129. xasprintf(&final_win_template_middle,
  130. " \001tq\001> %s", win_template);
  131. xasprintf(&final_win_template_last,
  132. " \001mq\001> %s", win_template);
  133. } else if (wflag) {
  134. final_win_template_middle = xstrdup(win_template);
  135. final_win_template_last = xstrdup(win_template);
  136. } else
  137. final_win_template_middle = final_win_template_last = NULL;
  138. idx_ses = cur_win = -1;
  139. RB_FOREACH(s2, sessions, &sessions) {
  140. idx_ses++;
  141. /*
  142. * If we're just choosing windows, jump straight there. Note
  143. * that this implies the current session, so only choose
  144. * windows when the session matches this one.
  145. */
  146. if (wflag && !sflag) {
  147. if (s != s2)
  148. continue;
  149. goto windows_only;
  150. }
  151. wcd = window_choose_add_session(wl->window->active,
  152. c, s2, ses_template, ses_action, idx_ses);
  153. /* If we're just choosing sessions, skip choosing windows. */
  154. if (sflag && !wflag) {
  155. if (s == s2)
  156. cur_win = idx_ses;
  157. continue;
  158. }
  159. windows_only:
  160. win_ses = win_max = -1;
  161. RB_FOREACH(wm, winlinks, &s2->windows)
  162. win_max++;
  163. RB_FOREACH(wm, winlinks, &s2->windows) {
  164. win_ses++;
  165. if (sflag && wflag)
  166. idx_ses++;
  167. if (wm == s2->curw && s == s2) {
  168. if (wflag && !sflag) {
  169. /*
  170. * Then we're only counting windows.
  171. * So remember which is the current
  172. * window in the list.
  173. */
  174. cur_win = win_ses;
  175. } else
  176. cur_win = idx_ses;
  177. }
  178. xasprintf(&final_win_action, "%s %s %s",
  179. wcd != NULL ? wcd->command : "",
  180. wcd != NULL ? ";" : "", win_action);
  181. if (win_ses != win_max)
  182. cur_win_template = final_win_template_middle;
  183. else
  184. cur_win_template = final_win_template_last;
  185. window_choose_add_window(wl->window->active,
  186. c, s2, wm, cur_win_template,
  187. final_win_action,
  188. (wflag && !sflag) ? win_ses : idx_ses);
  189. free(final_win_action);
  190. }
  191. /*
  192. * If we're just drawing windows, don't consider moving on to
  193. * other sessions as we only list windows in this session.
  194. */
  195. if (wflag && !sflag)
  196. break;
  197. }
  198. free(final_win_template_middle);
  199. free(final_win_template_last);
  200. window_choose_ready(wl->window->active, cur_win, NULL);
  201. if (args_has(args, 'u')) {
  202. window_choose_expand_all(wl->window->active);
  203. window_choose_set_current(wl->window->active, cur_win);
  204. }
  205. return (CMD_RETURN_NORMAL);
  206. }