[PATCH] add keys for first/last item in a choose list
Hello and thanks for tmux! As a recovering screen user, I'm used to hitting or in the choose-window command so that I can warp the selected row to the first or last item in the list. For completeness, the patch adds some other key mappings in both vi and emacs mode that I think make sense. - Tor # # Patch adds support for warping to the first/last item in a choose list... # Index: tmux-1.8/mode-key.c === --- tmux-1.8.orig/mode-key.c 2013-02-24 04:42:49.0 -0800 +++ tmux-1.8/mode-key.c 2013-06-11 09:43:40.0 -0700 @@ -80,6 +80,8 @@ { MODEKEYCHOICE_DOWN, "down" }, { MODEKEYCHOICE_PAGEDOWN, "page-down" }, { MODEKEYCHOICE_PAGEUP, "page-up" }, + { MODEKEYCHOICE_FIRST, "first" }, + { MODEKEYCHOICE_LAST, "last" }, { MODEKEYCHOICE_SCROLLDOWN, "scroll-down" }, { MODEKEYCHOICE_SCROLLUP, "scroll-up" }, { MODEKEYCHOICE_STARTNUMBERPREFIX, "start-number-prefix" }, @@ -224,6 +226,12 @@ { KEYC_DOWN, 0, MODEKEYCHOICE_DOWN }, { KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN }, { KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP }, + { 'g', 0, MODEKEYCHOICE_FIRST }, + { 'G', 0, MODEKEYCHOICE_LAST }, + { KEYC_HOME,0, MODEKEYCHOICE_FIRST }, + { KEYC_END, 0, MODEKEYCHOICE_LAST }, + { KEYC_HOME | KEYC_CTRL,0, MODEKEYCHOICE_FIRST }, + { KEYC_END | KEYC_CTRL,0, MODEKEYCHOICE_LAST }, { KEYC_UP | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLUP }, { KEYC_UP, 0, MODEKEYCHOICE_UP }, { ' ', 0, MODEKEYCHOICE_TREE_TOGGLE }, @@ -366,6 +374,10 @@ { KEYC_DOWN, 0, MODEKEYCHOICE_DOWN }, { KEYC_NPAGE, 0, MODEKEYCHOICE_PAGEDOWN }, { KEYC_PPAGE, 0, MODEKEYCHOICE_PAGEUP }, + { KEYC_HOME,0, MODEKEYCHOICE_FIRST }, + { KEYC_END, 0, MODEKEYCHOICE_LAST }, + { '<' | KEYC_ESCAPE,0, MODEKEYCHOICE_FIRST }, + { '>' | KEYC_ESCAPE,0, MODEKEYCHOICE_LAST }, { KEYC_UP | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLUP }, { KEYC_UP, 0, MODEKEYCHOICE_UP }, { ' ', 0, MODEKEYCHOICE_TREE_TOGGLE }, Index: tmux-1.8/tmux.h === --- tmux-1.8.orig/tmux.h 2013-06-11 09:42:42.0 -0700 +++ tmux-1.8/tmux.h 2013-06-11 09:42:42.0 -0700 @@ -570,6 +570,8 @@ MODEKEYCHOICE_DOWN, MODEKEYCHOICE_PAGEDOWN, MODEKEYCHOICE_PAGEUP, + MODEKEYCHOICE_FIRST, + MODEKEYCHOICE_LAST, MODEKEYCHOICE_SCROLLDOWN, MODEKEYCHOICE_SCROLLUP, MODEKEYCHOICE_STARTNUMBERPREFIX, Index: tmux-1.8/window-choose.c === --- tmux-1.8.orig/window-choose.c 2013-03-17 07:03:37.0 -0700 +++ tmux-1.8/window-choose.c 2013-06-11 09:42:42.0 -0700 @@ -650,6 +650,19 @@ data->top = data->selected; window_choose_redraw_screen(wp); break; + case MODEKEYCHOICE_FIRST: +data->selected = 0; +data->top = 0; +window_choose_redraw_screen(wp); +break; + case MODEKEYCHOICE_LAST: +data->selected = items - 1; +if (screen_size_y(s) < items) { + data->top = items - screen_size_y(s); +} else + data->top = 0; +window_choose_redraw_screen(wp); +break; case MODEKEYCHOICE_BACKSPACE: input_len = strlen(data->input_str); if (input_len > 0) -- 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
[PATCH 5/6] Move to the indentation of a line on scrolling
When scrolling by page or half-page, vim moves to the first non-whitespace character of a line. Emulate the behavior in copy mode. --- window-copy.c | 4 1 file changed, 4 insertions(+) diff --git a/window-copy.c b/window-copy.c index ee6a2e8..17808b8 100644 --- a/window-copy.c +++ b/window-copy.c @@ -458,6 +458,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) case MODEKEYCOPY_PREVIOUSPAGE: for (; np != 0; np--) window_copy_pageup(wp); + window_copy_cursor_back_to_indentation(wp); break; case MODEKEYCOPY_NEXTPAGE: n = 1; @@ -471,6 +472,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) } window_copy_update_selection(wp); window_copy_redraw_screen(wp); + window_copy_cursor_back_to_indentation(wp); break; case MODEKEYCOPY_HALFPAGEUP: n = screen_size_y(s) / 2; @@ -482,6 +484,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) } window_copy_update_selection(wp); window_copy_redraw_screen(wp); + window_copy_cursor_back_to_indentation(wp); break; case MODEKEYCOPY_HALFPAGEDOWN: n = screen_size_y(s) / 2; @@ -493,6 +496,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key) } window_copy_update_selection(wp); window_copy_redraw_screen(wp); + window_copy_cursor_back_to_indentation(wp); break; case MODEKEYCOPY_TOPLINE: data->cx = 0; -- 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
[PATCH 6/6] Whitespace fixes
--- mode-key.c| 8 status.c | 2 +- window-copy.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mode-key.c b/mode-key.c index 2d6d468..1ed6d40 100644 --- a/mode-key.c +++ b/mode-key.c @@ -231,8 +231,8 @@ const struct mode_key_entry mode_key_vi_choice[] = { { KEYC_UP | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLUP }, { KEYC_UP, 0, MODEKEYCHOICE_UP }, { ' ', 0, MODEKEYCHOICE_TREE_TOGGLE }, - { KEYC_LEFT,0, MODEKEYCHOICE_TREE_COLLAPSE }, - { KEYC_RIGHT, 0, MODEKEYCHOICE_TREE_EXPAND }, + { KEYC_LEFT,0, MODEKEYCHOICE_TREE_COLLAPSE }, + { KEYC_RIGHT, 0, MODEKEYCHOICE_TREE_EXPAND }, { KEYC_LEFT | KEYC_CTRL,0, MODEKEYCHOICE_TREE_COLLAPSE_ALL }, { KEYC_RIGHT | KEYC_CTRL, 0, MODEKEYCHOICE_TREE_EXPAND_ALL }, @@ -373,8 +373,8 @@ const struct mode_key_entry mode_key_emacs_choice[] = { { KEYC_UP | KEYC_CTRL, 0, MODEKEYCHOICE_SCROLLUP }, { KEYC_UP, 0, MODEKEYCHOICE_UP }, { ' ', 0, MODEKEYCHOICE_TREE_TOGGLE }, - { KEYC_LEFT,0, MODEKEYCHOICE_TREE_COLLAPSE }, - { KEYC_RIGHT, 0, MODEKEYCHOICE_TREE_EXPAND }, + { KEYC_LEFT,0, MODEKEYCHOICE_TREE_COLLAPSE }, + { KEYC_RIGHT, 0, MODEKEYCHOICE_TREE_EXPAND }, { KEYC_LEFT | KEYC_CTRL,0, MODEKEYCHOICE_TREE_COLLAPSE_ALL }, { KEYC_RIGHT | KEYC_CTRL, 0, MODEKEYCHOICE_TREE_EXPAND_ALL }, diff --git a/status.c b/status.c index 351852e..a843507 100644 --- a/status.c +++ b/status.c @@ -143,7 +143,7 @@ status_set_window_at(struct client *c, u_int x) x += c->wlmouse; RB_FOREACH(wl, winlinks, &s->windows) { if (x < wl->status_width && - session_select(s, wl->idx) == 0) { + session_select(s, wl->idx) == 0) { server_redraw_session(s); } x -= wl->status_width + 1; diff --git a/window-copy.c b/window-copy.c index 17808b8..7e078bd 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1138,7 +1138,7 @@ window_copy_write_line( struct options *oo = &wp->window->options; struct grid_cell gc; char hdr[32]; - size_t last, xoff = 0, size = 0; + size_t last, xoff = 0, size = 0; window_mode_attrs(&gc, oo); -- 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
[PATCH 3/6] Don't loop in copy mode on first and last lines
Because we first move to the first column, then down, on the last line, the first column is to "the right" of the last column. To fix this, the current line is checked and if it changed, *then* the start of the line motion is used. Similar logic is done for the first line. --- window-copy.c | 17 +++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/window-copy.c b/window-copy.c index b8286e8..325c29f 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1622,10 +1622,16 @@ void window_copy_cursor_left(struct window_pane *wp) { struct window_copy_mode_data*data = wp->modedata; + u_intpy; if (data->cx == 0) { + /* Remember the current line. */ + py = data->cy; + window_copy_cursor_up(wp, 0); - window_copy_cursor_end_of_line(wp); + + if (data->cy != py) + window_copy_cursor_end_of_line(wp); } else { window_copy_update_cursor(wp, data->cx - 1, data->cy); if (window_copy_update_selection(wp)) @@ -1647,8 +1653,15 @@ window_copy_cursor_right(struct window_pane *wp) } if (data->cx >= px) { - window_copy_cursor_start_of_line(wp); + /* Remember the current line. */ + py = data->cy; + window_copy_cursor_down(wp, 0); + + /* 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) + window_copy_cursor_start_of_line(wp); } else { window_copy_update_cursor(wp, data->cx + 1, data->cy); if (window_copy_update_selection(wp)) -- 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
[PATCH 1/6] Implement 's', 'S', and 'C' vi keybindings
--- mode-key.c | 13 ++--- status.c | 3 +++ tmux.h | 3 +++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/mode-key.c b/mode-key.c index 94115eb..2d6d468 100644 --- a/mode-key.c +++ b/mode-key.c @@ -35,9 +35,7 @@ * * vi command mode is handled by having a mode flag in the struct which allows * two sets of bindings to be swapped between. A couple of editing commands - * (MODEKEYEDIT_SWITCHMODE, MODEKEYEDIT_SWITCHMODEAPPEND, - * MODEKEYEDIT_SWITCHMODEAPPENDLINE, and MODEKEYEDIT_SWITCHMODEBEGINLINE) - * are special-cased to do this. + * (any matching MODEKEYEDIT_SWITCHMODE*) are special-cased to do this. */ /* Edit keys command strings. */ @@ -67,6 +65,9 @@ const struct mode_key_cmdstr mode_key_cmdstr_edit[] = { { MODEKEYEDIT_SWITCHMODEAPPEND, "switch-mode-append" }, { MODEKEYEDIT_SWITCHMODEAPPENDLINE, "switch-mode-append-line" }, { MODEKEYEDIT_SWITCHMODEBEGINLINE, "switch-mode-begin-line" }, + { MODEKEYEDIT_SWITCHMODECHANGELINE, "switch-mode-change-line" }, + { MODEKEYEDIT_SWITCHMODESUBSTITUTE, "switch-mode-substitute" }, + { MODEKEYEDIT_SWITCHMODESUBSTITUTELINE, "switch-mode-substitute-line" }, { MODEKEYEDIT_TRANSPOSECHARS, "transpose-chars" }, { 0, NULL } @@ -166,9 +167,11 @@ const struct mode_key_entry mode_key_vi_edit[] = { { '0', 1, MODEKEYEDIT_STARTOFLINE }, { 'A', 1, MODEKEYEDIT_SWITCHMODEAPPENDLINE }, { 'B', 1, MODEKEYEDIT_PREVIOUSSPACE }, + { 'C', 1, MODEKEYEDIT_SWITCHMODECHANGELINE }, { 'D', 1, MODEKEYEDIT_DELETETOENDOFLINE }, { 'E', 1, MODEKEYEDIT_NEXTSPACEEND }, { 'I', 1, MODEKEYEDIT_SWITCHMODEBEGINLINE }, + { 'S', 1, MODEKEYEDIT_SWITCHMODESUBSTITUTELINE }, { 'W', 1, MODEKEYEDIT_NEXTSPACE }, { 'X', 1, MODEKEYEDIT_BACKSPACE }, { '\003' /* C-c */, 1, MODEKEYEDIT_CANCEL }, @@ -185,6 +188,7 @@ const struct mode_key_entry mode_key_vi_edit[] = { { 'k', 1, MODEKEYEDIT_HISTORYUP }, { 'l', 1, MODEKEYEDIT_CURSORRIGHT }, { 'p', 1, MODEKEYEDIT_PASTE }, + { 's', 1, MODEKEYEDIT_SWITCHMODESUBSTITUTE }, { 'w', 1, MODEKEYEDIT_NEXTWORD }, { 'x', 1, MODEKEYEDIT_DELETE }, { KEYC_BSPACE, 1, MODEKEYEDIT_BACKSPACE }, @@ -545,6 +549,9 @@ mode_key_lookup(struct mode_key_data *mdata, int key, const char **arg) case MODEKEYEDIT_SWITCHMODEAPPEND: case MODEKEYEDIT_SWITCHMODEAPPENDLINE: case MODEKEYEDIT_SWITCHMODEBEGINLINE: + case MODEKEYEDIT_SWITCHMODECHANGELINE: + case MODEKEYEDIT_SWITCHMODESUBSTITUTE: + case MODEKEYEDIT_SWITCHMODESUBSTITUTELINE: mdata->mode = 1 - mdata->mode; /* FALLTHROUGH */ default: diff --git a/status.c b/status.c index 385ec8e..de56750 100644 --- a/status.c +++ b/status.c @@ -1099,6 +1099,7 @@ status_prompt_key(struct client *c, int key) } break; case MODEKEYEDIT_DELETE: + case MODEKEYEDIT_SWITCHMODESUBSTITUTE: if (c->prompt_index != size) { memmove(c->prompt_buffer + c->prompt_index, c->prompt_buffer + c->prompt_index + 1, @@ -1107,11 +1108,13 @@ status_prompt_key(struct client *c, int key) } break; case MODEKEYEDIT_DELETELINE: + case MODEKEYEDIT_SWITCHMODESUBSTITUTELINE: *c->prompt_buffer = '\0'; c->prompt_index = 0; c->flags |= CLIENT_STATUS; break; case MODEKEYEDIT_DELETETOENDOFLINE: + case MODEKEYEDIT_SWITCHMODECHANGELINE: if (c->prompt_index < size) { c->prompt_buffer[c->prompt_index] = '\0'; c->flags |= CLIENT_STATUS; diff --git a/tmux.h b/tmux.h index 9ab9f58..3ae4195 100644 --- a/tmux.h +++ b/tmux.h @@ -544,6 +544,9 @@ enum mode_key_cmd { MODEKEYEDIT_SWITCHMODEAPPEND, MODEKEYEDIT_SWITCHMODEAPPENDLINE, MODEKEYEDIT_SWITCHMODEBEGINLINE, + MODEKEYEDIT_SWITCHMODECHANGELINE, + MODEKEYEDIT_SWITCHMODESUBSTITUTE, + MODEKEYEDIT_SWITCHMODESUBSTITUTELINE, MODEKEYEDIT_TRANSPOSECHARS, /* Menu (choice) keys. */ -- 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
[PATCH 0/6] Various vi-ish patches
This patchset contains various fixes and changes to behave more like vi (commands referenced by their vi keybindings since that's what I'm familiar with). The patches are fairly distinct (though the EOL tracking should go after the looping fix). I have done light spot testing, but will be using them in my local tmux build to further work them. Fixes: - Backs up a character with the 'e' and 'E' motions to match vi if the vi keybindings are selected in the statusbar and copy mode. - Looping when moving left on the first line and right on the last line in copy mode. Features: - New 's', 'S', and 'C' commands when editing on the status line. These commands enter insert mode while replacing the current character, the entire line, and the text to the end of the line, respectively. I do not think that emacs has equivalents of these since they are normal mode commands (C-k for 'S' behavior is already bound). Behavior changes: - EOL tracking in copy mode. When '$' is used when navigating in copy mode to go the the end of a line, this fact is forgotten when moving up and down between lines. Any other motion seems to reset this flag in vi, so that behavior is copied here. - Moving to the "front" of the line on page-wise motions. When moving page-wise, the cursor can end up hanging off the end of the text of the new line. Vim seems to do '^' after page-wise movements which seems to me to be a good compromise. If this should be guarded by a rectflag check or only happen for vi keybindings, that can be changed. Nits: - Some whitespace errors I came across while implementing the changes (take as you see fit). Ben Boeckel (6): Implement 's', 'S', and 'C' vi keybindings Act like vi with word motions in the statusline Don't loop in copy mode on first and last lines Implement EOL tracking Move to the indentation of a line on scrolling Whitespace fixes mode-key.c| 21 --- status.c | 10 - tmux.h| 3 +++ window-copy.c | 66 --- 4 files changed, 85 insertions(+), 15 deletions(-) -- 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
[PATCH 2/6] Act like vi with word motions in the statusline
Vi uses the end-of-word character as the cursor location after an 'e' or 'E' motion. Once the motion is complete, we back up one character from where emacs ends up (one-past-the-word). --- status.c | 5 + window-copy.c | 6 ++ 2 files changed, 11 insertions(+) diff --git a/status.c b/status.c index de56750..351852e 100644 --- a/status.c +++ b/status.c @@ -1193,6 +1193,11 @@ status_prompt_key(struct client *c, int key) break; } + /* Back up to the end-of-word like vi. */ + if ((MODEKEY_VI == options_get_number(oo, "status-keys")) && + c->prompt_index) + c->prompt_index--; + c->flags |= CLIENT_STATUS; break; case MODEKEYEDIT_PREVIOUSSPACE: diff --git a/window-copy.c b/window-copy.c index 51a8f10..b8286e8 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1894,6 +1894,7 @@ void window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators) { struct window_copy_mode_data*data = wp->modedata; + struct options *oo = &wp->window->options; struct screen *back_s = data->backing; u_intpx, py, xx, yy; int expected = 1; @@ -1927,6 +1928,11 @@ window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators) expected = !expected; } while (expected == 0); + /* Back up to the end-of-word like vi. */ + if ((MODEKEY_VI == options_get_number(oo, "status-keys")) && + px) + --px; + window_copy_update_cursor(wp, px, data->cy); if (window_copy_update_selection(wp)) window_copy_redraw_lines(wp, data->cy, 1); -- 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
[PATCH 4/6] Implement EOL tracking
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_intn; + u_intn, old_eolflag; int np, keys; enum mode_key_cmdcmd; 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