=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/tmux/window-copy.c,v retrieving revision 1.53 retrieving revision 1.54 diff -u -r1.53 -r1.54 --- src/usr.bin/tmux/window-copy.c 2010/03/22 19:13:28 1.53 +++ src/usr.bin/tmux/window-copy.c 2010/04/06 21:35:44 1.54 @@ -1,4 +1,4 @@ -/* $OpenBSD: window-copy.c,v 1.53 2010/03/22 19:13:28 nicm Exp $ */ +/* $OpenBSD: window-copy.c,v 1.54 2010/04/06 21:35:44 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -93,9 +93,28 @@ WINDOW_COPY_GOTOLINE, }; +/* + * Copy-mode's visible screen (the "screen" field) is filled from one of + * two sources: the original contents of the pane (used when we + * actually enter via the "copy-mode" command, to copy the contents of + * the current pane), or else a series of lines containing the output + * from an output-writing tmux command (such as any of the "show-*" or + * "list-*" commands). + * + * In either case, the full content of the copy-mode grid is pointed at + * by the "backing" field, and is copied into "screen" as needed (that + * is, when scrolling occurs). When copy-mode is backed by a pane, + * backing points directly at that pane's screen structure (&wp->base); + * when backed by a list of output-lines from a command, it points at + * a newly-allocated screen structure (which is deallocated when the + * mode ends). + */ struct window_copy_mode_data { struct screen screen; + struct screen *backing; + int backing_written; /* backing display has started */ + struct mode_key_data mdata; u_int oy; @@ -129,18 +148,18 @@ { struct window_copy_mode_data *data; struct screen *s; - struct screen_write_ctx ctx; - u_int i; int keys; wp->modedata = data = xmalloc(sizeof *data); data->oy = 0; - data->cx = wp->base.cx; - data->cy = wp->base.cy; + data->cx = 0; + data->cy = 0; data->lastcx = 0; data->lastsx = 0; + data->backing_written = 0; + data->rectflag = 0; data->inputtype = WINDOW_COPY_OFF; @@ -168,6 +187,26 @@ else mode_key_init(&data->mdata, &mode_key_tree_vi_copy); + data->backing = NULL; + + return (s); +} + +void +window_copy_init_from_pane(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = &data->screen; + struct screen_write_ctx ctx; + u_int i; + + if (wp->mode != &window_copy_mode) + fatalx("not in copy mode"); + + data->backing = &wp->base; + data->cx = data->backing->cx; + data->cy = data->backing->cy; + s->cx = data->cx; s->cy = data->cy; @@ -176,8 +215,17 @@ window_copy_write_line(wp, &ctx, i); screen_write_cursormove(&ctx, data->cx, data->cy); screen_write_stop(&ctx); +} - return (s); +void +window_copy_init_for_output(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + + data->backing = xmalloc(sizeof *data->backing); + screen_init(data->backing, screen_size_x(&wp->base), + screen_size_y(&wp->base), UINT_MAX); + data->backing->mode &= ~MODE_WRAP; } void @@ -192,12 +240,74 @@ xfree(data->searchstr); xfree(data->inputstr); + if (data->backing != &wp->base) { + screen_free(data->backing); + xfree(data->backing); + } screen_free(&data->screen); xfree(data); } void +window_copy_add(struct window_pane *wp, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + window_copy_vadd(wp, fmt, ap); + va_end(ap); +} + +void +window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap) +{ + struct window_copy_mode_data *data = wp->modedata; + struct screen *backing = data->backing; + struct screen_write_ctx back_ctx, ctx; + struct grid_cell gc; + int utf8flag; + u_int old_hsize; + + if (backing == &wp->base) + return; + + utf8flag = options_get_number(&wp->window->options, "utf8"); + memcpy(&gc, &grid_default_cell, sizeof gc); + + old_hsize = screen_hsize(data->backing); + screen_write_start(&back_ctx, NULL, backing); + if (data->backing_written) { + /* + * On the second or later line, do a CRLF before writing + * (so it's on a new line). + */ + screen_write_carriagereturn(&back_ctx); + screen_write_linefeed(&back_ctx, 0); + } else + data->backing_written = 1; + screen_write_vnputs(&back_ctx, 0, &gc, utf8flag, fmt, ap); + screen_write_stop(&back_ctx); + + data->oy += screen_hsize(data->backing) - old_hsize; + + screen_write_start(&ctx, wp, &data->screen); + + /* + * If the history has changed, draw the top line. + * (If there's any history at all, it has changed.) + */ + if (screen_hsize(data->backing)) + window_copy_redraw_lines(wp, 0, 1); + + /* Write the line, if it's visible. */ + if (backing->cy + data->oy < screen_size_y(backing)) + window_copy_redraw_lines(wp, backing->cy, 1); + + screen_write_stop(&ctx); +} + +void window_copy_pageup(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; @@ -207,8 +317,8 @@ n = 1; if (screen_size_y(s) > 2) n = screen_size_y(s) - 2; - if (data->oy + n > screen_hsize(&wp->base)) - data->oy = screen_hsize(&wp->base); + if (data->oy + n > screen_hsize(data->backing)) + data->oy = screen_hsize(data->backing); else data->oy += n; window_copy_update_selection(wp); @@ -223,6 +333,8 @@ struct screen_write_ctx ctx; screen_resize(s, sx, sy); + if (data->backing != &wp->base) + screen_resize(data->backing, sx, sy); if (data->cy > sy - 1) data->cy = sy - 1; @@ -329,8 +441,8 @@ case MODEKEYCOPY_HALFPAGEUP: n = screen_size_y(s) / 2; for (; np != 0; np--) { - if (data->oy + n > screen_hsize(&wp->base)) - data->oy = screen_hsize(&wp->base); + if (data->oy + n > screen_hsize(data->backing)) + data->oy = screen_hsize(data->backing); else data->oy += n; } @@ -369,7 +481,7 @@ case MODEKEYCOPY_HISTORYTOP: data->cx = 0; data->cy = 0; - data->oy = screen_hsize(&wp->base); + data->oy = screen_hsize(data->backing); window_copy_update_selection(wp); window_copy_redraw_screen(wp); break; @@ -665,8 +777,7 @@ 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; + struct grid *gd = data->backing->grid; u_int offset, gap; data->cx = px; @@ -761,7 +872,7 @@ 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 *s = data->backing, ss; struct screen_write_ctx ctx; struct grid *gd = s->grid, *sgd; struct grid_cell gc; @@ -818,7 +929,7 @@ 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 *s = data->backing, ss; struct screen_write_ctx ctx; struct grid *gd = s->grid, *sgd; struct grid_cell gc; @@ -878,7 +989,7 @@ const char *errstr; u_int lineno; - lineno = strtonum(linestr, 0, screen_hsize(&wp->base), &errstr); + lineno = strtonum(linestr, 0, screen_hsize(data->backing), &errstr); if (errstr != NULL) return; @@ -906,7 +1017,7 @@ last = screen_size_y(s) - 1; if (py == 0) { size = xsnprintf(hdr, sizeof hdr, - "[%u/%u]", data->oy, screen_hsize(&wp->base)); + "[%u/%u]", data->oy, screen_hsize(data->backing)); 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) { @@ -923,8 +1034,9 @@ 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); + screen_write_copy(ctx, data->backing, xoff, + (screen_hsize(data->backing) - data->oy) + py, + screen_size_x(s) - size, 1); if (py == data->cy && data->cx == screen_size_x(s)) { memcpy(&gc, &grid_default_cell, sizeof gc); @@ -993,7 +1105,7 @@ struct screen *s = &data->screen; data->selx = data->cx; - data->sely = screen_hsize(&wp->base) + data->cy - data->oy; + data->sely = screen_hsize(data->backing) + data->cy - data->oy; s->sel.flag = 1; window_copy_update_selection(wp); @@ -1018,7 +1130,7 @@ gc.attr |= options_get_number(oo, "mode-attr"); /* Find top of screen. */ - ty = screen_hsize(&wp->base) - data->oy; + ty = screen_hsize(data->backing) - data->oy; /* Adjust the selection. */ sx = data->selx; @@ -1079,7 +1191,7 @@ /* Find start and end. */ xx = data->cx; - yy = screen_hsize(&wp->base) + data->cy - data->oy; + yy = screen_hsize(data->backing) + data->cy - data->oy; if (yy < data->sely || (yy == data->sely && xx < data->selx)) { sx = xx; sy = yy; ex = data->selx; ey = data->sely; @@ -1158,12 +1270,13 @@ window_copy_copy_line(struct window_pane *wp, char **buf, size_t *off, u_int sy, u_int sx, u_int ex) { - struct grid *gd = wp->base.grid; - const struct grid_cell *gc; - const struct grid_utf8 *gu; - struct grid_line *gl; - u_int i, xx, wrapped = 0; - size_t size; + struct window_copy_mode_data *data = wp->modedata; + struct grid *gd = data->backing->grid; + const struct grid_cell *gc; + const struct grid_utf8 *gu; + struct grid_line *gl; + u_int i, xx, wrapped = 0; + size_t size; if (sx > ex) return; @@ -1218,7 +1331,7 @@ screen_clear_selection(&data->screen); - py = screen_hsize(&wp->base) + data->cy - data->oy; + py = screen_hsize(data->backing) + data->cy - data->oy; px = window_copy_find_length(wp, py); if (data->cx > px) window_copy_update_cursor(wp, px, data->cy); @@ -1227,9 +1340,10 @@ int window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set) { - const struct grid_cell *gc; + struct window_copy_mode_data *data = wp->modedata; + const struct grid_cell *gc; - gc = grid_peek_cell(wp->base.grid, px, py); + gc = grid_peek_cell(data->backing->grid, px, py); if (gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) return (0); if (gc->data == 0x00 || gc->data == 0x7f) @@ -1240,8 +1354,10 @@ u_int window_copy_find_length(struct window_pane *wp, u_int py) { - const struct grid_cell *gc; - u_int px; + struct window_copy_mode_data *data = wp->modedata; + struct screen *s = data->backing; + const struct grid_cell *gc; + u_int px; /* * If the pane has been resized, its grid can contain old overlong @@ -1249,11 +1365,11 @@ * width of the grid, and screen_write_copy treats them as spaces, so * ignore them here too. */ - px = wp->base.grid->linedata[py].cellsize; - if (px > screen_size_x(&wp->base)) - px = screen_size_x(&wp->base); + px = s->grid->linedata[py].cellsize; + if (px > screen_size_x(s)) + px = screen_size_x(s); while (px > 0) { - gc = grid_peek_cell(wp->base.grid, px - 1, py); + gc = grid_peek_cell(s->grid, px - 1, py); if (gc->flags & GRID_FLAG_UTF8) break; if (gc->data != ' ') @@ -1281,11 +1397,11 @@ const struct grid_cell *gc; px = 0; - py = screen_hsize(&wp->base) + data->cy - data->oy; + py = screen_hsize(data->backing) + data->cy - data->oy; xx = window_copy_find_length(wp, py); while (px < xx) { - gc = grid_peek_cell(wp->base.grid, px, py); + gc = grid_peek_cell(data->backing->grid, px, py); if (gc->flags & GRID_FLAG_UTF8) break; if (gc->data != ' ') @@ -1302,21 +1418,22 @@ window_copy_cursor_end_of_line(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; - struct screen *base_s = &wp->base; - struct grid *gd = base_s->grid; + struct screen *back_s = data->backing; + struct grid *gd = back_s->grid; u_int px, py; - py = screen_hsize(base_s) + data->cy - data->oy; + py = screen_hsize(back_s) + data->cy - data->oy; px = window_copy_find_length(wp, py); if (data->cx == px) { if (data->screen.sel.flag && data->rectflag) - px = screen_size_x(&wp->base); + px = screen_size_x(back_s); if (gd->linedata[py].flags & GRID_LINE_WRAPPED) { while (py < gd->sy + gd->hsize && gd->linedata[py].flags & GRID_LINE_WRAPPED) { window_copy_cursor_down(wp, 0); - py = screen_hsize(base_s) + data->cy - data->oy; + py = screen_hsize(back_s) + + data->cy - data->oy; } px = window_copy_find_length(wp, py); } @@ -1351,7 +1468,7 @@ if (data->screen.sel.flag && data->rectflag) px = screen_size_x(&data->screen); else { - py = screen_hsize(&wp->base) + data->cy - data->oy; + py = screen_hsize(data->backing) + data->cy - data->oy; px = window_copy_find_length(wp, py); } @@ -1372,7 +1489,7 @@ struct screen *s = &data->screen; u_int ox, oy, px, py; - oy = screen_hsize(&wp->base) + data->cy - data->oy; + oy = screen_hsize(data->backing) + data->cy - data->oy; ox = window_copy_find_length(wp, oy); if (ox != 0) { data->lastcx = data->cx; @@ -1399,7 +1516,7 @@ } if (!data->screen.sel.flag || !data->rectflag) { - py = screen_hsize(&wp->base) + data->cy - data->oy; + py = screen_hsize(data->backing) + data->cy - data->oy; px = window_copy_find_length(wp, py); if ((data->cx >= data->lastsx && data->cx != px) || data->cx > px) @@ -1414,7 +1531,7 @@ struct screen *s = &data->screen; u_int ox, oy, px, py; - oy = screen_hsize(&wp->base) + data->cy - data->oy; + oy = screen_hsize(data->backing) + data->cy - data->oy; ox = window_copy_find_length(wp, oy); if (ox != 0) { data->lastcx = data->cx; @@ -1433,7 +1550,7 @@ } if (!data->screen.sel.flag || !data->rectflag) { - py = screen_hsize(&wp->base) + data->cy - data->oy; + py = screen_hsize(data->backing) + data->cy - data->oy; px = window_copy_find_length(wp, py); if ((data->cx >= data->lastsx && data->cx != px) || data->cx > px) @@ -1445,16 +1562,16 @@ window_copy_cursor_jump(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; - struct screen *base_s = &wp->base; + struct screen *back_s = data->backing; const struct grid_cell *gc; uint px, py, xx; px = data->cx + 1; - py = screen_hsize(base_s) + data->cy - data->oy; + py = screen_hsize(back_s) + data->cy - data->oy; xx = window_copy_find_length(wp, py); while (px < xx) { - gc = grid_peek_cell(base_s->grid, px, py); + gc = grid_peek_cell(back_s->grid, px, py); if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0 && gc->data == data->jumpchar) { @@ -1471,18 +1588,18 @@ window_copy_cursor_jump_back(struct window_pane *wp) { struct window_copy_mode_data *data = wp->modedata; - struct screen *base_s = &wp->base; + struct screen *back_s = data->backing; const struct grid_cell *gc; uint px, py; px = data->cx; - py = screen_hsize(base_s) + data->cy - data->oy; + py = screen_hsize(back_s) + data->cy - data->oy; if (px > 0) px--; for (;;) { - gc = grid_peek_cell(base_s->grid, px, py); + gc = grid_peek_cell(back_s->grid, px, py); if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0 && gc->data == data->jumpchar) { @@ -1501,14 +1618,14 @@ window_copy_cursor_next_word(struct window_pane *wp, const char *separators) { struct window_copy_mode_data *data = wp->modedata; - struct screen *base_s = &wp->base; + struct screen *back_s = data->backing; u_int px, py, xx, yy; int expected = 0; px = data->cx; - py = screen_hsize(base_s) + data->cy - data->oy; + py = screen_hsize(back_s) + data->cy - data->oy; xx = window_copy_find_length(wp, py); - yy = screen_hsize(base_s) + screen_size_y(base_s) - 1; + yy = screen_hsize(back_s) + screen_size_y(back_s) - 1; /* * First skip past any nonword characters and then any word characters. @@ -1526,7 +1643,7 @@ window_copy_cursor_down(wp, 0); px = 0; - py = screen_hsize(base_s) + data->cy - data->oy; + py = screen_hsize(back_s) + data->cy - data->oy; xx = window_copy_find_length(wp, py); } else px++; @@ -1543,14 +1660,14 @@ window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators) { struct window_copy_mode_data *data = wp->modedata; - struct screen *base_s = &wp->base; + struct screen *back_s = data->backing; u_int px, py, xx, yy; int expected = 1; px = data->cx; - py = screen_hsize(base_s) + data->cy - data->oy; + py = screen_hsize(back_s) + data->cy - data->oy; xx = window_copy_find_length(wp, py); - yy = screen_hsize(base_s) + screen_size_y(base_s) - 1; + yy = screen_hsize(back_s) + screen_size_y(back_s) - 1; /* * First skip past any word characters, then any nonword characters. @@ -1568,7 +1685,7 @@ window_copy_cursor_down(wp, 0); px = 0; - py = screen_hsize(base_s) + data->cy - data->oy; + py = screen_hsize(back_s) + data->cy - data->oy; xx = window_copy_find_length(wp, py); } else px++; @@ -1589,7 +1706,7 @@ u_int px, py; px = data->cx; - py = screen_hsize(&wp->base) + data->cy - data->oy; + py = screen_hsize(data->backing) + data->cy - data->oy; /* Move back to the previous word character. */ for (;;) { @@ -1599,12 +1716,12 @@ break; } else { if (data->cy == 0 && - (screen_hsize(&wp->base) == 0 || - data->oy >= screen_hsize(&wp->base) - 1)) + (screen_hsize(data->backing) == 0 || + data->oy >= screen_hsize(data->backing) - 1)) goto out; window_copy_cursor_up(wp, 0); - py = screen_hsize(&wp->base) + data->cy - data->oy; + py = screen_hsize(data->backing) + data->cy - data->oy; px = window_copy_find_length(wp, py); } } @@ -1657,11 +1774,11 @@ struct screen *s = &data->screen; struct screen_write_ctx ctx; - if (ny > screen_hsize(&wp->base)) + if (ny > screen_hsize(data->backing)) return; - if (data->oy > screen_hsize(&wp->base) - ny) - ny = screen_hsize(&wp->base) - data->oy; + if (data->oy > screen_hsize(data->backing) - ny) + ny = screen_hsize(data->backing) - data->oy; if (ny == 0) return; data->oy += ny; @@ -1688,7 +1805,7 @@ data->rectflag = !data->rectflag; - py = screen_hsize(&wp->base) + data->cy - data->oy; + py = screen_hsize(data->backing) + data->cy - data->oy; px = window_copy_find_length(wp, py); if (data->cx > px) window_copy_update_cursor(wp, px, data->cy);