From 5ef5bd7c3127f00dca54499b48802bba85953a6a Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 14 Jul 2009 06:39:25 +0000 Subject: [PATCH] Add a "back to indentation" key in copy mode to move the cursor to the first non-whitespace character. ^ with vi and M-m with emacs key bindings. Another from Kalle Olavi Niemitalo, thanks. --- key-bindings.c | 31 ++++++++++++++++++++++--------- mode-key.c | 7 +++++-- server.c | 5 ++++- status.c | 3 ++- tmux.1 | 5 +++-- tmux.h | 3 ++- window-copy.c | 33 ++++++++++++++++++++++++++++++++- 7 files changed, 70 insertions(+), 17 deletions(-) diff --git a/key-bindings.c b/key-bindings.c index 91d63474..d383530b 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -1,4 +1,4 @@ -/* $Id: key-bindings.c,v 1.72 2009-05-16 11:48:47 nicm Exp $ */ +/* $Id: key-bindings.c,v 1.73 2009-07-14 06:39:25 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -27,6 +27,7 @@ SPLAY_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp); struct key_bindings key_bindings; +struct key_bindings dead_key_bindings; int key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2) @@ -48,12 +49,12 @@ key_bindings_add(int key, int can_repeat, struct cmd_list *cmdlist) { struct key_binding *bd; - if ((bd = key_bindings_lookup(key)) == NULL) { - bd = xmalloc(sizeof *bd); - bd->key = key; - SPLAY_INSERT(key_bindings, &key_bindings, bd); - } else - cmd_list_free(bd->cmdlist); + key_bindings_remove(key); + + bd = xmalloc(sizeof *bd); + bd->key = key; + SPLAY_INSERT(key_bindings, &key_bindings, bd); + bd->can_repeat = can_repeat; bd->cmdlist = cmdlist; } @@ -66,9 +67,20 @@ key_bindings_remove(int key) if ((bd = key_bindings_lookup(key)) == NULL) return; SPLAY_REMOVE(key_bindings, &key_bindings, bd); + SPLAY_INSERT(key_bindings, &dead_key_bindings, bd); +} - cmd_list_free(bd->cmdlist); - xfree(bd); +void +key_bindings_clean(void) +{ + struct key_binding *bd; + + while (!SPLAY_EMPTY(&dead_key_bindings)) { + bd = SPLAY_ROOT(&dead_key_bindings); + SPLAY_REMOVE(key_bindings, &dead_key_bindings, bd); + cmd_list_free(bd->cmdlist); + xfree(bd); + } } void @@ -162,6 +174,7 @@ key_bindings_free(void) { struct key_binding *bd; + key_bindings_clean(); while (!SPLAY_EMPTY(&key_bindings)) { bd = SPLAY_ROOT(&key_bindings); SPLAY_REMOVE(key_bindings, &key_bindings, bd); diff --git a/mode-key.c b/mode-key.c index c83b9a59..958cac0d 100644 --- a/mode-key.c +++ b/mode-key.c @@ -1,4 +1,4 @@ -/* $Id: mode-key.c,v 1.12 2009-05-14 19:36:56 nicm Exp $ */ +/* $Id: mode-key.c,v 1.13 2009-07-14 06:39:10 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -105,8 +105,9 @@ mode_key_lookup_vi(struct mode_key_data *mdata, int key) return (MODEKEYCMD_CHOOSE); return (MODEKEYCMD_COPYSELECTION); case '0': - case '^': return (MODEKEYCMD_STARTOFLINE); + case '^': + return (MODEKEYCMD_BACKTOINDENTATION); case '\033': return (MODEKEYCMD_CLEARSELECTION); case 'j': @@ -160,6 +161,8 @@ mode_key_lookup_emacs(struct mode_key_data *mdata, int key) return (MODEKEYCMD_CHOOSE); case '\001': return (MODEKEYCMD_STARTOFLINE); + case KEYC_ADDESC('m'): + return (MODEKEYCMD_BACKTOINDENTATION); case '\007': return (MODEKEYCMD_CLEARSELECTION); case '\027': diff --git a/server.c b/server.c index 7f556952..fee656fd 100644 --- a/server.c +++ b/server.c @@ -1,4 +1,4 @@ -/* $Id: server.c,v 1.156 2009-07-14 06:38:14 nicm Exp $ */ +/* $Id: server.c,v 1.157 2009-07-14 06:39:25 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -351,6 +351,9 @@ server_main(int srv_fd) server_handle_windows(&pfd); server_handle_clients(&pfd); + /* Collect any unset key bindings. */ + key_bindings_clean(); + /* * If we have no sessions and clients left, let's get out * of here... diff --git a/status.c b/status.c index 820925f6..29c30067 100644 --- a/status.c +++ b/status.c @@ -1,4 +1,4 @@ -/* $Id: status.c,v 1.90 2009-07-01 23:06:32 nicm Exp $ */ +/* $Id: status.c,v 1.91 2009-07-14 06:39:10 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -709,6 +709,7 @@ status_prompt_key(struct client *c, int key) } break; case MODEKEYCMD_STARTOFLINE: + case MODEKEYCMD_BACKTOINDENTATION: if (c->prompt_index != 0) { c->prompt_index = 0; c->flags |= CLIENT_STATUS; diff --git a/tmux.1 b/tmux.1 index 6d808b23..506fe51a 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1,4 +1,4 @@ -.\" $Id: tmux.1,v 1.113 2009-07-14 06:38:14 nicm Exp $ +.\" $Id: tmux.1,v 1.114 2009-07-14 06:39:10 nicm Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott .\" @@ -306,7 +306,8 @@ option). The following keys are supported as appropriate for the mode: .Bl -column "FunctionXXXXXXXXXXXX" "viXXXXXX" "emacs" -offset indent .It Sy "Function" Ta Sy "vi" Ta Sy "emacs" -.It Li "Start of line" Ta "0 or ^" Ta "C-a" +.It Li "Start of line" Ta "0" Ta "C-a" +.It Li "Back to indentation" Ta "^" Ta "M-m" .It Li "Clear selection" Ta "Escape" Ta "C-g" .It Li "Copy selection" Ta "Enter" Ta "M-w" .It Li "Cursor down" Ta "j" Ta "Down" diff --git a/tmux.h b/tmux.h index 427ef578..adbcb171 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.356 2009-07-14 06:38:14 nicm Exp $ */ +/* $Id: tmux.h,v 1.357 2009-07-14 06:39:10 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -356,6 +356,7 @@ struct msg_resize_data { /* Editing keys. */ enum mode_key_cmd { MODEKEYCMD_BACKSPACE = 0x1000, + MODEKEYCMD_BACKTOINDENTATION, MODEKEYCMD_CHOOSE, MODEKEYCMD_CLEARSELECTION, MODEKEYCMD_COMPLETE, diff --git a/window-copy.c b/window-copy.c index d94d13e0..c782e5e2 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1,4 +1,4 @@ -/* $Id: window-copy.c,v 1.64 2009-07-14 06:38:32 nicm Exp $ */ +/* $Id: window-copy.c,v 1.65 2009-07-14 06:39:10 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -50,6 +50,7 @@ int window_copy_is_space(struct window_pane *, u_int, u_int); u_int window_copy_find_length(struct window_pane *, u_int); void window_copy_set_cursor_x(struct window_pane *, u_int); void window_copy_cursor_start_of_line(struct window_pane *); +void window_copy_cursor_back_to_indentation(struct window_pane *); void window_copy_cursor_end_of_line(struct window_pane *); void window_copy_cursor_left(struct window_pane *); void window_copy_cursor_right(struct window_pane *); @@ -207,6 +208,9 @@ window_copy_key(struct window_pane *wp, struct client *c, int key) case MODEKEYCMD_STARTOFLINE: window_copy_cursor_start_of_line(wp); break; + case MODEKEYCMD_BACKTOINDENTATION: + window_copy_cursor_back_to_indentation(wp); + break; case MODEKEYCMD_ENDOFLINE: window_copy_cursor_end_of_line(wp); break; @@ -600,6 +604,33 @@ window_copy_cursor_start_of_line(struct window_pane *wp) window_copy_update_cursor(wp); } +void +window_copy_cursor_back_to_indentation(struct window_pane *wp) +{ + struct window_copy_mode_data *data = wp->modedata; + u_int px, py, xx; + const struct grid_cell *gc; + + px = 0; + py = screen_hsize(&wp->base) + data->cy - data->oy; + xx = window_copy_find_length(wp, py); + + /* + * Don't use window_copy_is_space because that treats some word + * delimiters as spaces. + */ + while (px < xx) { + gc = grid_peek_cell(wp->base.grid, px, py); + if (gc->flags & GRID_FLAG_UTF8) + break; + if (gc->data != ' ') + break; + px++; + } + + window_copy_set_cursor_x(wp, px); +} + void window_copy_cursor_end_of_line(struct window_pane *wp) {