Łukasz Piątkowski
2014-08-05 02:47:28 UTC
I have split up my changes into 3 diffs, first is refactoring search code
in window-copy.c, second is adding incremental search and the last one is
adding search highlighting.
Cheers
Lukas
--
I am providing code in this repository to you under an open source license.
Because this is my personal repository, the license you receive to my code
is from me and not from my employer (Facebook).
--
Refactor window-copy search functions
============================
diff --git window-copy.c window-copy.c
index 0775bcb..1213380 100644
--- window-copy.c
+++ window-copy.c
@@ -47,8 +47,16 @@ int window_copy_search_lr(
struct grid *, struct grid *, u_int *, u_int, u_int, u_int, int);
int window_copy_search_rl(
struct grid *, struct grid *, u_int *, u_int, u_int, u_int, int);
-void window_copy_search_up(struct window_pane *, const char *);
-void window_copy_search_down(struct window_pane *, const char *);
+void window_copy_move_coordinates(
+ struct screen *, u_int *, u_int *, const int);
+int window_copy_is_lowercase(const char *);
+void window_copy_jump_to_searched_string(
+ struct window_pane *, struct grid *, struct grid *, u_int, u_int,
+ u_int, int, int, const int);
+void window_copy_search(struct window_pane *, const char *,
+ const int, const int);
+void window_copy_search_up(struct window_pane *, const char *, const int);
+void window_copy_search_down(struct window_pane *, const char *, const
int);
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 *);
@@ -685,12 +693,12 @@ window_copy_key(struct window_pane *wp, struct
session *sess, int key)
if (cmd == MODEKEYCOPY_SEARCHAGAIN) {
for (; np != 0; np--) {
window_copy_search_up(
- wp, data->searchstr);
+ wp, data->searchstr, 1);
}
} else {
for (; np != 0; np--) {
window_copy_search_down(
- wp, data->searchstr);
+ wp, data->searchstr, 1);
}
}
break;
@@ -698,12 +706,12 @@ window_copy_key(struct window_pane *wp, struct
session *sess, int key)
if (cmd == MODEKEYCOPY_SEARCHAGAIN) {
for (; np != 0; np--) {
window_copy_search_down(
- wp, data->searchstr);
+ wp, data->searchstr, 1);
}
} else {
for (; np != 0; np--) {
window_copy_search_up(
- wp, data->searchstr);
+ wp, data->searchstr, 1);
}
}
break;
@@ -811,16 +819,16 @@ window_copy_key_input(struct window_pane *wp, int key)
case WINDOW_COPY_NUMERICPREFIX:
break;
case WINDOW_COPY_SEARCHUP:
- for (; np != 0; np--)
- window_copy_search_up(wp, data->inputstr);
data->searchtype = data->inputtype;
data->searchstr = xstrdup(data->inputstr);
+ for (; np != 0; np--)
+ window_copy_search_up(wp, data->inputstr, 0);
break;
case WINDOW_COPY_SEARCHDOWN:
- for (; np != 0; np--)
- window_copy_search_down(wp, data->inputstr);
data->searchtype = data->inputtype;
data->searchstr = xstrdup(data->inputstr);
+ for (; np != 0; np--)
+ window_copy_search_down(wp, data->inputstr, 0);
break;
case WINDOW_COPY_NAMEDBUFFER:
window_copy_copy_selection(wp, data->inputstr);
@@ -1033,88 +1041,97 @@ window_copy_search_rl(struct grid *gd,
return (0);
}
+/* For direction == 0 move left, otherwise right; jump line if needed */
void
-window_copy_search_up(struct window_pane *wp, const char *searchstr)
+window_copy_move_coordinates(struct screen *s,
+ u_int *fx, u_int *fy, const int direction)
{
- struct window_copy_mode_data *data = wp->modedata;
- struct screen *s = data->backing, 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, wrapflag, cis;
- const char *ptr;
-
- if (*searchstr == '\0')
- return;
- utf8flag = options_get_number(&wp->window->options, "utf8");
- wrapflag = options_get_number(&wp->window->options, "wrap-search");
- 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)
+ /* If on left/right border */
+ if (*fx == (direction ? screen_size_x(s) - 1 : 0)) {
+ /* If on top/bottom border */
+ if (*fy == (direction ? screen_hsize(s) + screen_size_y(s) : 0))
+ /* Nowhere to go */
return;
- fx = gd->sx - 1;
- fy--;
- } else
- fx--;
- n = wrapped = 0;
+ /* Jump to beggin/end of lower/upper line */
+ *fx = direction ? 0 : screen_size_x(s) - 1;
+ *fy = direction ? *fy + 1 : *fy - 1;
+ } else {
+ *fx = direction ? *fx + 1 : *fx - 1;
+ }
+}
- cis = 1;
- for (ptr = searchstr; *ptr != '\0'; ptr++) {
+int
+window_copy_is_lowercase(const char *ptr)
+{
+ while (*ptr != '\0') {
if (*ptr != tolower((u_char)*ptr)) {
- cis = 0;
- break;
+ return 0;
}
+ ++ptr;
}
+ return 1;
+}
-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, cis);
- if (n) {
- window_copy_scroll_to(wp, px, i - 1);
- break;
+/* Search in grid `gd` for text stored in grid `sgd` starting from position
+ * (`fx`, `fy`) up to line `endline` and if found then jump to it.
+ * If `cis` do it case-insensitive.
+ * `direction` 0 for searching up, down otherwise
+ * If `wrap` then go to begin/end of grid and try again up to line `fy` */
+void
+window_copy_jump_to_searched_string(struct window_pane *wp,
+ struct grid *gd, struct grid *sgd, u_int fx, u_int fy,
+ u_int endline, int cis, int wrap, const int direction)
+{
+ u_int i, px;
+ int firstIteration, found;
+
+ firstIteration = 1;
+ if (direction) {
+ for (i = fy; i <= endline; ++i) {
+ found = window_copy_search_lr(gd, sgd, &px, i,
+ firstIteration ? fx : 0, gd->sx, cis);
+ if (found) break;
+ firstIteration = 0;
+ }
+ } else {
+ for (i = fy + 1; endline < i; --i) {
+ found = window_copy_search_rl(gd, sgd, &px, i - 1,
+ 0, firstIteration ? fx : gd->sx, cis);
+ if (found) {
+ --i;
+ break;
+ }
+ firstIteration = 0;
}
}
- if (wrapflag && !n && !wrapped) {
- fx = gd->sx - 1;
- fy = gd->hsize + gd->sy - 1;
- wrapped = 1;
- goto retry;
+ if (found) {
+ window_copy_scroll_to(wp, px, i);
+ } else if (wrap) {
+ /* Start searching from begin/end of grid up to `fy` line */
+ window_copy_jump_to_searched_string(wp, gd, sgd,
+ direction ? 0 : gd->sx - 1,
+ direction ? 0 : gd->hsize + gd->sy - 1,
+ fy, cis, 0, direction);
}
-
- screen_free(&ss);
}
void
-window_copy_search_down(struct window_pane *wp, const char *searchstr)
+window_copy_search(struct window_pane *wp,
+ const char *searchstr, const int direction, const int move)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = data->backing, ss;
struct screen_write_ctx ctx;
- struct grid *gd = s->grid, *sgd;
- struct grid_cell gc;
+ struct grid *gd = s->grid;
+ struct grid_cell gc;
size_t searchlen;
- u_int i, first, fx, fy, px;
- int utf8flag, n, wrapped, wrapflag, cis;
- const char *ptr;
+ u_int fx, fy;
+ int utf8flag, wrapflag, cis;
+
+ /* current cursor coordinates */
+ fx = data->cx;
+ fy = screen_hsize(data->backing) - data->oy + data->cy;
- if (*searchstr == '\0')
- return;
utf8flag = options_get_number(&wp->window->options, "utf8");
wrapflag = options_get_number(&wp->window->options, "wrap-search");
searchlen = screen_write_strlen(utf8flag, "%s", searchstr);
@@ -1125,50 +1142,35 @@ window_copy_search_down(struct window_pane *wp,
const char *searchstr)
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 == gd->sx - 1) {
- if (fy == gd->hsize + gd->sy)
- return;
- fx = 0;
- fy++;
- } else
- fx++;
- n = wrapped = 0;
-
- cis = 1;
- for (ptr = searchstr; *ptr != '\0'; ptr++) {
- if (*ptr != tolower((u_char)*ptr)) {
- cis = 0;
- break;
- }
+ if (move) {
+ window_copy_move_coordinates(s, &fx, &fy, direction);
}
-retry:
- sgd = ss.grid;
- for (i = fy + 1; i < gd->hsize + gd->sy + 1; i++) {
- first = 0;
- if (i == fy + 1)
- first = fx;
- n = window_copy_search_lr(gd, sgd, &px, i - 1, first, gd->sx,
- cis);
- if (n) {
- window_copy_scroll_to(wp, px, i - 1);
- break;
- }
- }
- if (wrapflag && !n && !wrapped) {
- fx = 0;
- fy = 0;
- wrapped = 1;
- goto retry;
- }
+ cis = window_copy_is_lowercase(searchstr);
+ window_copy_clear_selection(wp);
+
+ window_copy_jump_to_searched_string(wp, gd, ss.grid, fx, fy,
+ direction ? gd->hsize + gd->sy - 1 : 0,
+ cis, wrapflag, direction);
screen_free(&ss);
}
void
+window_copy_search_up(struct window_pane *wp, const char *searchstr,
+ const int move)
+{
+ window_copy_search(wp, searchstr, 0, move);
+}
+
+void
+window_copy_search_down(struct window_pane *wp, const char *searchstr,
+ const int move)
+{
+ window_copy_search(wp, searchstr, 1, move);
+}
+
+void
window_copy_goto_line(struct window_pane *wp, const char *linestr)
{
struct window_copy_mode_data *data = wp->modedata;
Incremental search in window-copy mode
==============================
diff --git window-copy.c window-copy.c
index 1213380..243c755 100644
--- window-copy.c
+++ window-copy.c
@@ -53,6 +53,9 @@ int window_copy_is_lowercase(const char *);
void window_copy_jump_to_searched_string(
struct window_pane *, struct grid *, struct grid *, u_int, u_int,
u_int, int, int, const int);
+int window_copy_coord_from_hist(struct window_pane *wp,
+ const size_t searchlen, u_int *fx, u_int *fy);
+void window_copy_clear_search_hist(struct window_pane *, u_int *, u_int *);
void window_copy_search(struct window_pane *, const char *,
const int, const int);
void window_copy_search_up(struct window_pane *, const char *, const int);
@@ -115,6 +118,22 @@ enum window_copy_input_type {
};
/*
+ * x, y - coordinates from which the search was made
+ * found - if the text was found
+ * searchlen - lenght of text that was searched
+ * prev - data of previous searches
+ */
+struct window_copy_search_hist {
+ u_int x;
+ u_int y;
+ int found;
+
+ size_t searchlen;
+
+ struct window_copy_search_hist *prev;
+};
+
+/*
* 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
@@ -159,6 +178,7 @@ struct window_copy_mode_data {
enum window_copy_input_type searchtype;
char *searchstr;
+ struct window_copy_search_hist *searchhist;
enum window_copy_input_type jumptype;
char jumpchar;
@@ -190,6 +210,7 @@ window_copy_init(struct window_pane *wp)
data->searchtype = WINDOW_COPY_OFF;
data->searchstr = NULL;
+ data->searchhist = NULL;
if (wp->fd != -1)
bufferevent_disable(wp->event, EV_READ|EV_WRITE);
@@ -259,6 +280,7 @@ window_copy_free(struct window_pane *wp)
free(data->searchstr);
free(data->inputstr);
+ window_copy_clear_search_hist(wp, NULL, NULL);
if (data->backing != &wp->base) {
screen_free(data->backing);
@@ -672,10 +694,12 @@ window_copy_key(struct window_pane *wp, struct
session *sess, int key)
case MODEKEYCOPY_SEARCHUP:
data->inputtype = WINDOW_COPY_SEARCHUP;
data->inputprompt = "Search Up";
+ *data->inputstr = '\0';
goto input_on;
case MODEKEYCOPY_SEARCHDOWN:
data->inputtype = WINDOW_COPY_SEARCHDOWN;
data->inputprompt = "Search Down";
+ *data->inputstr = '\0';
goto input_on;
case MODEKEYCOPY_SEARCHAGAIN:
case MODEKEYCOPY_SEARCHREVERSE:
@@ -778,6 +802,7 @@ window_copy_key_input(struct window_pane *wp, int key)
int np;
struct paste_buffer *pb;
u_char ch;
+ u_int fx, fy;
switch (mode_key_lookup(&data->mdata, key, NULL)) {
case MODEKEYEDIT_CANCEL:
@@ -787,9 +812,29 @@ window_copy_key_input(struct window_pane *wp, int key)
inputlen = strlen(data->inputstr);
if (inputlen > 0)
data->inputstr[inputlen - 1] = '\0';
+ switch (data->inputtype) {
+ case WINDOW_COPY_SEARCHUP:
+ data->searchtype = data->inputtype;
+ free(data->searchstr);
+ data->searchstr = xstrdup(data->inputstr);
+ window_copy_search_up(wp, data->inputstr, 0);
+ break;
+ case WINDOW_COPY_SEARCHDOWN:
+ data->searchtype = data->inputtype;
+ free(data->searchstr);
+ data->searchstr = xstrdup(data->inputstr);
+ window_copy_search_down(wp, data->inputstr, 0);
+ break;
+ default:
+ break;
+ }
break;
case MODEKEYEDIT_DELETELINE:
*data->inputstr = '\0';
+ fx = data->cx;
+ fy = screen_hsize(data->backing) - data->oy + data->cy;
+ window_copy_clear_search_hist(wp, &fx, &fy);
+ window_copy_scroll_to(wp, fx, fy);
break;
case MODEKEYEDIT_PASTE:
if ((pb = paste_get_top()) == NULL)
@@ -820,15 +865,17 @@ window_copy_key_input(struct window_pane *wp, int key)
break;
case WINDOW_COPY_SEARCHUP:
data->searchtype = data->inputtype;
+ free(data->searchstr);
data->searchstr = xstrdup(data->inputstr);
- for (; np != 0; np--)
- window_copy_search_up(wp, data->inputstr, 0);
+ for (; np > 1; np--)
+ window_copy_search_up(wp, data->inputstr, 1);
break;
case WINDOW_COPY_SEARCHDOWN:
data->searchtype = data->inputtype;
+ free(data->searchstr);
data->searchstr = xstrdup(data->inputstr);
- for (; np != 0; np--)
- window_copy_search_down(wp, data->inputstr, 0);
+ for (; np > 1; np--)
+ window_copy_search_down(wp, data->inputstr, 1);
break;
case WINDOW_COPY_NAMEDBUFFER:
window_copy_copy_selection(wp, data->inputstr);
@@ -850,6 +897,22 @@ window_copy_key_input(struct window_pane *wp, int key)
data->inputstr = xrealloc(data->inputstr, 1, inputlen);
data->inputstr[inputlen - 2] = key;
data->inputstr[inputlen - 1] = '\0';
+ switch (data->inputtype) {
+ case WINDOW_COPY_SEARCHUP:
+ data->searchtype = data->inputtype;
+ free(data->searchstr);
+ data->searchstr = xstrdup(data->inputstr);
+ window_copy_search_up(wp, data->inputstr, 0);
+ break;
+ case WINDOW_COPY_SEARCHDOWN:
+ data->searchtype = data->inputtype;
+ free(data->searchstr);
+ data->searchstr = xstrdup(data->inputstr);
+ window_copy_search_down(wp, data->inputstr, 0);
+ break;
+ default:
+ break;
+ }
break;
default:
break;
@@ -1082,6 +1145,8 @@ window_copy_jump_to_searched_string(struct
window_pane *wp,
struct grid *gd, struct grid *sgd, u_int fx, u_int fy,
u_int endline, int cis, int wrap, const int direction)
{
+ struct window_copy_mode_data *data = wp->modedata;
+ struct window_copy_search_hist *searchhist = data->searchhist;
u_int i, px;
int firstIteration, found;
@@ -1112,6 +1177,60 @@ window_copy_jump_to_searched_string(struct
window_pane *wp,
direction ? 0 : gd->sx - 1,
direction ? 0 : gd->hsize + gd->sy - 1,
fy, cis, 0, direction);
+ } else {
+ if (searchhist != NULL) {
+ searchhist->found = 0;
+ }
+ }
+}
+
+/* If it returns 0 then, according to search history, last time we searched
+ * a shorter string we haven't found anything, so there is no point in
+ * incremental-searching a longer string (just an optimization) */
+int
+window_copy_coord_from_hist(struct window_pane *wp,
+ const size_t searchlen, u_int *fx, u_int *fy)
+{
+ struct window_copy_mode_data *data = wp->modedata;
+ struct window_copy_search_hist *searchhist = data->searchhist;
+
+ if (searchhist == NULL || searchhist->searchlen < searchlen) {
+ searchhist = xmalloc(sizeof (struct window_copy_search_hist));
+ searchhist->x = data->cx;
+ searchhist->y =
+ screen_hsize(data->backing) - data->oy + data->cy;
+ searchhist->searchlen = searchlen;
+ searchhist->found = data->searchhist == NULL ?
+ 1 : data->searchhist->found;
+
+ searchhist->prev = data->searchhist;
+ data->searchhist = searchhist;
+
+ *fx = searchhist->x;
+ *fy = searchhist->y;
+ } else {
+ *fx = searchhist->x;
+ *fy = searchhist->y;
+ searchhist = data->searchhist->prev;
+ free(data->searchhist);
+ data->searchhist = searchhist;
+ }
+
+ return searchhist == NULL ? 1 : searchhist->found;
+}
+
+void
+window_copy_clear_search_hist(struct window_pane *wp, u_int *fx, u_int *fy)
+{
+ struct window_copy_mode_data *data = wp->modedata;
+ struct window_copy_search_hist *searchhist = data->searchhist;
+
+ while (searchhist != NULL) {
+ if (fx != NULL) *fx = searchhist->x;
+ if (fy != NULL) *fy = searchhist->y;
+ searchhist = searchhist->prev;
+ free(data->searchhist);
+ data->searchhist = searchhist;
}
}
@@ -1132,6 +1251,14 @@ window_copy_search(struct window_pane *wp,
fx = data->cx;
fy = screen_hsize(data->backing) - data->oy + data->cy;
+ /* User deleted all searched text, jump to the initial cursor
+ * position and delete the searchhistory */
+ if ((searchstr == NULL) || (*searchstr == '\0')) {
+ window_copy_clear_search_hist(wp, &fx, &fy);
+ window_copy_scroll_to(wp, fx, fy);
+ return;
+ }
+
utf8flag = options_get_number(&wp->window->options, "utf8");
wrapflag = options_get_number(&wp->window->options, "wrap-search");
searchlen = screen_write_strlen(utf8flag, "%s", searchstr);
@@ -1142,8 +1269,19 @@ window_copy_search(struct window_pane *wp,
screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr);
screen_write_stop(&ctx);
+ /*
+ * `move` is useful for incremental searching. When we do incremental,
+ * we don't want to jump to the next matching word if we already stand
+ * on one, so `move=0`.
+ * But when user wants the next result, then we use `move=1`, so
+ * we start searching from the place next to the current cursor
+ * position */
if (move) {
window_copy_move_coordinates(s, &fx, &fy, direction);
+ } else {
+ if (!window_copy_coord_from_hist(wp, searchlen, &fx, &fy)) {
+ return;
+ }
}
cis = window_copy_is_lowercase(searchstr);
Highlight last search in window-copy mode
===============================
diff --git options-table.c options-table.c
index 8d680b3..79ecae3 100644
--- options-table.c
+++ options-table.c
@@ -619,6 +619,11 @@ const struct options_table_entry
window_options_table[] = {
.default_str = "bg=yellow,fg=black"
},
+ { .name = "highlight-style",
+ .type = OPTIONS_TABLE_STYLE,
+ .default_str = "bg=green,fg=black"
+ },
+
{ .name = "monitor-activity",
.type = OPTIONS_TABLE_FLAG,
.default_num = 0
@@ -802,6 +807,11 @@ const struct options_table_entry
window_options_table[] = {
.default_num = 1
},
+ { .name = "highlight-search",
+ .type = OPTIONS_TABLE_FLAG,
+ .default_num = 1
+ },
+
{ .name = "xterm-keys",
.type = OPTIONS_TABLE_FLAG,
.default_num = 0
diff --git screen-write.c screen-write.c
index 325fb9a..a36a1f2 100644
--- screen-write.c
+++ screen-write.c
@@ -902,7 +902,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const
struct grid_cell *gc)
struct grid *gd = s->grid;
struct tty_ctx ttyctx;
u_int width, xx, last;
- struct grid_cell tmp_gc, *tmp_gcp;
+ struct grid_cell tmp_gc, *tmp_gcp, *cell = NULL;
struct utf8_data ud;
int insert;
@@ -995,6 +995,15 @@ screen_write_cell(struct screen_write_ctx *ctx, const
struct grid_cell *gc)
(GRID_FLAG_FG256|GRID_FLAG_BG256);
ttyctx.cell = &tmp_gc;
tty_write(tty_cmd_cell, &ttyctx);
+ } else if (screen_check_highlight(s, s->cx - width, s->cy, &cell)) {
+ memcpy(&tmp_gc, cell, sizeof tmp_gc);
+ grid_cell_get(gc, &ud);
+ grid_cell_set(&tmp_gc, &ud);
+ tmp_gc.flags = gc->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256);
+ tmp_gc.flags |= cell->flags &
+ (GRID_FLAG_FG256|GRID_FLAG_BG256);
+ ttyctx.cell = &tmp_gc;
+ tty_write(tty_cmd_cell, &ttyctx);
} else {
ttyctx.cell = gc;
tty_write(tty_cmd_cell, &ttyctx);
diff --git screen.c screen.c
index 7bfc015..734b38e 100644
--- screen.c
+++ screen.c
@@ -44,6 +44,7 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int
hlimit)
s->cstyle = 0;
s->ccolour = xstrdup("");
s->tabs = NULL;
+ s->hls = NULL;
screen_reinit(s);
}
@@ -65,6 +66,7 @@ screen_reinit(struct screen *s)
grid_clear_lines(s->grid, s->grid->hsize, s->grid->sy);
screen_clear_selection(s);
+ screen_clear_highlight(s);
}
/* Destroy a screen. */
@@ -75,6 +77,7 @@ screen_free(struct screen *s)
free(s->title);
free(s->ccolour);
grid_destroy(s->grid);
+ screen_clear_highlight(s);
}
/* Reset tabs to default, eight spaces apart. */
@@ -357,6 +360,56 @@ screen_check_selection(struct screen *s, u_int px,
u_int py)
return (1);
}
+/* Set highlight. */
+void
+screen_set_highlight(struct screen *s,
+ u_int sx, u_int ex, u_int y, struct grid_cell *gc)
+{
+ struct screen_hls *hls = xmalloc(sizeof (struct screen_hls));
+
+ hls->sx = sx;
+ hls->ex = ex;
+ hls->y = y;
+ hls->next = s->hls;
+
+ memcpy(&hls->cell, gc, sizeof hls->cell);
+
+ s->hls = hls;
+}
+
+/* Clear highlights. */
+void
+screen_clear_highlight(struct screen *s)
+{
+ struct screen_hls *hls = s->hls, *hlsPrev;
+
+ while (hls != NULL) {
+ hlsPrev = hls;
+ hls = hls->next;
+ free(hlsPrev);
+ }
+
+ s->hls = NULL;
+}
+
+/* Check if cell in highlight. */
+int
+screen_check_highlight(struct screen *s, u_int px, u_int py,
+ struct grid_cell **cell)
+{
+ struct screen_hls *hls = s->hls;
+
+ while (hls != NULL) {
+ if (hls->sx <= px && px <= hls->ex && hls->y == py) {
+ *cell = &hls->cell;
+ return 1;
+ }
+ hls = hls->next;
+ }
+
+ return 0;
+}
+
/* Reflow wrapped lines. */
void
screen_reflow(struct screen *s, u_int new_x)
diff --git tmux.h tmux.h
index c4c5236..6fc5fd0 100644
--- tmux.h
+++ tmux.h
@@ -766,6 +766,17 @@ struct screen_sel {
struct grid_cell cell;
};
+/* Screen highlights. */
+struct screen_hls {
+ u_int sx;
+ u_int ex;
+
+ u_int y;
+
+ struct grid_cell cell;
+ struct screen_hls *next;
+};
+
/* Virtual screen. */
struct screen {
char *title;
@@ -786,6 +797,7 @@ struct screen {
bitstr_t *tabs;
struct screen_sel sel;
+ struct screen_hls *hls;
};
/* Screen write context. */
@@ -2118,6 +2130,11 @@ void screen_set_selection(struct screen *,
u_int, u_int, u_int, u_int, u_int, struct grid_cell *);
void screen_clear_selection(struct screen *);
int screen_check_selection(struct screen *, u_int, u_int);
+void screen_set_highlight(struct screen *,
+ u_int, u_int, u_int, struct grid_cell *);
+void screen_clear_highlight(struct screen *);
+int screen_check_highlight(struct screen *, u_int, u_int,
+ struct grid_cell **);
void screen_reflow(struct screen *, u_int);
/* window.c */
diff --git tty.c tty.c
index 7688e90..4511533 100644
--- tty.c
+++ tty.c
@@ -614,7 +614,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int
py, u_int ox, u_int oy)
{
const struct grid_cell *gc;
struct grid_line *gl;
- struct grid_cell tmpgc;
+ struct grid_cell tmpgc, *cell = NULL;
struct utf8_data ud;
u_int i, sx;
@@ -649,6 +649,15 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int
py, u_int ox, u_int oy)
tmpgc.flags |= s->sel.cell.flags &
(GRID_FLAG_FG256|GRID_FLAG_BG256);
tty_cell(tty, &tmpgc);
+ } else if (screen_check_highlight(s, i, py, &cell)) {
+ memcpy(&tmpgc, cell, sizeof tmpgc);
+ grid_cell_get(gc, &ud);
+ grid_cell_set(&tmpgc, &ud);
+ tmpgc.flags = gc->flags &
+ ~(GRID_FLAG_FG256|GRID_FLAG_BG256);
+ tmpgc.flags |= cell->flags &
+ (GRID_FLAG_FG256|GRID_FLAG_BG256);
+ tty_cell(tty, &tmpgc);
} else
tty_cell(tty, gc);
}
diff --git window-copy.c window-copy.c
index 243c755..00cdc3f 100644
--- window-copy.c
+++ window-copy.c
@@ -28,10 +28,13 @@ 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 session *, int);
+void window_copy_key_internal(struct window_pane *, struct session *, int);
int window_copy_key_input(struct window_pane *, int);
int window_copy_key_numeric_prefix(struct window_pane *, int);
void window_copy_mouse(
struct window_pane *, struct session *, struct mouse_event *);
+void window_copy_mouse_internal(
+ struct window_pane *, struct session *, struct mouse_event *);
void window_copy_redraw_lines(struct window_pane *, u_int, u_int);
void window_copy_redraw_screen(struct window_pane *);
@@ -53,6 +56,7 @@ int window_copy_is_lowercase(const char *);
void window_copy_jump_to_searched_string(
struct window_pane *, struct grid *, struct grid *, u_int, u_int,
u_int, int, int, const int);
+void window_copy_highlight_search(struct window_pane *);
int window_copy_coord_from_hist(struct window_pane *wp,
const size_t searchlen, u_int *fx, u_int *fy);
void window_copy_clear_search_hist(struct window_pane *, u_int *, u_int *);
@@ -397,6 +401,16 @@ window_copy_resize(struct window_pane *wp, u_int sx,
u_int sy)
void
window_copy_key(struct window_pane *wp, struct session *sess, int key)
{
+ window_copy_key_internal(wp, sess, key);
+
+ if (wp->mode != NULL) {
+ window_copy_highlight_search(wp);
+ }
+}
+
+void
+window_copy_key_internal(struct window_pane *wp, struct session *sess, int
key)
+{
const char *word_separators;
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
@@ -944,6 +958,17 @@ void
window_copy_mouse(
struct window_pane *wp, struct session *sess, struct mouse_event *m)
{
+ window_copy_mouse_internal(wp, sess, m);
+
+ if (wp->mode != NULL) {
+ window_copy_highlight_search(wp);
+ }
+}
+
+void
+window_copy_mouse_internal(
+ struct window_pane *wp, struct session *sess, struct mouse_event *m)
+{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
u_int i;
@@ -1184,6 +1209,68 @@ window_copy_jump_to_searched_string(struct
window_pane *wp,
}
}
+void
+window_copy_highlight_search(struct window_pane *wp)
+{
+ struct window_copy_mode_data *data = wp->modedata;
+ struct screen *s = data->backing, ss;
+ struct screen_write_ctx ctx;
+ struct grid *gd = s->grid;
+ struct grid_cell gc;
+ struct options *oo = &wp->window->options;
+ const char *searchstr = data->searchstr;
+ size_t searchlen;
+ u_int i, px, last, beginline, endline;
+ int found, utf8flag, cis, highlight;
+
+ highlight = options_get_number(
+ &wp->window->options, "highlight-search");
+ if (!highlight) {
+ return;
+ }
+
+ screen_clear_highlight(&data->screen);
+
+ if ((searchstr != NULL) && (*searchstr != '\0')) {
+ 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);
+
+ cis = window_copy_is_lowercase(searchstr);
+
+ /* Set colours. */
+ style_apply(&gc, oo, "highlight-style");
+
+ beginline = screen_hsize(s) - data->oy;
+ endline = screen_hsize(s) - data->oy + screen_size_y(s) - 1;
+
+ for (i = beginline; i <= endline; ++i) {
+ last = 0;
+ do {
+ found = window_copy_search_lr(gd, ss.grid, &px,
+ i, last, gd->sx, cis);
+ if (found) {
+ screen_set_highlight(
+ &data->screen,
+ px,
+ px + searchlen - 1,
+ i - (screen_hsize(s)
+ - data->oy),
+ &gc);
+ last += searchlen;
+ }
+ } while (found);
+ }
+ }
+
+ window_copy_redraw_screen(wp);
+}
+
/* If it returns 0 then, according to search history, last time we searched
* a shorter string we haven't found anything, so there is no point in
* incremental-searching a longer string (just an optimization) */
in window-copy.c, second is adding incremental search and the last one is
adding search highlighting.
Cheers
Lukas
--
I am providing code in this repository to you under an open source license.
Because this is my personal repository, the license you receive to my code
is from me and not from my employer (Facebook).
--
Refactor window-copy search functions
============================
diff --git window-copy.c window-copy.c
index 0775bcb..1213380 100644
--- window-copy.c
+++ window-copy.c
@@ -47,8 +47,16 @@ int window_copy_search_lr(
struct grid *, struct grid *, u_int *, u_int, u_int, u_int, int);
int window_copy_search_rl(
struct grid *, struct grid *, u_int *, u_int, u_int, u_int, int);
-void window_copy_search_up(struct window_pane *, const char *);
-void window_copy_search_down(struct window_pane *, const char *);
+void window_copy_move_coordinates(
+ struct screen *, u_int *, u_int *, const int);
+int window_copy_is_lowercase(const char *);
+void window_copy_jump_to_searched_string(
+ struct window_pane *, struct grid *, struct grid *, u_int, u_int,
+ u_int, int, int, const int);
+void window_copy_search(struct window_pane *, const char *,
+ const int, const int);
+void window_copy_search_up(struct window_pane *, const char *, const int);
+void window_copy_search_down(struct window_pane *, const char *, const
int);
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 *);
@@ -685,12 +693,12 @@ window_copy_key(struct window_pane *wp, struct
session *sess, int key)
if (cmd == MODEKEYCOPY_SEARCHAGAIN) {
for (; np != 0; np--) {
window_copy_search_up(
- wp, data->searchstr);
+ wp, data->searchstr, 1);
}
} else {
for (; np != 0; np--) {
window_copy_search_down(
- wp, data->searchstr);
+ wp, data->searchstr, 1);
}
}
break;
@@ -698,12 +706,12 @@ window_copy_key(struct window_pane *wp, struct
session *sess, int key)
if (cmd == MODEKEYCOPY_SEARCHAGAIN) {
for (; np != 0; np--) {
window_copy_search_down(
- wp, data->searchstr);
+ wp, data->searchstr, 1);
}
} else {
for (; np != 0; np--) {
window_copy_search_up(
- wp, data->searchstr);
+ wp, data->searchstr, 1);
}
}
break;
@@ -811,16 +819,16 @@ window_copy_key_input(struct window_pane *wp, int key)
case WINDOW_COPY_NUMERICPREFIX:
break;
case WINDOW_COPY_SEARCHUP:
- for (; np != 0; np--)
- window_copy_search_up(wp, data->inputstr);
data->searchtype = data->inputtype;
data->searchstr = xstrdup(data->inputstr);
+ for (; np != 0; np--)
+ window_copy_search_up(wp, data->inputstr, 0);
break;
case WINDOW_COPY_SEARCHDOWN:
- for (; np != 0; np--)
- window_copy_search_down(wp, data->inputstr);
data->searchtype = data->inputtype;
data->searchstr = xstrdup(data->inputstr);
+ for (; np != 0; np--)
+ window_copy_search_down(wp, data->inputstr, 0);
break;
case WINDOW_COPY_NAMEDBUFFER:
window_copy_copy_selection(wp, data->inputstr);
@@ -1033,88 +1041,97 @@ window_copy_search_rl(struct grid *gd,
return (0);
}
+/* For direction == 0 move left, otherwise right; jump line if needed */
void
-window_copy_search_up(struct window_pane *wp, const char *searchstr)
+window_copy_move_coordinates(struct screen *s,
+ u_int *fx, u_int *fy, const int direction)
{
- struct window_copy_mode_data *data = wp->modedata;
- struct screen *s = data->backing, 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, wrapflag, cis;
- const char *ptr;
-
- if (*searchstr == '\0')
- return;
- utf8flag = options_get_number(&wp->window->options, "utf8");
- wrapflag = options_get_number(&wp->window->options, "wrap-search");
- 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)
+ /* If on left/right border */
+ if (*fx == (direction ? screen_size_x(s) - 1 : 0)) {
+ /* If on top/bottom border */
+ if (*fy == (direction ? screen_hsize(s) + screen_size_y(s) : 0))
+ /* Nowhere to go */
return;
- fx = gd->sx - 1;
- fy--;
- } else
- fx--;
- n = wrapped = 0;
+ /* Jump to beggin/end of lower/upper line */
+ *fx = direction ? 0 : screen_size_x(s) - 1;
+ *fy = direction ? *fy + 1 : *fy - 1;
+ } else {
+ *fx = direction ? *fx + 1 : *fx - 1;
+ }
+}
- cis = 1;
- for (ptr = searchstr; *ptr != '\0'; ptr++) {
+int
+window_copy_is_lowercase(const char *ptr)
+{
+ while (*ptr != '\0') {
if (*ptr != tolower((u_char)*ptr)) {
- cis = 0;
- break;
+ return 0;
}
+ ++ptr;
}
+ return 1;
+}
-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, cis);
- if (n) {
- window_copy_scroll_to(wp, px, i - 1);
- break;
+/* Search in grid `gd` for text stored in grid `sgd` starting from position
+ * (`fx`, `fy`) up to line `endline` and if found then jump to it.
+ * If `cis` do it case-insensitive.
+ * `direction` 0 for searching up, down otherwise
+ * If `wrap` then go to begin/end of grid and try again up to line `fy` */
+void
+window_copy_jump_to_searched_string(struct window_pane *wp,
+ struct grid *gd, struct grid *sgd, u_int fx, u_int fy,
+ u_int endline, int cis, int wrap, const int direction)
+{
+ u_int i, px;
+ int firstIteration, found;
+
+ firstIteration = 1;
+ if (direction) {
+ for (i = fy; i <= endline; ++i) {
+ found = window_copy_search_lr(gd, sgd, &px, i,
+ firstIteration ? fx : 0, gd->sx, cis);
+ if (found) break;
+ firstIteration = 0;
+ }
+ } else {
+ for (i = fy + 1; endline < i; --i) {
+ found = window_copy_search_rl(gd, sgd, &px, i - 1,
+ 0, firstIteration ? fx : gd->sx, cis);
+ if (found) {
+ --i;
+ break;
+ }
+ firstIteration = 0;
}
}
- if (wrapflag && !n && !wrapped) {
- fx = gd->sx - 1;
- fy = gd->hsize + gd->sy - 1;
- wrapped = 1;
- goto retry;
+ if (found) {
+ window_copy_scroll_to(wp, px, i);
+ } else if (wrap) {
+ /* Start searching from begin/end of grid up to `fy` line */
+ window_copy_jump_to_searched_string(wp, gd, sgd,
+ direction ? 0 : gd->sx - 1,
+ direction ? 0 : gd->hsize + gd->sy - 1,
+ fy, cis, 0, direction);
}
-
- screen_free(&ss);
}
void
-window_copy_search_down(struct window_pane *wp, const char *searchstr)
+window_copy_search(struct window_pane *wp,
+ const char *searchstr, const int direction, const int move)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = data->backing, ss;
struct screen_write_ctx ctx;
- struct grid *gd = s->grid, *sgd;
- struct grid_cell gc;
+ struct grid *gd = s->grid;
+ struct grid_cell gc;
size_t searchlen;
- u_int i, first, fx, fy, px;
- int utf8flag, n, wrapped, wrapflag, cis;
- const char *ptr;
+ u_int fx, fy;
+ int utf8flag, wrapflag, cis;
+
+ /* current cursor coordinates */
+ fx = data->cx;
+ fy = screen_hsize(data->backing) - data->oy + data->cy;
- if (*searchstr == '\0')
- return;
utf8flag = options_get_number(&wp->window->options, "utf8");
wrapflag = options_get_number(&wp->window->options, "wrap-search");
searchlen = screen_write_strlen(utf8flag, "%s", searchstr);
@@ -1125,50 +1142,35 @@ window_copy_search_down(struct window_pane *wp,
const char *searchstr)
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 == gd->sx - 1) {
- if (fy == gd->hsize + gd->sy)
- return;
- fx = 0;
- fy++;
- } else
- fx++;
- n = wrapped = 0;
-
- cis = 1;
- for (ptr = searchstr; *ptr != '\0'; ptr++) {
- if (*ptr != tolower((u_char)*ptr)) {
- cis = 0;
- break;
- }
+ if (move) {
+ window_copy_move_coordinates(s, &fx, &fy, direction);
}
-retry:
- sgd = ss.grid;
- for (i = fy + 1; i < gd->hsize + gd->sy + 1; i++) {
- first = 0;
- if (i == fy + 1)
- first = fx;
- n = window_copy_search_lr(gd, sgd, &px, i - 1, first, gd->sx,
- cis);
- if (n) {
- window_copy_scroll_to(wp, px, i - 1);
- break;
- }
- }
- if (wrapflag && !n && !wrapped) {
- fx = 0;
- fy = 0;
- wrapped = 1;
- goto retry;
- }
+ cis = window_copy_is_lowercase(searchstr);
+ window_copy_clear_selection(wp);
+
+ window_copy_jump_to_searched_string(wp, gd, ss.grid, fx, fy,
+ direction ? gd->hsize + gd->sy - 1 : 0,
+ cis, wrapflag, direction);
screen_free(&ss);
}
void
+window_copy_search_up(struct window_pane *wp, const char *searchstr,
+ const int move)
+{
+ window_copy_search(wp, searchstr, 0, move);
+}
+
+void
+window_copy_search_down(struct window_pane *wp, const char *searchstr,
+ const int move)
+{
+ window_copy_search(wp, searchstr, 1, move);
+}
+
+void
window_copy_goto_line(struct window_pane *wp, const char *linestr)
{
struct window_copy_mode_data *data = wp->modedata;
Incremental search in window-copy mode
==============================
diff --git window-copy.c window-copy.c
index 1213380..243c755 100644
--- window-copy.c
+++ window-copy.c
@@ -53,6 +53,9 @@ int window_copy_is_lowercase(const char *);
void window_copy_jump_to_searched_string(
struct window_pane *, struct grid *, struct grid *, u_int, u_int,
u_int, int, int, const int);
+int window_copy_coord_from_hist(struct window_pane *wp,
+ const size_t searchlen, u_int *fx, u_int *fy);
+void window_copy_clear_search_hist(struct window_pane *, u_int *, u_int *);
void window_copy_search(struct window_pane *, const char *,
const int, const int);
void window_copy_search_up(struct window_pane *, const char *, const int);
@@ -115,6 +118,22 @@ enum window_copy_input_type {
};
/*
+ * x, y - coordinates from which the search was made
+ * found - if the text was found
+ * searchlen - lenght of text that was searched
+ * prev - data of previous searches
+ */
+struct window_copy_search_hist {
+ u_int x;
+ u_int y;
+ int found;
+
+ size_t searchlen;
+
+ struct window_copy_search_hist *prev;
+};
+
+/*
* 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
@@ -159,6 +178,7 @@ struct window_copy_mode_data {
enum window_copy_input_type searchtype;
char *searchstr;
+ struct window_copy_search_hist *searchhist;
enum window_copy_input_type jumptype;
char jumpchar;
@@ -190,6 +210,7 @@ window_copy_init(struct window_pane *wp)
data->searchtype = WINDOW_COPY_OFF;
data->searchstr = NULL;
+ data->searchhist = NULL;
if (wp->fd != -1)
bufferevent_disable(wp->event, EV_READ|EV_WRITE);
@@ -259,6 +280,7 @@ window_copy_free(struct window_pane *wp)
free(data->searchstr);
free(data->inputstr);
+ window_copy_clear_search_hist(wp, NULL, NULL);
if (data->backing != &wp->base) {
screen_free(data->backing);
@@ -672,10 +694,12 @@ window_copy_key(struct window_pane *wp, struct
session *sess, int key)
case MODEKEYCOPY_SEARCHUP:
data->inputtype = WINDOW_COPY_SEARCHUP;
data->inputprompt = "Search Up";
+ *data->inputstr = '\0';
goto input_on;
case MODEKEYCOPY_SEARCHDOWN:
data->inputtype = WINDOW_COPY_SEARCHDOWN;
data->inputprompt = "Search Down";
+ *data->inputstr = '\0';
goto input_on;
case MODEKEYCOPY_SEARCHAGAIN:
case MODEKEYCOPY_SEARCHREVERSE:
@@ -778,6 +802,7 @@ window_copy_key_input(struct window_pane *wp, int key)
int np;
struct paste_buffer *pb;
u_char ch;
+ u_int fx, fy;
switch (mode_key_lookup(&data->mdata, key, NULL)) {
case MODEKEYEDIT_CANCEL:
@@ -787,9 +812,29 @@ window_copy_key_input(struct window_pane *wp, int key)
inputlen = strlen(data->inputstr);
if (inputlen > 0)
data->inputstr[inputlen - 1] = '\0';
+ switch (data->inputtype) {
+ case WINDOW_COPY_SEARCHUP:
+ data->searchtype = data->inputtype;
+ free(data->searchstr);
+ data->searchstr = xstrdup(data->inputstr);
+ window_copy_search_up(wp, data->inputstr, 0);
+ break;
+ case WINDOW_COPY_SEARCHDOWN:
+ data->searchtype = data->inputtype;
+ free(data->searchstr);
+ data->searchstr = xstrdup(data->inputstr);
+ window_copy_search_down(wp, data->inputstr, 0);
+ break;
+ default:
+ break;
+ }
break;
case MODEKEYEDIT_DELETELINE:
*data->inputstr = '\0';
+ fx = data->cx;
+ fy = screen_hsize(data->backing) - data->oy + data->cy;
+ window_copy_clear_search_hist(wp, &fx, &fy);
+ window_copy_scroll_to(wp, fx, fy);
break;
case MODEKEYEDIT_PASTE:
if ((pb = paste_get_top()) == NULL)
@@ -820,15 +865,17 @@ window_copy_key_input(struct window_pane *wp, int key)
break;
case WINDOW_COPY_SEARCHUP:
data->searchtype = data->inputtype;
+ free(data->searchstr);
data->searchstr = xstrdup(data->inputstr);
- for (; np != 0; np--)
- window_copy_search_up(wp, data->inputstr, 0);
+ for (; np > 1; np--)
+ window_copy_search_up(wp, data->inputstr, 1);
break;
case WINDOW_COPY_SEARCHDOWN:
data->searchtype = data->inputtype;
+ free(data->searchstr);
data->searchstr = xstrdup(data->inputstr);
- for (; np != 0; np--)
- window_copy_search_down(wp, data->inputstr, 0);
+ for (; np > 1; np--)
+ window_copy_search_down(wp, data->inputstr, 1);
break;
case WINDOW_COPY_NAMEDBUFFER:
window_copy_copy_selection(wp, data->inputstr);
@@ -850,6 +897,22 @@ window_copy_key_input(struct window_pane *wp, int key)
data->inputstr = xrealloc(data->inputstr, 1, inputlen);
data->inputstr[inputlen - 2] = key;
data->inputstr[inputlen - 1] = '\0';
+ switch (data->inputtype) {
+ case WINDOW_COPY_SEARCHUP:
+ data->searchtype = data->inputtype;
+ free(data->searchstr);
+ data->searchstr = xstrdup(data->inputstr);
+ window_copy_search_up(wp, data->inputstr, 0);
+ break;
+ case WINDOW_COPY_SEARCHDOWN:
+ data->searchtype = data->inputtype;
+ free(data->searchstr);
+ data->searchstr = xstrdup(data->inputstr);
+ window_copy_search_down(wp, data->inputstr, 0);
+ break;
+ default:
+ break;
+ }
break;
default:
break;
@@ -1082,6 +1145,8 @@ window_copy_jump_to_searched_string(struct
window_pane *wp,
struct grid *gd, struct grid *sgd, u_int fx, u_int fy,
u_int endline, int cis, int wrap, const int direction)
{
+ struct window_copy_mode_data *data = wp->modedata;
+ struct window_copy_search_hist *searchhist = data->searchhist;
u_int i, px;
int firstIteration, found;
@@ -1112,6 +1177,60 @@ window_copy_jump_to_searched_string(struct
window_pane *wp,
direction ? 0 : gd->sx - 1,
direction ? 0 : gd->hsize + gd->sy - 1,
fy, cis, 0, direction);
+ } else {
+ if (searchhist != NULL) {
+ searchhist->found = 0;
+ }
+ }
+}
+
+/* If it returns 0 then, according to search history, last time we searched
+ * a shorter string we haven't found anything, so there is no point in
+ * incremental-searching a longer string (just an optimization) */
+int
+window_copy_coord_from_hist(struct window_pane *wp,
+ const size_t searchlen, u_int *fx, u_int *fy)
+{
+ struct window_copy_mode_data *data = wp->modedata;
+ struct window_copy_search_hist *searchhist = data->searchhist;
+
+ if (searchhist == NULL || searchhist->searchlen < searchlen) {
+ searchhist = xmalloc(sizeof (struct window_copy_search_hist));
+ searchhist->x = data->cx;
+ searchhist->y =
+ screen_hsize(data->backing) - data->oy + data->cy;
+ searchhist->searchlen = searchlen;
+ searchhist->found = data->searchhist == NULL ?
+ 1 : data->searchhist->found;
+
+ searchhist->prev = data->searchhist;
+ data->searchhist = searchhist;
+
+ *fx = searchhist->x;
+ *fy = searchhist->y;
+ } else {
+ *fx = searchhist->x;
+ *fy = searchhist->y;
+ searchhist = data->searchhist->prev;
+ free(data->searchhist);
+ data->searchhist = searchhist;
+ }
+
+ return searchhist == NULL ? 1 : searchhist->found;
+}
+
+void
+window_copy_clear_search_hist(struct window_pane *wp, u_int *fx, u_int *fy)
+{
+ struct window_copy_mode_data *data = wp->modedata;
+ struct window_copy_search_hist *searchhist = data->searchhist;
+
+ while (searchhist != NULL) {
+ if (fx != NULL) *fx = searchhist->x;
+ if (fy != NULL) *fy = searchhist->y;
+ searchhist = searchhist->prev;
+ free(data->searchhist);
+ data->searchhist = searchhist;
}
}
@@ -1132,6 +1251,14 @@ window_copy_search(struct window_pane *wp,
fx = data->cx;
fy = screen_hsize(data->backing) - data->oy + data->cy;
+ /* User deleted all searched text, jump to the initial cursor
+ * position and delete the searchhistory */
+ if ((searchstr == NULL) || (*searchstr == '\0')) {
+ window_copy_clear_search_hist(wp, &fx, &fy);
+ window_copy_scroll_to(wp, fx, fy);
+ return;
+ }
+
utf8flag = options_get_number(&wp->window->options, "utf8");
wrapflag = options_get_number(&wp->window->options, "wrap-search");
searchlen = screen_write_strlen(utf8flag, "%s", searchstr);
@@ -1142,8 +1269,19 @@ window_copy_search(struct window_pane *wp,
screen_write_nputs(&ctx, -1, &gc, utf8flag, "%s", searchstr);
screen_write_stop(&ctx);
+ /*
+ * `move` is useful for incremental searching. When we do incremental,
+ * we don't want to jump to the next matching word if we already stand
+ * on one, so `move=0`.
+ * But when user wants the next result, then we use `move=1`, so
+ * we start searching from the place next to the current cursor
+ * position */
if (move) {
window_copy_move_coordinates(s, &fx, &fy, direction);
+ } else {
+ if (!window_copy_coord_from_hist(wp, searchlen, &fx, &fy)) {
+ return;
+ }
}
cis = window_copy_is_lowercase(searchstr);
Highlight last search in window-copy mode
===============================
diff --git options-table.c options-table.c
index 8d680b3..79ecae3 100644
--- options-table.c
+++ options-table.c
@@ -619,6 +619,11 @@ const struct options_table_entry
window_options_table[] = {
.default_str = "bg=yellow,fg=black"
},
+ { .name = "highlight-style",
+ .type = OPTIONS_TABLE_STYLE,
+ .default_str = "bg=green,fg=black"
+ },
+
{ .name = "monitor-activity",
.type = OPTIONS_TABLE_FLAG,
.default_num = 0
@@ -802,6 +807,11 @@ const struct options_table_entry
window_options_table[] = {
.default_num = 1
},
+ { .name = "highlight-search",
+ .type = OPTIONS_TABLE_FLAG,
+ .default_num = 1
+ },
+
{ .name = "xterm-keys",
.type = OPTIONS_TABLE_FLAG,
.default_num = 0
diff --git screen-write.c screen-write.c
index 325fb9a..a36a1f2 100644
--- screen-write.c
+++ screen-write.c
@@ -902,7 +902,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const
struct grid_cell *gc)
struct grid *gd = s->grid;
struct tty_ctx ttyctx;
u_int width, xx, last;
- struct grid_cell tmp_gc, *tmp_gcp;
+ struct grid_cell tmp_gc, *tmp_gcp, *cell = NULL;
struct utf8_data ud;
int insert;
@@ -995,6 +995,15 @@ screen_write_cell(struct screen_write_ctx *ctx, const
struct grid_cell *gc)
(GRID_FLAG_FG256|GRID_FLAG_BG256);
ttyctx.cell = &tmp_gc;
tty_write(tty_cmd_cell, &ttyctx);
+ } else if (screen_check_highlight(s, s->cx - width, s->cy, &cell)) {
+ memcpy(&tmp_gc, cell, sizeof tmp_gc);
+ grid_cell_get(gc, &ud);
+ grid_cell_set(&tmp_gc, &ud);
+ tmp_gc.flags = gc->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256);
+ tmp_gc.flags |= cell->flags &
+ (GRID_FLAG_FG256|GRID_FLAG_BG256);
+ ttyctx.cell = &tmp_gc;
+ tty_write(tty_cmd_cell, &ttyctx);
} else {
ttyctx.cell = gc;
tty_write(tty_cmd_cell, &ttyctx);
diff --git screen.c screen.c
index 7bfc015..734b38e 100644
--- screen.c
+++ screen.c
@@ -44,6 +44,7 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int
hlimit)
s->cstyle = 0;
s->ccolour = xstrdup("");
s->tabs = NULL;
+ s->hls = NULL;
screen_reinit(s);
}
@@ -65,6 +66,7 @@ screen_reinit(struct screen *s)
grid_clear_lines(s->grid, s->grid->hsize, s->grid->sy);
screen_clear_selection(s);
+ screen_clear_highlight(s);
}
/* Destroy a screen. */
@@ -75,6 +77,7 @@ screen_free(struct screen *s)
free(s->title);
free(s->ccolour);
grid_destroy(s->grid);
+ screen_clear_highlight(s);
}
/* Reset tabs to default, eight spaces apart. */
@@ -357,6 +360,56 @@ screen_check_selection(struct screen *s, u_int px,
u_int py)
return (1);
}
+/* Set highlight. */
+void
+screen_set_highlight(struct screen *s,
+ u_int sx, u_int ex, u_int y, struct grid_cell *gc)
+{
+ struct screen_hls *hls = xmalloc(sizeof (struct screen_hls));
+
+ hls->sx = sx;
+ hls->ex = ex;
+ hls->y = y;
+ hls->next = s->hls;
+
+ memcpy(&hls->cell, gc, sizeof hls->cell);
+
+ s->hls = hls;
+}
+
+/* Clear highlights. */
+void
+screen_clear_highlight(struct screen *s)
+{
+ struct screen_hls *hls = s->hls, *hlsPrev;
+
+ while (hls != NULL) {
+ hlsPrev = hls;
+ hls = hls->next;
+ free(hlsPrev);
+ }
+
+ s->hls = NULL;
+}
+
+/* Check if cell in highlight. */
+int
+screen_check_highlight(struct screen *s, u_int px, u_int py,
+ struct grid_cell **cell)
+{
+ struct screen_hls *hls = s->hls;
+
+ while (hls != NULL) {
+ if (hls->sx <= px && px <= hls->ex && hls->y == py) {
+ *cell = &hls->cell;
+ return 1;
+ }
+ hls = hls->next;
+ }
+
+ return 0;
+}
+
/* Reflow wrapped lines. */
void
screen_reflow(struct screen *s, u_int new_x)
diff --git tmux.h tmux.h
index c4c5236..6fc5fd0 100644
--- tmux.h
+++ tmux.h
@@ -766,6 +766,17 @@ struct screen_sel {
struct grid_cell cell;
};
+/* Screen highlights. */
+struct screen_hls {
+ u_int sx;
+ u_int ex;
+
+ u_int y;
+
+ struct grid_cell cell;
+ struct screen_hls *next;
+};
+
/* Virtual screen. */
struct screen {
char *title;
@@ -786,6 +797,7 @@ struct screen {
bitstr_t *tabs;
struct screen_sel sel;
+ struct screen_hls *hls;
};
/* Screen write context. */
@@ -2118,6 +2130,11 @@ void screen_set_selection(struct screen *,
u_int, u_int, u_int, u_int, u_int, struct grid_cell *);
void screen_clear_selection(struct screen *);
int screen_check_selection(struct screen *, u_int, u_int);
+void screen_set_highlight(struct screen *,
+ u_int, u_int, u_int, struct grid_cell *);
+void screen_clear_highlight(struct screen *);
+int screen_check_highlight(struct screen *, u_int, u_int,
+ struct grid_cell **);
void screen_reflow(struct screen *, u_int);
/* window.c */
diff --git tty.c tty.c
index 7688e90..4511533 100644
--- tty.c
+++ tty.c
@@ -614,7 +614,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int
py, u_int ox, u_int oy)
{
const struct grid_cell *gc;
struct grid_line *gl;
- struct grid_cell tmpgc;
+ struct grid_cell tmpgc, *cell = NULL;
struct utf8_data ud;
u_int i, sx;
@@ -649,6 +649,15 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int
py, u_int ox, u_int oy)
tmpgc.flags |= s->sel.cell.flags &
(GRID_FLAG_FG256|GRID_FLAG_BG256);
tty_cell(tty, &tmpgc);
+ } else if (screen_check_highlight(s, i, py, &cell)) {
+ memcpy(&tmpgc, cell, sizeof tmpgc);
+ grid_cell_get(gc, &ud);
+ grid_cell_set(&tmpgc, &ud);
+ tmpgc.flags = gc->flags &
+ ~(GRID_FLAG_FG256|GRID_FLAG_BG256);
+ tmpgc.flags |= cell->flags &
+ (GRID_FLAG_FG256|GRID_FLAG_BG256);
+ tty_cell(tty, &tmpgc);
} else
tty_cell(tty, gc);
}
diff --git window-copy.c window-copy.c
index 243c755..00cdc3f 100644
--- window-copy.c
+++ window-copy.c
@@ -28,10 +28,13 @@ 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 session *, int);
+void window_copy_key_internal(struct window_pane *, struct session *, int);
int window_copy_key_input(struct window_pane *, int);
int window_copy_key_numeric_prefix(struct window_pane *, int);
void window_copy_mouse(
struct window_pane *, struct session *, struct mouse_event *);
+void window_copy_mouse_internal(
+ struct window_pane *, struct session *, struct mouse_event *);
void window_copy_redraw_lines(struct window_pane *, u_int, u_int);
void window_copy_redraw_screen(struct window_pane *);
@@ -53,6 +56,7 @@ int window_copy_is_lowercase(const char *);
void window_copy_jump_to_searched_string(
struct window_pane *, struct grid *, struct grid *, u_int, u_int,
u_int, int, int, const int);
+void window_copy_highlight_search(struct window_pane *);
int window_copy_coord_from_hist(struct window_pane *wp,
const size_t searchlen, u_int *fx, u_int *fy);
void window_copy_clear_search_hist(struct window_pane *, u_int *, u_int *);
@@ -397,6 +401,16 @@ window_copy_resize(struct window_pane *wp, u_int sx,
u_int sy)
void
window_copy_key(struct window_pane *wp, struct session *sess, int key)
{
+ window_copy_key_internal(wp, sess, key);
+
+ if (wp->mode != NULL) {
+ window_copy_highlight_search(wp);
+ }
+}
+
+void
+window_copy_key_internal(struct window_pane *wp, struct session *sess, int
key)
+{
const char *word_separators;
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
@@ -944,6 +958,17 @@ void
window_copy_mouse(
struct window_pane *wp, struct session *sess, struct mouse_event *m)
{
+ window_copy_mouse_internal(wp, sess, m);
+
+ if (wp->mode != NULL) {
+ window_copy_highlight_search(wp);
+ }
+}
+
+void
+window_copy_mouse_internal(
+ struct window_pane *wp, struct session *sess, struct mouse_event *m)
+{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
u_int i;
@@ -1184,6 +1209,68 @@ window_copy_jump_to_searched_string(struct
window_pane *wp,
}
}
+void
+window_copy_highlight_search(struct window_pane *wp)
+{
+ struct window_copy_mode_data *data = wp->modedata;
+ struct screen *s = data->backing, ss;
+ struct screen_write_ctx ctx;
+ struct grid *gd = s->grid;
+ struct grid_cell gc;
+ struct options *oo = &wp->window->options;
+ const char *searchstr = data->searchstr;
+ size_t searchlen;
+ u_int i, px, last, beginline, endline;
+ int found, utf8flag, cis, highlight;
+
+ highlight = options_get_number(
+ &wp->window->options, "highlight-search");
+ if (!highlight) {
+ return;
+ }
+
+ screen_clear_highlight(&data->screen);
+
+ if ((searchstr != NULL) && (*searchstr != '\0')) {
+ 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);
+
+ cis = window_copy_is_lowercase(searchstr);
+
+ /* Set colours. */
+ style_apply(&gc, oo, "highlight-style");
+
+ beginline = screen_hsize(s) - data->oy;
+ endline = screen_hsize(s) - data->oy + screen_size_y(s) - 1;
+
+ for (i = beginline; i <= endline; ++i) {
+ last = 0;
+ do {
+ found = window_copy_search_lr(gd, ss.grid, &px,
+ i, last, gd->sx, cis);
+ if (found) {
+ screen_set_highlight(
+ &data->screen,
+ px,
+ px + searchlen - 1,
+ i - (screen_hsize(s)
+ - data->oy),
+ &gc);
+ last += searchlen;
+ }
+ } while (found);
+ }
+ }
+
+ window_copy_redraw_screen(wp);
+}
+
/* If it returns 0 then, according to search history, last time we searched
* a shorter string we haven't found anything, so there is no point in
* incremental-searching a longer string (just an optimization) */