-/* $OpenBSD: window-copy.c,v 1.320 2021/03/09 13:07:50 nicm Exp $ */
+/* $OpenBSD: window-copy.c,v 1.321 2021/04/01 06:46:12 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
static int window_copy_last_regex(struct grid *, u_int, u_int, u_int,
u_int, u_int *, u_int *, const char *, const regex_t *,
int);
+static int window_copy_search_mark_at(struct window_copy_mode_data *,
+ u_int, u_int, u_int *);
static char *window_copy_stringify(struct grid *, u_int, u_int, u_int,
char *, u_int *);
static void window_copy_cstrtocellpos(struct grid *, u_int, u_int *,
static int window_copy_search_marks(struct window_mode_entry *,
struct screen *, int, int);
static void window_copy_clear_marks(struct window_mode_entry *);
-static void window_copy_move_left(struct screen *, u_int *, u_int *, int);
static int window_copy_is_lowercase(const char *);
static void window_copy_search_back_overlap(struct grid *, regex_t *,
u_int *, u_int *, u_int *, u_int);
static int window_copy_search_jump(struct window_mode_entry *,
struct grid *, struct grid *, u_int, u_int, u_int, int, int,
- int, int, u_int *);
-static int window_copy_search(struct window_mode_entry *, int, int, int);
-static int window_copy_search_up(struct window_mode_entry *, int, int);
-static int window_copy_search_down(struct window_mode_entry *, int, int);
+ int, int);
+static int window_copy_search(struct window_mode_entry *, int, int);
+static int window_copy_search_up(struct window_mode_entry *, int);
+static int window_copy_search_down(struct window_mode_entry *, int);
static void window_copy_goto_line(struct window_mode_entry *, const char *);
static void window_copy_update_cursor(struct window_mode_entry *, u_int,
u_int);
int showmark;
int searchtype;
+ int searchdirection;
int searchregex;
char *searchstr;
u_char *searchmark;
if (data->searchtype == WINDOW_COPY_SEARCHUP) {
for (; np != 0; np--)
- window_copy_search_up(wme, data->searchregex, 1);
+ window_copy_search_up(wme, data->searchregex);
} else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
for (; np != 0; np--)
- window_copy_search_down(wme, data->searchregex, 1);
+ window_copy_search_down(wme, data->searchregex);
}
return (WINDOW_COPY_CMD_NOTHING);
}
if (data->searchtype == WINDOW_COPY_SEARCHUP) {
for (; np != 0; np--)
- window_copy_search_down(wme, data->searchregex, 1);
+ window_copy_search_down(wme, data->searchregex);
} else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
for (; np != 0; np--)
- window_copy_search_up(wme, data->searchregex, 1);
+ window_copy_search_up(wme, data->searchregex);
}
return (WINDOW_COPY_CMD_NOTHING);
}
data->searchregex = 1;
data->timeout = 0;
for (; np != 0; np--)
- window_copy_search_up(wme, 1, 0);
+ window_copy_search_up(wme, 1);
}
return (WINDOW_COPY_CMD_NOTHING);
}
data->searchregex = 0;
data->timeout = 0;
for (; np != 0; np--)
- window_copy_search_up(wme, 0, 0);
+ window_copy_search_up(wme, 0);
}
return (WINDOW_COPY_CMD_NOTHING);
}
data->searchregex = 1;
data->timeout = 0;
for (; np != 0; np--)
- window_copy_search_down(wme, 1, 0);
+ window_copy_search_down(wme, 1);
}
return (WINDOW_COPY_CMD_NOTHING);
}
data->searchregex = 0;
data->timeout = 0;
for (; np != 0; np--)
- window_copy_search_down(wme, 0, 0);
+ window_copy_search_down(wme, 0);
}
return (WINDOW_COPY_CMD_NOTHING);
}
data->searchregex = 0;
free(data->searchstr);
data->searchstr = xstrdup(argument);
- if (!window_copy_search_up(wme, 0, 1)) {
+ if (!window_copy_search_up(wme, 0)) {
window_copy_clear_marks(wme);
return (WINDOW_COPY_CMD_REDRAW);
}
data->searchregex = 0;
free(data->searchstr);
data->searchstr = xstrdup(argument);
- if (!window_copy_search_down(wme, 0, 0)) {
+ if (!window_copy_search_down(wme, 0)) {
window_copy_clear_marks(wme);
return (WINDOW_COPY_CMD_REDRAW);
}
data->searchregex = 0;
free(data->searchstr);
data->searchstr = xstrdup(argument);
- if (!window_copy_search_down(wme, 0, 1)) {
+ if (!window_copy_search_down(wme, 0)) {
window_copy_clear_marks(wme);
return (WINDOW_COPY_CMD_REDRAW);
}
data->searchregex = 0;
free(data->searchstr);
data->searchstr = xstrdup(argument);
- if (!window_copy_search_up(wme, 0, 1)) {
+ if (!window_copy_search_up(wme, 0)) {
window_copy_clear_marks(wme);
return (WINDOW_COPY_CMD_REDRAW);
}
*fx = *fx - 1;
}
+static void
+window_copy_move_right(struct screen *s, u_int *fx, u_int *fy, int wrapflag)
+{
+ if (*fx == screen_size_x(s) - 1) { /* right */
+ if (*fy == screen_hsize(s) + screen_size_y(s) - 1) { /* bottom */
+ if (wrapflag) {
+ *fx = 0;
+ *fy = 0;
+ }
+ return;
+ }
+ *fx = 0;
+ *fy = *fy + 1;
+ } else
+ *fx = *fx + 1;
+}
+
static int
window_copy_is_lowercase(const char *ptr)
{
static int
window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd,
struct grid *sgd, u_int fx, u_int fy, u_int endline, int cis, int wrap,
- int direction, int regex, u_int *foundlen)
+ int direction, int regex)
{
u_int i, px, sx, ssize = 1;
int found = 0, cflags = REG_EXTENDED;
if (regex) {
found = window_copy_search_lr_regex(gd,
&px, &sx, i, fx, gd->sx, ®);
- if (found)
- *foundlen = sx;
} else {
found = window_copy_search_lr(gd, sgd,
&px, i, fx, gd->sx, cis);
- if (found)
- *foundlen = sgd->sx;
}
if (found)
break;
fx = 0;
}
} else {
- *foundlen = 0;
for (i = fy + 1; endline < i; i--) {
if (regex) {
found = window_copy_search_rl_regex(gd,
return (window_copy_search_jump(wme, gd, sgd,
direction ? 0 : gd->sx - 1,
direction ? 0 : gd->hsize + gd->sy - 1, fy, cis, 0,
- direction, regex, foundlen));
+ direction, regex));
}
return (0);
}
+static void
+window_copy_move_after_search_mark(struct window_copy_mode_data *data,
+ u_int *fx, u_int *fy, int wrapflag)
+{
+ struct screen *s = data->backing;
+ u_int at, start;
+
+ if (window_copy_search_mark_at(data, *fx, *fy, &start) == 0 &&
+ data->searchmark[start] != 0) {
+ while (window_copy_search_mark_at(data, *fx, *fy, &at) == 0) {
+ if (data->searchmark[at] != data->searchmark[start])
+ break;
+ /* Stop if not wrapping and at the end of the grid. */
+ if (!wrapflag &&
+ *fx == screen_size_x(s) - 1 &&
+ *fy == screen_hsize(s) + screen_size_y(s) - 1)
+ break;
+
+ window_copy_move_right(s, fx, fy, wrapflag);
+ }
+ }
+}
+
/*
* Search in for text searchstr. If direction is 0 then search up, otherwise
* down.
*/
static int
-window_copy_search(struct window_mode_entry *wme, int direction, int regex,
- int again)
+window_copy_search(struct window_mode_entry *wme, int direction, int regex)
{
struct window_pane *wp = wme->wp;
struct window_copy_mode_data *data = wme->data;
struct screen_write_ctx ctx;
struct grid *gd = s->grid;
const char *str = data->searchstr;
- u_int fx, fy, endline, i, foundlen;
- int wrapflag, cis, found, visible_only;
+ u_int at, endline, fx, fy, start;
+ int cis, found, keys, visible_only;
+ int wrapflag;
if (regex && str[strcspn(str, "^$*+()?[].\\")] == '\0')
regex = 0;
+ data->searchdirection = direction;
+
if (data->timeout)
return (0);
wrapflag = options_get_number(wp->window->options, "wrap-search");
cis = window_copy_is_lowercase(str);
- if (direction)
+ keys = options_get_number(wp->window->options, "mode-keys");
+
+ if (direction) {
+ /*
+ * Behave according to mode-keys. If it is emacs, search forward
+ * leaves the cursor after the match. If it is vi, the cursor
+ * remains at the beginning of the match, regardless of
+ * direction, which means that we need to start the next search
+ * after the term the cursor is currently on when searching
+ * forward.
+ */
+ if (keys == MODEKEY_VI) {
+ if (data->searchmark != NULL)
+ window_copy_move_after_search_mark(data, &fx,
+ &fy, wrapflag);
+ else {
+ /*
+ * When there are no search marks, start the
+ * search after the current cursor position.
+ */
+ window_copy_move_right(s, &fx, &fy, wrapflag);
+ }
+ }
endline = gd->hsize + gd->sy - 1;
+ }
else {
- if (again)
- window_copy_move_left(s, &fx, &fy, wrapflag);
+ window_copy_move_left(s, &fx, &fy, wrapflag);
endline = 0;
}
found = window_copy_search_jump(wme, gd, ss.grid, fx, fy, endline, cis,
- wrapflag, direction, regex, &foundlen);
+ wrapflag, direction, regex);
if (found) {
window_copy_search_marks(wme, &ss, regex, visible_only);
- if (foundlen != 0) {
- /* Adjust for wrapped lines eating one right. */
- i = data->cx + foundlen;
- while (i > gd->sx - 1) {
- i -= gd->sx;
- window_copy_cursor_right(wme, 1);
+ fx = data->cx;
+ fy = screen_hsize(data->backing) - data->oy + data->cy;
+
+ /*
+ * When searching forward, if the cursor is not at the beginning
+ * of the mark, search again.
+ */
+ if (direction &&
+ window_copy_search_mark_at(data, fx, fy, &at) == 0 &&
+ at > 0 &&
+ data->searchmark[at] == data->searchmark[at - 1]) {
+ window_copy_move_after_search_mark(data, &fx, &fy,
+ wrapflag);
+ window_copy_search_jump(wme, gd, ss.grid, fx,
+ fy, endline, cis, wrapflag, direction,
+ regex);
+ fx = data->cx;
+ fy = screen_hsize(data->backing) - data->oy + data->cy;
+ }
+
+ if (direction) {
+ /*
+ * When in Emacs mode, position the cursor just after
+ * the mark.
+ */
+ if (keys == MODEKEY_EMACS) {
+ window_copy_move_after_search_mark(data, &fx,
+ &fy, wrapflag);
+ data->cx = fx;
+ data->cy = fy - screen_hsize(data->backing) +
+ data-> oy;
+ }
+ }
+ else {
+ /*
+ * When searching backward, position the cursor at the
+ * beginning of the mark.
+ */
+ if (window_copy_search_mark_at(data, fx, fy,
+ &start) == 0) {
+ while (window_copy_search_mark_at(data, fx, fy,
+ &at) == 0 &&
+ data->searchmark[at] ==
+ data->searchmark[start]) {
+ data->cx = fx;
+ data->cy = fy -
+ screen_hsize(data->backing) +
+ data-> oy;
+ if (at == 0)
+ break;
+
+ window_copy_move_left(s, &fx, &fy, 0);
+ }
}
- for (i = 0; i < foundlen; i++)
- window_copy_cursor_right(wme, 1);
}
}
window_copy_redraw_screen(wme);
}
static int
-window_copy_search_up(struct window_mode_entry *wme, int regex, int again)
+window_copy_search_up(struct window_mode_entry *wme, int regex)
{
- return (window_copy_search(wme, 0, regex, again));
+ return (window_copy_search(wme, 0, regex));
}
static int
-window_copy_search_down(struct window_mode_entry *wme, int regex, int again)
+window_copy_search_down(struct window_mode_entry *wme, int regex)
{
- return (window_copy_search(wme, 1, regex, again));
+ return (window_copy_search(wme, 1, regex));
}
static void
struct grid_cell *gc, const struct grid_cell *mgc,
const struct grid_cell *cgc, const struct grid_cell *mkgc)
{
+ struct window_pane *wp = wme->wp;
struct window_copy_mode_data *data = wme->data;
u_int mark, start, end, cy, cursor, current;
int inv = 0, found = 0;
+ int keys;
if (data->showmark && fy == data->my) {
gc->attr = mkgc->attr;
cy = screen_hsize(data->backing) - data->oy + data->cy;
if (window_copy_search_mark_at(data, data->cx, cy, &cursor) == 0) {
- if (data->searchmark[cursor] == mark)
- found = 1;
- else if (cursor != 0) {
- cursor--;
- if (data->searchmark[cursor] == mark)
+ keys = options_get_number(wp->window->options, "mode-keys");
+ if (cursor != 0 &&
+ keys == MODEKEY_EMACS &&
+ data->searchdirection) {
+ if (data->searchmark[cursor - 1] == mark) {
+ cursor--;
found = 1;
- }
+ }
+ } else if (data->searchmark[cursor] == mark)
+ found = 1;
if (found) {
window_copy_match_start_end(data, cursor, &start, &end);
if (current >= start && current <= end) {