Add vi-style "jump" commands for copy mode, from Micah Cowan.

pull/1/head
Nicholas Marriott 2010-03-22 19:10:42 +00:00
parent 6f04866044
commit 0ac6efa6d5
4 changed files with 154 additions and 4 deletions

View File

@ -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 },

20
tmux.1
View File

@ -1,4 +1,4 @@
.\" $OpenBSD$ .\" $Id$
.\" .\"
.\" 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,18 @@ 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, typing
.Ql f
followed by
.Ql /
will move the cursor to the next
.Ql /
character on the current line.
A
.Ql \&;
will then jump to the next occurrence.
.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.

4
tmux.h
View File

@ -459,6 +459,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 @@
/* $OpenBSD$ */ /* $Id$ */
/* /*
* 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,36 @@ 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 */
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 +477,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 +583,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 +1441,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)
{ {