diff options
author | Nicholas Marriott <nicm@cvs.openbsd.org> | 2019-05-26 17:34:46 +0000 |
---|---|---|
committer | Nicholas Marriott <nicm@cvs.openbsd.org> | 2019-05-26 17:34:46 +0000 |
commit | d42f75e5c0133d899df058f961447782d34b158a (patch) | |
tree | 3b2c39dad3e63840d0b3198f9194293f2bce8803 | |
parent | 48405956365d8c4a9a95d0823ee24aaa49eec67f (diff) |
Add formats for word and line under the mouse and use them to add some
items to the pane menu.
-rw-r--r-- | usr.bin/tmux/cmd-display-menu.c | 4 | ||||
-rw-r--r-- | usr.bin/tmux/format.c | 146 | ||||
-rw-r--r-- | usr.bin/tmux/grid.c | 21 | ||||
-rw-r--r-- | usr.bin/tmux/menu.c | 50 | ||||
-rw-r--r-- | usr.bin/tmux/mode-tree.c | 4 | ||||
-rw-r--r-- | usr.bin/tmux/options-table.c | 4 | ||||
-rw-r--r-- | usr.bin/tmux/tmux.1 | 6 | ||||
-rw-r--r-- | usr.bin/tmux/tmux.h | 6 | ||||
-rw-r--r-- | usr.bin/tmux/utf8.c | 22 | ||||
-rw-r--r-- | usr.bin/tmux/window-copy.c | 41 |
10 files changed, 234 insertions, 70 deletions
diff --git a/usr.bin/tmux/cmd-display-menu.c b/usr.bin/tmux/cmd-display-menu.c index 4299d9a6b3f..08d22add102 100644 --- a/usr.bin/tmux/cmd-display-menu.c +++ b/usr.bin/tmux/cmd-display-menu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd-display-menu.c,v 1.2 2019/05/12 07:27:08 nicm Exp $ */ +/* $OpenBSD: cmd-display-menu.c,v 1.3 2019/05/26 17:34:45 nicm Exp $ */ /* * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -79,7 +79,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item) title = format_single(NULL, args_get(args, 'T'), c, s, wl, wp); else title = xstrdup(""); - menu = menu_create(string, c, fs, title); + menu = menu_create(string, item, c, fs, title); free(title); if (menu == NULL) { cmdq_error(item, "invalid menu %s", string); diff --git a/usr.bin/tmux/format.c b/usr.bin/tmux/format.c index 562b1ae016c..68d0d64205a 100644 --- a/usr.bin/tmux/format.c +++ b/usr.bin/tmux/format.c @@ -1,4 +1,4 @@ -/* $OpenBSD: format.c,v 1.196 2019/05/26 12:02:42 nicm Exp $ */ +/* $OpenBSD: format.c,v 1.197 2019/05/26 17:34:45 nicm Exp $ */ /* * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -84,6 +84,12 @@ static void format_defaults_winlink(struct format_tree *, struct winlink *); "New After,w,new-window -a|" \ "New At End,W,new-window" #define DEFAULT_PANE_MENU \ + "#{?mouse_word,Search For #[underscore]#{=/9/...:mouse_word},},,copy-mode -t=; send -Xt= search-backward \"#{q:mouse_word}\"|" \ + "#{?mouse_word,Type #[underscore]#{=/9/...:mouse_word},},,send-keys -l \"#{q:mouse_word}\"|" \ + "|" \ + "#{?mouse_word,Copy #[underscore]#{=/9/...:mouse_word},},c,set-buffer \"#{q:mouse_word}\"|" \ + "#{?mouse_line,Copy Line,},l,set-buffer \"#{q:mouse_line}\"|" \ + "|" \ "Horizontal Split,h,split-window -h|" \ "Vertical Split,v,split-window -v|" \ "|" \ @@ -170,6 +176,8 @@ struct format_tree { time_t time; u_int loop; + struct mouse_event m; + RB_HEAD(format_entry_tree, format_entry) tree; }; static int format_entry_cmp(struct format_entry *, struct format_entry *); @@ -743,6 +751,121 @@ format_cb_cursor_character(struct format_tree *ft, struct format_entry *fe) xasprintf(&fe->value, "%.*s", (int)gc.data.size, gc.data.data); } +/* Callback for mouse_word. */ +static void +format_cb_mouse_word(struct format_tree *ft, struct format_entry *fe) +{ + struct window_pane *wp; + u_int x, y, end; + struct grid *gd; + struct grid_line *gl; + struct grid_cell gc; + const char *ws; + struct utf8_data *ud = NULL; + size_t size = 0; + int found = 0; + + if (!ft->m.valid) + return; + wp = cmd_mouse_pane(&ft->m, NULL, NULL); + if (wp == NULL) + return; + if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0) + return; + gd = wp->base.grid; + ws = options_get_string(global_s_options, "word-separators"); + + y = gd->hsize + y; + for (;;) { + grid_get_cell(gd, x, y, &gc); + if (gc.flags & GRID_FLAG_PADDING) + break; + if (utf8_cstrhas(ws, &gc.data)) { + found = 1; + break; + } + + if (x == 0) { + if (y == 0) + break; + gl = &gd->linedata[y - 1]; + if (~gl->flags & GRID_LINE_WRAPPED) + break; + y--; + x = grid_line_length(gd, y); + if (x == 0) + break; + } + x--; + } + for (;;) { + if (found) { + end = grid_line_length(gd, y); + if (end == 0 || x == end - 1) { + if (y == gd->hsize + gd->sy - 1) + break; + gl = &gd->linedata[y]; + if (~gl->flags & GRID_LINE_WRAPPED) + break; + y++; + x = 0; + } else + x++; + } + found = 1; + + grid_get_cell(gd, x, y, &gc); + if (gc.flags & GRID_FLAG_PADDING) + break; + if (utf8_cstrhas(ws, &gc.data)) + break; + + ud = xreallocarray(ud, size + 2, sizeof *ud); + memcpy(&ud[size++], &gc.data, sizeof *ud); + } + if (size != 0) { + ud[size].size = 0; + fe->value = utf8_tocstr(ud); + free(ud); + } +} + +/* Callback for mouse_line. */ +static void +format_cb_mouse_line(struct format_tree *ft, struct format_entry *fe) +{ + struct window_pane *wp; + u_int x, y; + struct grid *gd; + struct grid_cell gc; + struct utf8_data *ud = NULL; + size_t size = 0; + + if (!ft->m.valid) + return; + wp = cmd_mouse_pane(&ft->m, NULL, NULL); + if (wp == NULL) + return; + if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0) + return; + gd = wp->base.grid; + + y = gd->hsize + y; + for (x = 0; x < grid_line_length(gd, y); x++) { + grid_get_cell(gd, x, y, &gc); + if (gc.flags & GRID_FLAG_PADDING) + break; + + ud = xreallocarray(ud, size + 2, sizeof *ud); + memcpy(&ud[size++], &gc.data, sizeof *ud); + } + if (size != 0) { + ud[size].size = 0; + fe->value = utf8_tocstr(ud); + free(ud); + } +} + /* Merge a format tree. */ static void format_merge(struct format_tree *ft, struct format_tree *from) @@ -759,10 +882,29 @@ format_merge(struct format_tree *ft, struct format_tree *from) static void format_create_add_item(struct format_tree *ft, struct cmdq_item *item) { + struct mouse_event *m; + struct window_pane *wp; + u_int x, y; + if (item->cmd != NULL) format_add(ft, "command", "%s", item->cmd->entry->name); - if (item->shared != NULL && item->shared->formats != NULL) + + if (item->shared == NULL) + return; + if (item->shared->formats != NULL) format_merge(ft, item->shared->formats); + + m = &item->shared->mouse; + if (m->valid && ((wp = cmd_mouse_pane(m, NULL, NULL)) != NULL)) { + format_add(ft, "mouse_pane", "%%%u", wp->id); + if (cmd_mouse_at(wp, m, &x, &y, 0) == 0) { + format_add(ft, "mouse_x", "%u", x); + format_add(ft, "mouse_y", "%u", y); + format_add_cb(ft, "mouse_word", format_cb_mouse_word); + format_add_cb(ft, "mouse_line", format_cb_mouse_line); + } + } + memcpy(&ft->m, m, sizeof ft->m); } /* Create a new tree. */ diff --git a/usr.bin/tmux/grid.c b/usr.bin/tmux/grid.c index 451df187b77..6d070c9907e 100644 --- a/usr.bin/tmux/grid.c +++ b/usr.bin/tmux/grid.c @@ -1,4 +1,4 @@ -/* $OpenBSD: grid.c,v 1.94 2019/05/13 20:10:23 nicm Exp $ */ +/* $OpenBSD: grid.c,v 1.95 2019/05/26 17:34:45 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -1350,3 +1350,22 @@ grid_unwrap_position(struct grid *gd, u_int *px, u_int *py, u_int wx, u_int wy) *px = wx; *py = yy; } + +/* Get length of line. */ +u_int +grid_line_length(struct grid *gd, u_int py) +{ + struct grid_cell gc; + u_int px; + + px = grid_get_line(gd, py)->cellsize; + if (px > gd->sx) + px = gd->sx; + while (px > 0) { + grid_get_cell(gd, px - 1, py, &gc); + if (gc.data.size != 1 || *gc.data.data != ' ') + break; + px--; + } + return (px); +} diff --git a/usr.bin/tmux/menu.c b/usr.bin/tmux/menu.c index 96bde640535..4e7c1b5a4df 100644 --- a/usr.bin/tmux/menu.c +++ b/usr.bin/tmux/menu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: menu.c,v 1.5 2019/05/23 11:13:30 nicm Exp $ */ +/* $OpenBSD: menu.c,v 1.6 2019/05/26 17:34:45 nicm Exp $ */ /* * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -41,8 +41,8 @@ struct menu_data { }; static void -menu_add_item(struct menu *menu, struct menu_item *item, struct client *c, - struct cmd_find_state *fs) +menu_add_item(struct menu *menu, struct menu_item *item, + struct cmdq_item *qitem, struct client *c, struct cmd_find_state *fs) { struct menu_item *new_item; const char *key; @@ -57,24 +57,31 @@ menu_add_item(struct menu *menu, struct menu_item *item, struct client *c, if (item == NULL || *item->name == '\0') /* horizontal line */ return; if (fs != NULL) { - name = format_single(NULL, item->name, c, fs->s, fs->wl, + name = format_single(qitem, item->name, c, fs->s, fs->wl, fs->wp); } else - name = xstrdup(item->name); + name = format_single(qitem, item->name, c, NULL, NULL, NULL); if (*name == '\0') { /* no item if empty after format expanded */ menu->count--; return; } if (item->key != KEYC_UNKNOWN) { key = key_string_lookup_key(item->key); - xasprintf(&new_item->name, "%s #[align=right](%s)", name, key); + xasprintf(&new_item->name, "%s#[default] #[align=right](%s)", + name, key); } else xasprintf(&new_item->name, "%s", name); free(name); - if (item->command != NULL) - new_item->command = xstrdup(item->command); - else + if (item->command != NULL) { + if (fs != NULL) { + new_item->command = format_single(qitem, item->command, + c, fs->s, fs->wl, fs->wp); + } else { + new_item->command = format_single(qitem, item->command, + c, NULL, NULL, NULL); + } + } else new_item->command = NULL; new_item->key = item->key; @@ -84,8 +91,8 @@ menu_add_item(struct menu *menu, struct menu_item *item, struct client *c, } static void -menu_parse_item(struct menu *menu, const char *s, struct client *c, - struct cmd_find_state *fs) +menu_parse_item(struct menu *menu, const char *s, struct cmdq_item *qitem, + struct client *c, struct cmd_find_state *fs) { char *copy, *first; const char *second, *third; @@ -100,15 +107,15 @@ menu_parse_item(struct menu *menu, const char *s, struct client *c, item.name = first; item.command = (char *)third; item.key = key_string_lookup_string(second); - menu_add_item(menu, &item, c, fs); + menu_add_item(menu, &item, qitem, c, fs); } } free(copy); } struct menu * -menu_create(const char *s, struct client *c, struct cmd_find_state *fs, - const char *title) +menu_create(const char *s, struct cmdq_item *qitem, struct client *c, + struct cmd_find_state *fs, const char *title) { struct menu *menu; char *copy, *string, *next; @@ -124,10 +131,11 @@ menu_create(const char *s, struct client *c, struct cmd_find_state *fs, next = (char *)format_skip(string, "|"); if (next != NULL) *next++ = '\0'; - if (*string == '\0') - menu_add_item(menu, NULL, c, fs); - else - menu_parse_item(menu, string, c, fs); + if (*string == '\0') { + if (menu->count != 0) + menu_add_item(menu, NULL, qitem, c, fs); + } else + menu_parse_item(menu, string, qitem, c, fs); string = next; } while (next != NULL); free(copy); @@ -283,7 +291,11 @@ chosen: cmdq_append(c, new_item); break; case CMD_PARSE_SUCCESS: - new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0); + if (md->item != NULL) + m = &md->item->shared->mouse; + else + m = NULL; + new_item = cmdq_get_command(pr->cmdlist, &md->fs, m, 0); cmd_list_free(pr->cmdlist); cmdq_append(c, new_item); break; diff --git a/usr.bin/tmux/mode-tree.c b/usr.bin/tmux/mode-tree.c index 05067b3db30..4b60e626f85 100644 --- a/usr.bin/tmux/mode-tree.c +++ b/usr.bin/tmux/mode-tree.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mode-tree.c,v 1.30 2019/05/23 11:13:30 nicm Exp $ */ +/* $OpenBSD: mode-tree.c,v 1.31 2019/05/26 17:34:45 nicm Exp $ */ /* * Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -828,7 +828,7 @@ mode_tree_display_menu(struct mode_tree_data *mtd, struct client *c, u_int x, s = MODE_TREE_MENU; title = xstrdup(""); } - menu = menu_create(s, c, NULL, title); + menu = menu_create(s, NULL, c, NULL, title); free(title); if (menu == NULL) return; diff --git a/usr.bin/tmux/options-table.c b/usr.bin/tmux/options-table.c index 85cd09a7f25..f6b0f1b6e08 100644 --- a/usr.bin/tmux/options-table.c +++ b/usr.bin/tmux/options-table.c @@ -1,4 +1,4 @@ -/* $OpenBSD: options-table.c,v 1.105 2019/04/26 11:38:51 nicm Exp $ */ +/* $OpenBSD: options-table.c,v 1.106 2019/05/26 17:34:45 nicm Exp $ */ /* * Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -551,7 +551,7 @@ const struct options_table_entry options_table[] = { { .name = "word-separators", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_SESSION, - .default_str = " -_@" + .default_str = " " }, /* Window options. */ diff --git a/usr.bin/tmux/tmux.1 b/usr.bin/tmux/tmux.1 index a5ef04993bb..c37b6854a01 100644 --- a/usr.bin/tmux/tmux.1 +++ b/usr.bin/tmux/tmux.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: tmux.1,v 1.653 2019/05/26 12:02:42 nicm Exp $ +.\" $OpenBSD: tmux.1,v 1.654 2019/05/26 17:34:45 nicm Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> .\" @@ -4129,6 +4129,10 @@ The following variables are available, where appropriate: .It Li "mouse_any_flag" Ta "" Ta "Pane mouse any flag" .It Li "mouse_button_flag" Ta "" Ta "Pane mouse button flag" .It Li "mouse_standard_flag" Ta "" Ta "Pane mouse standard flag" +.It Li "mouse_x" Ta "" Ta "Mouse X position, if any" +.It Li "mouse_y" Ta "" Ta "Mouse Y position, if any" +.It Li "mouse_word" Ta "" Ta "Word under mouse, if any" +.It Li "mouse_line" Ta "" Ta "Line under mouse, if any" .It Li "pane_active" Ta "" Ta "1 if active pane" .It Li "pane_at_bottom" Ta "" Ta "1 if pane is at the bottom of window" .It Li "pane_at_left" Ta "" Ta "1 if pane is at the left of window" diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h index cde11dc618a..2a18becbf95 100644 --- a/usr.bin/tmux/tmux.h +++ b/usr.bin/tmux/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.905 2019/05/25 07:18:20 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.906 2019/05/26 17:34:45 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -2219,6 +2219,7 @@ void grid_duplicate_lines(struct grid *, u_int, struct grid *, u_int, void grid_reflow(struct grid *, u_int); void grid_wrap_position(struct grid *, u_int, u_int, u_int *, u_int *); void grid_unwrap_position(struct grid *, u_int *, u_int *, u_int, u_int); +u_int grid_line_length(struct grid *, u_int); /* grid-view.c */ void grid_view_get_cell(struct grid *, u_int, u_int, struct grid_cell *); @@ -2583,6 +2584,7 @@ struct utf8_data *utf8_fromcstr(const char *); char *utf8_tocstr(struct utf8_data *); u_int utf8_cstrwidth(const char *); char *utf8_padcstr(const char *, u_int); +int utf8_cstrhas(const char *, const struct utf8_data *); /* procname.c */ char *get_proc_name(int, char *); @@ -2598,7 +2600,7 @@ __dead void printflike(1, 2) fatal(const char *, ...); __dead void printflike(1, 2) fatalx(const char *, ...); /* menu.c */ -struct menu *menu_create(const char *, struct client *, +struct menu *menu_create(const char *, struct cmdq_item *, struct client *, struct cmd_find_state *, const char *); void menu_free(struct menu *); int menu_display(struct menu *, int, struct cmdq_item *, u_int, diff --git a/usr.bin/tmux/utf8.c b/usr.bin/tmux/utf8.c index eb6dcad08eb..82720a9da61 100644 --- a/usr.bin/tmux/utf8.c +++ b/usr.bin/tmux/utf8.c @@ -1,4 +1,4 @@ -/* $OpenBSD: utf8.c,v 1.42 2019/05/23 18:22:13 nicm Exp $ */ +/* $OpenBSD: utf8.c,v 1.43 2019/05/26 17:34:45 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -410,3 +410,23 @@ utf8_padcstr(const char *s, u_int width) out[slen] = '\0'; return (out); } + +int +utf8_cstrhas(const char *s, const struct utf8_data *ud) +{ + struct utf8_data *copy, *loop; + int found = 0; + + copy = utf8_fromcstr(s); + for (loop = copy; loop->size != 0; loop++) { + if (loop->size != ud->size) + continue; + if (memcmp(loop->data, ud->data, loop->size) == 0) { + found = 1; + break; + } + } + free(copy); + + return (found); +} diff --git a/usr.bin/tmux/window-copy.c b/usr.bin/tmux/window-copy.c index 52664e510f5..a9568cbd8f3 100644 --- a/usr.bin/tmux/window-copy.c +++ b/usr.bin/tmux/window-copy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: window-copy.c,v 1.223 2019/05/15 19:25:53 nicm Exp $ */ +/* $OpenBSD: window-copy.c,v 1.224 2019/05/26 17:34:45 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com> @@ -2810,54 +2810,19 @@ window_copy_in_set(struct window_mode_entry *wme, u_int px, u_int py, { struct window_copy_mode_data *data = wme->data; struct grid_cell gc; - const struct utf8_data *ud; - struct utf8_data *copy; - struct utf8_data *loop; - int found = 0; grid_get_cell(data->backing->grid, px, py, &gc); if (gc.flags & GRID_FLAG_PADDING) return (0); - ud = &gc.data; - - copy = utf8_fromcstr(set); - for (loop = copy; loop->size != 0; loop++) { - if (loop->size != ud->size) - continue; - if (memcmp(loop->data, ud->data, loop->size) == 0) { - found = 1; - break; - } - } - free(copy); - - return (found); + return (utf8_cstrhas(set, &gc.data)); } static u_int window_copy_find_length(struct window_mode_entry *wme, u_int py) { struct window_copy_mode_data *data = wme->data; - struct screen *s = data->backing; - struct grid_cell gc; - u_int px; - /* - * If the pane has been resized, its grid can contain old overlong - * lines. grid_peek_cell does not allow accessing cells beyond the - * width of the grid, and screen_write_copy treats them as spaces, so - * ignore them here too. - */ - px = grid_get_line(s->grid, py)->cellsize; - if (px > screen_size_x(s)) - px = screen_size_x(s); - while (px > 0) { - grid_get_cell(s->grid, px - 1, py, &gc); - if (gc.data.size != 1 || *gc.data.data != ' ') - break; - px--; - } - return (px); + return (grid_line_length(data->backing->grid, py)); } static void |