There currently are a number of differences between tmux's jump commands
[fFtT,;] in copy mode and the behavior of the corresponding keys in vi:

1. The repeat count is not reset after a jump with [fFtT], but it is
   reset after the `repeat movement' keys [;,].  For example, in tmux
   `3fa;;' jumps to the seventh (3+3+1) occurrence of `a' whereas vi
   would jump to the fifth (3+1+1).

2. The repeat count to [tT] has no effect: the cursor gets stuck in
   front of the first match and the count is then decremented to zero
   with no further movement.  In vi, t and T are equivalent to f and F
   plus one step back in the direction of the original cursor position. 

3. If the repeat count for [fF] exceeds the number of matching
   characters in the direction of the movement, the cursor is moved to
   the last match.  vi wouldn't move the cursor at all.


This patch does a number of things (the first two are cosmetic):

a. Rename WINDOW_COPY_JUMPFORWARD to WINDOW_COPY_JUMP in order to match
   the corresponding MODEKEYCOPY_JUMP and window_copy_cursor_jump()
   more closely.  Similarly for WINDOW_COPY_JUMPTOFORWARD.

b. Replace a few if .. else if .. snakes by equivalent switch
   statements. 

c. Fix 1. by setting data->numprefix = -1 after a jump.

d. Take care of the repeat count inside the jump{,_back} routines to be
   able to fix 3. without too much hassle.  Use the same logic inside
   window_copy_cursor_jump() and window_copy_cursor_jump_back().

e. Eliminate essentially duplicated code by handling the jump_to{,_back}
   movements by combining jump{,_back} with cursor_{left,right}.  To do
   so, add a return value to jump{,_back} indicating success (cursor
   movement).  This fixes 2.


In case the current behavior in 3. should be desired in emacs mode, I
have an additional diff ready for that.


