Move jump commands to grid reader, make them UTF-8 aware, and tidy up,
authornicm <nicm@openbsd.org>
Mon, 22 Feb 2021 06:53:04 +0000 (06:53 +0000)
committernicm <nicm@openbsd.org>
Mon, 22 Feb 2021 06:53:04 +0000 (06:53 +0000)
from Anindya Mukherjee.

usr.bin/tmux/grid-reader.c
usr.bin/tmux/status.c
usr.bin/tmux/tmux.h
usr.bin/tmux/window-copy.c

index 6bfae49..79f853b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: grid-reader.c,v 1.1 2020/12/22 09:22:14 nicm Exp $ */
+/* $OpenBSD: grid-reader.c,v 1.2 2021/02/22 06:53:04 nicm Exp $ */
 
 /*
  * Copyright (c) 2020 Anindya Mukherjee <anindya49@hotmail.com>
@@ -17,6 +17,7 @@
  */
 
 #include "tmux.h"
+#include <string.h>
 
 /* Initialise virtual cursor. */
 void
@@ -301,3 +302,64 @@ grid_reader_cursor_previous_word(struct grid_reader *gr, const char *separators,
        gr->cx = oldx;
        gr->cy = oldy;
 }
+
+/* Jump forward to character. */
+int
+grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc)
+{
+       struct grid_cell        gc;
+       u_int                   px, py, xx, yy;
+
+       px = gr->cx;
+       yy = gr->gd->hsize + gr->gd->sy - 1;
+
+       for (py = gr->cy; py <= yy; py++) {
+               xx = grid_line_length(gr->gd, py);
+               while (px < xx) {
+                       grid_get_cell(gr->gd, px, py, &gc);
+                       if (!(gc.flags & GRID_FLAG_PADDING) &&
+                           gc.data.size == jc->size &&
+                           memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
+                               gr->cx = px;
+                               gr->cy = py;
+                               return 1;
+                       }
+                       px++;
+               }
+
+               if (py == yy ||
+                   !(grid_get_line(gr->gd, py)->flags & GRID_LINE_WRAPPED))
+                       return 0;
+               px = 0;
+       }
+       return 0;
+}
+
+/* Jump back to character. */
+int
+grid_reader_cursor_jump_back(struct grid_reader *gr, const struct utf8_data *jc)
+{
+       struct grid_cell        gc;
+       u_int                   px, py, xx;
+
+       xx = gr->cx + 1;
+
+       for (py = gr->cy + 1; py > 0; py--) {
+               for (px = xx; px > 0; px--) {
+                       grid_get_cell(gr->gd, px - 1, py - 1, &gc);
+                       if (!(gc.flags & GRID_FLAG_PADDING) &&
+                           gc.data.size == jc->size &&
+                           memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
+                               gr->cx = px - 1;
+                               gr->cy = py - 1;
+                               return 1;
+                       }
+               }
+
+               if (py == 1 ||
+                   !(grid_get_line(gr->gd, py - 2)->flags & GRID_LINE_WRAPPED))
+                       return 0;
+               xx = grid_line_length(gr->gd, py - 2);
+       }
+       return 0;
+}
index f0e3eed..451c513 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: status.c,v 1.219 2021/01/08 08:22:10 nicm Exp $ */
+/* $OpenBSD: status.c,v 1.220 2021/02/22 06:53:04 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1319,12 +1319,14 @@ append_key:
        }
 
        if (c->prompt_flags & PROMPT_SINGLE) {
-               s = utf8_tocstr(c->prompt_buffer);
-               if (strlen(s) != 1)
-                       status_prompt_clear(c);
-               else if (c->prompt_inputcb(c, c->prompt_data, s, 1) == 0)
+               if (utf8_strlen(c->prompt_buffer) != 1)
                        status_prompt_clear(c);
-               free(s);
+               else {
+                       s = utf8_tocstr(c->prompt_buffer);
+                       if (c->prompt_inputcb(c, c->prompt_data, s, 1) == 0)
+                               status_prompt_clear(c);
+                       free(s);
+               }
        }
 
 changed:
index cb1b8a7..92aee93 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.1092 2021/02/17 07:18:36 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.1093 2021/02/22 06:53:04 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -2589,6 +2589,10 @@ void      grid_reader_cursor_next_word(struct grid_reader *, const char *);
 void    grid_reader_cursor_next_word_end(struct grid_reader *, const char *);
 void    grid_reader_cursor_previous_word(struct grid_reader *, const char *,
             int);
+int     grid_reader_cursor_jump(struct grid_reader *,
+            const struct utf8_data *);
+int     grid_reader_cursor_jump_back(struct grid_reader *,
+            const struct utf8_data *);
 
 /* grid-view.c */
 void    grid_view_get_cell(struct grid *, u_int, u_int, struct grid_cell *);
