=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/tmux/window-copy.c,v retrieving revision 1.20 retrieving revision 1.21 diff -c -r1.20 -r1.21 *** src/usr.bin/tmux/window-copy.c 2009/08/13 22:32:18 1.20 --- src/usr.bin/tmux/window-copy.c 2009/08/18 07:08:26 1.21 *************** *** 1,4 **** ! /* $OpenBSD: window-copy.c,v 1.20 2009/08/13 22:32:18 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott --- 1,4 ---- ! /* $OpenBSD: window-copy.c,v 1.21 2009/08/18 07:08:26 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott *************** *** 18,23 **** --- 18,24 ---- #include + #include #include #include "tmux.h" *************** *** 26,31 **** --- 27,33 ---- 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,41 **** --- 38,53 ---- 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,82 **** NULL, }; struct window_copy_mode_data { struct screen screen; ! struct mode_key_data mdata; ! u_int oy; ! u_int selx; ! u_int sely; ! u_int cx; ! u_int cy; }; struct screen * --- 77,108 ---- 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; ! u_int oy; ! u_int selx; ! u_int sely; ! 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,98 **** --- 119,131 ---- 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,127 **** --- 154,165 ---- { 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,178 **** --- 210,223 ---- 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: window_pane_reset_mode(wp); *************** *** 250,260 **** --- 295,407 ---- 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 window_copy_mouse(struct window_pane *wp, unused struct client *c, u_char b, u_char x, u_char y) *************** *** 275,280 **** --- 422,650 ---- } 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,304 **** struct screen *s = &data->screen; struct grid_cell gc; char hdr[32]; ! size_t size; 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 size = 0; ! screen_write_cursormove(ctx, 0, py); ! screen_write_copy(ctx, &wp->base, 0, (screen_hsize(&wp->base) - data->oy) + py, screen_size_x(s) - size, 1); if (py == data->cy && data->cx == screen_size_x(s)) { --- 652,680 ---- struct screen *s = &data->screen; struct grid_cell gc; char hdr[32]; ! 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) { size = xsnprintf(hdr, sizeof hdr, "[%u/%u]", data->oy, screen_hsize(&wp->base)); 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, 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)) {