From bc2e4a36df2023a738c433779ba8f1e08b6951fe Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 15 Jan 2013 22:55:29 +0000 Subject: [PATCH 1/3] If timing between keys is less than (by default) 1 millisecond, assume the text is being pasted. assume-paste-time option changes the value (0 disables). Based on a diff from Marcin Kulik. --- options-table.c | 7 +++++++ server-client.c | 54 ++++++++++++++++++++++++++++++++++++------------- tmux.1 | 7 +++++++ tmux.h | 2 +- 4 files changed, 55 insertions(+), 15 deletions(-) diff --git a/options-table.c b/options-table.c index d9bbe382..9baf6835 100644 --- a/options-table.c +++ b/options-table.c @@ -91,6 +91,13 @@ const struct options_table_entry server_options_table[] = { /* Session options. */ const struct options_table_entry session_options_table[] = { + { .name = "assume-paste-time", + .type = OPTIONS_TABLE_NUMBER, + .minimum = 0, + .maximum = INT_MAX, + .default_num = 1, + }, + { .name = "base-index", .type = OPTIONS_TABLE_NUMBER, .minimum = 0, diff --git a/server-client.c b/server-client.c index 3db11ecb..a8d48c54 100644 --- a/server-client.c +++ b/server-client.c @@ -34,6 +34,7 @@ void server_client_check_exit(struct client *); void server_client_check_redraw(struct client *); void server_client_set_title(struct client *); void server_client_reset_state(struct client *); +int server_client_assume_paste(struct session *); int server_client_msg_dispatch(struct client *); void server_client_msg_command(struct client *, struct msg_command_data *); @@ -325,6 +326,22 @@ server_client_check_mouse(struct client *c, struct window_pane *wp) window_pane_mouse(wp, c->session, m); } +/* Is this fast enough to probably be a paste? */ +int +server_client_assume_paste(struct session *s) +{ + struct timeval tv; + u_int t; + + if ((t = options_get_number(&s->options, "assume-paste-time")) == 0) + return 0; + + timersub(&s->activity_time, &s->last_activity_time, &tv); + if (tv.tv_sec == 0 && tv.tv_usec < t * 1000) + return 1; + return 0; +} + /* Handle data key input from client. */ void server_client_handle_key(struct client *c, int key) @@ -334,7 +351,7 @@ server_client_handle_key(struct client *c, int key) struct window_pane *wp; struct timeval tv; struct key_binding *bd; - int xtimeout, isprefix; + int xtimeout, isprefix, ispaste; /* Check the client is good to accept input. */ if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) @@ -346,6 +363,9 @@ server_client_handle_key(struct client *c, int key) /* Update the activity timer. */ if (gettimeofday(&c->activity_time, NULL) != 0) fatal("gettimeofday failed"); + + memcpy(&s->last_activity_time, &s->activity_time, + sizeof s->last_activity_time); memcpy(&s->activity_time, &c->activity_time, sizeof s->activity_time); w = c->session->curw->window; @@ -382,25 +402,31 @@ server_client_handle_key(struct client *c, int key) } /* Is this a prefix key? */ - if (key == options_get_number(&c->session->options, "prefix")) + if (key == options_get_number(&s->options, "prefix")) isprefix = 1; - else if (key == options_get_number(&c->session->options, "prefix2")) + else if (key == options_get_number(&s->options, "prefix2")) isprefix = 1; else isprefix = 0; + /* Treat prefix as a regular key when pasting is detected. */ + ispaste = server_client_assume_paste(s); + if (ispaste) + isprefix = 0; + /* No previous prefix key. */ if (!(c->flags & CLIENT_PREFIX)) { - if (isprefix) + if (isprefix) { c->flags |= CLIENT_PREFIX; - else { - /* Try as a non-prefix key binding. */ - if ((bd = key_bindings_lookup(key)) == NULL) { - if (!(c->flags & CLIENT_READONLY)) - window_pane_key(wp, c->session, key); - } else - key_bindings_dispatch(bd, c); + return; } + + /* Try as a non-prefix key binding. */ + if (ispaste || (bd = key_bindings_lookup(key)) == NULL) { + if (!(c->flags & CLIENT_READONLY)) + window_pane_key(wp, s, key); + } else + key_bindings_dispatch(bd, c); return; } @@ -413,7 +439,7 @@ server_client_handle_key(struct client *c, int key) if (isprefix) c->flags |= CLIENT_PREFIX; else if (!(c->flags & CLIENT_READONLY)) - window_pane_key(wp, c->session, key); + window_pane_key(wp, s, key); } return; } @@ -424,12 +450,12 @@ server_client_handle_key(struct client *c, int key) if (isprefix) c->flags |= CLIENT_PREFIX; else if (!(c->flags & CLIENT_READONLY)) - window_pane_key(wp, c->session, key); + window_pane_key(wp, s, key); return; } /* If this key can repeat, reset the repeat flags and timer. */ - xtimeout = options_get_number(&c->session->options, "repeat-time"); + xtimeout = options_get_number(&s->options, "repeat-time"); if (xtimeout != 0 && bd->can_repeat) { c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; diff --git a/tmux.1 b/tmux.1 index 7abb8f88..975aa103 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2044,6 +2044,13 @@ interactive menu when required. .Pp Available session options are: .Bl -tag -width Ds +.It Ic assume-paste-time Ar milliseconds +If keys are entered faster than one in +.Ar milliseconds , +they are assumed to have been pasted rather than typed and +.Nm +key bindings are not processed. +The default is one millisecond and zero disables. .It Ic base-index Ar index Set the base index from which an unused index should be searched when a new window is created. diff --git a/tmux.h b/tmux.h index c1fec028..f1a9e4d4 100644 --- a/tmux.h +++ b/tmux.h @@ -1095,6 +1095,7 @@ struct session { struct timeval creation_time; struct timeval activity_time; + struct timeval last_activity_time; u_int sx; u_int sy; @@ -1707,7 +1708,6 @@ char *paste_print(struct paste_buffer *, size_t); void paste_send_pane(struct paste_buffer *, struct window_pane *, const char *, int); - /* clock.c */ extern const char clock_table[14][5][5]; void clock_draw(struct screen_write_ctx *, int, int); From 44f8e1caffce2e887682c3314ee22becc09e1d3c Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 15 Jan 2013 23:18:55 +0000 Subject: [PATCH 2/3] Implement ECH (erase character, CSI X). Reported by Christian Neukirchen. --- input.c | 5 +++++ screen-write.c | 24 ++++++++++++++++++++++++ tmux.h | 3 +++ tty-term.c | 1 + tty.c | 17 +++++++++++++++++ 5 files changed, 50 insertions(+) diff --git a/input.c b/input.c index 71ef3b00..7d26a661 100644 --- a/input.c +++ b/input.c @@ -135,6 +135,7 @@ enum input_csi_type { INPUT_CSI_DECSTBM, INPUT_CSI_DL, INPUT_CSI_DSR, + INPUT_CSI_ECH, INPUT_CSI_ED, INPUT_CSI_EL, INPUT_CSI_HPA, @@ -167,6 +168,7 @@ const struct input_table_entry input_csi_table[] = { { 'L', "", INPUT_CSI_IL }, { 'M', "", INPUT_CSI_DL }, { 'P', "", INPUT_CSI_DCH }, + { 'X', "", INPUT_CSI_ECH }, { 'Z', "", INPUT_CSI_CBT }, { 'c', "", INPUT_CSI_DA }, { 'c', ">", INPUT_CSI_DA_TWO }, @@ -1143,6 +1145,9 @@ input_csi_dispatch(struct input_ctx *ictx) break; } break; + case INPUT_CSI_ECH: + screen_write_clearcharacter(sctx, input_get(ictx, 0, 1, 1)); + break; case INPUT_CSI_DCH: screen_write_deletecharacter(sctx, input_get(ictx, 0, 1, 1)); break; diff --git a/screen-write.c b/screen-write.c index ec7d741e..4d147b5b 100644 --- a/screen-write.c +++ b/screen-write.c @@ -649,6 +649,30 @@ screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx) tty_write(tty_cmd_deletecharacter, &ttyctx); } +/* Clear nx characters. */ +void +screen_write_clearcharacter(struct screen_write_ctx *ctx, u_int nx) +{ + struct screen *s = ctx->s; + struct tty_ctx ttyctx; + + if (nx == 0) + nx = 1; + + if (nx > screen_size_x(s) - s->cx) + nx = screen_size_x(s) - s->cx; + if (nx == 0) + return; + + screen_write_initctx(ctx, &ttyctx, 0); + + if (s->cx <= screen_size_x(s) - 1) + grid_view_clear(s->grid, s->cx, s->cy, nx, 1); + + ttyctx.num = nx; + tty_write(tty_cmd_clearcharacter, &ttyctx); +} + /* Insert ny lines. */ void screen_write_insertline(struct screen_write_ctx *ctx, u_int ny) diff --git a/tmux.h b/tmux.h index f1a9e4d4..d790dd25 100644 --- a/tmux.h +++ b/tmux.h @@ -274,6 +274,7 @@ enum tty_code_code { TTYC_DL, /* parm_delete_line, DL */ TTYC_DL1, /* delete_line, dl */ TTYC_E3, + TTYC_ECH, /* erase_chars, ec */ TTYC_EL, /* clr_eol, ce */ TTYC_EL1, /* clr_bol, cb */ TTYC_ENACS, /* ena_acs, eA */ @@ -1660,6 +1661,7 @@ void tty_cmd_clearscreen(struct tty *, const struct tty_ctx *); void tty_cmd_clearstartofline(struct tty *, const struct tty_ctx *); void tty_cmd_clearstartofscreen(struct tty *, const struct tty_ctx *); void tty_cmd_deletecharacter(struct tty *, const struct tty_ctx *); +void tty_cmd_clearcharacter(struct tty *, const struct tty_ctx *); void tty_cmd_deleteline(struct tty *, const struct tty_ctx *); void tty_cmd_erasecharacter(struct tty *, const struct tty_ctx *); void tty_cmd_insertcharacter(struct tty *, const struct tty_ctx *); @@ -2049,6 +2051,7 @@ void screen_write_cursorleft(struct screen_write_ctx *, u_int); void screen_write_alignmenttest(struct screen_write_ctx *); void screen_write_insertcharacter(struct screen_write_ctx *, u_int); void screen_write_deletecharacter(struct screen_write_ctx *, u_int); +void screen_write_clearcharacter(struct screen_write_ctx *, u_int); void screen_write_insertline(struct screen_write_ctx *, u_int); void screen_write_deleteline(struct screen_write_ctx *, u_int); void screen_write_clearline(struct screen_write_ctx *); diff --git a/tty-term.c b/tty-term.c index f088d251..c827a444 100644 --- a/tty-term.c +++ b/tty-term.c @@ -62,6 +62,7 @@ const struct tty_term_code_entry tty_term_codes[NTTYCODE] = { { TTYC_DL, TTYCODE_STRING, "dl" }, { TTYC_DL1, TTYCODE_STRING, "dl1" }, { TTYC_E3, TTYCODE_STRING, "E3" }, + { TTYC_ECH, TTYCODE_STRING, "ech" }, { TTYC_EL, TTYCODE_STRING, "el" }, { TTYC_EL1, TTYCODE_STRING, "el1" }, { TTYC_ENACS, TTYCODE_STRING, "enacs" }, diff --git a/tty.c b/tty.c index 6bc7139c..a650c836 100644 --- a/tty.c +++ b/tty.c @@ -718,6 +718,23 @@ tty_cmd_deletecharacter(struct tty *tty, const struct tty_ctx *ctx) tty_emulate_repeat(tty, TTYC_DCH, TTYC_DCH1, ctx->num); } +void +tty_cmd_clearcharacter(struct tty *tty, const struct tty_ctx *ctx) +{ + u_int i; + + tty_reset(tty); + + tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); + + if (tty_term_has(tty->term, TTYC_ECH)) + tty_putcode1(tty, TTYC_ECH, ctx->num); + else { + for (i = 0; i < ctx->num; i++) + tty_putc(tty, ' '); + } +} + void tty_cmd_insertline(struct tty *tty, const struct tty_ctx *ctx) { From e33ba57c13139bc9ae6e92be169de6dc322e38eb Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 17 Jan 2013 00:11:22 +0000 Subject: [PATCH 3/3] Remove the layout undo/redo code which never really worked. --- cmd-resize-pane.c | 1 - cmd-select-layout.c | 45 +++++++--------------------- key-bindings.c | 2 -- layout.c | 72 --------------------------------------------- options-table.c | 7 ----- tmux.1 | 16 +--------- tmux.h | 16 +--------- window.c | 1 - 8 files changed, 12 insertions(+), 148 deletions(-) diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index 4842d411..c200ee10 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -103,7 +103,6 @@ cmd_resize_pane_exec(struct cmd *self, struct cmd_ctx *ctx) } } - layout_list_add(wp->window); if (args_has(self->args, 'L')) layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust); else if (args_has(self->args, 'R')) diff --git a/cmd-select-layout.c b/cmd-select-layout.c index 982c0b27..3ca8766e 100644 --- a/cmd-select-layout.c +++ b/cmd-select-layout.c @@ -29,8 +29,8 @@ enum cmd_retval cmd_select_layout_exec(struct cmd *, struct cmd_ctx *); const struct cmd_entry cmd_select_layout_entry = { "select-layout", "selectl", - "nprut:", 0, 1, - "[-npUu] " CMD_TARGET_WINDOW_USAGE " [layout-name]", + "npt:", 0, 1, + "[-np] " CMD_TARGET_WINDOW_USAGE " [layout-name]", 0, cmd_select_layout_key_binding, NULL, @@ -76,14 +76,6 @@ cmd_select_layout_key_binding(struct cmd *self, int key) case '5' | KEYC_ESCAPE: self->args = args_create(1, "tiled"); break; - case 'u': - self->args = args_create(0); - args_set(self->args, 'u', NULL); - break; - case 'U': - self->args = args_create(0); - args_set(self->args, 'U', NULL); - break; default: self->args = args_create(0); break; @@ -110,21 +102,6 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) if (args_has(self->args, 'p')) previous = 1; - layout_list_add(w); - if (args_has(self->args, 'U')) { - if ((layoutname = layout_list_redo(w)) == NULL) { - ctx->info(ctx, "no more layout history"); - return (CMD_RETURN_ERROR); - } - goto set_layout; - } else if (args_has(self->args, 'u')) { - if ((layoutname = layout_list_undo(w)) == NULL) { - ctx->info(ctx, "no more layout history"); - return (CMD_RETURN_ERROR); - } - goto set_layout; - } - if (next || previous) { if (next) layout = layout_set_next(wl->window); @@ -146,16 +123,14 @@ cmd_select_layout_exec(struct cmd *self, struct cmd_ctx *ctx) return (CMD_RETURN_NORMAL); } - if (args->argc == 0) - return (CMD_RETURN_NORMAL); - layoutname = args->argv[0]; - -set_layout: - if (layout_parse(wl->window, layoutname) == -1) { - ctx->error(ctx, "can't set layout: %s", layoutname); - return (CMD_RETURN_ERROR); + if (args->argc != 0) { + layoutname = args->argv[0]; + if (layout_parse(wl->window, layoutname) == -1) { + ctx->error(ctx, "can't set layout: %s", layoutname); + return (CMD_RETURN_ERROR); + } + server_redraw_window(wl->window); + ctx->info(ctx, "arranging in: %s", layoutname); } - server_redraw_window(wl->window); - ctx->info(ctx, "arranging in: %s", layoutname); return (CMD_RETURN_NORMAL); } diff --git a/key-bindings.c b/key-bindings.c index 8434cc03..5ebde40c 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -130,7 +130,6 @@ key_bindings_init(void) { '?', 0, &cmd_list_keys_entry }, { 'D', 0, &cmd_choose_client_entry }, { 'L', 0, &cmd_switch_client_entry }, - { 'U', 1, &cmd_select_layout_entry }, { '[', 0, &cmd_copy_mode_entry }, { '\'', 0, &cmd_command_prompt_entry }, { '\002', /* C-b */ 0, &cmd_send_prefix_entry }, @@ -149,7 +148,6 @@ key_bindings_init(void) { 'r', 0, &cmd_refresh_client_entry }, { 's', 0, &cmd_choose_tree_entry }, { 't', 0, &cmd_clock_mode_entry }, - { 'u', 1, &cmd_select_layout_entry }, { 'w', 0, &cmd_choose_window_entry }, { 'x', 0, &cmd_confirm_before_entry }, { '{', 0, &cmd_swap_pane_entry }, diff --git a/layout.c b/layout.c index adae0ec3..7c13b539 100644 --- a/layout.c +++ b/layout.c @@ -19,7 +19,6 @@ #include #include -#include #include "tmux.h" @@ -747,74 +746,3 @@ layout_close_pane(struct window_pane *wp) } notify_window_layout_changed(wp->window); } - -/* Add layout to list. */ -void -layout_list_add(struct window *w) -{ - struct last_layout *ll, *ll_last; - char *layout; - u_int limit; - - layout = layout_dump(w); - - ll_last = w->layout_list_last; - if (ll_last != NULL && strcmp(ll_last->layout, layout) == 0) { - free(layout); - return; - } - - ll = xmalloc(sizeof *ll); - ll->layout = layout; - if (ll_last == NULL) - TAILQ_INSERT_TAIL(&w->layout_list, ll, entry); - else - TAILQ_INSERT_AFTER(&w->layout_list, ll_last, ll, entry); - w->layout_list_size++; - w->layout_list_last = ll; - - limit = options_get_number(&w->options, "layout-history-limit"); - while (w->layout_list_size > limit) { - ll = TAILQ_LAST(&w->layout_list, last_layouts); - if (ll == w->layout_list_last) - ll = TAILQ_FIRST(&w->layout_list); - - TAILQ_REMOVE(&w->layout_list, ll, entry); - w->layout_list_size--; - - free(ll->layout); - free(ll); - } -} - -/* Apply next layout from list. */ -const char * -layout_list_redo(struct window *w) -{ - struct last_layout *ll, *ll_last; - - ll_last = w->layout_list_last; - if (ll_last == NULL) - return (NULL); - ll = TAILQ_NEXT(ll_last, entry); - if (ll == NULL) - return (NULL); - w->layout_list_last = ll; - return (ll->layout); -} - -/* Apply previous layout from list. */ -const char * -layout_list_undo(struct window *w) -{ - struct last_layout *ll, *ll_last; - - ll_last = w->layout_list_last; - if (ll_last == NULL) - return (NULL); - ll = TAILQ_PREV(ll_last, last_layouts, entry); - if (ll == NULL) - return (NULL); - w->layout_list_last = ll; - return (ll->layout); -} diff --git a/options-table.c b/options-table.c index 9baf6835..529b3c26 100644 --- a/options-table.c +++ b/options-table.c @@ -517,13 +517,6 @@ const struct options_table_entry window_options_table[] = { .default_num = 0 }, - { .name = "layout-history-limit", - .type = OPTIONS_TABLE_NUMBER, - .minimum = 1, - .maximum = USHRT_MAX, - .default_num = 20 - }, - { .name = "main-pane-height", .type = OPTIONS_TABLE_NUMBER, .minimum = 1, diff --git a/tmux.1 b/tmux.1 index 975aa103..ceebfcef 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1601,7 +1601,7 @@ lower) with .Fl U or downward (numerically higher). .It Xo Ic select-layout -.Op Fl npUu +.Op Fl np .Op Fl t Ar target-window .Op Ar layout-name .Xc @@ -1618,13 +1618,6 @@ are equivalent to the and .Ic previous-layout commands. -.Pp -.Fl U -and -.Fl u -step forward and back through previous layouts, up to the maximum set by the -.Ic layout-history-limit -option. .It Xo Ic select-pane .Op Fl lDLRU .Op Fl t Ar target-pane @@ -2677,13 +2670,6 @@ or .Ar height . A value of zero restores the default unlimited setting. .Pp -.It Ic layout-history-limit Ar limit -Set the number of previous layouts stored for recovery with -.Ic select-layout -.Fl U -and -.Fl u . -.Pp .It Ic main-pane-height Ar height .It Ic main-pane-width Ar width Set the width or height of the main (left or top) pane in the diff --git a/tmux.h b/tmux.h index d790dd25..9c062d65 100644 --- a/tmux.h +++ b/tmux.h @@ -974,13 +974,6 @@ struct window_pane { TAILQ_HEAD(window_panes, window_pane); RB_HEAD(window_pane_tree, window_pane); -/* Window last layout. */ -struct last_layout { - char *layout; - - TAILQ_ENTRY(last_layout) entry; -}; - /* Window structure. */ struct window { u_int id; @@ -994,9 +987,6 @@ struct window { int lastlayout; struct layout_cell *layout_root; - TAILQ_HEAD(last_layouts, last_layout) layout_list; - u_int layout_list_size; - struct last_layout *layout_list_last; u_int sx; u_int sy; @@ -2179,8 +2169,7 @@ u_int layout_count_cells(struct layout_cell *); struct layout_cell *layout_create_cell(struct layout_cell *); void layout_free_cell(struct layout_cell *); void layout_print_cell(struct layout_cell *, const char *, u_int); -void layout_destroy_cell( - struct layout_cell *, struct layout_cell **); +void layout_destroy_cell(struct layout_cell *, struct layout_cell **); void layout_set_size( struct layout_cell *, u_int, u_int, u_int, u_int); void layout_make_leaf( @@ -2201,9 +2190,6 @@ void layout_assign_pane(struct layout_cell *, struct window_pane *); struct layout_cell *layout_split_pane( struct window_pane *, enum layout_type, int, int); void layout_close_pane(struct window_pane *); -void layout_list_add(struct window *); -const char *layout_list_redo(struct window *); -const char *layout_list_undo(struct window *); /* layout-custom.c */ char *layout_dump(struct window *); diff --git a/window.c b/window.c index 97e5b4a3..97168455 100644 --- a/window.c +++ b/window.c @@ -286,7 +286,6 @@ window_create1(u_int sx, u_int sy) w->lastlayout = -1; w->layout_root = NULL; - TAILQ_INIT(&w->layout_list); w->sx = sx; w->sy = sy;