index 0238f64..a6cb274 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: window-copy.c,v 1.314 2021/02/08 14:46:53 nicm Exp $ */
+/* $OpenBSD: window-copy.c,v 1.315 2021/02/22 06:53:04 nicm Exp $ */
 
 /*
  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -135,6 +135,10 @@ static void        window_copy_move_mouse(struct mouse_event *);
 static void    window_copy_drag_update(struct client *, struct mouse_event *);
 static void    window_copy_drag_release(struct client *, struct mouse_event *);
 static void    window_copy_jump_to_mark(struct window_mode_entry *);
+static void    window_copy_acquire_cursor_up(struct window_mode_entry *,
+                   u_int, u_int, u_int, u_int, u_int);
+static void    window_copy_acquire_cursor_down(struct window_mode_entry *,
+                   u_int, u_int, u_int, u_int, u_int, u_int, int);
 
 const struct window_mode window_copy_mode = {
        .name = "copy-mode",
@@ -284,8 +288,8 @@ struct window_copy_mode_data {
 #define WINDOW_COPY_SEARCH_TIMEOUT 10000
 #define WINDOW_COPY_SEARCH_ALL_TIMEOUT 200
 
-       int              jumptype;
-       char             jumpchar;
+       int                      jumptype;
+       struct utf8_data        *jumpchar;
 
        struct event     dragtimer;
 #define WINDOW_COPY_DRAG_REPEAT_TIME 50000
@@ -401,7 +405,7 @@ window_copy_common_init(struct window_mode_entry *wme)
        data->searchall = 1;
 
        data->jumptype = WINDOW_COPY_OFF;
-       data->jumpchar = '\0';
+       data->jumpchar = NULL;
 
        screen_init(&data->screen, screen_size_x(base), screen_size_y(base), 0);
        data->modekeys = options_get_number(wp->window->options, "mode-keys");
@@ -482,6 +486,7 @@ window_copy_free(struct window_mode_entry *wme)
 
        free(data->searchmark);
        free(data->searchstr);
+       free(data->jumpchar);
 
        screen_free(data->backing);
        free(data->backing);
@@ -1935,7 +1940,8 @@ window_copy_cmd_jump_backward(struct window_copy_cmd_state *cs)
 
        if (*argument != '\0') {
                data->jumptype = WINDOW_COPY_JUMPBACKWARD;
-               data->jumpchar = *argument;
+               free(data->jumpchar);
+               data->jumpchar = utf8_fromcstr(argument);
                for (; np != 0; np--)
                        window_copy_cursor_jump_back(wme);
        }
@@ -1952,7 +1958,8 @@ window_copy_cmd_jump_forward(struct window_copy_cmd_state *cs)
 
        if (*argument != '\0') {
                data->jumptype = WINDOW_COPY_JUMPFORWARD;
-               data->jumpchar = *argument;
+               free(data->jumpchar);
+               data->jumpchar = utf8_fromcstr(argument);
                for (; np != 0; np--)
                        window_copy_cursor_jump(wme);
        }
@@ -1969,7 +1976,8 @@ window_copy_cmd_jump_to_backward(struct window_copy_cmd_state *cs)
 
        if (*argument != '\0') {
                data->jumptype = WINDOW_COPY_JUMPTOBACKWARD;
-               data->jumpchar = *argument;
+               free(data->jumpchar);
+               data->jumpchar = utf8_fromcstr(argument);
                for (; np != 0; np--)
                        window_copy_cursor_jump_to_back(wme);
        }
@@ -1986,7 +1994,8 @@ window_copy_cmd_jump_to_forward(struct window_copy_cmd_state *cs)
 
        if (*argument != '\0') {
                data->jumptype = WINDOW_COPY_JUMPTOFORWARD;
-               data->jumpchar = *argument;
+               free(data->jumpchar);
+               data->jumpchar = utf8_fromcstr(argument);
                for (; np != 0; np--)
                        window_copy_cursor_jump_to(wme);
        }
@@ -4074,7 +4083,7 @@ window_copy_cursor_start_of_line(struct window_mode_entry *wme)
        struct window_copy_mode_data    *data = wme->data;
        struct screen                   *back_s = data->backing;
        struct grid_reader               gr;
-       u_int                            px, py, cy, oldy, yy, ny, nd, hsize;
+       u_int                            px, py, oldy, hsize;
 
        px = data->cx;
        hsize = screen_hsize(back_s);
@@ -4084,25 +4093,7 @@ window_copy_cursor_start_of_line(struct window_mode_entry *wme)
        grid_reader_start(&gr, back_s->grid, px, py);
        grid_reader_cursor_start_of_line(&gr, 1);
        grid_reader_get_cursor(&gr, &px, &py);
-
-       /* Scroll up if we went off the visible screen. */
-       yy = hsize - data->oy;
-       if (py < yy) {
-               ny = yy - py;
-               cy = 0;
-               nd = 1;
-       } else {
-               ny = 0;
-               cy = py - yy;
-               nd = oldy - cy + 1;
-       }
-       while (ny > 0) {
-               window_copy_cursor_up(wme, 1);
-               ny--;
-       }
-       window_copy_update_cursor(wme, px, cy);
-       if (window_copy_update_selection(wme, 1, 0))
-               window_copy_redraw_lines(wme, data->cy, nd);
+       window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
 }
 
 static void
