summaryrefslogtreecommitdiff
path: root/usr.bin/tmux/window-copy.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/tmux/window-copy.c')
-rw-r--r--usr.bin/tmux/window-copy.c406
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)) {