When the EOL command is used, vim tracks that the EOL is the cursor
position, not the cursor that the EOL happened to occur on for the line
where the motion was given. To keep track of this, an EOL flag is added
to indicate this state. Most motions will clear this state, but a few
such as block mode toggle, up, down and right (on the last line)
preserve this state.

This change has the biggest impact on the block selection mode and
navigation (the cursor "sticks" to the end of the line rather than a
column when moving up and down). Block selection mode already has a "end
of screen" state, so no extra state is tracked for it.
---
 window-copy.c | 39 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 34 insertions(+), 5 deletions(-)

diff --git a/window-copy.c b/window-copy.c
index 325c29f..ee6a2e8 100644
--- a/window-copy.c
+++ b/window-copy.c
@@ -131,6 +131,7 @@ struct window_copy_mode_data {
        u_int           sely;
 
        u_int           rectflag; /* are we in rectangle copy mode? */
+       u_int           eolflag; /* are we at the end of the line? */
 
        u_int           cx;
        u_int           cy;
@@ -169,6 +170,7 @@ window_copy_init(struct window_pane *wp)
        data->backing_written = 0;
 
        data->rectflag = 0;
+       data->eolflag = 0;
 
        data->inputtype = WINDOW_COPY_OFF;
        data->inputprompt = NULL;
@@ -365,11 +367,18 @@ window_copy_key(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;
-       u_int                            n;
+       u_int                            n, old_eolflag;
        int                              np, keys;
        enum mode_key_cmd                cmd;
        const char                      *arg;
 
+       /* By default, all motions break the cursor from the sticky "eol"
+        * position. Only select commands preserve the state (up, down, the eol
+        * motion itself and right (which may clear it on its own). These
+        * commands should restore the eolflag as needed. */
+       old_eolflag = data->eolflag;
+       data->eolflag = 0;
+
        np = data->numprefix;
        if (np <= 0)
                np = 1;
@@ -420,22 +429,29 @@ window_copy_key(struct window_pane *wp, struct session 
*sess, int key)
                        window_copy_cursor_left(wp);
                break;
        case MODEKEYCOPY_RIGHT:
+               /* If the EOL flag needs clearing, window_copy_cursor_right
+                * clears it. */
+               data->eolflag = old_eolflag;
                for (; np != 0; np--)
                        window_copy_cursor_right(wp);
                break;
        case MODEKEYCOPY_UP:
+               data->eolflag = old_eolflag;
                for (; np != 0; np--)
                        window_copy_cursor_up(wp, 0);
                break;
        case MODEKEYCOPY_DOWN:
+               data->eolflag = old_eolflag;
                for (; np != 0; np--)
                        window_copy_cursor_down(wp, 0);
                break;
        case MODEKEYCOPY_SCROLLUP:
+               data->eolflag = old_eolflag;
                for (; np != 0; np--)
                        window_copy_cursor_up(wp, 1);
                break;
        case MODEKEYCOPY_SCROLLDOWN:
+               data->eolflag = old_eolflag;
                for (; np != 0; np--)
                        window_copy_cursor_down(wp, 1);
                break;
@@ -559,6 +575,7 @@ window_copy_key(struct window_pane *wp, struct session 
*sess, int key)
                window_copy_cursor_back_to_indentation(wp);
                break;
        case MODEKEYCOPY_ENDOFLINE:
+               data->eolflag = 1;
                window_copy_cursor_end_of_line(wp);
                break;
        case MODEKEYCOPY_NEXTSPACE:
@@ -707,6 +724,7 @@ window_copy_key(struct window_pane *wp, struct session 
*sess, int key)
                }
                break;
        case MODEKEYCOPY_RECTANGLETOGGLE:
+               data->eolflag = old_eolflag;
                window_copy_rectangle_toggle(wp);
                break;
        default:
@@ -1600,8 +1618,13 @@ window_copy_cursor_end_of_line(struct window_pane *wp)
        px = window_copy_find_length(wp, py);
 
        if (data->cx == px) {
-               if (data->screen.sel.flag && data->rectflag)
+               if (data->screen.sel.flag && data->rectflag) {
                        px = screen_size_x(back_s);
+                       /* The flag is reset here since we're not on the
+                        * end-of-line as defined by the text, but rather by
+                        * the screen. */
+                       data->eolflag = 0;
+               }
                if (gd->linedata[py].flags & GRID_LINE_WRAPPED) {
                        while (py < gd->sy + gd->hsize &&
                            gd->linedata[py].flags & GRID_LINE_WRAPPED) {
@@ -1660,8 +1683,10 @@ window_copy_cursor_right(struct window_pane *wp)
 
                /* If there is no line after the current line, there
                 * is no need to move to the start of the line. */
-               if (data->cy != py)
+               if (data->cy != py) {
+                       data->eolflag = 0;
                        window_copy_cursor_start_of_line(wp);
+               }
        } else {
                window_copy_update_cursor(wp, data->cx + 1, data->cy);
                if (window_copy_update_selection(wp))
@@ -1702,7 +1727,9 @@ window_copy_cursor_up(struct window_pane *wp, int 
scroll_only)
                }
        }
 
-       if (!data->screen.sel.flag || !data->rectflag) {
+       if (data->eolflag)
+               window_copy_cursor_end_of_line(wp);
+       else if (!data->screen.sel.flag || !data->rectflag) {
                py = screen_hsize(data->backing) + data->cy - data->oy;
                px = window_copy_find_length(wp, py);
                if ((data->cx >= data->lastsx && data->cx != px) ||
@@ -1736,7 +1763,9 @@ window_copy_cursor_down(struct window_pane *wp, int 
scroll_only)
                        window_copy_redraw_lines(wp, data->cy - 1, 2);
        }
 
-       if (!data->screen.sel.flag || !data->rectflag) {
+       if (data->eolflag)
+               window_copy_cursor_end_of_line(wp);
+       else if (!data->screen.sel.flag || !data->rectflag) {
                py = screen_hsize(data->backing) + data->cy - data->oy;
                px = window_copy_find_length(wp, py);
                if ((data->cx >= data->lastsx && data->cx != px) ||
-- 
1.8.2.1


------------------------------------------------------------------------------
This SF.net email is sponsored by Windows:

Build for Windows Store.

http://p.sf.net/sfu/windows-dev2dev
_______________________________________________
tmux-users mailing list
tmux-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tmux-users

Reply via email to