@@ -4134,7 +4125,7 @@ window_copy_cursor_end_of_line(struct window_mode_entry *wme)
        struct window_copy_mode_data    *data = wme->data;
        struct screen                   *back_s = data->backing;
        struct grid_reader               gr;
-       u_int                            px, py, cy, oldy, yy, ny, nd, hsize;
+       u_int                            px, py, oldy, hsize;
 
        px = data->cx;
        hsize = screen_hsize(back_s);
@@ -4147,28 +4138,8 @@ window_copy_cursor_end_of_line(struct window_mode_entry *wme)
        else
                grid_reader_cursor_end_of_line(&gr, 1, 0);
        grid_reader_get_cursor(&gr, &px, &py);
-
-       /* Scroll down if we went off the visible screen. */
-       cy = py - hsize + data->oy;
-       yy = screen_size_y(back_s) - 1;
-       if (cy > yy) {
-               ny = cy - yy;
-               oldy = yy;
-               nd = 1;
-       } else {
-               ny = 0;
-               nd = cy - oldy + 1;
-       }
-       while (ny > 0) {
-         window_copy_cursor_down(wme, 1);
-         ny--;
-       }
-       if (cy > yy)
-               window_copy_update_cursor(wme, px, yy);
-       else
-               window_copy_update_cursor(wme, px, cy);
-       if (window_copy_update_selection(wme, 1, 0))
-               window_copy_redraw_lines(wme, oldy, nd);
+       window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
+           data->oy, oldy, px, py, 0);
 }
 
 static void
@@ -4228,32 +4199,17 @@ window_copy_cursor_left(struct window_mode_entry *wme)
        struct window_copy_mode_data    *data = wme->data;
        struct screen                   *back_s = data->backing;
        struct grid_reader               gr;
-       u_int                            px, py, cy, yy, ny, hsize;
+       u_int                            px, py, oldy, hsize;
 
        px = data->cx;
        hsize = screen_hsize(back_s);
        py = hsize + data->cy - data->oy;
+       oldy = data->cy;
 
        grid_reader_start(&gr, back_s->grid, px, py);
        grid_reader_cursor_left(&gr);
        grid_reader_get_cursor(&gr, &px, &py);
-
-       /* Scroll up if we went off the visible screen. */
-       yy = hsize - data->oy;
-       if (py < yy) {
-               ny = yy - py;
-               cy = 0;
-       } else {
-               ny = 0;
-               cy = py - yy;
-       }
-       while (ny > 0) {
-               window_copy_cursor_up(wme, 1);
-               ny--;
-       }
-       window_copy_update_cursor(wme, px, cy);
-       if (window_copy_update_selection(wme, 1, 0))
-               window_copy_redraw_lines(wme, data->cy, 1);
+       window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
 }
 
 static void
@@ -4262,33 +4218,18 @@ window_copy_cursor_right(struct window_mode_entry *wme, int all)
        struct window_copy_mode_data    *data = wme->data;
        struct screen                   *back_s = data->backing;
        struct grid_reader               gr;
-       u_int                            px, py, cy, yy, ny, hsize;
+       u_int                            px, py, oldy, hsize;
 
        px = data->cx;
        hsize = screen_hsize(back_s);
        py = hsize + data->cy - data->oy;
