diff --git a/cmd-attach-session.c b/cmd-attach-session.c index 8094d78b..17c932e6 100644 --- a/cmd-attach-session.c +++ b/cmd-attach-session.c @@ -132,7 +132,7 @@ cmd_attach_session(struct cmd_q *cmdq, const char *tflag, int dflag, int rflag, server_redraw_client(cmdq->client); s->curw->flags &= ~WINLINK_ALERTFLAGS; } else { - if (server_client_open(cmdq->client, s, &cause) != 0) { + if (server_client_open(cmdq->client, &cause) != 0) { cmdq_error(cmdq, "open terminal failed: %s", cause); free(cause); return (CMD_RETURN_ERROR); diff --git a/cmd-choose-buffer.c b/cmd-choose-buffer.c index d79f6fdc..64edc845 100644 --- a/cmd-choose-buffer.c +++ b/cmd-choose-buffer.c @@ -49,6 +49,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq) char *action, *action_data; const char *template; u_int idx; + int utf8flag; if ((c = cmd_current_client(cmdq)) == NULL) { cmdq_error(cmdq, "no client available"); @@ -60,6 +61,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq) if ((wl = cmd_find_window(cmdq, args_get(args, 't'), NULL)) == NULL) return (CMD_RETURN_ERROR); + utf8flag = options_get_number(&wl->window->options, "utf8"); if (paste_get_top(&global_buffers) == NULL) return (CMD_RETURN_NORMAL); @@ -79,7 +81,7 @@ cmd_choose_buffer_exec(struct cmd *self, struct cmd_q *cmdq) cdata->ft_template = xstrdup(template); format_add(cdata->ft, "line", "%u", idx - 1); - format_paste_buffer(cdata->ft, pb); + format_paste_buffer(cdata->ft, pb, utf8flag); xasprintf(&action_data, "%u", idx - 1); cdata->command = cmd_template_replace(action, action_data, 1); diff --git a/cmd-list-buffers.c b/cmd-list-buffers.c index 02a4183e..53f65986 100644 --- a/cmd-list-buffers.c +++ b/cmd-list-buffers.c @@ -55,7 +55,7 @@ cmd_list_buffers_exec(unused struct cmd *self, struct cmd_q *cmdq) while ((pb = paste_walk_stack(&global_buffers, &idx)) != NULL) { ft = format_create(); format_add(ft, "line", "%u", idx - 1); - format_paste_buffer(ft, pb); + format_paste_buffer(ft, pb, 0); line = format_expand(ft, template); cmdq_print(cmdq, "%s", line); diff --git a/cmd-new-session.c b/cmd-new-session.c index 15e411d0..c190e972 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -145,7 +145,7 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) /* Open the terminal if necessary. */ if (!detached && !already_attached) { - if (server_client_open(c, NULL, &cause) != 0) { + if (server_client_open(c, &cause) != 0) { cmdq_error(cmdq, "open terminal failed: %s", cause); free(cause); goto error; diff --git a/format.c b/format.c index 497b5b52..29e26525 100644 --- a/format.c +++ b/format.c @@ -603,12 +603,14 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp) /* Set default format keys for paste buffer. */ void -format_paste_buffer(struct format_tree *ft, struct paste_buffer *pb) +format_paste_buffer(struct format_tree *ft, struct paste_buffer *pb, + int utf8flag) { - char *pb_print = paste_print(pb, 50); + char *s; format_add(ft, "buffer_size", "%zu", pb->size); - format_add(ft, "buffer_sample", "%s", pb_print); - free(pb_print); + s = paste_make_sample(pb, utf8flag); + format_add(ft, "buffer_sample", "%s", s); + free(s); } diff --git a/input-keys.c b/input-keys.c index 46c37d0b..f092f976 100644 --- a/input-keys.c +++ b/input-keys.c @@ -244,7 +244,7 @@ input_mouse(struct window_pane *wp, struct session *s, struct mouse_event *m) paste_send_pane(pb, wp, "\r", wp->screen->mode & MODE_BRACKETPASTE); } - } else if ((m->xb & 3) != 1 && + } else if (m->button != 1 && options_get_number(&wp->window->options, "mode-mouse") == 1) { if (window_pane_set_mode(wp, &window_copy_mode) == 0) { window_copy_init_from_pane(wp); diff --git a/options-table.c b/options-table.c index 7b09a687..c73ac84d 100644 --- a/options-table.c +++ b/options-table.c @@ -97,6 +97,14 @@ const struct options_table_entry server_options_table[] = { .default_num = 1 }, + { .name = "terminal-overrides", + .type = OPTIONS_TABLE_STRING, + .default_str = "*256col*:colors=256" + ",xterm*:XT:Ms=\\E]52;%p1%s;%p2%s\\007" + ":Cs=\\E]12;%p1%s\\007:Cr=\\E]112\\007" + ":Ss=\\E[%p1%d q:Se=\\E[2 q,screen*:XT" + }, + { .name = NULL } }; @@ -465,14 +473,6 @@ const struct options_table_entry session_options_table[] = { .default_num = 0 /* overridden in main() */ }, - { .name = "terminal-overrides", - .type = OPTIONS_TABLE_STRING, - .default_str = "*256col*:colors=256" - ",xterm*:XT:Ms=\\E]52;%p1%s;%p2%s\\007" - ":Cs=\\E]12;%p1%s\\007:Cr=\\E]112\\007" - ":Ss=\\E[%p1%d q:Se=\\E[2 q,screen*:XT" - }, - { .name = "update-environment", .type = OPTIONS_TABLE_STRING, .default_str = "DISPLAY SSH_ASKPASS SSH_AUTH_SOCK SSH_AGENT_PID " diff --git a/paste.c b/paste.c index 28f12306..00f37b9d 100644 --- a/paste.c +++ b/paste.c @@ -147,25 +147,26 @@ paste_replace(struct paste_stack *ps, u_int idx, char *data, size_t size) return (0); } -/* Convert a buffer into a visible string. */ +/* Convert start of buffer into a nice string. */ char * -paste_print(struct paste_buffer *pb, size_t width) +paste_make_sample(struct paste_buffer *pb, int utf8flag) { - char *buf; - size_t len, used; - - if (width < 3) - width = 3; - buf = xmalloc(width * 4 + 1); + char *buf; + size_t len, used; + const int flags = VIS_OCTAL|VIS_TAB|VIS_NL; + const size_t width = 200; len = pb->size; if (len > width) len = width; + buf = xmalloc(len * 4 + 4); - used = strvisx(buf, pb->data, len, VIS_OCTAL|VIS_TAB|VIS_NL); + if (utf8flag) + used = utf8_strvis(buf, pb->data, len, flags); + else + used = strvisx(buf, pb->data, len, flags); if (pb->size > width || used > width) - strlcpy(buf + width - 3, "...", 4); - + strlcpy(buf + width, "...", 4); return (buf); } diff --git a/server-client.c b/server-client.c index 98d1e043..2c407b8c 100644 --- a/server-client.c +++ b/server-client.c @@ -113,11 +113,8 @@ server_client_create(int fd) /* Open client terminal if needed. */ int -server_client_open(struct client *c, struct session *s, char **cause) +server_client_open(struct client *c, char **cause) { - struct options *oo = s != NULL ? &s->options : &global_s_options; - char *overrides; - if (c->flags & CLIENT_CONTROL) return (0); @@ -126,8 +123,7 @@ server_client_open(struct client *c, struct session *s, char **cause) return (-1); } - overrides = options_get_string(oo, "terminal-overrides"); - if (tty_open(&c->tty, overrides, cause) != 0) + if (tty_open(&c->tty, cause) != 0) return (-1); return (0); diff --git a/server-window.c b/server-window.c index 687d4239..900060b5 100644 --- a/server-window.c +++ b/server-window.c @@ -85,10 +85,11 @@ server_window_check_bell(struct session *s, struct winlink *wl) return (0); for (i = 0; i < ARRAY_LENGTH(&clients); i++) { c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != s || (c->flags & CLIENT_CONTROL)) + if (c == NULL || c->session != s || c->flags & CLIENT_CONTROL) continue; if (!visual) { - tty_bell(&c->tty); + if (c->session->curw->window == w || action == BELL_ANY) + tty_bell(&c->tty); continue; } if (c->session->curw->window == w) diff --git a/status.c b/status.c index e8bbf4c1..af9dd7bc 100644 --- a/status.c +++ b/status.c @@ -396,9 +396,6 @@ status_replace1(struct client *c, char **iptr, char **optr, char *out, case '{': ptr = (char *) "#{"; goto do_replace; - case '#': - *(*optr)++ = '#'; - break; default: xsnprintf(tmp, sizeof tmp, "#%c", *(*iptr - 1)); ptr = tmp; diff --git a/tmux.1 b/tmux.1 index 2e17c655..06a5d598 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2170,6 +2170,42 @@ disallowedWindowOps: 20,21,SetXprop Or changing this property from the .Xr xterm 1 interactive menu when required. +.It Ic terminal-overrides Ar string +Contains a list of entries which override terminal descriptions read using +.Xr terminfo 5 . +.Ar string +is a comma-separated list of items each a colon-separated string made up of a +terminal type pattern (matched using +.Xr fnmatch 3 ) +and a set of +.Em name=value +entries. +.Pp +For example, to set the +.Ql clear +.Xr terminfo 5 +entry to +.Ql \ee[H\ee[2J +for all terminal types and the +.Ql dch1 +entry to +.Ql \ee[P +for the +.Ql rxvt +terminal type, the option could be set to the string: +.Bd -literal -offset indent +"*:clear=\ee[H\ee[2J,rxvt:dch1=\ee[P" +.Ed +.Pp +The terminal entry value is passed through +.Xr strunvis 3 +before interpretation. +The default value forcibly corrects the +.Ql colors +entry for terminals which support 256 colours: +.Bd -literal -offset indent +"*256col*:colors=256,xterm*:XT" +.Ed .El .Pp Available session options are: @@ -2610,42 +2646,6 @@ and .Ic status-right strings as UTF-8; notably, this is important for wide characters. This option defaults to off. -.It Ic terminal-overrides Ar string -Contains a list of entries which override terminal descriptions read using -.Xr terminfo 5 . -.Ar string -is a comma-separated list of items each a colon-separated string made up of a -terminal type pattern (matched using -.Xr fnmatch 3 ) -and a set of -.Em name=value -entries. -.Pp -For example, to set the -.Ql clear -.Xr terminfo 5 -entry to -.Ql \ee[H\ee[2J -for all terminal types and the -.Ql dch1 -entry to -.Ql \ee[P -for the -.Ql rxvt -terminal type, the option could be set to the string: -.Bd -literal -offset indent -"*:clear=\ee[H\ee[2J,rxvt:dch1=\ee[P" -.Ed -.Pp -The terminal entry value is passed through -.Xr strunvis 3 -before interpretation. -The default value forcibly corrects the -.Ql colors -entry for terminals which support 256 colours: -.Bd -literal -offset indent -"*256col*:colors=256,xterm*:XT" -.Ed .It Ic update-environment Ar variables Set a space-separated string containing a list of environment variables to be copied into the session environment when a new session is created or an @@ -3091,7 +3091,7 @@ The following variables are available, where appropriate: .It Li "alternate_on" Ta "" Ta "If pane is in alternate screen" .It Li "alternate_saved_x" Ta "" Ta "Saved cursor X in alternate screen" .It Li "alternate_saved_y" Ta "" Ta "Saved cursor Y in alternate screen" -.It Li "buffer_sample" Ta "" Ta "First 50 characters from buffer" +.It Li "buffer_sample" Ta "" Ta "Sample of start of buffer" .It Li "buffer_size" Ta "" Ta "Size of the specified buffer in bytes" .It Li "client_activity" Ta "" Ta "Integer time client last had activity" .It Li "client_activity_string" Ta "" Ta "String time client last had activity" @@ -3133,7 +3133,6 @@ The following variables are available, where appropriate: .It Li "pane_index" Ta "#P" Ta "Index of pane" .It Li "pane_pid" Ta "" Ta "PID of first process in pane" .It Li "pane_start_command" Ta "" Ta "Command pane started with" -.It Li "pane_start_path" Ta "" Ta "Path pane started with" .It Li "pane_tabs" Ta "" Ta "Pane tab positions" .It Li "pane_title" Ta "#T" Ta "Title of pane" .It Li "pane_tty" Ta "" Ta "Pseudo terminal of pane" diff --git a/tmux.h b/tmux.h index 5aac390c..dacda666 100644 --- a/tmux.h +++ b/tmux.h @@ -82,7 +82,7 @@ extern char **environ; /* Default template for choose-buffer. */ #define CHOOSE_BUFFER_TEMPLATE \ - "#{line}: #{buffer_size} bytes: \"#{buffer_sample}\"" + "#{line}: #{buffer_size} bytes: #{buffer_sample}" /* Default template for choose-client. */ #define CHOOSE_CLIENT_TEMPLATE \ @@ -1165,6 +1165,7 @@ struct mouse_event { u_int button; u_int clicks; + u_int scroll; int wheel; int event; @@ -1541,7 +1542,7 @@ void format_winlink(struct format_tree *, struct session *, void format_window_pane(struct format_tree *, struct window_pane *); void format_paste_buffer(struct format_tree *, - struct paste_buffer *); + struct paste_buffer *, int); /* mode-key.c */ extern const struct mode_key_table mode_key_tables[]; @@ -1652,7 +1653,7 @@ void tty_set_title(struct tty *, const char *); void tty_update_mode(struct tty *, int, struct screen *); void tty_force_cursor_colour(struct tty *, const char *); void tty_draw_line(struct tty *, struct screen *, u_int, u_int, u_int); -int tty_open(struct tty *, const char *, char **); +int tty_open(struct tty *, char **); void tty_close(struct tty *); void tty_free(struct tty *); void tty_write( @@ -1681,7 +1682,7 @@ void tty_bell(struct tty *); /* tty-term.c */ extern struct tty_terms tty_terms; extern const struct tty_term_code_entry tty_term_codes[NTTYCODE]; -struct tty_term *tty_term_find(char *, int, const char *, char **); +struct tty_term *tty_term_find(char *, int, char **); void tty_term_free(struct tty_term *); int tty_term_has(struct tty_term *, enum tty_code_code); const char *tty_term_string(struct tty_term *, enum tty_code_code); @@ -1711,7 +1712,7 @@ int paste_free_top(struct paste_stack *); int paste_free_index(struct paste_stack *, u_int); void paste_add(struct paste_stack *, char *, size_t, u_int); int paste_replace(struct paste_stack *, u_int, char *, size_t); -char *paste_print(struct paste_buffer *, size_t); +char *paste_make_sample(struct paste_buffer *, int); void paste_send_pane(struct paste_buffer *, struct window_pane *, const char *, int); @@ -1891,7 +1892,7 @@ void server_add_accept(int); /* server-client.c */ void server_client_handle_key(struct client *, int); void server_client_create(int); -int server_client_open(struct client *, struct session *, char **); +int server_client_open(struct client *, char **); void server_client_lost(struct client *); void server_client_callback(int, short, void *); void server_client_status_timer(void); @@ -2323,6 +2324,7 @@ int utf8_open(struct utf8_data *, u_char); int utf8_append(struct utf8_data *, u_char); u_int utf8_combine(const struct utf8_data *); u_int utf8_split2(u_int, u_char *); +int utf8_strvis(char *, const char *, size_t, int); /* osdep-*.c */ char *osdep_get_name(int, char *); diff --git a/tty-keys.c b/tty-keys.c index 9dbe4503..42f2da40 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -749,6 +749,15 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) m->x = x; m->y = y; if (b & MOUSE_MASK_WHEEL) { + if (b & MOUSE_MASK_SHIFT) + m->scroll = 1; + else + m->scroll = 3; + if (b & MOUSE_MASK_META) + m->scroll *= 3; + if (b & MOUSE_MASK_CTRL) + m->scroll *= 3; + b &= MOUSE_MASK_BUTTONS; if (b == 0) m->wheel = MOUSE_WHEEL_UP; @@ -756,9 +765,9 @@ tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) m->wheel = MOUSE_WHEEL_DOWN; m->event = MOUSE_EVENT_WHEEL; } else if ((b & MOUSE_MASK_BUTTONS) == 3) { - if (~m->event & MOUSE_EVENT_DRAG && x == m->x && y == m->y) { + if (~m->event & MOUSE_EVENT_DRAG && x == m->x && y == m->y) m->event = MOUSE_EVENT_CLICK; - } else + else m->event = MOUSE_EVENT_DRAG; m->event |= MOUSE_EVENT_UP; } else { diff --git a/tty-term.c b/tty-term.c index a3292eb6..7f8a2d5b 100644 --- a/tty-term.c +++ b/tty-term.c @@ -308,7 +308,7 @@ tty_term_override(struct tty_term *term, const char *overrides) } struct tty_term * -tty_term_find(char *name, int fd, const char *overrides, char **cause) +tty_term_find(char *name, int fd, char **cause) { struct tty_term *term; const struct tty_term_code_entry *ent; @@ -386,7 +386,10 @@ tty_term_find(char *name, int fd, const char *overrides, char **cause) break; } } - tty_term_override(term, overrides); + + /* Apply terminal overrides. */ + s = options_get_string(&global_options, "terminal-overrides"); + tty_term_override(term, s); /* Delete curses data. */ #if !defined(NCURSES_VERSION_MAJOR) || NCURSES_VERSION_MAJOR > 5 || \ diff --git a/tty.c b/tty.c index eb2511c9..02b74ee6 100644 --- a/tty.c +++ b/tty.c @@ -128,7 +128,7 @@ tty_set_size(struct tty *tty, u_int sx, u_int sy) { } int -tty_open(struct tty *tty, const char *overrides, char **cause) +tty_open(struct tty *tty, char **cause) { char out[64]; int fd; @@ -141,7 +141,7 @@ tty_open(struct tty *tty, const char *overrides, char **cause) tty->log_fd = fd; } - tty->term = tty_term_find(tty->termname, tty->fd, overrides, cause); + tty->term = tty_term_find(tty->termname, tty->fd, cause); if (tty->term == NULL) { tty_close(tty); return (-1); diff --git a/utf8.c b/utf8.c index 5babcb3b..20e35137 100644 --- a/utf8.c +++ b/utf8.c @@ -352,3 +352,45 @@ utf8_width(const struct utf8_data *utf8data) } return (1); } + +/* + * Encode len characters from src into dst, which is guaranteed to have four + * bytes available for each character from src (for \abc or UTF-8) plus space + * for \0. + */ +int +utf8_strvis(char *dst, const char *src, size_t len, int flag) +{ + struct utf8_data utf8data; + const char *start, *end; + int more; + size_t i; + + start = dst; + end = src + len; + + while (src < end) { + if (utf8_open(&utf8data, *src)) { + more = 1; + while (++src < end && more) + more = utf8_append(&utf8data, *src); + if (!more) { + /* UTF-8 character finished. */ + for (i = 0; i < utf8data.size; i++) + *dst++ = utf8data.data[i]; + continue; + } else if (utf8data.have > 0) { + /* Not a complete UTF-8 character. */ + src -= utf8data.have; + } + } + if (src < end - 1) + dst = vis(dst, src[0], flag, src[1]); + else if (src < end) + dst = vis(dst, src[0], flag, '\0'); + src++; + } + + *dst = '\0'; + return (dst - start); +} diff --git a/window-choose.c b/window-choose.c index e7578fe6..e75858ef 100644 --- a/window-choose.c +++ b/window-choose.c @@ -721,7 +721,17 @@ window_choose_mouse( struct window_choose_mode_data *data = wp->modedata; struct screen *s = &data->screen; struct window_choose_mode_item *item; - u_int idx; + u_int i, idx; + + if (m->event == MOUSE_EVENT_WHEEL) { + for (i = 0; i < m->scroll; i++) { + if (m->wheel == MOUSE_WHEEL_UP) + window_choose_key(wp, sess, KEYC_UP); + else + window_choose_key(wp, sess, KEYC_DOWN); + } + return; + } if (~m->event & MOUSE_EVENT_CLICK) return; diff --git a/window-copy.c b/window-copy.c index e3164f6f..9aaf554c 100644 --- a/window-copy.c +++ b/window-copy.c @@ -871,18 +871,19 @@ window_copy_mouse( /* If mouse wheel (buttons 4 and 5), scroll. */ if (m->event == MOUSE_EVENT_WHEEL) { - if (m->wheel == MOUSE_WHEEL_UP) { - for (i = 0; i < 5; i++) + for (i = 0; i < m->scroll; i++) { + if (m->wheel == MOUSE_WHEEL_UP) window_copy_cursor_up(wp, 1); - } else if (m->wheel == MOUSE_WHEEL_DOWN) { - for (i = 0; i < 5; i++) + else { window_copy_cursor_down(wp, 1); - /* - * We reached the bottom, leave copy mode, - * but only if no selection is in progress. - */ - if (data->oy == 0 && !s->sel.flag) - goto reset_mode; + + /* + * We reached the bottom, leave copy mode, but + * only if no selection is in progress. + */ + if (data->oy == 0 && !s->sel.flag) + goto reset_mode; + } } return; }