Index: window-copy.c
===================================================================
RCS file: /cvs/src/usr.bin/tmux/window-copy.c,v
retrieving revision 1.120
diff -u -p -r1.120 window-copy.c
--- window-copy.c       9 Nov 2014 15:13:01 -0000       1.120
+++ window-copy.c       10 Nov 2014 11:14:42 -0000
@@ -73,8 +73,8 @@ void  window_copy_cursor_left(struct wind
 void   window_copy_cursor_right(struct window_pane *);
 void   window_copy_cursor_up(struct window_pane *, int);
 void   window_copy_cursor_down(struct window_pane *, int);
-void   window_copy_cursor_jump(struct window_pane *);
-void   window_copy_cursor_jump_back(struct window_pane *);
+int    window_copy_cursor_jump(struct window_pane *);
+int    window_copy_cursor_jump_back(struct window_pane *);
 void   window_copy_cursor_jump_to(struct window_pane *);
 void   window_copy_cursor_jump_to_back(struct window_pane *);
 void   window_copy_cursor_next_word(struct window_pane *, const char *);
@@ -99,9 +99,9 @@ enum window_copy_input_type {
        WINDOW_COPY_NUMERICPREFIX,
        WINDOW_COPY_SEARCHUP,
        WINDOW_COPY_SEARCHDOWN,
-       WINDOW_COPY_JUMPFORWARD,
+       WINDOW_COPY_JUMP,
        WINDOW_COPY_JUMPBACK,
-       WINDOW_COPY_JUMPTOFORWARD,
+       WINDOW_COPY_JUMPTO,
        WINDOW_COPY_JUMPTOBACK,
        WINDOW_COPY_GOTOLINE,
 };
@@ -375,46 +375,52 @@ window_copy_key(struct window_pane *wp, 
        enum mode_key_cmd                cmd;
        const char                      *arg, *ss;
 
-       np = data->numprefix;
-       if (np <= 0)
-               np = 1;
-
-       if (data->inputtype == WINDOW_COPY_JUMPFORWARD ||
-           data->inputtype == WINDOW_COPY_JUMPBACK ||
-           data->inputtype == WINDOW_COPY_JUMPTOFORWARD ||
-           data->inputtype == WINDOW_COPY_JUMPTOBACK) {
+       switch (data->inputtype) {
+       case WINDOW_COPY_OFF:
+               break;
+       case WINDOW_COPY_JUMP:
+       case WINDOW_COPY_JUMPBACK:
+       case WINDOW_COPY_JUMPTO:
+       case WINDOW_COPY_JUMPTOBACK:
                /* Ignore keys with modifiers. */
                if ((key & KEYC_MASK_MOD) == 0) {
                        data->jumpchar = key;
-                       if (data->inputtype == WINDOW_COPY_JUMPFORWARD) {
-                               for (; np != 0; np--)
-                                       window_copy_cursor_jump(wp);
-                       } else if (data->inputtype == WINDOW_COPY_JUMPBACK) {
-                               for (; np != 0; np--)
-                                       window_copy_cursor_jump_back(wp);
-                       } else if (data->inputtype == 
WINDOW_COPY_JUMPTOFORWARD) {
-                               for (; np != 0; np--)
-                                       window_copy_cursor_jump_to(wp);
-                       } else if (data->inputtype == WINDOW_COPY_JUMPTOBACK) {
-                               for (; np != 0; np--)
-                                       window_copy_cursor_jump_to_back(wp);
+                       switch (data->inputtype) {
+                       case WINDOW_COPY_JUMP:
+                               (void)window_copy_cursor_jump(wp);
+                               break;
+                       case WINDOW_COPY_JUMPBACK:
+                               (void)window_copy_cursor_jump_back(wp);
+                               break;
+                       case WINDOW_COPY_JUMPTO:
+                               window_copy_cursor_jump_to(wp);
+                               break;
+                       case WINDOW_COPY_JUMPTOBACK:
+                               window_copy_cursor_jump_to_back(wp);
+                               break;
                        }
                }
                data->jumptype = data->inputtype;
                data->inputtype = WINDOW_COPY_OFF;
+               data->numprefix = -1;
                window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
                return;
-       } else if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) {
+       case WINDOW_COPY_NUMERICPREFIX:
                if (window_copy_key_numeric_prefix(wp, key) == 0)
                        return;
                data->inputtype = WINDOW_COPY_OFF;
                window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
-       } else if (data->inputtype != WINDOW_COPY_OFF) {
+               break;
+       default:
                if (window_copy_key_input(wp, key) != 0)
                        goto input_off;
                return;
        }
 
+       np = data->numprefix;
+       if (np <= 0)
+               np = 1;
+
        cmd = mode_key_lookup(&data->mdata, key, &arg);
        switch (cmd) {
        case MODEKEYCOPY_APPENDSELECTION:
@@ -611,42 +617,44 @@ window_copy_key(struct window_pane *wp, 
                for (; np != 0; np--)
                        window_copy_cursor_previous_word(wp, word_separators);
                break;
-       case MODEKEYCOPY_JUMP:
-               data->inputtype = WINDOW_COPY_JUMPFORWARD;
-               data->inputprompt = "Jump Forward";
-               *data->inputstr = '\0';
-               window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
-               return; /* skip numprefix reset */
        case MODEKEYCOPY_JUMPAGAIN:
-               if (data->jumptype == WINDOW_COPY_JUMPFORWARD) {
-                       for (; np != 0; np--)
-                               window_copy_cursor_jump(wp);
-               } else if (data->jumptype == WINDOW_COPY_JUMPBACK) {
-                       for (; np != 0; np--)
-                               window_copy_cursor_jump_back(wp);
-               } else if (data->jumptype == WINDOW_COPY_JUMPTOFORWARD) {
-                       for (; np != 0; np--)
-                               window_copy_cursor_jump_to(wp);
-               } else if (data->jumptype == WINDOW_COPY_JUMPTOBACK) {
-                       for (; np != 0; np--)
-                               window_copy_cursor_jump_to_back(wp);
+               switch (data->jumptype) {
+               case WINDOW_COPY_JUMP:
+                       (void)window_copy_cursor_jump(wp);
+                       break;
+               case WINDOW_COPY_JUMPBACK:
+                       (void)window_copy_cursor_jump_back(wp);
+                       break;
+               case WINDOW_COPY_JUMPTO:
+                       window_copy_cursor_jump_to(wp);
+                       break;
+               case WINDOW_COPY_JUMPTOBACK:
+                       window_copy_cursor_jump_to_back(wp);
+                       break;
                }
                break;
        case MODEKEYCOPY_JUMPREVERSE:
-               if (data->jumptype == WINDOW_COPY_JUMPFORWARD) {
-                       for (; np != 0; np--)
-                               window_copy_cursor_jump_back(wp);
-               } else if (data->jumptype == WINDOW_COPY_JUMPBACK) {
-                       for (; np != 0; np--)
-                               window_copy_cursor_jump(wp);
-               } else if (data->jumptype == WINDOW_COPY_JUMPTOFORWARD) {
-                       for (; np != 0; np--)
-                               window_copy_cursor_jump_to_back(wp);
-               } else if (data->jumptype == WINDOW_COPY_JUMPTOBACK) {
-                       for (; np != 0; np--)
-                               window_copy_cursor_jump_to(wp);
+               switch (data->jumptype) {
+               case WINDOW_COPY_JUMP:
+                       (void)window_copy_cursor_jump_back(wp);
+                       break;
+               case WINDOW_COPY_JUMPBACK:
+                       (void)window_copy_cursor_jump(wp);
+                       break;
+               case WINDOW_COPY_JUMPTO:
+                       window_copy_cursor_jump_to_back(wp);
+                       break;
+               case WINDOW_COPY_JUMPTOBACK:
+                       window_copy_cursor_jump_to(wp);
+                       break;
                }
                break;
+       case MODEKEYCOPY_JUMP:
+               data->inputtype = WINDOW_COPY_JUMP;
+               data->inputprompt = "Jump Forward";
+               *data->inputstr = '\0';
+               window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
+               return; /* skip numprefix reset */
        case MODEKEYCOPY_JUMPBACK:
                data->inputtype = WINDOW_COPY_JUMPBACK;
                data->inputprompt = "Jump Back";
@@ -654,7 +662,7 @@ window_copy_key(struct window_pane *wp, 
                window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
                return; /* skip numprefix reset */
        case MODEKEYCOPY_JUMPTO:
-               data->inputtype = WINDOW_COPY_JUMPTOFORWARD;
+               data->inputtype = WINDOW_COPY_JUMPTO;
                data->inputprompt = "Jump To";
                *data->inputstr = '\0';
                window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
@@ -678,9 +686,9 @@ window_copy_key(struct window_pane *wp, 
                switch (data->searchtype) {
                case WINDOW_COPY_OFF:
                case WINDOW_COPY_GOTOLINE:
-               case WINDOW_COPY_JUMPFORWARD:
+               case WINDOW_COPY_JUMP:
                case WINDOW_COPY_JUMPBACK:
-               case WINDOW_COPY_JUMPTOFORWARD:
+               case WINDOW_COPY_JUMPTO:
                case WINDOW_COPY_JUMPTOBACK:
                case WINDOW_COPY_NAMEDBUFFER:
                case WINDOW_COPY_NUMERICPREFIX:
@@ -803,9 +811,9 @@ window_copy_key_input(struct window_pane
 
                switch (data->inputtype) {
                case WINDOW_COPY_OFF:
-               case WINDOW_COPY_JUMPFORWARD:
+               case WINDOW_COPY_JUMP:
                case WINDOW_COPY_JUMPBACK:
-               case WINDOW_COPY_JUMPTOFORWARD:
+               case WINDOW_COPY_JUMPTO:
                case WINDOW_COPY_JUMPTOBACK:
                case WINDOW_COPY_NUMERICPREFIX:
                        break;
@@ -1915,7 +1923,7 @@ window_copy_cursor_down(struct window_pa
                window_copy_cursor_start_of_line(wp);
 }
 
-void
+int
 window_copy_cursor_jump(struct window_pane *wp)
 {
        struct window_copy_mode_data    *data = wp->modedata;
@@ -1923,26 +1931,35 @@ window_copy_cursor_jump(struct window_pa
        const struct grid_cell          *gc;
        struct utf8_data                 ud;
        u_int                            px, py, xx;
+       int                              np;
+
+       if ((np = data->numprefix) <= 0)
+               np = 1;
 
-       px = data->cx + 1;
+       px = data->cx;
        py = screen_hsize(back_s) + data->cy - data->oy;
        xx = window_copy_find_length(wp, py);
 
-       while (px < xx) {
+       while (px < xx - 1 && np > 0) {
+               px++;
                gc = grid_peek_cell(back_s->grid, px, py);
                grid_cell_get(gc, &ud);
                if (!(gc->flags & GRID_FLAG_PADDING) &&
-                   ud.size == 1 && *ud.data == data->jumpchar) {
-                       window_copy_update_cursor(wp, px, data->cy);
-                       if (window_copy_update_selection(wp, 1))
-                               window_copy_redraw_lines(wp, data->cy, 1);
-                       return;
-               }
-               px++;
+                   ud.size == 1 && *ud.data == data->jumpchar)
+                       np--;
        }
+
+       if (np == 0) {
+               window_copy_update_cursor(wp, px, data->cy);
+               if (window_copy_update_selection(wp, 1))
+                       window_copy_redraw_lines(wp, data->cy, 1);
+               return (0);
+       }
+
+       return (1);
 }
 
-void
+int
 window_copy_cursor_jump_back(struct window_pane *wp)
 {
        struct window_copy_mode_data    *data = wp->modedata;
@@ -1950,85 +1967,45 @@ window_copy_cursor_jump_back(struct wind
        const struct grid_cell          *gc;
        struct utf8_data                 ud;
        u_int                            px, py;
+       int                              np;
+
+       if ((np = data->numprefix) <= 0)
+               np = 1;
 
        px = data->cx;
        py = screen_hsize(back_s) + data->cy - data->oy;
 
-       if (px > 0)
+       while (px > 0 && np > 0) {
                px--;
-
-       for (;;) {
                gc = grid_peek_cell(back_s->grid, px, py);
                grid_cell_get(gc, &ud);
                if (!(gc->flags & GRID_FLAG_PADDING) &&
-                   ud.size == 1 && *ud.data == data->jumpchar) {
-                       window_copy_update_cursor(wp, px, data->cy);
-                       if (window_copy_update_selection(wp, 1))
-                               window_copy_redraw_lines(wp, data->cy, 1);
-                       return;
-               }
-               if (px == 0)
-                       break;
-               px--;
+                   ud.size == 1 && *ud.data == data->jumpchar)
+                       np--;
+       }
+
+       if (np == 0) {
+               window_copy_update_cursor(wp, px, data->cy);
+               if (window_copy_update_selection(wp, 1))
+                       window_copy_redraw_lines(wp, data->cy, 1);
+               return (0);
        }
+
+       return (1);
 }
 
 void
 window_copy_cursor_jump_to(struct window_pane *wp)
 {
-       struct window_copy_mode_data    *data = wp->modedata;
-       struct screen                   *back_s = data->backing;
-       const struct grid_cell          *gc;
-       struct utf8_data                 ud;
-       u_int                            px, py, xx;
-
-       px = data->cx + 1;
-       py = screen_hsize(back_s) + data->cy - data->oy;
-       xx = window_copy_find_length(wp, py);
-
-       while (px < xx) {
-               gc = grid_peek_cell(back_s->grid, px, py);
-               grid_cell_get(gc, &ud);
-               if (!(gc->flags & GRID_FLAG_PADDING) &&
-                   ud.size == 1 && *ud.data == data->jumpchar) {
-                       window_copy_update_cursor(wp, px - 1, data->cy);
-                       if (window_copy_update_selection(wp, 1))
-                               window_copy_redraw_lines(wp, data->cy, 1);
-                       return;
-               }
-               px++;
-       }
+       if (window_copy_cursor_jump(wp) == 0)   /* cursor moved to the right */
+               window_copy_cursor_left(wp);    /* one step back */
 }
 
 void
 window_copy_cursor_jump_to_back(struct window_pane *wp)
 {
-       struct window_copy_mode_data    *data = wp->modedata;
-       struct screen                   *back_s = data->backing;
-       const struct grid_cell          *gc;
-       struct utf8_data                 ud;
-       u_int                            px, py;
-
-       px = data->cx;
-       py = screen_hsize(back_s) + data->cy - data->oy;
-
-       if (px > 0)
-               px--;
-
-       for (;;) {
-               gc = grid_peek_cell(back_s->grid, px, py);
-               grid_cell_get(gc, &ud);
-               if (!(gc->flags & GRID_FLAG_PADDING) &&
-                   ud.size == 1 && *ud.data == data->jumpchar) {
-                       window_copy_update_cursor(wp, px + 1, data->cy);
-                       if (window_copy_update_selection(wp, 1))
-                               window_copy_redraw_lines(wp, data->cy, 1);
-                       return;
-               }
-               if (px == 0)
-                       break;
-               px--;
-       }
+       if (window_copy_cursor_jump_back(wp) == 0)      /* cursor moved left */
+               window_copy_cursor_right(wp);           /* one step forward */
 }
 
 void

Reply via email to