+       oldy = data->cy;
 
        grid_reader_start(&gr, back_s->grid, px, py);
        grid_reader_cursor_right(&gr, 1, all);
        grid_reader_get_cursor(&gr, &px, &py);
-
-       /* Scroll down if we went off the visible screen. */
-       cy = py - hsize + data->oy;
-       yy = screen_size_y(back_s) - 1;
-       if (cy > yy)
-               ny = cy - yy;
-       else
-               ny = 0;
-       while (ny > 0) {
-         window_copy_cursor_down(wme, 1);
-         ny--;
-       }
-       if (cy > yy)
-               window_copy_update_cursor(wme, px, yy);
-       else
-               window_copy_update_cursor(wme, px, cy);
-       if (window_copy_update_selection(wme, 1, 0))
-               window_copy_redraw_lines(wme, data->cy, 1);
+       window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
+           data->oy, oldy, px, py, 0);
 }
 
 static void
@@ -4422,23 +4363,19 @@ window_copy_cursor_jump(struct window_mode_entry *wme)
 {
        struct window_copy_mode_data    *data = wme->data;
        struct screen                   *back_s = data->backing;
-       struct grid_cell                 gc;
-       u_int                            px, py, xx;
+       struct grid_reader               gr;
+       u_int                            px, py, oldy, hsize;
 
        px = data->cx + 1;
-       py = screen_hsize(back_s) + data->cy - data->oy;
-       xx = window_copy_find_length(wme, py);
+       hsize = screen_hsize(back_s);
+       py = hsize + data->cy - data->oy;
+       oldy = data->cy;
 
-       while (px < xx) {
-               grid_get_cell(back_s->grid, px, py, &gc);
-               if (!(gc.flags & GRID_FLAG_PADDING) &&
-                   gc.data.size == 1 && *gc.data.data == data->jumpchar) {
-                       window_copy_update_cursor(wme, px, data->cy);
-                       if (window_copy_update_selection(wme, 1, 0))
-                               window_copy_redraw_lines(wme, data->cy, 1);
-                       return;
-               }
-               px++;
+       grid_reader_start(&gr, back_s->grid, px, py);
+       if (grid_reader_cursor_jump(&gr, data->jumpchar)) {
+               grid_reader_get_cursor(&gr, &px, &py);
+               window_copy_acquire_cursor_down(wme, hsize,
+                   screen_size_y(back_s), data->oy, oldy, px, py, 0);
        }
 }
 
@@ -4447,27 +4384,22 @@ window_copy_cursor_jump_back(struct window_mode_entry *wme)
 {
        struct window_copy_mode_data    *data = wme->data;
        struct screen                   *back_s = data->backing;
-       struct grid_cell                 gc;
-       u_int                            px, py;
+       struct grid_reader               gr;
+       u_int                            px, py, oldy, hsize;
 
        px = data->cx;
-       py = screen_hsize(back_s) + data->cy - data->oy;
+       hsize = screen_hsize(back_s);
+       py = hsize + data->cy - data->oy;
+       oldy = data->cy;
 
        if (px > 0)
                px--;
 
-       for (;;) {
-               grid_get_cell(back_s->grid, px, py, &gc);
-               if (!(gc.flags & GRID_FLAG_PADDING) &&
-                   gc.data.size == 1 && *gc.data.data == data->jumpchar) {
-                       window_copy_update_cursor(wme, px, data->cy);
-                       if (window_copy_update_selection(wme, 1, 0))
-                               window_copy_redraw_lines(wme, data->cy, 1);
-                       return;
-               }
-               if (px == 0)
-                       break;
-               px--;
+       grid_reader_start(&gr, back_s->grid, px, py);
+       if (grid_reader_cursor_jump_back(&gr, data->jumpchar)) {
+               grid_reader_get_cursor(&gr, &px, &py);
+               window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px,
+                   py);
        }
 }
 
@@ -4476,23 +4408,20 @@ window_copy_cursor_jump_to(struct window_mode_entry *wme)
 {
        struct window_copy_mode_data    *data = wme->data;
        struct screen                   *back_s = data->backing;
-       struct grid_cell                 gc;
-       u_int                            px, py, xx;
+       struct grid_reader               gr;
+       u_int                            px, py, oldy, hsize;
 
        px = data->cx + 2;
-       py = screen_hsize(back_s) + data->cy - data->oy;
-       xx = window_copy_find_length(wme, py);
+       hsize = screen_hsize(back_s);
+       py = hsize + data->cy - data->oy;
+       oldy = data->cy;
 
-       while (px < xx) {
-               grid_get_cell(back_s->grid, px, py, &gc);
-               if (!(gc.flags & GRID_FLAG_PADDING) &&
-                   gc.data.size == 1 && *gc.data.data == data->jumpchar) {
-                       window_copy_update_cursor(wme, px - 1, data->cy);
-                       if (window_copy_update_selection(wme, 1, 0))
-                               window_copy_redraw_lines(wme, data->cy, 1);
-                       return;
-               }
-               px++;
+       grid_reader_start(&gr, back_s->grid, px, py);
+       if (grid_reader_cursor_jump(&gr, data->jumpchar)) {
+               grid_reader_cursor_left(&gr);
+               grid_reader_get_cursor(&gr, &px, &py);
+               window_copy_acquire_cursor_down(wme, hsize,
+                   screen_size_y(back_s), data->oy, oldy, px, py, 0);
        }
 }
 
@@ -4501,11 +4430,13 @@ window_copy_cursor_jump_to_back(struct window_mode_entry *wme)
 {
        struct window_copy_mode_data    *data = wme->data;
        struct screen                   *back_s = data->backing;
-       struct grid_cell                 gc;
-       u_int                            px, py;
+       struct grid_reader               gr;
+       u_int                            px, py, oldy, hsize;
 
        px = data->cx;
-       py = screen_hsize(back_s) + data->cy - data->oy;
+       hsize = screen_hsize(back_s);
+       py = hsize + data->cy - data->oy;
+       oldy = data->cy;
 
        if (px > 0)
                px--;
@@ -4513,18 +4444,12 @@ window_copy_cursor_jump_to_back(struct window_mode_entry *wme)
        if (px > 0)
                px--;
 
-       for (;;) {
-               grid_get_cell(back_s->grid, px, py, &gc);
-               if (!(gc.flags & GRID_FLAG_PADDING) &&
-                   gc.data.size == 1 && *gc.data.data == data->jumpchar) {
-                       window_copy_update_cursor(wme, px + 1, data->cy);
-                       if (window_copy_update_selection(wme, 1, 0))
-                               window_copy_redraw_lines(wme, data->cy, 1);
-                       return;
-               }
-               if (px == 0)
-                       break;
-               px--;
+       grid_reader_start(&gr, back_s->grid, px, py);
+       if (grid_reader_cursor_jump_back(&gr, data->jumpchar)) {
+               grid_reader_cursor_right(&gr, 1, 0);
+               grid_reader_get_cursor(&gr, &px, &py);
+               window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px,
+                   py);
        }
 }
 
@@ -4535,7 +4460,7 @@ window_copy_cursor_next_word(struct window_mode_entry *wme,
        struct window_copy_mode_data    *data = wme->data;
        struct screen                   *back_s = data->backing;
        struct grid_reader               gr;
-       u_int                            px, py, cy, oldy, yy, ny, nd, hsize;
+       u_int                            px, py, oldy, hsize;
 
        px = data->cx;
        hsize = screen_hsize(back_s);
@@ -4545,28 +4470,8 @@ window_copy_cursor_next_word(struct window_mode_entry *wme,
        grid_reader_start(&gr, back_s->grid, px, py);
        grid_reader_cursor_next_word(&gr, separators);
        grid_reader_get_cursor(&gr, &px, &py);
-
-       /* Scroll down if we went off the visible screen. */
-       cy = py - hsize + data->oy;
-       yy = screen_size_y(back_s) - 1;
-       if (cy > yy) {
-               ny = cy - yy;
-               oldy = yy;
-               nd = 1;
-       } else {
-               ny = 0;
-               nd = cy - oldy + 1;
-       }
-       while (ny > 0) {
-         window_copy_cursor_down(wme, 1);
-         ny--;
-       }
-       if (cy > yy)
-               window_copy_update_cursor(wme, px, yy);
-       else
-               window_copy_update_cursor(wme, px, cy);
-       if (window_copy_update_selection(wme, 1, 0))
-               window_copy_redraw_lines(wme, oldy, nd);
+       window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
+           data->oy, oldy, px, py, 0);
 }
 
 static void
@@ -4627,7 +4532,7 @@ window_copy_cursor_next_word_end(struct window_mode_entry *wme,
        struct options                  *oo = wp->window->options;
        struct screen                   *back_s = data->backing;
        struct grid_reader               gr;
-       u_int                            px, py, cy, oldy, yy, ny, nd, hsize;
+       u_int                            px, py, oldy, hsize;
        int                              keys;
 
        px = data->cx;
@@ -4643,28 +4548,8 @@ window_copy_cursor_next_word_end(struct window_mode_entry *wme,
        if (keys == MODEKEY_VI)
                grid_reader_cursor_left(&gr);
        grid_reader_get_cursor(&gr, &px, &py);
-
-       /* Scroll down if we went off the visible screen. */
-       cy = py - hsize + data->oy;
-       yy = screen_size_y(back_s) - 1;
-       if (cy > yy) {
-               ny = cy - yy;
-               oldy = yy;
-               nd = 1;
-       } else {
-               ny = 0;
-               nd = cy - oldy + 1;
-       }
-       while (ny > 0) {
-         window_copy_cursor_down(wme, 1);
-         ny--;
-       }
-       if (cy > yy)
-               window_copy_update_cursor(wme, px, yy);
-       else
-               window_copy_update_cursor(wme, px, cy);
-       if (window_copy_update_selection(wme, 1, no_reset))
-               window_copy_redraw_lines(wme, oldy, nd);
+       window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
+           data->oy, oldy, px, py, no_reset);
 }
 
 /* Compute the previous place where a word begins. */
@@ -4721,7 +4606,7 @@ window_copy_cursor_previous_word(struct window_mode_entry *wme,
        struct window_copy_mode_data    *data = wme->data;
        struct screen                   *back_s = data->backing;
        struct grid_reader               gr;
-       u_int                            px, py, cy, oldy, yy, ny, nd, hsize;
+       u_int                            px, py, oldy, hsize;
 
        px = data->cx;
        hsize = screen_hsize(back_s);
@@ -4731,25 +4616,7 @@ window_copy_cursor_previous_word(struct window_mode_entry *wme,
        grid_reader_start(&gr, back_s->grid, px, py);
        grid_reader_cursor_previous_word(&gr, separators, already);
        grid_reader_get_cursor(&gr, &px, &py);
-
-       /* Scroll up if we went off the visible screen. */
-       yy = hsize - data->oy;
-       if (py < yy) {
-               ny = yy - py;
-               cy = 0;
-               nd = 1;
-       } else {
-               ny = 0;
-               cy = py - yy;
-               nd = oldy - cy + 1;
-       }
-       while (ny > 0) {
-               window_copy_cursor_up(wme, 1);
-               ny--;
-       }
-       window_copy_update_cursor(wme, px, cy);
-       if (window_copy_update_selection(wme, 1, 0))
-               window_copy_redraw_lines(wme, data->cy, nd);
+       window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py);
 }
 
 static void
@@ -5000,3 +4867,58 @@ window_copy_jump_to_mark(struct window_mode_entry *wme)
        window_copy_update_selection(wme, 0, 0);
        window_copy_redraw_screen(wme);
 }
+
+/* Scroll up if the cursor went off the visible screen. */
+static void
+window_copy_acquire_cursor_up(struct window_mode_entry *wme, u_int hsize,
+    u_int oy, u_int oldy, u_int px, u_int py)
+{
+       u_int   cy, yy, ny, nd;
+
+       yy = hsize - oy;
+       if (py < yy) {
+               ny = yy - py;
+               cy = 0;
+               nd = 1;
+       } else {
+               ny = 0;
+               cy = py - yy;
+               nd = oldy - cy + 1;
+       }
+       while (ny > 0) {
+               window_copy_cursor_up(wme, 1);
+               ny--;
+       }
+       window_copy_update_cursor(wme, px, cy);
+       if (window_copy_update_selection(wme, 1, 0))
+               window_copy_redraw_lines(wme, cy, nd);
+}
+
+/* Scroll down if the cursor went off the visible screen. */
+static void
+window_copy_acquire_cursor_down(struct window_mode_entry *wme, u_int hsize,
+    u_int sy, u_int oy, u_int oldy, u_int px, u_int py, int no_reset)
+{
+       u_int   cy, yy, ny, nd;
+
+       cy = py - hsize + oy;
+       yy = sy - 1;
+       if (cy > yy) {
+               ny = cy - yy;
+               oldy = yy;
+               nd = 1;
+       } else {
+               ny = 0;
+               nd = cy - oldy + 1;
+       }
+       while (ny > 0) {
+         window_copy_cursor_down(wme, 1);
+         ny--;
+       }
+       if (cy > yy)
+               window_copy_update_cursor(wme, px, yy);
+       else
+               window_copy_update_cursor(wme, px, cy);
+       if (window_copy_update_selection(wme, 1, no_reset))
+               window_copy_redraw_lines(wme, oldy, nd);
+}