1
0
mirror of https://github.com/tmate-io/tmate-ssh-server.git synced 2020-11-18 19:53:51 -08:00

Jump-forward, jump-backward in copy mode, based on vi's F and f commands.

This commit is contained in:
Micah Cowan 2010-03-16 17:30:58 +00:00
parent aa8f9018ea
commit 009d8d2ea7
4 changed files with 155 additions and 6 deletions

View File

@ -1,4 +1,4 @@
/* $Id: mode-key.c,v 1.45 2010-03-08 15:02:07 tcunha Exp $ */ /* $Id: mode-key.c,v 1.46 2010-03-16 17:30:58 micahcowan Exp $ */
/* /*
* Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2008 Nicholas Marriott <nicm@users.sourceforge.net>
@ -88,6 +88,10 @@ struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
{ MODEKEYCOPY_GOTOLINE, "goto-line" }, { MODEKEYCOPY_GOTOLINE, "goto-line" },
{ MODEKEYCOPY_HISTORYBOTTOM, "history-bottom" }, { MODEKEYCOPY_HISTORYBOTTOM, "history-bottom" },
{ MODEKEYCOPY_HISTORYTOP, "history-top" }, { MODEKEYCOPY_HISTORYTOP, "history-top" },
{ MODEKEYCOPY_JUMP, "jump-forward" },
{ MODEKEYCOPY_JUMPAGAIN, "jump-again" },
{ MODEKEYCOPY_JUMPREVERSE, "jump-reverse" },
{ MODEKEYCOPY_JUMPBACK, "jump-backward" },
{ MODEKEYCOPY_LEFT, "cursor-left" }, { MODEKEYCOPY_LEFT, "cursor-left" },
{ MODEKEYCOPY_RECTANGLETOGGLE, "rectangle-toggle" }, { MODEKEYCOPY_RECTANGLETOGGLE, "rectangle-toggle" },
{ MODEKEYCOPY_MIDDLELINE, "middle-line" }, { MODEKEYCOPY_MIDDLELINE, "middle-line" },
@ -177,6 +181,8 @@ struct mode_key_tree mode_key_tree_vi_choice;
const struct mode_key_entry mode_key_vi_copy[] = { const struct mode_key_entry mode_key_vi_copy[] = {
{ ' ', 0, MODEKEYCOPY_STARTSELECTION }, { ' ', 0, MODEKEYCOPY_STARTSELECTION },
{ '$', 0, MODEKEYCOPY_ENDOFLINE }, { '$', 0, MODEKEYCOPY_ENDOFLINE },
{ ',', 0, MODEKEYCOPY_JUMPREVERSE },
{ ';', 0, MODEKEYCOPY_JUMPAGAIN },
{ '/', 0, MODEKEYCOPY_SEARCHDOWN }, { '/', 0, MODEKEYCOPY_SEARCHDOWN },
{ '0', 0, MODEKEYCOPY_STARTOFLINE }, { '0', 0, MODEKEYCOPY_STARTOFLINE },
{ '1', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, { '1', 0, MODEKEYCOPY_STARTNUMBERPREFIX },
@ -192,6 +198,7 @@ const struct mode_key_entry mode_key_vi_copy[] = {
{ '?', 0, MODEKEYCOPY_SEARCHUP }, { '?', 0, MODEKEYCOPY_SEARCHUP },
{ 'B', 0, MODEKEYCOPY_PREVIOUSSPACE }, { 'B', 0, MODEKEYCOPY_PREVIOUSSPACE },
{ 'E', 0, MODEKEYCOPY_NEXTSPACEEND }, { 'E', 0, MODEKEYCOPY_NEXTSPACEEND },
{ 'F', 0, MODEKEYCOPY_JUMPBACK },
{ 'G', 0, MODEKEYCOPY_HISTORYBOTTOM }, { 'G', 0, MODEKEYCOPY_HISTORYBOTTOM },
{ 'H', 0, MODEKEYCOPY_TOPLINE }, { 'H', 0, MODEKEYCOPY_TOPLINE },
{ 'J', 0, MODEKEYCOPY_SCROLLDOWN }, { 'J', 0, MODEKEYCOPY_SCROLLDOWN },
@ -213,6 +220,7 @@ const struct mode_key_entry mode_key_vi_copy[] = {
{ '^', 0, MODEKEYCOPY_BACKTOINDENTATION }, { '^', 0, MODEKEYCOPY_BACKTOINDENTATION },
{ 'b', 0, MODEKEYCOPY_PREVIOUSWORD }, { 'b', 0, MODEKEYCOPY_PREVIOUSWORD },
{ 'e', 0, MODEKEYCOPY_NEXTWORDEND }, { 'e', 0, MODEKEYCOPY_NEXTWORDEND },
{ 'f', 0, MODEKEYCOPY_JUMP },
{ 'g', 0, MODEKEYCOPY_HISTORYTOP }, { 'g', 0, MODEKEYCOPY_HISTORYTOP },
{ 'h', 0, MODEKEYCOPY_LEFT }, { 'h', 0, MODEKEYCOPY_LEFT },
{ 'j', 0, MODEKEYCOPY_DOWN }, { 'j', 0, MODEKEYCOPY_DOWN },
@ -290,6 +298,8 @@ struct mode_key_tree mode_key_tree_emacs_choice;
/* emacs copy mode keys. */ /* emacs copy mode keys. */
const struct mode_key_entry mode_key_emacs_copy[] = { const struct mode_key_entry mode_key_emacs_copy[] = {
{ ' ', 0, MODEKEYCOPY_NEXTPAGE }, { ' ', 0, MODEKEYCOPY_NEXTPAGE },
{ ',', 0, MODEKEYCOPY_JUMPREVERSE },
{ ';', 0, MODEKEYCOPY_JUMPAGAIN },
{ '1' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, { '1' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '2' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, { '2' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '3' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, { '3' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
@ -301,6 +311,8 @@ const struct mode_key_entry mode_key_emacs_copy[] = {
{ '9' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, { '9' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX },
{ '<' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYTOP }, { '<' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYTOP },
{ '>' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYBOTTOM }, { '>' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYBOTTOM },
{ 'F', 0, MODEKEYCOPY_JUMPBACK },
{ 'N', 0, MODEKEYCOPY_SEARCHREVERSE },
{ 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE }, { 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE },
{ 'R', 0, MODEKEYCOPY_RECTANGLETOGGLE }, { 'R', 0, MODEKEYCOPY_RECTANGLETOGGLE },
{ '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION }, { '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION },
@ -319,6 +331,7 @@ const struct mode_key_entry mode_key_emacs_copy[] = {
{ '\033' /* Escape */, 0, MODEKEYCOPY_CANCEL }, { '\033' /* Escape */, 0, MODEKEYCOPY_CANCEL },
{ 'N', 0, MODEKEYCOPY_SEARCHREVERSE }, { 'N', 0, MODEKEYCOPY_SEARCHREVERSE },
{ 'b' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSWORD }, { 'b' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSWORD },
{ 'f', 0, MODEKEYCOPY_JUMP },
{ 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTWORDEND }, { 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTWORDEND },
{ 'g', 0, MODEKEYCOPY_GOTOLINE }, { 'g', 0, MODEKEYCOPY_GOTOLINE },
{ 'm' | KEYC_ESCAPE, 0, MODEKEYCOPY_BACKTOINDENTATION }, { 'm' | KEYC_ESCAPE, 0, MODEKEYCOPY_BACKTOINDENTATION },

18
tmux.1
View File

@ -1,4 +1,4 @@
.\" $Id: tmux.1,v 1.238 2010-03-15 22:03:38 nicm Exp $ .\" $Id: tmux.1,v 1.239 2010-03-16 17:30:58 micahcowan Exp $
.\" .\"
.\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> .\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
.\" .\"
@ -610,7 +610,7 @@ The keys available depend on whether emacs or vi mode is selected
.Ic mode-keys .Ic mode-keys
option). option).
The following keys are supported as appropriate for the mode: The following keys are supported as appropriate for the mode:
.Bl -column "FunctionXXXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent .Bl -column "FunctionXXXXXXXXXXXXXXXXX" "viXXXXXXXXXX" "emacs" -offset indent
.It Sy "Function" Ta Sy "vi" Ta Sy "emacs" .It Sy "Function" Ta Sy "vi" Ta Sy "emacs"
.It Li "Back to indentation" Ta "^" Ta "M-m" .It Li "Back to indentation" Ta "^" Ta "M-m"
.It Li "Bottom of history" Ta "G" Ta "M-<" .It Li "Bottom of history" Ta "G" Ta "M-<"
@ -629,6 +629,10 @@ The following keys are supported as appropriate for the mode:
.It Li "Go to line" Ta ":" Ta "g" .It Li "Go to line" Ta ":" Ta "g"
.It Li "Half page down" Ta "C-d" Ta "M-Down" .It Li "Half page down" Ta "C-d" Ta "M-Down"
.It Li "Half page up" Ta "C-u" Ta "M-Up" .It Li "Half page up" Ta "C-u" Ta "M-Up"
.It Li "Jump forward" Ta "f" Ta "f"
.It Li "Jump backward" Ta "F" Ta "F"
.It Li "Jump again" Ta ";" Ta ";"
.It Li "Jump again in reverse" Ta "," Ta ","
.It Li "Next page" Ta "C-f" Ta "Page down" .It Li "Next page" Ta "C-f" Ta "Page down"
.It Li "Next space" Ta "W" Ta "" .It Li "Next space" Ta "W" Ta ""
.It Li "Next space, end of word" Ta "E" Ta "" .It Li "Next space, end of word" Ta "E" Ta ""
@ -666,6 +670,16 @@ next word and previous word to the start of the previous word.
The three next and previous space keys work similarly but use a space alone as The three next and previous space keys work similarly but use a space alone as
the word separator. the word separator.
.Pp .Pp
The jump commands enable quick movement within a line.
For instance, with the default bindings (in either vi or emacs mode),
you can type
.Ql f/ ,
and the cursor will jump to the next slash character on the current line.
You can then type
.Ql \&;
to cause the cursor to jump to the next occurrence of a slash.
(These are based on vi editor commands.)
.Pp
Commands in copy mode may be prefaced by an optional repeat count. Commands in copy mode may be prefaced by an optional repeat count.
With vi key bindings, a prefix is entered using the number keys; with With vi key bindings, a prefix is entered using the number keys; with
emacs, the Alt (meta) key and a number begins prefix entry. emacs, the Alt (meta) key and a number begins prefix entry.

6
tmux.h
View File

@ -1,4 +1,4 @@
/* $Id: tmux.h,v 1.549 2010-03-15 22:03:38 nicm Exp $ */ /* $Id: tmux.h,v 1.550 2010-03-16 17:30:58 micahcowan Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -458,6 +458,10 @@ enum mode_key_cmd {
MODEKEYCOPY_HALFPAGEUP, MODEKEYCOPY_HALFPAGEUP,
MODEKEYCOPY_HISTORYBOTTOM, MODEKEYCOPY_HISTORYBOTTOM,
MODEKEYCOPY_HISTORYTOP, MODEKEYCOPY_HISTORYTOP,
MODEKEYCOPY_JUMP,
MODEKEYCOPY_JUMPAGAIN,
MODEKEYCOPY_JUMPREVERSE,
MODEKEYCOPY_JUMPBACK,
MODEKEYCOPY_LEFT, MODEKEYCOPY_LEFT,
MODEKEYCOPY_MIDDLELINE, MODEKEYCOPY_MIDDLELINE,
MODEKEYCOPY_NEXTPAGE, MODEKEYCOPY_NEXTPAGE,

View File

@ -1,4 +1,4 @@
/* $Id: window-copy.c,v 1.110 2010-03-14 23:17:59 nicm Exp $ */ /* $Id: window-copy.c,v 1.111 2010-03-16 17:30:58 micahcowan Exp $ */
/* /*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
@ -65,6 +65,8 @@ void window_copy_cursor_left(struct window_pane *);
void window_copy_cursor_right(struct window_pane *); void window_copy_cursor_right(struct window_pane *);
void window_copy_cursor_up(struct window_pane *, int); void window_copy_cursor_up(struct window_pane *, int);
void window_copy_cursor_down(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 *);
void window_copy_cursor_next_word(struct window_pane *, const char *); void window_copy_cursor_next_word(struct window_pane *, const char *);
void window_copy_cursor_next_word_end(struct window_pane *, const char *); void window_copy_cursor_next_word_end(struct window_pane *, const char *);
void window_copy_cursor_previous_word(struct window_pane *, const char *); void window_copy_cursor_previous_word(struct window_pane *, const char *);
@ -86,6 +88,8 @@ enum window_copy_input_type {
WINDOW_COPY_NUMERICPREFIX, WINDOW_COPY_NUMERICPREFIX,
WINDOW_COPY_SEARCHUP, WINDOW_COPY_SEARCHUP,
WINDOW_COPY_SEARCHDOWN, WINDOW_COPY_SEARCHDOWN,
WINDOW_COPY_JUMPFORWARD,
WINDOW_COPY_JUMPBACK,
WINDOW_COPY_GOTOLINE, WINDOW_COPY_GOTOLINE,
}; };
@ -115,6 +119,9 @@ struct window_copy_mode_data {
enum window_copy_input_type searchtype; enum window_copy_input_type searchtype;
char *searchstr; char *searchstr;
enum window_copy_input_type jumptype;
char jumpchar;
}; };
struct screen * struct screen *
@ -147,6 +154,9 @@ window_copy_init(struct window_pane *wp)
wp->flags |= PANE_FREEZE; wp->flags |= PANE_FREEZE;
bufferevent_disable(wp->event, EV_READ|EV_WRITE); bufferevent_disable(wp->event, EV_READ|EV_WRITE);
data->jumptype = WINDOW_COPY_OFF;
data->jumpchar = '\0';
s = &data->screen; s = &data->screen;
screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
if (options_get_number(&wp->window->options, "mode-mouse")) if (options_get_number(&wp->window->options, "mode-mouse"))
@ -242,7 +252,24 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
if (np == 0) if (np == 0)
np = 1; np = 1;
if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) { if (data->inputtype == WINDOW_COPY_JUMPFORWARD
|| data->inputtype == WINDOW_COPY_JUMPBACK) {
/* Ignore keys with modifiers. */
if ((key & 0xff00) == 0) {
data->jumpchar = key;
if (data->inputtype == WINDOW_COPY_JUMPFORWARD) {
for ( ; np != 0; np--)
window_copy_cursor_jump(wp);
} else {
for ( ; np != 0; np--)
window_copy_cursor_jump_back(wp);
}
}
data->jumptype = data->inputtype;
data->inputtype = WINDOW_COPY_OFF;
window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
return;
} if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) {
if (window_copy_key_numeric_prefix(wp, key) == 0) if (window_copy_key_numeric_prefix(wp, key) == 0)
return; return;
data->inputtype = WINDOW_COPY_OFF; data->inputtype = WINDOW_COPY_OFF;
@ -407,6 +434,37 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
for (; np != 0; np--) for (; np != 0; np--)
window_copy_cursor_previous_word(wp, word_separators); window_copy_cursor_previous_word(wp, word_separators);
break; 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);
}
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);
}
break;
case MODEKEYCOPY_JUMPBACK:
data->inputtype = WINDOW_COPY_JUMPBACK;
data->inputprompt = "Jump Back";
*data->inputstr = '\0';
window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
return; /* skip numprefix reset */
return; /* skip numprefix reset */
case MODEKEYCOPY_SEARCHUP: case MODEKEYCOPY_SEARCHUP:
data->inputtype = WINDOW_COPY_SEARCHUP; data->inputtype = WINDOW_COPY_SEARCHUP;
data->inputprompt = "Search Up"; data->inputprompt = "Search Up";
@ -420,6 +478,8 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
switch (data->searchtype) { switch (data->searchtype) {
case WINDOW_COPY_OFF: case WINDOW_COPY_OFF:
case WINDOW_COPY_GOTOLINE: case WINDOW_COPY_GOTOLINE:
case WINDOW_COPY_JUMPFORWARD:
case WINDOW_COPY_JUMPBACK:
case WINDOW_COPY_NUMERICPREFIX: case WINDOW_COPY_NUMERICPREFIX:
break; break;
case WINDOW_COPY_SEARCHUP: case WINDOW_COPY_SEARCHUP:
@ -524,6 +584,8 @@ window_copy_key_input(struct window_pane *wp, int key)
switch (data->inputtype) { switch (data->inputtype) {
case WINDOW_COPY_OFF: case WINDOW_COPY_OFF:
case WINDOW_COPY_JUMPFORWARD:
case WINDOW_COPY_JUMPBACK:
case WINDOW_COPY_NUMERICPREFIX: case WINDOW_COPY_NUMERICPREFIX:
break; break;
case WINDOW_COPY_SEARCHUP: case WINDOW_COPY_SEARCHUP:
@ -1380,6 +1442,62 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only)
} }
} }
void
window_copy_cursor_jump(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *base_s = &wp->base;
const struct grid_cell *gc;
uint px, py, xx;
px = data->cx + 1;
py = screen_hsize(base_s) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
while (px < xx) {
gc = grid_peek_cell(base_s->grid, px, py);
if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0
&& gc->data == data->jumpchar) {
window_copy_update_cursor(wp, px, data->cy);
if (window_copy_update_selection(wp))
window_copy_redraw_lines(wp, data->cy, 1);
return;
}
px++;
}
}
void
window_copy_cursor_jump_back(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *base_s = &wp->base;
const struct grid_cell *gc;
uint px, py;
px = data->cx;
py = screen_hsize(base_s) + data->cy - data->oy;
if (px > 0)
px--;
for (;;) {
gc = grid_peek_cell(base_s->grid, px, py);
if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0
&& gc->data == data->jumpchar) {
window_copy_update_cursor(wp, px, data->cy);
if (window_copy_update_selection(wp))
window_copy_redraw_lines(wp, data->cy, 1);
return;
}
if (px == 0)
break;
px--;
}
}
void void
window_copy_cursor_next_word(struct window_pane *wp, const char *separators) window_copy_cursor_next_word(struct window_pane *wp, const char *separators)
{ {