diff options
-rw-r--r-- | input.c | 71 | ||||
-rw-r--r-- | log.c | 21 | ||||
-rw-r--r-- | mode-tree.c | 4 | ||||
-rw-r--r-- | proc.c | 6 | ||||
-rw-r--r-- | screen-write.c | 2 | ||||
-rw-r--r-- | screen.c | 3 | ||||
-rw-r--r-- | server.c | 5 | ||||
-rw-r--r-- | signal.c | 6 | ||||
-rw-r--r-- | tmux.1 | 21 | ||||
-rw-r--r-- | tmux.h | 3 | ||||
-rw-r--r-- | tty.c | 2 | ||||
-rw-r--r-- | utf8.c | 24 | ||||
-rw-r--r-- | window.c | 2 |
13 files changed, 144 insertions, 26 deletions
@@ -93,6 +93,8 @@ struct input_ctx { const struct input_state *state; + struct event timer; + /* * All input received since we were last in the ground state. Sent to * control clients on connection. @@ -118,6 +120,7 @@ static void input_osc_104(struct window_pane *, const char *); /* Transition entry/exit handlers. */ static void input_clear(struct input_ctx *); static void input_ground(struct input_ctx *); +static void input_enter_dcs(struct input_ctx *); static void input_enter_osc(struct input_ctx *); static void input_exit_osc(struct input_ctx *); static void input_enter_apc(struct input_ctx *); @@ -364,7 +367,7 @@ static const struct input_state input_state_csi_ignore = { /* dcs_enter state definition. */ static const struct input_state input_state_dcs_enter = { "dcs_enter", - input_clear, NULL, + input_enter_dcs, NULL, input_state_dcs_enter_table }; @@ -756,6 +759,30 @@ input_table_compare(const void *key, const void *value) return (strcmp(ictx->interm_buf, entry->interm)); } +/* + * Timer - if this expires then have been waiting for a terminator for too + * long, so reset to ground. + */ +static void +input_timer_callback(__unused int fd, __unused short events, void *arg) +{ + struct input_ctx *ictx = arg; + struct window_pane *wp = ictx->wp; + + log_debug("%s: %%%u %s expired" , __func__, wp->id, ictx->state->name); + input_reset(wp, 0); +} + +/* Start the timer. */ +static void +input_start_timer(struct input_ctx *ictx) +{ + struct timeval tv = { .tv_usec = 100000 }; + + event_del(&ictx->timer); + event_add(&ictx->timer, &tv); +} + /* Reset cell state to default. */ static void input_reset_cell(struct input_ctx *ictx) @@ -782,6 +809,8 @@ input_init(struct window_pane *wp) ictx->since_ground = evbuffer_new(); + evtimer_set(&ictx->timer, input_timer_callback, ictx); + input_reset(wp, 0); } @@ -791,6 +820,8 @@ input_free(struct window_pane *wp) { struct input_ctx *ictx = wp->ictx; + event_del(&ictx->timer); + free(ictx->input_buf); evbuffer_free(ictx->since_ground); @@ -815,14 +846,7 @@ input_reset(struct window_pane *wp, int clear) screen_write_stop(&ictx->ctx); } - *ictx->interm_buf = '\0'; - ictx->interm_len = 0; - - *ictx->param_buf = '\0'; - ictx->param_len = 0; - - *ictx->input_buf = '\0'; - ictx->input_len = 0; + input_clear(ictx); ictx->state = &input_state_ground; ictx->flags = 0; @@ -997,6 +1021,8 @@ input_reply(struct input_ctx *ictx, const char *fmt, ...) static void input_clear(struct input_ctx *ictx) { + event_del(&ictx->timer); + *ictx->interm_buf = '\0'; ictx->interm_len = 0; @@ -1013,6 +1039,7 @@ input_clear(struct input_ctx *ictx) static void input_ground(struct input_ctx *ictx) { + event_del(&ictx->timer); evbuffer_drain(ictx->since_ground, EVBUFFER_LENGTH(ictx->since_ground)); if (ictx->input_space > INPUT_BUF_START) { @@ -1842,6 +1869,16 @@ input_csi_dispatch_sgr(struct input_ctx *ictx) } } +/* DCS string started. */ +static void +input_enter_dcs(struct input_ctx *ictx) +{ + log_debug("%s", __func__); + + input_clear(ictx); + input_start_timer(ictx); +} + /* DCS terminator (ST) received. */ static int input_dcs_dispatch(struct input_ctx *ictx) @@ -1871,6 +1908,7 @@ input_enter_osc(struct input_ctx *ictx) log_debug("%s", __func__); input_clear(ictx); + input_start_timer(ictx); } /* OSC terminator (ST) received. */ @@ -1896,8 +1934,10 @@ input_exit_osc(struct input_ctx *ictx) switch (option) { case 0: case 2: - screen_set_title(ictx->ctx.s, p); - server_status_window(ictx->wp->window); + if (utf8_isvalid(p)) { + screen_set_title(ictx->ctx.s, p); + server_status_window(ictx->wp->window); + } break; case 4: input_osc_4(ictx->wp, p); @@ -1909,7 +1949,7 @@ input_exit_osc(struct input_ctx *ictx) input_osc_11(ictx->wp, p); break; case 12: - if (*p != '?') /* ? is colour request */ + if (utf8_isvalid(p) && *p != '?') /* ? is colour request */ screen_set_cursor_colour(ictx->ctx.s, p); break; case 52: @@ -1935,6 +1975,7 @@ input_enter_apc(struct input_ctx *ictx) log_debug("%s", __func__); input_clear(ictx); + input_start_timer(ictx); } /* APC terminator (ST) received. */ @@ -1945,6 +1986,8 @@ input_exit_apc(struct input_ctx *ictx) return; log_debug("%s: \"%s\"", __func__, ictx->input_buf); + if (!utf8_isvalid(ictx->input_buf)) + return; screen_set_title(ictx->ctx.s, ictx->input_buf); server_status_window(ictx->wp->window); } @@ -1956,6 +1999,7 @@ input_enter_rename(struct input_ctx *ictx) log_debug("%s", __func__); input_clear(ictx); + input_start_timer(ictx); } /* Rename terminator (ST) received. */ @@ -1968,9 +2012,10 @@ input_exit_rename(struct input_ctx *ictx) return; log_debug("%s: \"%s\"", __func__, ictx->input_buf); + if (!utf8_isvalid(ictx->input_buf)) + return; window_set_name(ictx->wp->window, ictx->input_buf); options_set_number(ictx->wp->window->options, "automatic-rename", 0); - server_status_window(ictx->wp->window); } @@ -61,12 +61,10 @@ log_open(const char *name) if (log_level == 0) return; - - if (log_file != NULL) - fclose(log_file); + log_close(); xasprintf(&path, "tmux-%s-%ld.log", name, (long)getpid()); - log_file = fopen(path, "w"); + log_file = fopen(path, "a"); free(path); if (log_file == NULL) return; @@ -75,6 +73,21 @@ log_open(const char *name) event_set_log_callback(log_event_cb); } +/* Toggle logging. */ +void +log_toggle(const char *name) +{ + if (log_level == 0) { + log_level = 1; + log_open(name); + log_debug("log opened"); + } else { + log_debug("log closed"); + log_level = 0; + log_close(); + } +} + /* Close logging. */ void log_close(void) diff --git a/mode-tree.c b/mode-tree.c index f3155fbf..437f0008 100644 --- a/mode-tree.c +++ b/mode-tree.c @@ -685,8 +685,10 @@ mode_tree_run_command(struct client *c, struct cmd_find_state *fs, char *command, *cause; command = cmd_template_replace(template, name, 1); - if (command == NULL || *command == '\0') + if (command == NULL || *command == '\0') { + free(command); return; + } cmdlist = cmd_string_parse(command, NULL, 0, &cause); if (cmdlist == NULL) { @@ -263,3 +263,9 @@ proc_kill_peer(struct tmuxpeer *peer) { peer->flags |= PEER_BAD; } + +void +proc_toggle_log(struct tmuxproc *tp) +{ + log_toggle(tp->name); +} diff --git a/screen-write.c b/screen-write.c index c5af7c07..1f122482 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1390,7 +1390,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) } } - /* Update the selection the flag and set the cell. */ + /* Update the selected flag and set the cell. */ selected = screen_check_selection(s, s->cx, s->cy); if (selected && (~gc->flags & GRID_FLAG_SELECTED)) { memcpy(&tmp_gc, gc, sizeof tmp_gc); @@ -21,6 +21,7 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <vis.h> #include "tmux.h" @@ -107,7 +108,7 @@ void screen_set_title(struct screen *s, const char *title) { free(s->title); - s->title = xstrdup(title); + utf8_stravis(&s->title, title, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL); } /* Resize screen. */ @@ -150,7 +150,7 @@ server_start(struct event_base *base, int lockfd, char *lockfile) } close(pair[0]); - if (log_get_level() > 3) + if (log_get_level() > 1) tty_create_log(); if (pledge("stdio rpath wpath cpath fattr unix getpw recvfd proc exec " "tty ps", NULL) != 0) @@ -364,6 +364,9 @@ server_signal(int sig) } server_add_accept(0); break; + case SIGUSR2: + proc_toggle_log(server_proc); + break; } } @@ -29,6 +29,7 @@ static struct event ev_sigchld; static struct event ev_sigcont; static struct event ev_sigterm; static struct event ev_sigusr1; +static struct event ev_sigusr2; static struct event ev_sigwinch; void @@ -59,6 +60,8 @@ set_signals(void (*handler)(int, short, void *), void *arg) signal_add(&ev_sigterm, NULL); signal_set(&ev_sigusr1, SIGUSR1, handler, arg); signal_add(&ev_sigusr1, NULL); + signal_set(&ev_sigusr2, SIGUSR2, handler, arg); + signal_add(&ev_sigusr2, NULL); signal_set(&ev_sigwinch, SIGWINCH, handler, arg); signal_add(&ev_sigwinch, NULL); } @@ -92,6 +95,8 @@ clear_signals(int after_fork) fatal("sigaction failed"); if (sigaction(SIGUSR1, &sigact, NULL) != 0) fatal("sigaction failed"); + if (sigaction(SIGUSR2, &sigact, NULL) != 0) + fatal("sigaction failed"); if (sigaction(SIGWINCH, &sigact, NULL) != 0) fatal("sigaction failed"); } else { @@ -100,6 +105,7 @@ clear_signals(int after_fork) event_del(&ev_sigcont); event_del(&ev_sigterm); event_del(&ev_sigusr1); + event_del(&ev_sigusr2); event_del(&ev_sigwinch); } } @@ -199,7 +199,6 @@ characters to the terminal it is running (if not, they are replaced by .Ql _ ) . .It Fl v Request verbose logging. -This option may be specified multiple times for increasing verbosity. Log messages will be saved into .Pa tmux-client-PID.log and @@ -211,6 +210,22 @@ is the PID of the server or client process. Report the .Nm version. +.Pp +If +.Fl v +is specified twice, an additional +.Pa tmux-out-PID.log +file is generated with a copy of everything +.Nm +writes to the terminal. +.Pp +The +.Dv SIGUSR2 +signal may be sent to the +.Nm +server process to toggle logging between on (as if +.Fl v +was given) and off. .It Ar command Op Ar flags This specifies one of a set of commands used to control .Nm , @@ -1398,7 +1413,7 @@ The following keys may be used in tree mode: .It Li "t" Ta "Toggle if item is tagged" .It Li "T" Ta "Tag no items" .It Li "C-t" Ta "Tag all items" -.It Li ":" Ta "Run a command for each tagged item" +.It Li "\&:" Ta "Run a command for each tagged item" .It Li "f" Ta "Enter a format to filter items" .It Li "O" Ta "Change sort order" .It Li "q" Ta "Exit mode" @@ -3742,7 +3757,7 @@ The flag is one of the following symbols appended to the window name: .It Li "*" Ta "Denotes the current window." .It Li "-" Ta "Marks the last window (previously selected)." .It Li "#" Ta "Window is monitored and activity has been detected." -.It Li "!" Ta "A bell has occurred in the window." +.It Li "\&!" Ta "A bell has occurred in the window." .It Li "~" Ta "The window has been silent for the monitor-silence interval." .It Li "M" Ta "The window contains the marked pane." .It Li "Z" Ta "The window's active pane is zoomed." @@ -1497,6 +1497,7 @@ struct tmuxpeer *proc_add_peer(struct tmuxproc *, int, void (*)(struct imsg *, void *), void *); void proc_remove_peer(struct tmuxpeer *); void proc_kill_peer(struct tmuxpeer *); +void proc_toggle_log(struct tmuxproc *); /* cfg.c */ extern int cfg_finished; @@ -2321,6 +2322,7 @@ enum utf8_state utf8_open(struct utf8_data *, u_char); enum utf8_state utf8_append(struct utf8_data *, u_char); enum utf8_state utf8_combine(const struct utf8_data *, wchar_t *); enum utf8_state utf8_split(wchar_t, struct utf8_data *); +int utf8_isvalid(const char *); int utf8_strvis(char *, const char *, size_t, int); int utf8_stravis(char **, const char *, int); char *utf8_sanitize(const char *); @@ -2342,6 +2344,7 @@ struct event_base *osdep_event_init(void); void log_add_level(void); int log_get_level(void); void log_open(const char *); +void log_toggle(const char *); void log_close(void); void printflike(1, 2) log_debug(const char *, ...); __dead void printflike(1, 2) fatal(const char *, ...); @@ -1848,7 +1848,7 @@ tty_check_fg(struct tty *tty, const struct window_pane *wp, */ if (~gc->flags & GRID_FLAG_NOPALETTE) { c = gc->fg; - if (gc->fg < 8 && gc->attr & GRID_ATTR_BRIGHT) + if (c < 8 && gc->attr & GRID_ATTR_BRIGHT) c += 90; if ((c = window_pane_get_palette(wp, c)) != -1) gc->fg = c; @@ -232,6 +232,30 @@ utf8_stravis(char **dst, const char *src, int flag) return (len); } +/* Does this string contain anything that isn't valid UTF-8? */ +int +utf8_isvalid(const char *s) +{ + struct utf8_data ud; + const char *end; + enum utf8_state more; + + end = s + strlen(s); + while (s < end) { + if ((more = utf8_open(&ud, *s)) == UTF8_MORE) { + while (++s < end && more == UTF8_MORE) + more = utf8_append(&ud, *s); + if (more == UTF8_DONE) + continue; + return (0); + } + if (*s < 0x20 || *s > 0x7e) + return (0); + s++; + } + return (1); +} + /* * Sanitize a string, changing any UTF-8 characters to '_'. Caller should free * the returned string. Anything not valid printable ASCII or UTF-8 is @@ -408,7 +408,7 @@ void window_set_name(struct window *w, const char *new_name) { free(w->name); - w->name = xstrdup(new_name); + utf8_stravis(&w->name, new_name, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL); notify_window("window-renamed", w); } |