diff --git a/mode-key.c b/mode-key.c index a5eb22ab..2be7d1e3 100644 --- a/mode-key.c +++ b/mode-key.c @@ -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 @@ -88,6 +88,10 @@ struct mode_key_cmdstr mode_key_cmdstr_copy[] = { { MODEKEYCOPY_GOTOLINE, "goto-line" }, { MODEKEYCOPY_HISTORYBOTTOM, "history-bottom" }, { 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_RECTANGLETOGGLE, "rectangle-toggle" }, { 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[] = { { ' ', 0, MODEKEYCOPY_STARTSELECTION }, { '$', 0, MODEKEYCOPY_ENDOFLINE }, + { ',', 0, MODEKEYCOPY_JUMPREVERSE }, + { ';', 0, MODEKEYCOPY_JUMPAGAIN }, { '/', 0, MODEKEYCOPY_SEARCHDOWN }, { '0', 0, MODEKEYCOPY_STARTOFLINE }, { '1', 0, MODEKEYCOPY_STARTNUMBERPREFIX }, @@ -192,6 +198,7 @@ const struct mode_key_entry mode_key_vi_copy[] = { { '?', 0, MODEKEYCOPY_SEARCHUP }, { 'B', 0, MODEKEYCOPY_PREVIOUSSPACE }, { 'E', 0, MODEKEYCOPY_NEXTSPACEEND }, + { 'F', 0, MODEKEYCOPY_JUMPBACK }, { 'G', 0, MODEKEYCOPY_HISTORYBOTTOM }, { 'H', 0, MODEKEYCOPY_TOPLINE }, { 'J', 0, MODEKEYCOPY_SCROLLDOWN }, @@ -213,6 +220,7 @@ const struct mode_key_entry mode_key_vi_copy[] = { { '^', 0, MODEKEYCOPY_BACKTOINDENTATION }, { 'b', 0, MODEKEYCOPY_PREVIOUSWORD }, { 'e', 0, MODEKEYCOPY_NEXTWORDEND }, + { 'f', 0, MODEKEYCOPY_JUMP }, { 'g', 0, MODEKEYCOPY_HISTORYTOP }, { 'h', 0, MODEKEYCOPY_LEFT }, { 'j', 0, MODEKEYCOPY_DOWN }, @@ -290,6 +298,8 @@ struct mode_key_tree mode_key_tree_emacs_choice; /* emacs copy mode keys. */ const struct mode_key_entry mode_key_emacs_copy[] = { { ' ', 0, MODEKEYCOPY_NEXTPAGE }, + { ',', 0, MODEKEYCOPY_JUMPREVERSE }, + { ';', 0, MODEKEYCOPY_JUMPAGAIN }, { '1' | KEYC_ESCAPE, 0, MODEKEYCOPY_STARTNUMBERPREFIX }, { '2' | 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 }, { '<' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYTOP }, { '>' | KEYC_ESCAPE, 0, MODEKEYCOPY_HISTORYBOTTOM }, + { 'F', 0, MODEKEYCOPY_JUMPBACK }, + { 'N', 0, MODEKEYCOPY_SEARCHREVERSE }, { 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE }, { 'R', 0, MODEKEYCOPY_RECTANGLETOGGLE }, { '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION }, @@ -319,6 +331,7 @@ const struct mode_key_entry mode_key_emacs_copy[] = { { '\033' /* Escape */, 0, MODEKEYCOPY_CANCEL }, { 'N', 0, MODEKEYCOPY_SEARCHREVERSE }, { 'b' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSWORD }, + { 'f', 0, MODEKEYCOPY_JUMP }, { 'f' | KEYC_ESCAPE, 0, MODEKEYCOPY_NEXTWORDEND }, { 'g', 0, MODEKEYCOPY_GOTOLINE }, { 'm' | KEYC_ESCAPE, 0, MODEKEYCOPY_BACKTOINDENTATION }, diff --git a/tmux.1 b/tmux.1 index 806df283..8c151bb8 100644 --- a/tmux.1 +++ b/tmux.1 @@ -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 .\" @@ -610,7 +610,7 @@ The keys available depend on whether emacs or vi mode is selected .Ic mode-keys option). 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 Li "Back to indentation" Ta "^" Ta "M-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 "Half page down" Ta "C-d" Ta "M-Down" .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 space" Ta "W" 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 word separator. .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. With vi key bindings, a prefix is entered using the number keys; with emacs, the Alt (meta) key and a number begins prefix entry. diff --git a/tmux.h b/tmux.h index 65927067..81c11aa6 100644 --- a/tmux.h +++ b/tmux.h @@ -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 @@ -458,6 +458,10 @@ enum mode_key_cmd { MODEKEYCOPY_HALFPAGEUP, MODEKEYCOPY_HISTORYBOTTOM, MODEKEYCOPY_HISTORYTOP, + MODEKEYCOPY_JUMP, + MODEKEYCOPY_JUMPAGAIN, + MODEKEYCOPY_JUMPREVERSE, + MODEKEYCOPY_JUMPBACK, MODEKEYCOPY_LEFT, MODEKEYCOPY_MIDDLELINE, MODEKEYCOPY_NEXTPAGE, diff --git a/window-copy.c b/window-copy.c index 204db0bd..97803675 100644 --- a/window-copy.c +++ b/window-copy.c @@ -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 @@ -65,6 +65,8 @@ void window_copy_cursor_left(struct window_pane *); 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 *); 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_previous_word(struct window_pane *, const char *); @@ -86,6 +88,8 @@ enum window_copy_input_type { WINDOW_COPY_NUMERICPREFIX, WINDOW_COPY_SEARCHUP, WINDOW_COPY_SEARCHDOWN, + WINDOW_COPY_JUMPFORWARD, + WINDOW_COPY_JUMPBACK, WINDOW_COPY_GOTOLINE, }; @@ -115,6 +119,9 @@ struct window_copy_mode_data { enum window_copy_input_type searchtype; char *searchstr; + + enum window_copy_input_type jumptype; + char jumpchar; }; struct screen * @@ -147,6 +154,9 @@ window_copy_init(struct window_pane *wp) wp->flags |= PANE_FREEZE; bufferevent_disable(wp->event, EV_READ|EV_WRITE); + data->jumptype = WINDOW_COPY_OFF; + data->jumpchar = '\0'; + s = &data->screen; screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0); 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) 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) return; 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--) 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); + } + 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: data->inputtype = WINDOW_COPY_SEARCHUP; data->inputprompt = "Search Up"; @@ -420,6 +478,8 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) switch (data->searchtype) { case WINDOW_COPY_OFF: case WINDOW_COPY_GOTOLINE: + case WINDOW_COPY_JUMPFORWARD: + case WINDOW_COPY_JUMPBACK: case WINDOW_COPY_NUMERICPREFIX: break; case WINDOW_COPY_SEARCHUP: @@ -524,6 +584,8 @@ window_copy_key_input(struct window_pane *wp, int key) switch (data->inputtype) { case WINDOW_COPY_OFF: + case WINDOW_COPY_JUMPFORWARD: + case WINDOW_COPY_JUMPBACK: case WINDOW_COPY_NUMERICPREFIX: break; 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 window_copy_cursor_next_word(struct window_pane *wp, const char *separators) {