From 1e426896611f81dd6306263cb337e7ea7d80238e Mon Sep 17 00:00:00 2001 From: nicm Date: Sat, 4 Jul 2020 14:24:02 +0000 Subject: [PATCH] kill-window -a cannot just walk the list of windows because if renumber-windows is on, the window it wants to keep could be moved. Change to renumber afterwards and also behave better if the window is linked into the session twice. GitHub issue 2287. --- cmd-join-pane.c | 2 +- cmd-kill-window.c | 48 +++++++++++++++++++++++++++++++++++---------- server-fn.c | 50 ++++++++++++++++++++++++++++++----------------- tmux.h | 4 +++- window-tree.c | 2 +- 5 files changed, 75 insertions(+), 31 deletions(-) diff --git a/cmd-join-pane.c b/cmd-join-pane.c index 9802083d..904d2c29 100644 --- a/cmd-join-pane.c +++ b/cmd-join-pane.c @@ -160,7 +160,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item) server_status_session(dst_s); if (window_count_panes(src_w) == 0) - server_kill_window(src_w); + server_kill_window(src_w, 1); else notify_window("window-layout-changed", src_w); notify_window("window-layout-changed", dst_w); diff --git a/cmd-kill-window.c b/cmd-kill-window.c index 68139faa..430f667e 100644 --- a/cmd-kill-window.c +++ b/cmd-kill-window.c @@ -57,9 +57,10 @@ cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item) { struct args *args = cmd_get_args(self); struct cmd_find_state *target = cmdq_get_target(item); - struct winlink *wl = target->wl, *wl2, *wl3; + struct winlink *wl = target->wl, *loop; struct window *w = wl->window; struct session *s = target->s; + u_int found; if (cmd_get_entry(self) == &cmd_unlink_window_entry) { if (!args_has(args, 'k') && !session_is_linked(s, w)) { @@ -67,16 +68,43 @@ cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item) return (CMD_RETURN_ERROR); } server_unlink_window(s, wl); - } else { - if (args_has(args, 'a')) { - RB_FOREACH_SAFE(wl2, winlinks, &s->windows, wl3) { - if (wl != wl2) - server_kill_window(wl2->window); - } - } else - server_kill_window(wl->window); + recalculate_sizes(); + return (CMD_RETURN_NORMAL); } - recalculate_sizes(); + if (args_has(args, 'a')) { + if (RB_PREV(winlinks, &s->windows, wl) == NULL && + RB_NEXT(winlinks, &s->windows, wl) == NULL) + return (CMD_RETURN_NORMAL); + + /* Kill all windows except the current one. */ + do { + found = 0; + RB_FOREACH(loop, winlinks, &s->windows) { + if (loop->window != wl->window) { + server_kill_window(loop->window, 0); + found++; + break; + } + } + } while (found != 0); + + /* + * If the current window appears in the session more than once, + * kill it as well. + */ + found = 0; + RB_FOREACH(loop, winlinks, &s->windows) { + if (loop->window == wl->window) + found++; + } + if (found > 1) + server_kill_window(wl->window, 0); + + server_renumber_all(); + return (CMD_RETURN_NORMAL); + } + + server_kill_window(wl->window, 1); return (CMD_RETURN_NORMAL); } diff --git a/server-fn.c b/server-fn.c index d66aed0b..84ec4123 100644 --- a/server-fn.c +++ b/server-fn.c @@ -183,7 +183,7 @@ server_kill_pane(struct window_pane *wp) struct window *w = wp->window; if (window_count_panes(w) == 1) { - server_kill_window(w); + server_kill_window(w, 1); recalculate_sizes(); } else { server_unzoom_window(w); @@ -195,19 +195,15 @@ server_kill_pane(struct window_pane *wp) } void -server_kill_window(struct window *w) +server_kill_window(struct window *w, int renumber) { - struct session *s, *next_s, *target_s; - struct session_group *sg; - struct winlink *wl; - - next_s = RB_MIN(sessions, &sessions); - while (next_s != NULL) { - s = next_s; - next_s = RB_NEXT(sessions, &sessions, s); + struct session *s, *s1; + struct winlink *wl; + RB_FOREACH_SAFE(s, sessions, &sessions, s1) { if (!session_has(s, w)) continue; + server_unzoom_window(w); while ((wl = winlink_find_by_window(&s->windows, w)) != NULL) { if (session_detach(s, wl)) { @@ -217,17 +213,35 @@ server_kill_window(struct window *w) server_redraw_session_group(s); } - if (options_get_number(s->options, "renumber-windows")) { - if ((sg = session_group_contains(s)) != NULL) { - TAILQ_FOREACH(target_s, &sg->sessions, gentry) - session_renumber_windows(target_s); - } else - session_renumber_windows(s); - } + if (renumber) + server_renumber_session(s); } recalculate_sizes(); } +void +server_renumber_session(struct session *s) +{ + struct session_group *sg; + + if (options_get_number(s->options, "renumber-windows")) { + if ((sg = session_group_contains(s)) != NULL) { + TAILQ_FOREACH(s, &sg->sessions, gentry) + session_renumber_windows(s); + } else + session_renumber_windows(s); + } +} + +void +server_renumber_all(void) +{ + struct session *s; + + RB_FOREACH(s, sessions, &sessions) + server_renumber_session(s); +} + int server_link_window(struct session *src, struct winlink *srcwl, struct session *dst, int dstidx, int killflag, int selectflag, @@ -354,7 +368,7 @@ server_destroy_pane(struct window_pane *wp, int notify) window_remove_pane(w, wp); if (TAILQ_EMPTY(&w->panes)) - server_kill_window(w); + server_kill_window(w, 1); else server_redraw_window(w); } diff --git a/tmux.h b/tmux.h index 0a1a740b..a8c67051 100644 --- a/tmux.h +++ b/tmux.h @@ -2420,7 +2420,9 @@ void server_lock(void); void server_lock_session(struct session *); void server_lock_client(struct client *); void server_kill_pane(struct window_pane *); -void server_kill_window(struct window *); +void server_kill_window(struct window *, int); +void server_renumber_session(struct session *); +void server_renumber_all(void); int server_link_window(struct session *, struct winlink *, struct session *, int, int, int, char **); void server_unlink_window(struct session *, struct winlink *); diff --git a/window-tree.c b/window-tree.c index 32b94e15..384cf392 100644 --- a/window-tree.c +++ b/window-tree.c @@ -1054,7 +1054,7 @@ window_tree_kill_each(__unused void *modedata, void *itemdata, break; case WINDOW_TREE_WINDOW: if (wl != NULL) - server_kill_window(wl->window); + server_kill_window(wl->window, 1); break; case WINDOW_TREE_PANE: if (wp != NULL)