summaryrefslogtreecommitdiff
path: root/usr.bin/tmux
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@cvs.openbsd.org>2009-08-18 07:08:27 +0000
committerNicholas Marriott <nicm@cvs.openbsd.org>2009-08-18 07:08:27 +0000
commit1cee65b0f7d3e704516348940da523cc3b61ff43 (patch)
tree53c809b30ff85f91cba87a92ee0704b3ac73034a /usr.bin/tmux
parent87c8955d67ec66ecc835cfd9e43820a049c8ed0e (diff)
Add (naive) searching and goto line in copy mode. Searching is C-r and C-s with
emacs keys, / and ? with vi; n repeats the search again with either key set. All searching wraps the top/bottom. Goto line is g for both emacs and vi. The search prompts don't have full line editing, just simple append and delete characters. Also sort the mode keys list in tmux.1.
Diffstat (limited to 'usr.bin/tmux')
-rw-r--r--usr.bin/tmux/mode-key.c16
-rw-r--r--usr.bin/tmux/tmux.120
-rw-r--r--usr.bin/tmux/tmux.h6
-rw-r--r--usr.bin/tmux/window-copy.c406
4 files changed, 422 insertions, 26 deletions
diff --git a/usr.bin/tmux/mode-key.c b/usr.bin/tmux/mode-key.c
index a9f3e5dec9c..ac0cdaa8214 100644
--- a/usr.bin/tmux/mode-key.c
+++ b/usr.bin/tmux/mode-key.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mode-key.c,v 1.14 2009/08/13 23:44:18 nicm Exp $ */
+/* $OpenBSD: mode-key.c,v 1.15 2009/08/18 07:08:26 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -74,18 +74,22 @@ struct mode_key_cmdstr mode_key_cmdstr_choice[] = {
/* Copy keys command strings. */
struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
- { MODEKEYCOPY_CANCEL, "cancel" },
{ MODEKEYCOPY_BACKTOINDENTATION, "back-to-indentation" },
+ { MODEKEYCOPY_CANCEL, "cancel" },
{ MODEKEYCOPY_CLEARSELECTION, "clear-selection" },
{ MODEKEYCOPY_COPYSELECTION, "copy-selection" },
{ MODEKEYCOPY_DOWN, "cursor-down" },
{ MODEKEYCOPY_ENDOFLINE, "end-of-line" },
+ { MODEKEYCOPY_GOTOLINE, "goto-line" },
{ MODEKEYCOPY_LEFT, "cursor-left" },
{ MODEKEYCOPY_NEXTPAGE, "page-down" },
{ MODEKEYCOPY_NEXTWORD, "next-word" },
{ MODEKEYCOPY_PREVIOUSPAGE, "page-up" },
{ MODEKEYCOPY_PREVIOUSWORD, "previous-word" },
{ MODEKEYCOPY_RIGHT, "cursor-right" },
+ { MODEKEYCOPY_SEARCHAGAIN, "search-again" },
+ { MODEKEYCOPY_SEARCHDOWN, "search-forward" },
+ { MODEKEYCOPY_SEARCHUP, "search-backward" },
{ MODEKEYCOPY_STARTOFLINE, "start-of-line" },
{ MODEKEYCOPY_STARTSELECTION, "begin-selection" },
{ MODEKEYCOPY_UP, "cursor-up" },
@@ -148,7 +152,9 @@ struct mode_key_tree mode_key_tree_vi_choice;
const struct mode_key_entry mode_key_vi_copy[] = {
{ ' ', 0, MODEKEYCOPY_STARTSELECTION },
{ '$', 0, MODEKEYCOPY_ENDOFLINE },
+ { '/', 0, MODEKEYCOPY_SEARCHUP },
{ '0', 0, MODEKEYCOPY_STARTOFLINE },
+ { '?', 0, MODEKEYCOPY_SEARCHDOWN },
{ '\002' /* C-b */, 0, MODEKEYCOPY_PREVIOUSPAGE },
{ '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL },
{ '\004' /* C-d */, 0, MODEKEYCOPY_HALFPAGEDOWN },
@@ -159,10 +165,12 @@ const struct mode_key_entry mode_key_vi_copy[] = {
{ '\r', 0, MODEKEYCOPY_COPYSELECTION },
{ '^', 0, MODEKEYCOPY_BACKTOINDENTATION },
{ 'b', 0, MODEKEYCOPY_PREVIOUSWORD },
+ { 'g', 0, MODEKEYCOPY_GOTOLINE },
{ 'h', 0, MODEKEYCOPY_LEFT },
{ 'j', 0, MODEKEYCOPY_DOWN },
{ 'k', 0, MODEKEYCOPY_UP },
{ 'l', 0, MODEKEYCOPY_RIGHT },
+ { 'n', 0, MODEKEYCOPY_SEARCHAGAIN },
{ 'q', 0, MODEKEYCOPY_CANCEL },
{ 'w', 0, MODEKEYCOPY_NEXTWORD },
{ KEYC_BSPACE, 0, MODEKEYCOPY_LEFT },
@@ -232,12 +240,16 @@ const struct mode_key_entry mode_key_emacs_copy[] = {
{ '\007' /* C-g */, 0, MODEKEYCOPY_CLEARSELECTION },
{ '\016' /* C-n */, 0, MODEKEYCOPY_DOWN },
{ '\020' /* C-p */, 0, MODEKEYCOPY_UP },
+ { '\022' /* C-r */, 0, MODEKEYCOPY_SEARCHUP },
+ { '\023' /* C-s */, 0, MODEKEYCOPY_SEARCHDOWN },
{ '\026' /* C-v */, 0, MODEKEYCOPY_NEXTPAGE },
{ '\027' /* C-w */, 0, MODEKEYCOPY_COPYSELECTION },
{ '\033' /* Escape */, 0, MODEKEYCOPY_CANCEL },
{ 'b' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSWORD },
{ 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTWORD },
+ { 'g', 0, MODEKEYCOPY_GOTOLINE },
{ 'm' | KEYC_ESCAPE, 0, MODEKEYCOPY_BACKTOINDENTATION },
+ { 'n', 0, MODEKEYCOPY_SEARCHAGAIN },
{ 'q', 0, MODEKEYCOPY_CANCEL },
{ 'v' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPAGE },
{ 'w' | KEYC_ESCAPE, 0, MODEKEYCOPY_COPYSELECTION },
diff --git a/usr.bin/tmux/tmux.1 b/usr.bin/tmux/tmux.1
index f83e4e51ab0..7c1b395a828 100644
--- a/usr.bin/tmux/tmux.1
+++ b/usr.bin/tmux/tmux.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.69 2009/08/13 20:11:58 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.70 2009/08/18 07:08:26 nicm Exp $
.\"
.\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
.\"
@@ -14,7 +14,7 @@
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: August 13 2009 $
+.Dd $Mdocdate: August 18 2009 $
.Dt TMUX 1
.Os
.Sh NAME
@@ -475,23 +475,27 @@ option).
The following keys are supported as appropriate for the mode:
.Bl -column "FunctionXXXXXXXXXXXX" "viXXXXXX" "emacs" -offset indent
.It Sy "Function" Ta Sy "vi" Ta Sy "emacs"
-.It Li "Start of line" Ta "0" Ta "C-a"
.It Li "Back to indentation" Ta "^" Ta "M-m"
.It Li "Clear selection" Ta "Escape" Ta "C-g"
.It Li "Copy selection" Ta "Enter" Ta "M-w"
.It Li "Cursor down" Ta "j" Ta "Down"
-.It Li "End of line" Ta "$" Ta "C-e"
.It Li "Cursor left" Ta "h" Ta "Left"
+.It Li "Cursor right" Ta "l" Ta "Right"
+.It Li "Cursor up" Ta "k" Ta "Up"
+.It Li "Delete to end of line" Ta "D" Ta "C-k"
+.It Li "End of line" Ta "$" Ta "C-e"
+.It Li "Goto line" Ta "g" Ta "g"
.It Li "Next page" Ta "C-f" Ta "Page down"
.It Li "Next word" Ta "w" Ta "M-f"
+.It Li "Paste buffer" Ta "p" Ta "C-y"
.It Li "Previous page" Ta "C-u" Ta "Page up"
.It Li "Previous word" Ta "b" Ta "M-b"
.It Li "Quit mode" Ta "q" Ta "Escape"
-.It Li "Cursor right" Ta "l" Ta "Right"
+.It Li "Search again" Ta "n" Ta "n"
+.It Li "Search backward" Ta "?" Ta "C-r"
+.It Li "Search forward" Ta "/" Ta "C-s"
+.It Li "Start of line" Ta "0" Ta "C-a"
.It Li "Start selection" Ta "Space" Ta "C-Space"
-.It Li "Cursor up" Ta "k" Ta "Up"
-.It Li "Delete to end of line" Ta "D" Ta "C-k"
-.It Li "Paste buffer" Ta "p" Ta "C-y"
.El
.Pp
These key bindings are defined in a set of named tables:
diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h
index a3b5d71f05e..c1bc9df1923 100644
--- a/usr.bin/tmux/tmux.h
+++ b/usr.bin/tmux/tmux.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.82 2009/08/13 22:32:18 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.83 2009/08/18 07:08:26 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@@ -394,6 +394,7 @@ enum mode_key_cmd {
MODEKEYCOPY_COPYSELECTION,
MODEKEYCOPY_DOWN,
MODEKEYCOPY_ENDOFLINE,
+ MODEKEYCOPY_GOTOLINE,
MODEKEYCOPY_HALFPAGEDOWN,
MODEKEYCOPY_HALFPAGEUP,
MODEKEYCOPY_LEFT,
@@ -402,6 +403,9 @@ enum mode_key_cmd {
MODEKEYCOPY_PREVIOUSPAGE,
MODEKEYCOPY_PREVIOUSWORD,
MODEKEYCOPY_RIGHT,
+ MODEKEYCOPY_SEARCHAGAIN,
+ MODEKEYCOPY_SEARCHDOWN,
+ MODEKEYCOPY_SEARCHUP,
MODEKEYCOPY_STARTOFLINE,
MODEKEYCOPY_STARTSELECTION,
MODEKEYCOPY_UP,
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)) {