diff options
Diffstat (limited to 'usr.bin/tmux/window-copy.c')
-rw-r--r-- | usr.bin/tmux/window-copy.c | 406 |
1 files changed, 391 insertions, 15 deletions
diff --git a/usr.bin/tmux/window-copy.c b/usr.bin/tmux/window-copy.c index 96fb55ce871..9e1fc1629fb 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.20 2009/08/13 22:32:18 nicm Exp $ */ +/* $OpenBSD: window-copy.c,v 1.21 2009/08/18 07:08:26 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -18,6 +18,7 @@ #include <sys/types.h> +#include <stdlib.h> #include <string.h> #include "tmux.h" @@ -26,6 +27,7 @@ struct screen *window_copy_init(struct window_pane *); void window_copy_free(struct window_pane *); void window_copy_resize(struct window_pane *, u_int, u_int); void window_copy_key(struct window_pane *, struct client *, int); +int window_copy_key_input(struct window_pane *, int); void window_copy_mouse( struct window_pane *, struct client *, u_char, u_char, u_char); @@ -36,6 +38,16 @@ void window_copy_write_line( void window_copy_write_lines( struct window_pane *, struct screen_write_ctx *, u_int, u_int); +void window_copy_scroll_to(struct window_pane *, u_int, u_int); +int window_copy_search_compare( + struct grid *, u_int, u_int, struct grid *, u_int); +int window_copy_search_lr( + struct grid *, struct grid *, u_int *, u_int, u_int, u_int); +int window_copy_search_rl( + struct grid *, struct grid *, u_int *, u_int, u_int, u_int); +void window_copy_search_up(struct window_pane *, const char *); +void window_copy_search_down(struct window_pane *, const char *); +void window_copy_goto_line(struct window_pane *, const char *); void window_copy_update_cursor(struct window_pane *, u_int, u_int); void window_copy_start_selection(struct window_pane *); int window_copy_update_selection(struct window_pane *); @@ -65,18 +77,32 @@ const struct window_mode window_copy_mode = { NULL, }; +enum window_copy_input_type { + WINDOW_COPY_OFF, + WINDOW_COPY_SEARCHUP, + WINDOW_COPY_SEARCHDOWN, + WINDOW_COPY_GOTOLINE, +}; + struct window_copy_mode_data { struct screen screen; - struct mode_key_data mdata; + struct mode_key_data mdata; + + u_int oy; - u_int oy; + u_int selx; + u_int sely; - u_int selx; - u_int sely; + u_int cx; + u_int cy; - u_int cx; - u_int cy; + enum window_copy_input_type inputtype; + const char *inputprompt; + char *inputstr; + + enum window_copy_input_type searchtype; + char *searchstr; }; struct screen * @@ -93,6 +119,13 @@ window_copy_init(struct window_pane *wp) data->cx = wp->base.cx; data->cy = wp->base.cy; + data->inputtype = WINDOW_COPY_OFF; + data->inputprompt = NULL; + data->inputstr = xstrdup(""); + + data->searchtype = WINDOW_COPY_OFF; + data->searchstr = NULL; + s = &data->screen; screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); if (options_get_number(&wp->window->options, "mode-mouse")) @@ -121,7 +154,12 @@ window_copy_free(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; + if (data->searchstr != NULL) + xfree(data->searchstr); + xfree(data->inputstr); + screen_free(&data->screen); + xfree(data); } @@ -172,6 +210,13 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; u_int n; + int keys; + + if (data->inputtype != WINDOW_COPY_OFF) { + if (window_copy_key_input(wp, key) != 0) + goto input_off; + return; + } switch (mode_key_lookup(&data->mdata, key)) { case MODEKEYCOPY_CANCEL: @@ -250,9 +295,111 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) case MODEKEYCOPY_PREVIOUSWORD: window_copy_cursor_previous_word(wp); break; + case MODEKEYCOPY_SEARCHUP: + data->inputtype = WINDOW_COPY_SEARCHUP; + data->inputprompt = "Search Up"; + goto input_on; + case MODEKEYCOPY_SEARCHDOWN: + data->inputtype = WINDOW_COPY_SEARCHDOWN; + data->inputprompt = "Search Down"; + goto input_on; + case MODEKEYCOPY_SEARCHAGAIN: + switch (data->searchtype) { + case WINDOW_COPY_OFF: + case WINDOW_COPY_GOTOLINE: + break; + case WINDOW_COPY_SEARCHUP: + window_copy_search_up(wp, data->searchstr); + break; + case WINDOW_COPY_SEARCHDOWN: + window_copy_search_down(wp, data->searchstr); + break; + } + break; + case MODEKEYCOPY_GOTOLINE: + data->inputtype = WINDOW_COPY_GOTOLINE; + data->inputprompt = "Goto Line"; + *data->inputstr = '\0'; + goto input_on; default: break; } + + return; + +input_on: + keys = options_get_number(&wp->window->options, "mode-keys"); + if (keys == MODEKEY_EMACS) + mode_key_init(&data->mdata, &mode_key_tree_emacs_edit); + else + mode_key_init(&data->mdata, &mode_key_tree_vi_edit); + + window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); + return; + +input_off: + keys = options_get_number(&wp->window->options, "mode-keys"); + if (keys == MODEKEY_EMACS) + mode_key_init(&data->mdata, &mode_key_tree_emacs_copy); + else + mode_key_init(&data->mdata, &mode_key_tree_vi_copy); + + data->inputtype = WINDOW_COPY_OFF; + data->inputprompt = NULL; + + window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); +} + +int +window_copy_key_input(struct window_pane *wp, int key) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + size_t inputlen; + + switch (mode_key_lookup(&data->mdata, key)) { + case MODEKEYEDIT_CANCEL: + return (-1); + case MODEKEYEDIT_BACKSPACE: + inputlen = strlen(data->inputstr); + if (inputlen > 0) + data->inputstr[inputlen - 1] = '\0'; + break; + case MODEKEYEDIT_ENTER: + switch (data->inputtype) { + case WINDOW_COPY_OFF: + break; + case WINDOW_COPY_SEARCHUP: + window_copy_search_up(wp, data->inputstr); + data->searchtype = data->inputtype; + data->searchstr = xstrdup(data->inputstr); + break; + case WINDOW_COPY_SEARCHDOWN: + window_copy_search_down(wp, data->inputstr); + data->searchtype = data->inputtype; + data->searchstr = xstrdup(data->inputstr); + break; + case WINDOW_COPY_GOTOLINE: + window_copy_goto_line(wp, data->inputstr); + *data->inputstr = '\0'; + break; + } + return (1); + case MODEKEY_OTHER: + if (key < 32 || key > 126) + break; + inputlen = strlen(data->inputstr) + 2; + + data->inputstr = xrealloc(data->inputstr, 1, inputlen); + data->inputstr[inputlen - 2] = key; + data->inputstr[inputlen - 1] = '\0'; + break; + default: + break; + } + + window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1); + return (0); } void @@ -275,6 +422,229 @@ window_copy_mouse(struct window_pane *wp, } void +window_copy_scroll_to(struct window_pane *wp, u_int px, u_int py) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &wp->base; + struct grid *gd = s->grid; + u_int offset, gap; + + data->cx = px; + + gap = gd->sy / 4; + if (py < gd->sy) { + offset = 0; + data->cy = py; + } else if (py > gd->hsize + gd->sy - gap) { + offset = gd->hsize; + data->cy = py - gd->hsize; + } else { + offset = py + gap - gd->sy; + data->cy = py - offset; + } + data->oy = gd->hsize - offset; + + window_copy_redraw_screen(wp); +} + +int +window_copy_search_compare( + struct grid *gd, u_int px, u_int py, struct grid *sgd, u_int spx) +{ + const struct grid_cell *gc, *sgc; + const struct grid_utf8 *gu, *sgu; + + gc = grid_peek_cell(gd, px, py); + sgc = grid_peek_cell(sgd, spx, 0); + + if ((gc->flags & GRID_FLAG_UTF8) != (sgc->flags & GRID_FLAG_UTF8)) + return (0); + + if (gc->flags & GRID_FLAG_UTF8) { + gu = grid_peek_utf8(gd, px, py); + sgu = grid_peek_utf8(sgd, spx, 0); + if (memcmp(gu->data, sgu->data, UTF8_SIZE) == 0) + return (1); + } else { + if (gc->data == sgc->data) + return (1); + } + return (0); +} + +int +window_copy_search_lr(struct grid *gd, + struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last) +{ + u_int ax, bx, px; + + for (ax = first; ax < last; ax++) { + if (ax + sgd->sx >= gd->sx) + break; + for (bx = 0; bx < sgd->sx; bx++) { + px = ax + bx; + if (!window_copy_search_compare(gd, px, py, sgd, bx)) + break; + } + if (bx == sgd->sx) { + *ppx = ax; + return (1); + } + } + return (0); +} + +int +window_copy_search_rl(struct grid *gd, + struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last) +{ + u_int ax, bx, px; + + for (ax = last + 1; ax > first; ax--) { + for (bx = 0; bx < sgd->sx; bx++) { + px = ax - 1 + bx; + if (!window_copy_search_compare(gd, px, py, sgd, bx)) + break; + } + if (bx == sgd->sx) { + *ppx = ax - 1; + return (1); + } + } + return (0); +} + +void +window_copy_search_up(struct window_pane *wp, const char *searchstr) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &wp->base, ss; + struct screen_write_ctx ctx; + struct grid *gd = s->grid, *sgd; + struct grid_cell gc; + size_t searchlen; + u_int i, last, fx, fy, px; + int utf8flag, n, wrapped; + + if (*searchstr == '\0') + return; + utf8flag = options_get_number(&wp->window->options, "utf8"); + searchlen = screen_write_strlen(utf8flag, "%s", searchstr); + + screen_init(&ss, searchlen, 1, 0); + screen_write_start(&ctx, NULL, &ss); + memcpy(&gc, &grid_default_cell, sizeof gc); + screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr); + screen_write_stop(&ctx); + + fx = data->cx; + fy = gd->hsize - data->oy + data->cy; + + if (fx == 0) { + if (fy == 0) + return; + fx = gd->sx - 1; + fy--; + } else + fx--; + n = wrapped = 0; + +retry: + sgd = ss.grid; + for (i = fy + 1; i > 0; i--) { + last = screen_size_x(s); + if (i == fy + 1) + last = fx; + n = window_copy_search_rl(gd, sgd, &px, i - 1, 0, last); + if (n) { + window_copy_scroll_to(wp, px, i - 1); + break; + } + } + if (!n && !wrapped) { + fx = gd->sx - 1; + fy = gd->hsize + gd->sy - 1; + wrapped = 1; + goto retry; + } + + screen_free(&ss); +} + +void +window_copy_search_down(struct window_pane *wp, const char *searchstr) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &wp->base, ss; + struct screen_write_ctx ctx; + struct grid *gd = s->grid, *sgd; + struct grid_cell gc; + size_t searchlen; + u_int i, first, fx, fy, px; + int utf8flag, n, wrapped; + + if (*searchstr == '\0') + return; + utf8flag = options_get_number(&wp->window->options, "utf8"); + searchlen = screen_write_strlen(utf8flag, "%s", searchstr); + + screen_init(&ss, searchlen, 1, 0); + screen_write_start(&ctx, NULL, &ss); + memcpy(&gc, &grid_default_cell, sizeof gc); + screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr); + screen_write_stop(&ctx); + searchlen = strlen(searchstr); + + fx = data->cx; + fy = gd->hsize - data->oy + data->cy; + + if (fx == gd->sx - 1) { + if (fy == gd->hsize + gd->sy) + return; + fx = 0; + fy++; + } else + fx++; + n = wrapped = 0; + +retry: + sgd = ss.grid; + for (i = fy + 1; i < gd->hsize + gd->sy; i++) { + first = 0; + if (i == fy + 1) + first = fx; + n = window_copy_search_lr(gd, sgd, &px, i - 1, first, gd->sx); + if (n) { + window_copy_scroll_to(wp, px, i - 1); + break; + } + } + if (!n && !wrapped) { + fx = 0; + fy = 0; + wrapped = 1; + goto retry; + } + + screen_free(&ss); +} + +void +window_copy_goto_line(struct window_pane *wp, const char *linestr) +{ + struct window_copy_mode_data *data = wp->modedata; + const char *errstr; + u_int lineno; + + lineno = strtonum(linestr, 0, screen_hsize(&wp->base), &errstr); + if (errstr != NULL) + return; + + data->oy = lineno; + window_copy_redraw_screen(wp); +} + +void window_copy_write_line( struct window_pane *wp, struct screen_write_ctx *ctx, u_int py) { @@ -282,23 +652,29 @@ window_copy_write_line( struct screen *s = &data->screen; struct grid_cell gc; char hdr[32]; - size_t size; + size_t last, xoff = 0, size = 0; + memcpy(&gc, &grid_default_cell, sizeof gc); + gc.fg = options_get_number(&wp->window->options, "mode-fg"); + gc.bg = options_get_number(&wp->window->options, "mode-bg"); + gc.attr |= options_get_number(&wp->window->options, "mode-attr"); + + last = screen_size_y(s) - 1; if (py == 0) { - memcpy(&gc, &grid_default_cell, sizeof gc); size = xsnprintf(hdr, sizeof hdr, "[%u/%u]", data->oy, screen_hsize(&wp->base)); - gc.fg = options_get_number(&wp->window->options, "mode-fg"); - gc.bg = options_get_number(&wp->window->options, "mode-bg"); - gc.attr |= options_get_number( - &wp->window->options, "mode-attr"); screen_write_cursormove(ctx, screen_size_x(s) - size, 0); screen_write_puts(ctx, &gc, "%s", hdr); + } else if (py == last && data->inputtype != WINDOW_COPY_OFF) { + xoff = size = xsnprintf(hdr, sizeof hdr, + "%s: %s", data->inputprompt, data->inputstr); + screen_write_cursormove(ctx, 0, last); + screen_write_puts(ctx, &gc, "%s", hdr); } else size = 0; - screen_write_cursormove(ctx, 0, py); - screen_write_copy(ctx, &wp->base, 0, (screen_hsize(&wp->base) - + screen_write_cursormove(ctx, xoff, py); + screen_write_copy(ctx, &wp->base, xoff, (screen_hsize(&wp->base) - data->oy) + py, screen_size_x(s) - size, 1); if (py == data->cy && data->cx == screen_size_x(s)) { |