diff options
author | Nicholas Marriott <nicholas.marriott@gmail.com> | 2021-03-02 12:08:34 +0000 |
---|---|---|
committer | Nicholas Marriott <nicholas.marriott@gmail.com> | 2021-03-02 12:08:34 +0000 |
commit | c01251d02388efceca515c47c257e2b5342e3716 (patch) | |
tree | ca89407cb43bd2caa40a6854ba49ce1720e892ce | |
parent | 5c275c2a1a963876d4ac392067e42120417dbf43 (diff) | |
parent | 1466b570eedda0423d5a386d2b16b7ff0c0e477c (diff) |
Merge branch 'master' into 3.2-rc
-rw-r--r-- | .github/travis/build-all.sh | 2 | ||||
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | CHANGES | 70 | ||||
-rw-r--r-- | Makefile.am | 14 | ||||
-rw-r--r-- | alerts.c | 1 | ||||
-rw-r--r-- | cfg.c | 30 | ||||
-rw-r--r-- | client.c | 343 | ||||
-rw-r--r-- | cmd-display-menu.c | 315 | ||||
-rw-r--r-- | cmd-display-panes.c | 15 | ||||
-rw-r--r-- | cmd-if-shell.c | 2 | ||||
-rw-r--r-- | cmd-join-pane.c | 5 | ||||
-rw-r--r-- | cmd-list-windows.c | 4 | ||||
-rw-r--r-- | cmd-new-window.c | 38 | ||||
-rw-r--r-- | cmd-parse.y | 6 | ||||
-rw-r--r-- | cmd-queue.c | 6 | ||||
-rw-r--r-- | cmd-run-shell.c | 85 | ||||
-rw-r--r-- | cmd-save-buffer.c | 2 | ||||
-rw-r--r-- | cmd-select-pane.c | 14 | ||||
-rw-r--r-- | cmd-set-option.c | 21 | ||||
-rw-r--r-- | cmd-show-options.c | 12 | ||||
-rw-r--r-- | colour.c | 611 | ||||
-rw-r--r-- | compat.h | 37 | ||||
-rw-r--r-- | compat/clock_gettime.c | 37 | ||||
-rw-r--r-- | compat/closefrom.c | 2 | ||||
-rw-r--r-- | compat/forkpty-haiku.c | 82 | ||||
-rw-r--r-- | configure.ac | 187 | ||||
-rw-r--r-- | control-notify.c | 2 | ||||
-rw-r--r-- | control.c | 1 | ||||
-rw-r--r-- | file.c | 454 | ||||
-rw-r--r-- | format-draw.c | 178 | ||||
-rw-r--r-- | format.c | 2725 | ||||
-rw-r--r-- | fuzz/input-fuzzer.c | 89 | ||||
-rw-r--r-- | fuzz/input-fuzzer.dict | 8 | ||||
-rw-r--r-- | fuzz/input-fuzzer.options | 2 | ||||
-rw-r--r-- | grid-reader.c | 365 | ||||
-rw-r--r-- | grid.c | 5 | ||||
-rw-r--r-- | input.c | 144 | ||||
-rw-r--r-- | job.c | 54 | ||||
-rw-r--r-- | names.c | 2 | ||||
-rw-r--r-- | options-table.c | 16 | ||||
-rw-r--r-- | options.c | 7 | ||||
-rw-r--r-- | osdep-cygwin.c | 1 | ||||
-rw-r--r-- | osdep-darwin.c | 3 | ||||
-rw-r--r-- | osdep-dragonfly.c | 1 | ||||
-rw-r--r-- | osdep-freebsd.c | 1 | ||||
-rw-r--r-- | osdep-haiku.c | 52 | ||||
-rw-r--r-- | osdep-hpux.c | 2 | ||||
-rw-r--r-- | osdep-linux.c | 1 | ||||
-rw-r--r-- | osdep-netbsd.c | 1 | ||||
-rw-r--r-- | osdep-openbsd.c | 3 | ||||
-rw-r--r-- | osdep-sunos.c | 1 | ||||
-rw-r--r-- | osdep-unknown.c | 2 | ||||
-rw-r--r-- | popup.c | 211 | ||||
-rw-r--r-- | proc.c | 38 | ||||
-rw-r--r-- | regress/osc-11colours.sh | 243 | ||||
-rw-r--r-- | screen-redraw.c | 34 | ||||
-rw-r--r-- | screen-write.c | 375 | ||||
-rw-r--r-- | screen.c | 41 | ||||
-rw-r--r-- | server-client.c | 132 | ||||
-rw-r--r-- | server-fn.c | 41 | ||||
-rw-r--r-- | server.c | 30 | ||||
-rw-r--r-- | spawn.c | 15 | ||||
-rw-r--r-- | status.c | 58 | ||||
-rw-r--r-- | tmux.1 | 277 | ||||
-rw-r--r-- | tmux.c | 57 | ||||
-rw-r--r-- | tmux.h | 156 | ||||
-rw-r--r-- | tty-term.c | 166 | ||||
-rw-r--r-- | tty.c | 47 | ||||
-rw-r--r-- | utf8.c | 8 | ||||
-rw-r--r-- | window-buffer.c | 12 | ||||
-rw-r--r-- | window-client.c | 12 | ||||
-rw-r--r-- | window-copy.c | 763 | ||||
-rw-r--r-- | window-customize.c | 10 | ||||
-rw-r--r-- | window-tree.c | 12 | ||||
-rw-r--r-- | window.c | 47 |
75 files changed, 6575 insertions, 2273 deletions
diff --git a/.github/travis/build-all.sh b/.github/travis/build-all.sh index 00f8f522..883868e8 100644 --- a/.github/travis/build-all.sh +++ b/.github/travis/build-all.sh @@ -35,4 +35,4 @@ tar -zxf ncurses-*.tar.gz || exit 1 sh autogen.sh || exit 1 PKG_CONFIG_PATH=$BUILD/lib/pkgconfig ./configure --prefix=$BUILD "$@" -make && make install || exit 1 +make && make install || (cat config.log; exit 1) @@ -19,3 +19,5 @@ configure tmux.1.* *.dSYM cmd-parse.c +fuzz/*-fuzzer +.dirstamp @@ -1,5 +1,69 @@ CHANGES FROM 3.1c TO 3.2 +* Improve performance of format evaluation. + +* Make jump command support UTF-8 in copy mode. + +* Support X11 colour names and other colour formats for OSC 10 and 11. + +* Add "pipe" variants of "copy-pipe" commands which do not copy. + +* Include "focused" in client flags. + +* Send Unicode directional isolate characters around horizontal pane borders if + the terminal supports UTF-8 and an extension terminfo(5) capability "Bidi" is + present. + +* Add a -S flag to new-window to make it select the existing window if one + with the given name already exists rather than failing with an error. + +* Addd a format modifier to check if a window or session name exists (N/w or + N/s). + +* Add compat clock_gettime for older macOS. + +* Add a no-detached choice to detach-on-destroy which detaches only if there + are no other detached sessions to switch to. + +* Add rectangle-on and rectangle-off copy mode commands. + +* Change so that window_flags escapes # automatically. A new format + window_raw_flags contains the old unescaped version. + +* Add -N flag to never start server even if command would normally do so. + +* With incremental search, start empty and only repeat the previous search if + the user tries to search again with an empty prompt. + +* Add a value for remain-on-exit that only keeps the pane if the program + failed. + +* Add a -C flag to run-shell to use a tmux command rather than a shell command. + +* Do not list user options with show-hooks. + +* Remove current match indicator in copy mode which can't work anymore since we + only search the visible region. + +* Make synchronize-panes a pane option and add -U flag to set-option to unset + an option on all panes. + +* Make replacement of ##s consistent when drawing formats, whether followed by + [ or not. Add a flag (e) to the q: format modifier to double up #s + +* Add -N flag to display-panes to ignore keys. + +* Change how escaping is processed for formats so that ## and # can be used in + styles. + +* Add a 'w' format modifier for string width. + +* Add support for Haiku. + +* Expand menu and popup -x and -y as formats. + +* Add numeric comparisons for formats. + * Fire focus events even when the pane is in a mode. * Add -O flag to display-menu to not automatically close when all mouse buttons @@ -267,9 +331,9 @@ CHANGES FROM 3.1c TO 3.2 * Change default position for display-menu -x and -y to centre rather than top left. -* Add support for per-client transient popups, similar to menus. These are - created with new command display-popup. Popups may either show fixed text and - trigger a tmux command when a key is pressed, or run a program (-R flag). +* Add support for per-client transient popups, similar to menus but which are + connected to an external command (like a pane). These are created with new + command display-popup. * Change double and triple click bindings so that only one is fired (previously double click was fired on the way to triple click). Also add default double diff --git a/Makefile.am b/Makefile.am index 91d641fd..3e15204f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -28,7 +28,7 @@ AM_CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations AM_CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare AM_CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align AM_CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes -AM_CFLAGS += -Wno-unused-result +AM_CFLAGS += -Wno-unused-result -Wno-format-y2k AM_CPPFLAGS += -DDEBUG endif AM_CPPFLAGS += -iquote. @@ -58,6 +58,11 @@ if IS_NETBSD AM_CPPFLAGS += -D_OPENBSD_SOURCE endif +# Set flags for Haiku. +if IS_HAIKU +AM_CPPFLAGS += -D_BSD_SOURCE +endif + # List of sources. dist_tmux_SOURCES = \ alerts.c \ @@ -136,6 +141,7 @@ dist_tmux_SOURCES = \ file.c \ format.c \ format-draw.c \ + grid-reader.c \ grid-view.c \ grid.c \ input-keys.c \ @@ -197,6 +203,12 @@ if HAVE_UTF8PROC nodist_tmux_SOURCES += compat/utf8proc.c endif +if NEED_FUZZING +check_PROGRAMS = fuzz/input-fuzzer +fuzz_input_fuzzer_LDFLAGS = $(FUZZING_LIBS) +fuzz_input_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS) +endif + # Install tmux.1 in the right format. install-exec-hook: if test x@MANFORMAT@ = xmdoc; then \ @@ -18,7 +18,6 @@ #include <sys/types.h> -#include <event.h> #include <stdlib.h> #include "tmux.h" @@ -27,12 +27,15 @@ #include "tmux.h" struct client *cfg_client; -static char *cfg_file; int cfg_finished; static char **cfg_causes; static u_int cfg_ncauses; static struct cmdq_item *cfg_item; +int cfg_quiet = 1; +char **cfg_files; +u_int cfg_nfiles; + static enum cmd_retval cfg_client_done(__unused struct cmdq_item *item, __unused void *data) { @@ -60,18 +63,10 @@ cfg_done(__unused struct cmdq_item *item, __unused void *data) } void -set_cfg_file(const char *path) -{ - free(cfg_file); - cfg_file = xstrdup(path); -} - -void start_cfg(void) { struct client *c; - char **paths; - u_int i, n; + u_int i; /* * Configuration files are loaded without a client, so commands are run @@ -89,15 +84,12 @@ start_cfg(void) cmdq_append(c, cfg_item); } - if (cfg_file == NULL) { - expand_paths(TMUX_CONF, &paths, &n); - for (i = 0; i < n; i++) { - load_cfg(paths[i], c, NULL, CMD_PARSE_QUIET, NULL); - free(paths[i]); - } - free(paths); - } else - load_cfg(cfg_file, c, NULL, 0, NULL); + for (i = 0; i < cfg_nfiles; i++) { + if (cfg_quiet) + load_cfg(cfg_files[i], c, NULL, CMD_PARSE_QUIET, NULL); + else + load_cfg(cfg_files[i], c, NULL, 0, NULL); + } cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL)); } @@ -24,7 +24,6 @@ #include <sys/file.h> #include <errno.h> -#include <event.h> #include <fcntl.h> #include <signal.h> #include <stdlib.h> @@ -62,7 +61,8 @@ static __dead void client_exec(const char *,const char *); static int client_get_lock(char *); static int client_connect(struct event_base *, const char *, uint64_t); -static void client_send_identify(const char *, const char *, int); +static void client_send_identify(const char *, const char *, + char **, u_int, const char *, int); static void client_signal(int); static void client_dispatch(struct imsg *, void *); static void client_dispatch_attached(struct imsg *); @@ -127,6 +127,8 @@ retry: log_debug("connect failed: %s", strerror(errno)); if (errno != ECONNREFUSED && errno != ENOENT) goto failed; + if (flags & CLIENT_NOSTARTSERVER) + goto failed; if (~flags & CLIENT_STARTSERVER) goto failed; close(fd); @@ -221,20 +223,7 @@ client_exit_message(void) static void client_exit(void) { - struct client_file *cf; - size_t left; - int waiting = 0; - - RB_FOREACH (cf, client_files, &client_files) { - if (cf->event == NULL) - continue; - left = EVBUFFER_LENGTH(cf->event->output); - if (left != 0) { - waiting++; - log_debug("file %u %zu bytes left", cf->stream, left); - } - } - if (waiting == 0) + if (!file_write_left(&client_files)) proc_exit(client_proc); } @@ -246,13 +235,14 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags, struct cmd_parse_result *pr; struct msg_command *data; int fd, i; - const char *ttynam, *cwd; + const char *ttynam, *termname, *cwd; pid_t ppid; enum msgtype msg; struct termios tio, saved_tio; size_t size, linesize = 0; ssize_t linelen; - char *line = NULL; + char *line = NULL, **caps = NULL, *cause; + u_int ncaps = 0; /* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */ signal(SIGCHLD, SIG_IGN); @@ -308,6 +298,8 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags, cwd = "/"; if ((ttynam = ttyname(STDIN_FILENO)) == NULL) ttynam = ""; + if ((termname = getenv("TERM")) == NULL) + termname = ""; /* * Drop privileges for client. "proc exec" is needed for -c and for @@ -323,6 +315,16 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags, NULL) != 0) fatal("pledge failed"); + /* Load terminfo entry if any. */ + if (isatty(STDIN_FILENO) && + *termname != '\0' && + tty_term_read_list(termname, STDIN_FILENO, &caps, &ncaps, + &cause) != 0) { + fprintf(stderr, "%s\n", cause); + free(cause); + return (1); + } + /* Free stuff that is not used in the client. */ if (ptm_fd != -1) close(ptm_fd); @@ -353,7 +355,8 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags, } /* Send identify messages. */ - client_send_identify(ttynam, cwd, feat); + client_send_identify(ttynam, termname, caps, ncaps, cwd, feat); + tty_term_free_list(caps, ncaps); /* Send first command. */ if (msg == MSG_COMMAND) { @@ -436,27 +439,32 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags, /* Send identify messages to server. */ static void -client_send_identify(const char *ttynam, const char *cwd, int feat) +client_send_identify(const char *ttynam, const char *termname, char **caps, + u_int ncaps, const char *cwd, int feat) { - const char *s; - char **ss; - size_t sslen; - int fd, flags = client_flags; - pid_t pid; + char **ss; + size_t sslen; + int fd, flags = client_flags; + pid_t pid; + u_int i; proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags); proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &client_flags, sizeof client_flags); - if ((s = getenv("TERM")) == NULL) - s = ""; - proc_send(client_peer, MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1); + proc_send(client_peer, MSG_IDENTIFY_TERM, -1, termname, + strlen(termname) + 1); proc_send(client_peer, MSG_IDENTIFY_FEATURES, -1, &feat, sizeof feat); proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam, strlen(ttynam) + 1); proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1); + for (i = 0; i < ncaps; i++) { + proc_send(client_peer, MSG_IDENTIFY_TERMINFO, -1, + caps[i], strlen(caps[i]) + 1); + } + if ((fd = dup(STDIN_FILENO)) == -1) fatal("dup failed"); proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0); @@ -477,257 +485,6 @@ client_send_identify(const char *ttynam, const char *cwd, int feat) proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0); } -/* File write error callback. */ -static void -client_write_error_callback(__unused struct bufferevent *bev, - __unused short what, void *arg) -{ - struct client_file *cf = arg; - - log_debug("write error file %d", cf->stream); - - bufferevent_free(cf->event); - cf->event = NULL; - - close(cf->fd); - cf->fd = -1; - - if (client_exitflag) - client_exit(); -} - -/* File write callback. */ -static void -client_write_callback(__unused struct bufferevent *bev, void *arg) -{ - struct client_file *cf = arg; - - if (cf->closed && EVBUFFER_LENGTH(cf->event->output) == 0) { - bufferevent_free(cf->event); - close(cf->fd); - RB_REMOVE(client_files, &client_files, cf); - file_free(cf); - } - - if (client_exitflag) - client_exit(); -} - -/* Open write file. */ -static void -client_write_open(void *data, size_t datalen) -{ - struct msg_write_open *msg = data; - const char *path; - struct msg_write_ready reply; - struct client_file find, *cf; - const int flags = O_NONBLOCK|O_WRONLY|O_CREAT; - int error = 0; - - if (datalen < sizeof *msg) - fatalx("bad MSG_WRITE_OPEN size"); - if (datalen == sizeof *msg) - path = "-"; - else - path = (const char *)(msg + 1); - log_debug("open write file %d %s", msg->stream, path); - - find.stream = msg->stream; - if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL) { - cf = file_create(NULL, msg->stream, NULL, NULL); - RB_INSERT(client_files, &client_files, cf); - } else { - error = EBADF; - goto reply; - } - if (cf->closed) { - error = EBADF; - goto reply; - } - - cf->fd = -1; - if (msg->fd == -1) - cf->fd = open(path, msg->flags|flags, 0644); - else { - if (msg->fd != STDOUT_FILENO && msg->fd != STDERR_FILENO) - errno = EBADF; - else { - cf->fd = dup(msg->fd); - if (~client_flags & CLIENT_CONTROL) - close(msg->fd); /* can only be used once */ - } - } - if (cf->fd == -1) { - error = errno; - goto reply; - } - - cf->event = bufferevent_new(cf->fd, NULL, client_write_callback, - client_write_error_callback, cf); - bufferevent_enable(cf->event, EV_WRITE); - goto reply; - -reply: - reply.stream = msg->stream; - reply.error = error; - proc_send(client_peer, MSG_WRITE_READY, -1, &reply, sizeof reply); -} - -/* Write to client file. */ -static void -client_write_data(void *data, size_t datalen) -{ - struct msg_write_data *msg = data; - struct client_file find, *cf; - size_t size = datalen - sizeof *msg; - - if (datalen < sizeof *msg) - fatalx("bad MSG_WRITE size"); - find.stream = msg->stream; - if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL) - fatalx("unknown stream number"); - log_debug("write %zu to file %d", size, cf->stream); - - if (cf->event != NULL) - bufferevent_write(cf->event, msg + 1, size); -} - -/* Close client file. */ -static void -client_write_close(void *data, size_t datalen) -{ - struct msg_write_close *msg = data; - struct client_file find, *cf; - - if (datalen != sizeof *msg) - fatalx("bad MSG_WRITE_CLOSE size"); - find.stream = msg->stream; - if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL) - fatalx("unknown stream number"); - log_debug("close file %d", cf->stream); - - if (cf->event == NULL || EVBUFFER_LENGTH(cf->event->output) == 0) { - if (cf->event != NULL) - bufferevent_free(cf->event); - if (cf->fd != -1) - close(cf->fd); - RB_REMOVE(client_files, &client_files, cf); - file_free(cf); - } -} - -/* File read callback. */ -static void -client_read_callback(__unused struct bufferevent *bev, void *arg) -{ - struct client_file *cf = arg; - void *bdata; - size_t bsize; - struct msg_read_data *msg; - size_t msglen; - - msg = xmalloc(sizeof *msg); - for (;;) { - bdata = EVBUFFER_DATA(cf->event->input); - bsize = EVBUFFER_LENGTH(cf->event->input); - - if (bsize == 0) - break; - if (bsize > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg) - bsize = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg; - log_debug("read %zu from file %d", bsize, cf->stream); - - msglen = (sizeof *msg) + bsize; - msg = xrealloc(msg, msglen); - msg->stream = cf->stream; - memcpy(msg + 1, bdata, bsize); - proc_send(client_peer, MSG_READ, -1, msg, msglen); - - evbuffer_drain(cf->event->input, bsize); - } - free(msg); -} - -/* File read error callback. */ -static void -client_read_error_callback(__unused struct bufferevent *bev, - __unused short what, void *arg) -{ - struct client_file *cf = arg; - struct msg_read_done msg; - - log_debug("read error file %d", cf->stream); - - msg.stream = cf->stream; - msg.error = 0; - proc_send(client_peer, MSG_READ_DONE, -1, &msg, sizeof msg); - - bufferevent_free(cf->event); - close(cf->fd); - RB_REMOVE(client_files, &client_files, cf); - file_free(cf); -} - -/* Open read file. */ -static void -client_read_open(void *data, size_t datalen) -{ - struct msg_read_open *msg = data; - const char *path; - struct msg_read_done reply; - struct client_file find, *cf; - const int flags = O_NONBLOCK|O_RDONLY; - int error; - - if (datalen < sizeof *msg) - fatalx("bad MSG_READ_OPEN size"); - if (datalen == sizeof *msg) - path = "-"; - else - path = (const char *)(msg + 1); - log_debug("open read file %d %s", msg->stream, path); - - find.stream = msg->stream; - if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL) { - cf = file_create(NULL, msg->stream, NULL, NULL); - RB_INSERT(client_files, &client_files, cf); - } else { - error = EBADF; - goto reply; - } |