From b7d640e7642e1660d28681a66e3257d62708de13 Mon Sep 17 00:00:00 2001 From: nicm <nicm> Date: Fri, 21 Mar 2025 13:26:39 +0000 Subject: [PATCH 1/3] Add some additional cursor format variables. From shiro at usagi dot io in GitHub issue 4414. --- format.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/format.c b/format.c index 39a4a9a7..db2bcd8a 100644 --- a/format.c +++ b/format.c @@ -1119,6 +1119,20 @@ format_cb_cursor_character(struct format_tree *ft) return (value); } +/* Callback for cursor_colour. */ +static void * +format_cb_cursor_colour(struct format_tree *ft) +{ + struct window_pane *wp = ft->wp; + + if (wp == NULL || wp->screen == NULL) + return (NULL); + + if (wp->screen->ccolour != -1) + return (xstrdup(colour_tostring(wp->screen->ccolour))); + return (xstrdup(colour_tostring(wp->screen->default_ccolour))); +} + /* Callback for mouse_word. */ static void * format_cb_mouse_word(struct format_tree *ft) @@ -1593,6 +1607,37 @@ format_cb_cursor_flag(struct format_tree *ft) return (NULL); } +/* Callback for cursor_shape. */ +static void * +format_cb_cursor_shape(struct format_tree *ft) +{ + if (ft->wp != NULL && ft->wp->screen != NULL) { + switch (ft->wp->screen->cstyle) { + case SCREEN_CURSOR_BLOCK: + return (xstrdup("block")); + case SCREEN_CURSOR_UNDERLINE: + return (xstrdup("underline")); + case SCREEN_CURSOR_BAR: + return (xstrdup("bar")); + default: + return (xstrdup("default")); + } + } + return (NULL); +} + +/* Callback for cursor_very_visible. */ +static void * +format_cb_cursor_very_visible(struct format_tree *ft) +{ + if (ft->wp != NULL && ft->wp->screen != NULL) { + if (ft->wp->screen->mode & MODE_CURSOR_VERY_VISIBLE) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + /* Callback for cursor_x. */ static void * format_cb_cursor_x(struct format_tree *ft) @@ -1611,6 +1656,18 @@ format_cb_cursor_y(struct format_tree *ft) return (NULL); } +/* Callback for cursor_blinking. */ +static void * +format_cb_cursor_blinking(struct format_tree *ft) +{ + if (ft->wp != NULL && ft->wp->screen != NULL) { + if (ft->wp->screen->mode & MODE_CURSOR_BLINKING) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + /* Callback for history_limit. */ static void * format_cb_history_limit(struct format_tree *ft) @@ -2918,12 +2975,24 @@ static const struct format_table_entry format_table[] = { { "config_files", FORMAT_TABLE_STRING, format_cb_config_files }, + { "cursor_blinking", FORMAT_TABLE_STRING, + format_cb_cursor_blinking + }, { "cursor_character", FORMAT_TABLE_STRING, format_cb_cursor_character }, + { "cursor_colour", FORMAT_TABLE_STRING, + format_cb_cursor_colour + }, { "cursor_flag", FORMAT_TABLE_STRING, format_cb_cursor_flag }, + { "cursor_shape", FORMAT_TABLE_STRING, + format_cb_cursor_shape + }, + { "cursor_very_visible", FORMAT_TABLE_STRING, + format_cb_cursor_very_visible + }, { "cursor_x", FORMAT_TABLE_STRING, format_cb_cursor_x }, From a541be395118c45abbe85e5a8225a00e3a452e15 Mon Sep 17 00:00:00 2001 From: nicm <nicm> Date: Fri, 21 Mar 2025 13:36:42 +0000 Subject: [PATCH 2/3] Add S-Up and S-Down to move windows in tree mode. From David Mandelberg in GitHub issue 4415. --- mode-tree.c | 45 +++++++++++++++++++++++++++++++++++--- tmux.1 | 6 ++++++ tmux.h | 6 ++++-- window-buffer.c | 2 +- window-client.c | 2 +- window-customize.c | 4 ++-- window-tree.c | 54 +++++++++++++++++++++++++++++++++++++++++++++- 7 files changed, 109 insertions(+), 10 deletions(-) diff --git a/mode-tree.c b/mode-tree.c index 24cbea04..508e870c 100644 --- a/mode-tree.c +++ b/mode-tree.c @@ -58,6 +58,7 @@ struct mode_tree_data { mode_tree_menu_cb menucb; mode_tree_height_cb heightcb; mode_tree_key_cb keycb; + mode_tree_swap_cb swapcb; struct mode_tree_list children; struct mode_tree_list saved; @@ -287,6 +288,35 @@ mode_tree_down(struct mode_tree_data *mtd, int wrap) return (1); } +static void +mode_tree_swap(struct mode_tree_data *mtd, int direction) +{ + u_int current_depth = mtd->line_list[mtd->current].depth; + u_int swap_with, swap_with_depth; + + if (mtd->swapcb == NULL) + return; + + /* Find the next line at the same depth with the same parent . */ + swap_with = mtd->current; + do { + if (direction < 0 && swap_with < (u_int)-direction) + return; + if (direction > 0 && swap_with + direction >= mtd->line_size) + return; + swap_with += direction; + swap_with_depth = mtd->line_list[swap_with].depth; + } while (swap_with_depth > current_depth); + if (swap_with_depth != current_depth) + return; + + if (mtd->swapcb(mtd->line_list[mtd->current].item->itemdata, + mtd->line_list[swap_with].item->itemdata)) { + mtd->current = swap_with; + mode_tree_build(mtd); + } +} + void * mode_tree_get_current(struct mode_tree_data *mtd) { @@ -410,9 +440,9 @@ struct mode_tree_data * mode_tree_start(struct window_pane *wp, struct args *args, mode_tree_build_cb buildcb, mode_tree_draw_cb drawcb, mode_tree_search_cb searchcb, mode_tree_menu_cb menucb, - mode_tree_height_cb heightcb, mode_tree_key_cb keycb, void *modedata, - const struct menu_item *menu, const char **sort_list, u_int sort_size, - struct screen **s) + mode_tree_height_cb heightcb, mode_tree_key_cb keycb, + mode_tree_swap_cb swapcb, void *modedata, const struct menu_item *menu, + const char **sort_list, u_int sort_size, struct screen **s) { struct mode_tree_data *mtd; const char *sort; @@ -455,6 +485,7 @@ mode_tree_start(struct window_pane *wp, struct args *args, mtd->menucb = menucb; mtd->heightcb = heightcb; mtd->keycb = keycb; + mtd->swapcb = swapcb; TAILQ_INIT(&mtd->children); @@ -1147,6 +1178,14 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, case 'n'|KEYC_CTRL: mode_tree_down(mtd, 1); break; + case KEYC_UP|KEYC_SHIFT: + case 'K': + mode_tree_swap(mtd, -1); + break; + case KEYC_DOWN|KEYC_SHIFT: + case 'J': + mode_tree_swap(mtd, 1); + break; case KEYC_PPAGE: case 'b'|KEYC_CTRL: for (i = 0; i < mtd->height; i++) { diff --git a/tmux.1 b/tmux.1 index e17a92b3..1c10fc5c 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2713,6 +2713,8 @@ The following keys may be used in tree mode: .It Li "Enter" Ta "Choose selected item" .It Li "Up" Ta "Select previous item" .It Li "Down" Ta "Select next item" +.It Li "S-Up" Ta "Swap the current window with the previous one" +.It Li "S-Down" Ta "Swap the current window with the next one" .It Li "+" Ta "Expand selected item" .It Li "-" Ta "Collapse selected item" .It Li "M-+" Ta "Expand all items" @@ -5942,6 +5944,7 @@ The following variables are available, where appropriate: .It Li "command_list_name" Ta "" Ta "Command name if listing commands" .It Li "command_list_usage" Ta "" Ta "Command usage if listing commands" .It Li "config_files" Ta "" Ta "List of configuration files loaded" +.It Li "cursor_blinking" Ta "" Ta "1 if the cursor is blinking" .It Li "copy_cursor_hyperlink" Ta "" Ta "Hyperlink under cursor in copy mode" .It Li "copy_cursor_line" Ta "" Ta "Line the cursor is on in copy mode" .It Li "copy_cursor_word" Ta "" Ta "Word under cursor in copy mode" @@ -5949,7 +5952,10 @@ The following variables are available, where appropriate: .It Li "copy_cursor_y" Ta "" Ta "Cursor Y position in copy mode" .It Li "current_file" Ta "" Ta "Current configuration file" .It Li "cursor_character" Ta "" Ta "Character at cursor in pane" +.It Li "cursor_colour" Ta "" Ta "Cursor colour in pane" .It Li "cursor_flag" Ta "" Ta "Pane cursor flag" +.It Li "cursor_shape" Ta "" Ta "Cursor shape in pane" +.It Li "cursor_very_visible" Ta "" Ta "1 if the cursor is in very visible mode" .It Li "cursor_x" Ta "" Ta "Cursor X position in pane" .It Li "cursor_y" Ta "" Ta "Cursor Y position in pane" .It Li "history_bytes" Ta "" Ta "Number of bytes in window history" diff --git a/tmux.h b/tmux.h index 3a437165..35577ae0 100644 --- a/tmux.h +++ b/tmux.h @@ -3276,6 +3276,7 @@ typedef int (*mode_tree_search_cb)(void *, void *, const char *); typedef void (*mode_tree_menu_cb)(void *, struct client *, key_code); typedef u_int (*mode_tree_height_cb)(void *, u_int); typedef key_code (*mode_tree_key_cb)(void *, void *, u_int); +typedef int (*mode_tree_swap_cb)(void *, void *); typedef void (*mode_tree_each_cb)(void *, void *, struct client *, key_code); u_int mode_tree_count_tagged(struct mode_tree_data *); void *mode_tree_get_current(struct mode_tree_data *); @@ -3290,8 +3291,9 @@ void mode_tree_up(struct mode_tree_data *, int); int mode_tree_down(struct mode_tree_data *, int); struct mode_tree_data *mode_tree_start(struct window_pane *, struct args *, mode_tree_build_cb, mode_tree_draw_cb, mode_tree_search_cb, - mode_tree_menu_cb, mode_tree_height_cb, mode_tree_key_cb, void *, - const struct menu_item *, const char **, u_int, struct screen **); + mode_tree_menu_cb, mode_tree_height_cb, mode_tree_key_cb, + mode_tree_swap_cb, void *, const struct menu_item *, const char **, + u_int, struct screen **); void mode_tree_zoom(struct mode_tree_data *, struct args *); void mode_tree_build(struct mode_tree_data *); void mode_tree_free(struct mode_tree_data *); diff --git a/window-buffer.c b/window-buffer.c index 5023e9fa..7ad33345 100644 --- a/window-buffer.c +++ b/window-buffer.c @@ -350,7 +350,7 @@ window_buffer_init(struct window_mode_entry *wme, struct cmd_find_state *fs, data->data = mode_tree_start(wp, args, window_buffer_build, window_buffer_draw, window_buffer_search, window_buffer_menu, NULL, - window_buffer_get_key, data, window_buffer_menu_items, + window_buffer_get_key, NULL, data, window_buffer_menu_items, window_buffer_sort_list, nitems(window_buffer_sort_list), &s); mode_tree_zoom(data->data, args); diff --git a/window-client.c b/window-client.c index b704b530..c1b962f1 100644 --- a/window-client.c +++ b/window-client.c @@ -310,7 +310,7 @@ window_client_init(struct window_mode_entry *wme, data->data = mode_tree_start(wp, args, window_client_build, window_client_draw, NULL, window_client_menu, NULL, - window_client_get_key, data, window_client_menu_items, + window_client_get_key, NULL, data, window_client_menu_items, window_client_sort_list, nitems(window_client_sort_list), &s); mode_tree_zoom(data->data, args); diff --git a/window-customize.c b/window-customize.c index c49e57af..f30becfe 100644 --- a/window-customize.c +++ b/window-customize.c @@ -891,8 +891,8 @@ window_customize_init(struct window_mode_entry *wme, struct cmd_find_state *fs, data->data = mode_tree_start(wp, args, window_customize_build, window_customize_draw, NULL, window_customize_menu, - window_customize_height, NULL, data, window_customize_menu_items, - NULL, 0, &s); + window_customize_height, NULL, NULL, data, + window_customize_menu_items, NULL, 0, &s); mode_tree_zoom(data->data, args); mode_tree_build(data->data); diff --git a/window-tree.c b/window-tree.c index 2c3e252d..af171956 100644 --- a/window-tree.c +++ b/window-tree.c @@ -902,6 +902,58 @@ window_tree_get_key(void *modedata, void *itemdata, u_int line) return (key); } +static int +window_tree_swap(void *cur_itemdata, void *other_itemdata) +{ + struct window_tree_itemdata *cur = cur_itemdata; + struct window_tree_itemdata *other = other_itemdata; + struct session *cur_session, *other_session; + struct winlink *cur_winlink, *other_winlink; + struct window *cur_window, *other_window; + struct window_pane *cur_pane, *other_pane; + + if (cur->type != other->type) + return (0); + if (cur->type != WINDOW_TREE_WINDOW) + return (0); + + window_tree_pull_item(cur, &cur_session, &cur_winlink, &cur_pane); + window_tree_pull_item(other, &other_session, &other_winlink, + &other_pane); + + if (cur_session != other_session) + return (0); + + if (window_tree_sort->field != WINDOW_TREE_BY_INDEX && + window_tree_cmp_window(&cur_winlink, &other_winlink) != 0) { + /* + * Swapping indexes would not swap positions in the tree, so + * prevent swapping to avoid confusing the user. + */ + return (0); + } + + other_window = other_winlink->window; + TAILQ_REMOVE(&other_window->winlinks, other_winlink, wentry); + cur_window = cur_winlink->window; + TAILQ_REMOVE(&cur_window->winlinks, cur_winlink, wentry); + + other_winlink->window = cur_window; + TAILQ_INSERT_TAIL(&cur_window->winlinks, other_winlink, wentry); + cur_winlink->window = other_window; + TAILQ_INSERT_TAIL(&other_window->winlinks, cur_winlink, wentry); + + if (cur_session->curw == cur_winlink) + session_set_current(cur_session, other_winlink); + else if (cur_session->curw == other_winlink) + session_set_current(cur_session, cur_winlink); + session_group_synchronize_from(cur_session); + server_redraw_session_group(cur_session); + recalculate_sizes(); + + return (1); +} + static struct screen * window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs, struct args *args) @@ -940,7 +992,7 @@ window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs, data->data = mode_tree_start(wp, args, window_tree_build, window_tree_draw, window_tree_search, window_tree_menu, NULL, - window_tree_get_key, data, window_tree_menu_items, + window_tree_get_key, window_tree_swap, data, window_tree_menu_items, window_tree_sort_list, nitems(window_tree_sort_list), &s); mode_tree_zoom(data->data, args); From f101762d1b357426834d062f9b97a8c5effc20b3 Mon Sep 17 00:00:00 2001 From: nicm <nicm> Date: Fri, 21 Mar 2025 14:04:26 +0000 Subject: [PATCH 3/3] Fix mouse_hyperlink format in copy mode. From someone in GitHub issue 4418. --- format.c | 6 ++++++ tmux.h | 1 + window-copy.c | 10 ++++++++++ 3 files changed, 17 insertions(+) diff --git a/format.c b/format.c index db2bcd8a..13e7f149 100644 --- a/format.c +++ b/format.c @@ -1173,6 +1173,12 @@ format_cb_mouse_hyperlink(struct format_tree *ft) return (NULL); if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0) return (NULL); + + if (!TAILQ_EMPTY(&wp->modes)) { + if (window_pane_mode(wp) != WINDOW_PANE_NO_MODE) + return (window_copy_get_hyperlink(wp, x, y)); + return (NULL); + } gd = wp->base.grid; return (format_grid_hyperlink(gd, x, gd->hsize + y, wp->screen)); } diff --git a/tmux.h b/tmux.h index 35577ae0..fcb064dd 100644 --- a/tmux.h +++ b/tmux.h @@ -3338,6 +3338,7 @@ char *window_copy_get_word(struct window_pane *, u_int, u_int); char *window_copy_get_line(struct window_pane *, u_int); int window_copy_get_current_offset(struct window_pane *, u_int *, u_int *); +char *window_copy_get_hyperlink(struct window_pane *, u_int, u_int); /* window-option.c */ extern const struct window_mode window_customize_mode; diff --git a/window-copy.c b/window-copy.c index 3a4f59bb..1dd12e45 100644 --- a/window-copy.c +++ b/window-copy.c @@ -884,6 +884,16 @@ window_copy_get_line(struct window_pane *wp, u_int y) return (format_grid_line(gd, gd->hsize + y)); } +char * +window_copy_get_hyperlink(struct window_pane *wp, u_int x, u_int y) +{ + struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes); + struct window_copy_mode_data *data = wme->data; + struct grid *gd = data->screen.grid; + + return (format_grid_hyperlink(gd, x, gd->hsize + y, wp->screen)); +} + static void * window_copy_cursor_hyperlink_cb(struct format_tree *ft) {