diff options
-rw-r--r-- | CHANGES | 26 | ||||
-rw-r--r-- | cmd-command-prompt.c | 25 | ||||
-rw-r--r-- | cmd-confirm-before.c | 16 | ||||
-rw-r--r-- | cmd-new-session.c | 15 | ||||
-rw-r--r-- | cmd-refresh-client.c | 5 | ||||
-rw-r--r-- | cmd-resize-pane.c | 56 | ||||
-rw-r--r-- | cmd-send-keys.c | 2 | ||||
-rw-r--r-- | cmd-set-option.c | 60 | ||||
-rw-r--r-- | cmd-show-options.c | 17 | ||||
-rw-r--r-- | configure.ac | 11 | ||||
-rw-r--r-- | environ.c | 10 | ||||
-rw-r--r-- | format.c | 36 | ||||
-rw-r--r-- | grid-view.c | 16 | ||||
-rw-r--r-- | grid.c | 10 | ||||
-rw-r--r-- | input.c | 59 | ||||
-rw-r--r-- | key-bindings.c | 17 | ||||
-rw-r--r-- | layout-set.c | 5 | ||||
-rw-r--r-- | regress/control-client-size.sh | 49 | ||||
-rw-r--r-- | regress/new-session-size.sh | 27 | ||||
-rw-r--r-- | resize.c | 3 | ||||
-rw-r--r-- | screen-write.c | 33 | ||||
-rw-r--r-- | server-client.c | 17 | ||||
-rw-r--r-- | server-fn.c | 2 | ||||
-rw-r--r-- | status.c | 23 | ||||
-rw-r--r-- | tmux.1 | 7 | ||||
-rw-r--r-- | tmux.h | 35 | ||||
-rw-r--r-- | tty-acs.c | 37 | ||||
-rw-r--r-- | tty-term.c | 1 | ||||
-rw-r--r-- | tty.c | 325 | ||||
-rw-r--r-- | window-copy.c | 27 | ||||
-rw-r--r-- | window.c | 1 |
31 files changed, 617 insertions, 356 deletions
@@ -1,3 +1,29 @@ +CHANGES FROM 2.5 to master + +* Support OSC 10 and OSC 11 to set foreground and background colours. + +* Check the U8 capability to determine whether to use UTF-8 line drawing + characters for ACS. + +* Some missing notifications for layout changes. + +* Control mode clients now do not affect session sizes until they issue + refresh-client -C. new-session -x and -y works with control clients even if + the session is not detached. + +* All new sessions that are unattached (whether with -d or started with no + terminal) are now created with size 80 x 24. Whether the status line is on or + off does not affect the size of new sessions until they are attached. + +* Expand formats in option names and add -F flag to expand them in option values. + +* Remember the search string for a pane even if copy mode is exited and entered + again. + +* Some further BCE fixes (scroll up, reverse index). + +* Improvements to how terminals are cleared (entirely or partially). + CHANGES FROM 2.4 to 2.5 09 May 2017 * Reset updated flag when restarting #() command so that new output is properly diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 45a71525..d7159ad0 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -32,7 +32,8 @@ static enum cmd_retval cmd_command_prompt_exec(struct cmd *, struct cmdq_item *); -static int cmd_command_prompt_callback(void *, const char *, int); +static int cmd_command_prompt_callback(struct client *, void *, + const char *, int); static void cmd_command_prompt_free(void *); const struct cmd_entry cmd_command_prompt_entry = { @@ -48,17 +49,16 @@ const struct cmd_entry cmd_command_prompt_entry = { }; struct cmd_command_prompt_cdata { - struct client *c; - int flags; + int flags; - char *inputs; - char *next_input; + char *inputs; + char *next_input; - char *prompts; - char *next_prompt; + char *prompts; + char *next_prompt; - char *template; - int idx; + char *template; + int idx; }; static enum cmd_retval @@ -78,7 +78,6 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item) return (CMD_RETURN_NORMAL); cdata = xcalloc(1, sizeof *cdata); - cdata->c = c; cdata->inputs = NULL; cdata->next_input = NULL; @@ -142,10 +141,10 @@ cmd_command_prompt_error(struct cmdq_item *item, void *data) } static int -cmd_command_prompt_callback(void *data, const char *s, int done) +cmd_command_prompt_callback(struct client *c, void *data, const char *s, + int done) { struct cmd_command_prompt_cdata *cdata = data; - struct client *c = cdata->c; struct cmd_list *cmdlist; struct cmdq_item *new_item; char *cause, *new_template, *prompt, *ptr; @@ -193,7 +192,7 @@ cmd_command_prompt_callback(void *data, const char *s, int done) if (!done) free(new_template); - if (c->prompt_callbackfn != cmd_command_prompt_callback) + if (c->prompt_inputcb != cmd_command_prompt_callback) return (1); return (0); } diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index 3042d066..7036d34b 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -31,7 +31,8 @@ static enum cmd_retval cmd_confirm_before_exec(struct cmd *, struct cmdq_item *); -static int cmd_confirm_before_callback(void *, const char *, int); +static int cmd_confirm_before_callback(struct client *, void *, + const char *, int); static void cmd_confirm_before_free(void *); const struct cmd_entry cmd_confirm_before_entry = { @@ -46,8 +47,7 @@ const struct cmd_entry cmd_confirm_before_entry = { }; struct cmd_confirm_before_data { - char *cmd; - struct client *client; + char *cmd; }; static enum cmd_retval @@ -74,9 +74,6 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item) cdata = xmalloc(sizeof *cdata); cdata->cmd = xstrdup(args->argv[0]); - cdata->client = c; - cdata->client->references++; - status_prompt_set(c, new_prompt, NULL, cmd_confirm_before_callback, cmd_confirm_before_free, cdata, PROMPT_SINGLE); @@ -97,10 +94,10 @@ cmd_confirm_before_error(struct cmdq_item *item, void *data) } static int -cmd_confirm_before_callback(void *data, const char *s, __unused int done) +cmd_confirm_before_callback(struct client *c, void *data, const char *s, + __unused int done) { struct cmd_confirm_before_data *cdata = data; - struct client *c = cdata->client; struct cmd_list *cmdlist; struct cmdq_item *new_item; char *cause; @@ -135,9 +132,6 @@ static void cmd_confirm_before_free(void *data) { struct cmd_confirm_before_data *cdata = data; - struct client *c = cdata->client; - - server_client_unref(c); free(cdata->cmd); free(cdata); diff --git a/cmd-new-session.c b/cmd-new-session.c index 1813288d..efddc228 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -77,6 +77,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) const char *path, *cmd, *cwd, *to_free = NULL; char **argv, *cause, *cp; int detached, already_attached, idx, argc; + int is_control = 0; u_int sx, sy; struct environ_entry *envent; struct cmd_find_state fs; @@ -139,6 +140,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) detached = args_has(args, 'd'); if (c == NULL) detached = 1; + else if (c->flags & CLIENT_CONTROL) + is_control = 1; /* Is this client already attached? */ already_attached = 0; @@ -185,29 +188,31 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) } /* Find new session size. */ - if (c != NULL) { + if (!detached) { sx = c->tty.sx; sy = c->tty.sy; + if (!is_control && + sy > 0 && + options_get_number(global_s_options, "status")) + sy--; } else { sx = 80; sy = 24; } - if (detached && args_has(args, 'x')) { + if ((is_control || detached) && args_has(args, 'x')) { sx = strtonum(args_get(args, 'x'), 1, USHRT_MAX, &errstr); if (errstr != NULL) { cmdq_error(item, "width %s", errstr); goto error; } } - if (detached && args_has(args, 'y')) { + if ((is_control || detached) && args_has(args, 'y')) { sy = strtonum(args_get(args, 'y'), 1, USHRT_MAX, &errstr); if (errstr != NULL) { cmdq_error(item, "height %s", errstr); goto error; } } - if (sy > 0 && options_get_number(global_s_options, "status")) - sy--; if (sx == 0) sx = 1; if (sy == 0) diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index 5190df89..df1d2135 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -67,8 +67,9 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item) cmdq_error(item, "not a control client"); return (CMD_RETURN_ERROR); } - if (tty_set_size(&c->tty, w, h)) - recalculate_sizes(); + tty_set_size(&c->tty, w, h); + c->flags |= CLIENT_SIZECHANGED; + recalculate_sizes(); } else if (args_has(args, 'S')) { c->flags |= CLIENT_STATUSFORCE; server_status_client(c); diff --git a/cmd-resize-pane.c b/cmd-resize-pane.c index 2ad11c23..bbb78de7 100644 --- a/cmd-resize-pane.c +++ b/cmd-resize-pane.c @@ -129,9 +129,8 @@ static void cmd_resize_pane_mouse_update(struct client *c, struct mouse_event *m) { struct winlink *wl; - struct window_pane *wp; - int found; - u_int y, ly; + struct window_pane *loop, *wp_x, *wp_y; + u_int y, ly, x, lx, sx, sy, ex, ey; wl = cmd_mouse_window(m, NULL); if (wl == NULL) { @@ -139,37 +138,48 @@ cmd_resize_pane_mouse_update(struct client *c, struct mouse_event *m) return; } - y = m->y; + y = m->y; x = m->x; if (m->statusat == 0 && y > 0) y--; else if (m->statusat > 0 && y >= (u_int)m->statusat) y = m->statusat - 1; - ly = m->ly; + ly = m->ly; lx = m->lx; if (m->statusat == 0 && ly > 0) ly--; else if (m->statusat > 0 && ly >= (u_int)m->statusat) ly = m->statusat - 1; - found = 0; - TAILQ_FOREACH(wp, &wl->window->panes, entry) { - if (!window_pane_visible(wp)) + wp_x = wp_y = NULL; + TAILQ_FOREACH(loop, &wl->window->panes, entry) { + if (!window_pane_visible(loop)) continue; - if (wp->xoff + wp->sx == m->lx && - wp->yoff <= 1 + ly && - wp->yoff + wp->sy >= ly) { - layout_resize_pane(wp, LAYOUT_LEFTRIGHT, m->x - m->lx, 0); - found = 1; - } - if (wp->yoff + wp->sy == ly && - wp->xoff <= 1 + m->lx && - wp->xoff + wp->sx >= m->lx) { - layout_resize_pane(wp, LAYOUT_TOPBOTTOM, y - ly, 0); - found = 1; - } + sx = loop->xoff; + if (sx != 0) + sx--; + ex = loop->xoff + loop->sx; + + sy = loop->yoff; + if (sy != 0) + sy--; + ey = loop->yoff + loop->sy; + + if ((lx == sx || lx == ex) && + (ly >= sy && ly <= ey) && + (wp_x == NULL || loop->sy > wp_x->sy)) + wp_x = loop; + if ((ly == sy || ly == ey) && + (lx >= sx && lx <= ex) && + (wp_y == NULL || loop->sx > wp_y->sx)) + wp_y = loop; } - if (found) - server_redraw_window(wl->window); - else + if (wp_x == NULL && wp_y == NULL) { c->tty.mouse_drag_update = NULL; + return; + } + if (wp_x != NULL) + layout_resize_pane(wp_x, LAYOUT_LEFTRIGHT, x - lx, 0); + if (wp_y != NULL) + layout_resize_pane(wp_y, LAYOUT_TOPBOTTOM, y - ly, 0); + server_redraw_window(wl->window); } diff --git a/cmd-send-keys.c b/cmd-send-keys.c index e54574fe..5c6db347 100644 --- a/cmd-send-keys.c +++ b/cmd-send-keys.c @@ -73,7 +73,7 @@ cmd_send_keys_inject(struct client *c, struct cmdq_item *item, key_code key) bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find); if (bd != NULL) { table->references++; - key_bindings_dispatch(bd, c, NULL, &item->target); + key_bindings_dispatch(bd, item, c, NULL, &item->target); key_bindings_unref_table(table); } } diff --git a/cmd-set-option.c b/cmd-set-option.c index b35d60d8..ad058b8e 100644 --- a/cmd-set-option.c +++ b/cmd-set-option.c @@ -42,8 +42,8 @@ const struct cmd_entry cmd_set_option_entry = { .name = "set-option", .alias = "set", - .args = { "agoqst:uw", 1, 2 }, - .usage = "[-agosquw] [-t target-window] option [value]", + .args = { "aFgoqst:uw", 1, 2 }, + .usage = "[-aFgosquw] [-t target-window] option [value]", .target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL }, @@ -55,8 +55,8 @@ const struct cmd_entry cmd_set_window_option_entry = { .name = "set-window-option", .alias = "setw", - .args = { "agoqt:u", 1, 2 }, - .usage = "[-agoqu] " CMD_TARGET_WINDOW_USAGE " option [value]", + .args = { "aFgoqt:u", 1, 2 }, + .usage = "[-aFgoqu] " CMD_TARGET_WINDOW_USAGE " option [value]", .target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL }, @@ -70,33 +70,38 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item) struct args *args = self->args; int append = args_has(args, 'a'); struct cmd_find_state *fs = &item->target; + struct client *c, *loop; struct session *s = fs->s; struct winlink *wl = fs->wl; struct window *w; - struct client *c; enum options_table_scope scope; struct options *oo; struct options_entry *parent, *o; - char *name; - const char *value, *target; + char *name, *argument, *value = NULL, *cause; + const char *target; int window, idx, already, error, ambiguous; - char *cause; + + /* Expand argument. */ + c = cmd_find_client(item, NULL, 1); + argument = format_single(item, args->argv[0], c, s, wl, NULL); /* Parse option name and index. */ - name = options_match(args->argv[0], &idx, &ambiguous); + name = options_match(argument, &idx, &ambiguous); if (name == NULL) { if (args_has(args, 'q')) - return (CMD_RETURN_NORMAL); + goto out; if (ambiguous) - cmdq_error(item, "ambiguous option: %s", args->argv[0]); + cmdq_error(item, "ambiguous option: %s", argument); else - cmdq_error(item, "invalid option: %s", args->argv[0]); - return (CMD_RETURN_ERROR); + cmdq_error(item, "invalid option: %s", argument); + goto fail; } if (args->argc < 2) value = NULL; + else if (args_has(args, 'F')) + value = format_single(item, args->argv[1], c, s, wl, NULL); else - value = args->argv[1]; + value = xstrdup(args->argv[1]); /* * Figure out the scope: for user options it comes from the arguments, @@ -114,12 +119,12 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item) scope = OPTIONS_TABLE_WINDOW; else { scope = OPTIONS_TABLE_NONE; - xasprintf(&cause, "unknown option: %s", args->argv[0]); + xasprintf(&cause, "unknown option: %s", argument); } } if (scope == OPTIONS_TABLE_NONE) { if (args_has(args, 'q')) - return (CMD_RETURN_NORMAL); + goto out; cmdq_error(item, "%s", cause); free(cause); goto fail; @@ -159,7 +164,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item) /* Check that array options and indexes match up. */ if (idx != -1) { if (*name == '@' || options_array_size(parent, NULL) == -1) { - cmdq_error(item, "not an array: %s", args->argv[0]); + cmdq_error(item, "not an array: %s", argument); goto fail; } } @@ -176,8 +181,8 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item) } if (already) { if (args_has(args, 'q')) - return (CMD_RETURN_NORMAL); - cmdq_error(item, "already set: %s", args->argv[0]); + goto out; + cmdq_error(item, "already set: %s", argument); goto fail; } } @@ -217,7 +222,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item) options_array_clear(o); options_array_assign(o, value); } else if (options_array_set(o, idx, value, append) != 0) { - cmdq_error(item, "invalid index: %s", args->argv[0]); + cmdq_error(item, "invalid index: %s", argument); goto fail; } } @@ -232,8 +237,8 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item) } } if (strcmp(name, "key-table") == 0) { - TAILQ_FOREACH(c, &clients, entry) - server_client_set_key_table(c, NULL); + TAILQ_FOREACH(loop, &clients, entry) + server_client_set_key_table(loop, NULL); } if (strcmp(name, "status") == 0 || strcmp(name, "status-interval") == 0) @@ -257,15 +262,20 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item) * anyway. */ recalculate_sizes(); - TAILQ_FOREACH(c, &clients, entry) { - if (c->session != NULL) - server_redraw_client(c); + TAILQ_FOREACH(loop, &clients, entry) { + if (loop->session != NULL) + server_redraw_client(loop); } +out: + free(argument); + free(value); free(name); return (CMD_RETURN_NORMAL); fail: + free(argument); + free(value); free(name); return (CMD_RETURN_ERROR); } diff --git a/cmd-show-options.c b/cmd-show-options.c index 382dd7fb..2dc3dee3 100644 --- a/cmd-show-options.c +++ b/cmd-show-options.c @@ -127,25 +127,36 @@ cmd_show_options_one(struct cmd *self, struct cmdq_item *item, struct options *oo) { struct args *args = self->args; + struct client *c = cmd_find_client(item, NULL, 1); + struct session *s = item->target.s; + struct winlink *wl = item->target.wl; struct options_entry *o; int idx, ambiguous; - const char *name = args->argv[0]; + char *name; + name = format_single(item, args->argv[0], c, s, wl, NULL); o = options_match_get(oo, name, &idx, 1, &ambiguous); if (o == NULL) { - if (args_has(args, 'q')) + if (args_has(args, 'q')) { + free(name); return (CMD_RETURN_NORMAL); + } if (ambiguous) { cmdq_error(item, "ambiguous option: %s", name); + free(name); return (CMD_RETURN_ERROR); } if (*name != '@' && - options_match_get(oo, name, &idx, 0, &ambiguous) != NULL) + options_match_get(oo, name, &idx, 0, &ambiguous) != NULL) { + free(name); return (CMD_RETURN_NORMAL); + } cmdq_error(item, "unknown option: %s", name); + free(name); return (CMD_RETURN_ERROR); } cmd_show_options_print(self, item, o, idx); + free(name); return (CMD_RETURN_NORMAL); } diff --git a/configure.ac b/configure.ac index 3591a730..dcf62ab9 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # configure.ac -AC_INIT(tmux, 2.5) +AC_INIT(tmux, master) AC_PREREQ([2.60]) AC_CONFIG_AUX_DIR(etc) @@ -104,7 +104,6 @@ AC_REPLACE_FUNCS([ \ closefrom \ explicit_bzero \ fgetln \ - fparseln \ freezero \ getdtablecount \ getprogname \ @@ -454,6 +453,14 @@ else AC_LIBOBJ(getopt) fi +# Look for fparseln in libutil. +AC_SEARCH_LIBS(fparseln, util, found_fparseln=yes, found_fparseln=no) +if test "x$found_fparseln" = xyes; then + AC_DEFINE(HAVE_FPARSELN) +else + AC_LIBOBJ(fparseln) +fi + # Look for fdforkpty and forkpty in libutil. AC_SEARCH_LIBS(fdforkpty, util, found_fdforkpty=yes, found_fdforkpty=no) if test "x$found_fdforkpty" = xyes; then @@ -208,9 +208,15 @@ environ_push(struct environ *env) /* Log the environment. */ void -environ_log(struct environ *env, const char *prefix) +environ_log(struct environ *env, const char *fmt, ...) { struct environ_entry *envent; + va_list ap; + char *prefix; + + va_start(ap, fmt); + vasprintf(&prefix, fmt, ap); + va_end(ap); RB_FOREACH(envent, environ, env) { if (envent->value != NULL && *envent->name != '\0') { @@ -218,6 +224,8 @@ environ_log(struct environ *env, const char *prefix) envent->value); } } + + free(prefix); } /* Create initial environment for new child. */ @@ -43,28 +43,6 @@ typedef void (*format_cb)(struct format_tree *, struct format_entry *); static char *format_job_get(struct format_tree *, const char *); static void format_job_timer(int, short, void *); -static void format_cb_host(struct format_tree *, struct format_entry *); -static void format_cb_host_short(struct format_tree *, - struct format_entry *); -static void format_cb_pid(struct format_tree *, struct format_entry *); -static void format_cb_session_alerts(struct format_tree *, - struct format_entry *); -static void format_cb_window_layout(struct format_tree *, - struct format_entry *); -static void format_cb_window_visible_layout(struct format_tree *, - struct format_entry *); -static void format_cb_start_command(struct format_tree *, - struct format_entry *); -static void format_cb_current_command(struct format_tree *, - struct format_entry *); -static void format_cb_history_bytes(struct format_tree *, - struct format_entry *); -static void format_cb_pane_tabs(struct format_tree *, - struct format_entry *); - -static void format_cb_current_path(struct format_tree *, - struct format_entry *); - static char *format_find(struct format_tree *, const char *, int); static void format_add_cb(struct format_tree *, const char *, format_cb); static void format_add_tv(struct format_tree *, const char *, @@ -217,7 +195,6 @@ format_job_update(struct job *job) struct format_job *fj = job->data; char *line; time_t t; - struct client *c; if ((line = evbuffer_readline(job->event->input)) == NULL) return; @@ -226,12 +203,12 @@ format_job_update(struct job *job) free(fj->out); fj->out = line; - log_debug("%s: %s: %s", __func__, fj->cmd, fj->out); + log_debug("%s: %p %s: %s", __func__, fj, fj->cmd, fj->out); t = time (NULL); if (fj->status && fj->last != t) { - TAILQ_FOREACH(c, &clients, entry) - server_status_client(c); + if (fj->client != NULL) + server_status_client(fj->client); fj->last = t; } } @@ -256,10 +233,11 @@ format_job_complete(struct job *job) } else buf = line; + log_debug("%s: %p %s: %s", __func__, fj, fj->cmd, buf); + if (*buf != '\0' || !fj->updated) { free(fj->out); fj->out = buf; - log_debug("%s: %s: %s", __func__, fj->cmd, fj->out); } else free(buf); @@ -1416,8 +1394,8 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp) format_add(ft, "pane_synchronized", "%d", !!options_get_number(wp->window->options, "synchronize-panes")); - format_add(ft, "pane_search_string", "%s", - window_copy_search_string(wp)); + if (wp->searchstr != NULL) + format_add(ft, "pane_search_string", "%s", wp->searchstr); format_add(ft, "pane_tty", "%s", wp->tty); format_add(ft, "pane_pid", "%ld", (long) wp->pid); diff --git a/grid-view.c b/grid-view.c index fe096252..033ec033 100644 --- a/grid-view.c +++ b/grid-view.c @@ -96,32 +96,34 @@ grid_view_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny, /* Scroll region up. */ void -grid_view_scroll_region_up(struct grid *gd, u_int rupper, u_int rlower) +grid_view_scroll_region_up(struct grid *gd, u_int rupper, u_int rlower, + u_int bg) { if (gd->flags & GRID_HISTORY) { - grid_collect_history(gd, 8); + grid_collect_history(gd, bg); if (rupper == 0 && rlower == gd->sy - 1) - grid_scroll_history(gd, 8); + grid_scroll_history(gd, bg); else { rupper = grid_view_y(gd, rupper); rlower = grid_view_y(gd, rlower); - grid_scroll_history_region(gd, rupper, rlower); + grid_scroll_history_region(gd, rupper, rlower, bg); } } else { rupper = grid_view_y(gd, rupper); rlower = grid_view_y(gd, rlower); - grid_move_lines(gd, rupper, rupper + 1, rlower - rupper, 8); + grid_move_lines(gd, rupper, rupper + 1, rlower - rupper, bg); } } /* Scroll region down. */ void -grid_view_scroll_region_down(struct grid *gd, u_int rupper, u_int rlower) +grid_view_scroll_region_down(struct grid *gd, u_int rupper, u_int rlower, + u_int bg) { rupper = grid_view_y(gd, rupper); rlower = grid_view_y(gd, rlower); - grid_move_lines(gd, rupper + 1, rupper, rlower - rupper, 8); + grid_move_lines(gd, rupper + 1, rupper, rlower - rupper, bg); } /* Insert lines. */ @@ -284,9 +284,9 @@ grid_clear_history(struct grid *gd) /* Scroll a region up, moving the top line into the history. */ void -grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower) +grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower, u_int bg) { - struct grid_line *gl_history, *gl_upper, *gl_lower; + struct grid_line *gl_history, *gl_upper; u_int yy; /* Create a space for a new line. */ @@ -302,14 +302,13 @@ grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower) upper++; gl_upper = &gd->linedata[upper]; lower++; - gl_lower = &gd->linedata[lower]; /* Move the line into the history. */ memcpy(gl_history, gl_upper, sizeof *gl_history); /* Then move the region up and clear the bottom line. */ memmove(gl_upper, gl_upper + 1, (lower - upper) * sizeof *gl_upper); - memset(gl_lower, 0, sizeof *gl_lower); + grid_empty_line(gd, lower, bg); /* Move the history offset down over the line. */ gd->hscrolled++; @@ -666,8 +665,7 @@ grid_string_cells_bg(const struct grid_cell *gc, int *values) /* * Returns ANSI code to set particular attributes (colour, bold and so on) - * given a current state. The output buffer must be able to hold at least 57 - * bytes. + * given a current state. */ static void grid_string_cells_code(const struct grid_cell *lastgc, @@ -110,6 +110,8 @@ static void input_set_state(struct window_pane *, static void input_reset_cell(struct input_ctx *); static void input_osc_4(struct window_pane *, const char *); +static void input_osc_10(struct window_pane *, const char *); +static void input_osc_11(struct window_pane *, const char *); static void input_osc_52(struct window_pane *, const char *); static void input_osc_104(struct window_pane *, const char *); @@ -1123,7 +1125,7 @@ input_c0_dispatch(struct input_ctx *ictx) case '\012': /* LF */ case '\013': /* VT */ case '\014': /* FF */ - screen_write_linefeed(sctx, 0); + screen_write_linefeed(sctx, 0, ictx->cell.cell.bg); break; case '\015': /* CR */ screen_write_carriagereturn(sctx); @@ -1168,18 +1170,18 @@ input_esc_dispatch(struct input_ctx *ictx) screen_write_reset(sctx); break; case INPUT_ESC_IND: - screen_write_linefeed(sctx, 0); + screen_write_linefeed(sctx, 0, ictx->cell.cell.bg); break; case INPUT_ESC_NEL: screen_write_carriagereturn(sctx); - screen_write_linefeed(sctx, 0); + screen_write_linefeed(sctx, 0, ictx->cell.cell.bg); break; case INPUT_ESC_HTS: if (s->cx < screen_size_x(s)) bit_set(s->tabs, s->cx); break; case INPUT_ESC_RI: - screen_write_reverseindex(sctx); + screen_write_reverseindex(sctx, ictx->cell.cell.bg); break; case INPUT_ESC_DECKPAM: screen_write_mode_set(sctx, MODE_KKEYPAD); @@ -1417,7 +1419,8 @@ input_csi_dispatch(struct input_ctx *ictx) input_csi_dispatch_sm_private(ictx); break; case INPUT_CSI_SU: - screen_write_scrollup(sctx, input_get(ictx, 0, 1, 1)); + screen_write_scrollup(sctx, input_get(ictx, 0, 1, 1), + ictx->cell.cell.bg); break; case INPUT_CSI_TBC: switch (input_get(ictx, 0, 0, 0)) { @@ -1899,13 +1902,19 @@ input_exit_osc(struct input_ctx *ictx) case 4: input_osc_4(ictx->wp, p); break; - case 52: - input_osc_52(ictx->wp, p); + case 10: + input_osc_10(ictx->wp, p); + break; + case 11: + input_osc_11(ictx->wp, p); break; case 12: if (*p != '?') /* ? is colour request */ screen_set_cursor_colour(ictx->ctx.s, p); break; + case 52: + input_osc_52(ictx->wp, p); + break; case 104: input_osc_104(ictx->wp, p); break; @@ -2051,6 +2060,42 @@ bad: free(copy); } +/* Handle the OSC 10 sequence for setting background colour. */ +static void +input_osc_10(struct window_pane *wp, const char *p) +{ + u_int r, g, b; + + if (sscanf(p, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3) + goto bad; + + wp->colgc.fg = colour_join_rgb(r, g, b); + wp->flags |= PANE_REDRAW; + + return; + +bad: + log_debug("bad OSC 10: %s", p); +} + +/* Handle the OSC 11 sequence for setting background colour. */ +static void +input_osc_11(struct window_pane *wp, const char *p) +{ + u_int r, g, b; + + if (sscanf(p, "rgb:%2x/%2x/%2x", &r, &g, &b) != 3) + goto bad; + + wp->colgc.bg = colour_join_rgb(r, g, b); + wp->flags |= PANE_REDRAW; + + return; + +bad: + log_debug("bad OSC 11: %s", p); +} + /* Handle the OSC 52 sequence for setting the clipboard. */ static void input_osc_52(struct window_pane *wp, const char *p) diff --git a/key-bindings.c b/key-bindings.c index 9e327655..8f56cbee 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -400,11 +400,11 @@ key_bindings_read_only(struct cmdq_item *item, __unused void *data) } void -key_bindings_dispatch(struct key_binding *bd, struct client *c, - struct mouse_event *m, struct cmd_find_state *fs) +key_bindings_dispatch(struct key_binding *bd, struct cmdq_item *item, + struct client *c, struct mouse_event *m, struct cmd_find_state *fs) { struct cmd *cmd; - struct cmdq_item *item; + struct cmdq_item *new_item; int readonly; readonly = 1; @@ -413,11 +413,14 @@ key_bindings_dispatch(struct key_binding *bd, struct client *c, readonly = 0; } if (!readonly && (c->flags & CLIENT_READONLY)) - cmdq_append(c, cmdq_get_callback(key_bindings_read_only, NULL)); + new_item = cmdq_get_callback(key_bindings_read_only, NULL); else { - item = cmdq_get_command(bd->cmdlist, fs, m, 0); + new_item = cmdq_get_command(bd->cmdlist, fs, m, 0); if (bd->flags & KEY_BINDING_REPEAT) - item->shared->flags |= CMDQ_SHARED_REPEAT; - cmdq_append(c, item); + new_item->shared->flags |= CMDQ_SHARED_REPEAT; } + if (item != NULL) + cmdq_insert_after(item, new_item); + else + cmdq_append(c, new_item); } diff --git a/layout-set.c b/layout-set.c index db621f61..7ba18fea 100644 --- a/layout-set.c +++ b/layout-set.c @@ -165,6 +165,7 @@ layout_set_even_h(struct window *w) layout_print_cell(w->layout_root, __func__, 1); + notify_window("window-layout-changed", w); server_redraw_window(w); } @@ -219,6 +220,7 @@ layout_set_even_v(struct window *w) layout_print_cell(w->layout_root, __func__, 1); + notify_window("window-layout-changed", w); server_redraw_window(w); } @@ -342,6 +344,7 @@ layout_set_main_h(struct window *w) layout_print_cell(w->layout_root, __func__, 1); + notify_window("window-layout-changed", w); server_redraw_window(w); } @@ -465,6 +468,7 @@ layout_set_main_v(struct window *w) layout_print_cell(w->layout_root, __func__, 1); + notify_window("window-layout-changed", w); server_redraw_window(w); } @@ -567,5 +571,6 @@ layout_set_tiled(struct window *w) layout_print_cell(w->layout_root, __func__, 1); + notify_window("window-layout-changed", w); server_redraw_window(w); } diff --git a/regress/control-client-size.sh b/regress/control-client-size.sh new file mode 100644 index 00000000..cef48a0e --- /dev/null +++ b/regress/control-client-size.sh @@ -0,0 +1,49 @@ +#!/bin/sh + +# 947 +# size in control mode should change after refresh-client -C, and -x and -y +# should work without -d for control clients + +PATH=/bin:/usr/bin +TERM=screen + +[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux) +TMUX="$TEST_TMUX -Ltest" +$TMUX kill-server 2>/dev/null + +TMP=$(mktemp) +OUT=$(mktemp) +trap "rm -f $TMP $OUT" 0 1 15 + +$TMUX -f/dev/null new -d || exit 1 +sleep 1 +cat <<EOF|$TMUX -C a >$TMP +ls -F':#{session_width} #{session_height}' +refresh -C 100,50 +ls -F':#{session_width} #{session_height}' +EOF +grep ^: $TMP >$OUT +printf ":80 24\n:100 50\n"|cmp -s $OUT || exit 1 +$TMUX kill-server 2>/dev/null + +$TMUX -f/dev/null new -d || exit 1 +sleep 1 +cat <<EOF|$TMUX -C a >$TMP +ls -F':#{session_width} #{session_height}' +refresh -C 80,24 +ls -F':#{session_width} #{session_height}' +EOF +grep ^: $TMP >$OUT +printf ":80 24\n:80 24\n"|cmp -s $OUT || exit 1 +$TMUX kill-server 2>/dev/null + +cat <<EOF|$TMUX -C new -x 100 -y 50 >$TMP +ls -F':#{session_width} #{session_height}' +refresh -C 80,24 +ls -F':#{session_width} #{session_height}' +EOF +grep ^: $TMP >$OUT +printf ":100 50\n:80 24\n"|cmp -s $OUT || exit 1 +$TMUX kill-server 2>/dev/null + +exit 0 diff --git a/regress/new-session-size.sh b/regress/new-session-size.sh new file mode 100644 index 00000000..f9394f35 --- /dev/null +++ b/regress/new-session-size.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# new-session without clients should be the right size + +PATH=/bin:/usr/bin +TERM=screen + +[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux) +TMUX="$TEST_TMUX -Ltest" +$TMUX kill-server 2>/dev/null + +TMP=$(mktemp) +trap "rm -f $TMP" 0 1 15 + +$TMUX -f/dev/null new -d </dev/null || exit 1 +sleep 1 +$TMUX ls -F "#{session_width} #{session_height}" >$TMP +printf "80 24\n"|cmp -s $TMP || exit 1 +$TMUX kill-server 2>/dev/null + +$TMUX -f/dev/null new -d -x 100 -y 50 </dev/null || exit 1 +sleep 1 +$TMUX ls -F "#{session_width} #{session_height}" >$TMP +printf "100 50\n"|cmp -s $TMP || exit 1 +$TMUX kill-server 2>/dev/null + +exit 0 @@ -60,6 +60,9 @@ recalculate_sizes(void) TAILQ_FOREACH(c, &clients, entry) { if (c->flags & CLIENT_SUSPENDED) continue; + if ((c->flags & (CLIENT_CONTROL|CLIENT_SIZECHANGED)) == + CLIENT_CONTROL) + continue; if (c->session == s) { if (c->tty.sx < ssx) ssx = c->tty.sx; diff --git a/screen-write.c b/screen-write.c index 0a63e1b6..1af623b1 100644 --- a/screen-write.c +++ b/screen-write.c @@ -75,6 +75,9 @@ screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp, TAILQ_INIT(&ctx->list[y].items); ctx->item = xcalloc(1, sizeof *ctx->item); + ctx->scrolled = 0; + ctx->bg = 8; + if (wp != NULL) snprintf(tmp, sizeof tmp, "pane %%%u", wp->id); log_debug("%s: size %ux%u, %s", __func__, screen_size_x(ctx->s), @@ -812,15 +815,16 @@ screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py) /* Reverse index (up with scroll). */ void -screen_write_reverseindex(struct screen_write_ctx *ctx) +screen_write_reverseindex(struct screen_write_ctx *ctx, u_int bg) { struct screen *s = ctx->s; struct tty_ctx ttyctx; screen_write_initctx(ctx, &ttyctx); + ttyctx.bg = bg; if (s->cy == s->rupper) - grid_view_scroll_region_down(s->grid, s->rupper, s->rlower); + grid_view_scroll_region_down(s->grid, s->rupper, s->rlower, bg); else if (s->cy > 0) s->cy--; @@ -854,7 +858,7 @@ screen_write_scrollregion(struct screen_write_ctx *ctx, u_int rupper, /* Line feed. */ void -screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) +screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg) { struct screen *s = ctx->s; struct grid *gd = s->grid; @@ -869,8 +873,13 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy, s->rupper, s->rlower); + if (bg != ctx->bg) { + screen_write_collect_flush(ctx, 1); + ctx->bg = bg; + } + if (s->cy == s->rlower) { - grid_view_scroll_region_up(gd, s->rupper, s->rlower); + grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg); screen_write_collect_scroll(ctx); ctx->scrolled++; } else if (s->cy < screen_size_y(s) - 1) @@ -879,7 +888,7 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) /* Scroll up. */ void -screen_write_scrollup(struct screen_write_ctx *ctx, u_int lines) +screen_write_scrollup(struct screen_write_ctx *ctx, u_int lines, u_int bg) { struct screen *s = ctx->s; struct grid *gd = s->grid; @@ -890,8 +899,13 @@ screen_write_scrollup(struct screen_write_ctx *ctx, u_int lines) else if (lines > s->rlower - s->rupper + 1) lines = s->rlower - s->rupper + 1; + if (bg != ctx->bg) { + screen_write_collect_flush(ctx, 1); + ctx->bg = bg; + } + for (i = 0; i < lines; i++) { - grid_view_scroll_region_up(gd, s->rupper, s->rlower); + grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg); screen_write_collect_scroll(ctx); } ctx->scrolled += lines; @@ -1046,9 +1060,12 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only) screen_write_initctx(ctx, &ttyctx); ttyctx.num = ctx->scrolled; + ttyctx.bg = ctx->bg; tty_write(tty_cmd_scrollup, &ttyctx); } ctx->scrolled = 0; + ctx->bg = 8; + if (scroll_only) return; @@ -1143,7 +1160,7 @@ screen_write_collect_add(struct screen_write_ctx *ctx, if (s->cx > sx - 1) { log_debug("%s: wrapped at %u,%u", __func__, s->cx, s->cy); ci->wrapped = 1; - screen_write_linefeed(ctx, 1); + screen_write_linefeed(ctx, 1, 8); s->cx = 0; } @@ -1204,7 +1221,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) /* Check this will fit on the current line and wrap if not. */ if ((s->mode & MODE_WRAP) && s->cx > sx - width) { - screen_write_linefeed(ctx, 1); + screen_write_linefeed(ctx, 1, 8); s->cx = 0; } diff --git a/server-client.c b/server-client.c index e8a9f757..e6761e30 100644 --- a/server-client.c +++ b/server-client.c @@ -49,7 +49,8 @@ static void server_client_dispatch_shell(struct client *); /* Identify mode callback. */ static void -server_client_callback_identify(__unused int fd, __unused short events, void *data) +server_client_callback_identify(__unused int fd, __unused short events, + void *data) { server_client_clear_identify(data, NULL); } @@ -328,7 +329,7 @@ server_client_free(__unused int fd, __unused short events, void *arg) void server_client_suspend(struct client *c) { - struct session *s = c->session; + struct session *s = c->session; if (s == NULL || (c->flags & CLIENT_DETACHING)) return; @@ -342,7 +343,7 @@ server_client_suspend(struct client *c) void server_client_detach(struct client *c, enum msgtype msgtype) { - struct session *s = c->session; + struct session *s = c->session; if (s == NULL || (c->flags & CLIENT_DETACHING)) return; @@ -945,7 +946,7 @@ retry: server_status_client(c); /* Execute the key binding. */ - key_bindings_dispatch(bd, c, m, &fs); + key_bindings_dispatch(bd, NULL, c, m, &fs); key_bindings_unref_table(table); return; } @@ -1238,7 +1239,7 @@ server_client_check_redraw(struct client *c) struct session *s = c->session; struct tty *tty = &c->tty; struct window_pane *wp; - int needed, flags, masked; + int needed, flags, masked; struct timeval tv = { .tv_usec = 1000 }; static struct event ev; size_t left; @@ -1543,7 +1544,7 @@ static void server_client_dispatch_identify(struct client *c, struct imsg *imsg) { const char *data, *home; - size_t datalen; + size_t datalen; int flags; char *name; @@ -1688,7 +1689,7 @@ void server_client_push_stdout(struct client *c) { struct msg_stdout_data data; - size_t sent, left; + size_t sent, left; left = EVBUFFER_LENGTH(c->stdout_data); while (left != 0) { @@ -1729,7 +1730,7 @@ void server_client_push_stderr(struct client *c) { struct msg_stderr_data data; - size_t sent, left; + size_t sent, left; if (c->stderr_data == c->stdout_data) { server_client_push_stdout(c); diff --git a/server-fn.c b/server-fn.c index 0be7f70d..5b1af13e 100644 --- a/server-fn.c +++ b/server-fn.c @@ -300,7 +300,7 @@ server_destroy_pane(struct window_pane *wp, int notify) screen_write_start(&ctx, wp, &wp->base); screen_write_scrollregion(&ctx, 0, screen_size_y(ctx.s) - 1); screen_write_cursormove(&ctx, 0, screen_size_y(ctx.s) - 1); - screen_write_linefeed(&ctx, 1); + screen_write_linefeed(&ctx, 1, 8); memcpy(&gc, &grid_default_cell, sizeof gc); gc.attr |= GRID_ATTR_BRIGHT; screen_write_puts(&ctx, &gc, "Pane is dead"); @@ -656,8 +656,7 @@ status_message_redraw(struct client *c) /* Enable status line prompt. */ void status_prompt_set(struct client *c, const char *msg, const char *input, - int (*callbackfn)(void *, const char *, int), void (*freefn)(void *), - void *data, int flags) + prompt_input_cb inputcb, prompt_free_cb freecb, void *data, int flags) { struct format_tree *ft; time_t t; @@ -677,8 +676,8 @@ status_prompt_set(struct client *c, const char *msg, const char *input, c->prompt_buffer = utf8_fromcstr(tmp); c->prompt_index = utf8_strlen(c->prompt_buffer); - c->prompt_callbackfn = callbackfn; - c->prompt_freefn = freefn; + c->prompt_inputcb = inputcb; + c->prompt_freecb = freecb; c->prompt_data = data; c->prompt_hindex = 0; @@ -692,7 +691,7 @@ status_prompt_set(struct client *c, const char *msg, const char *input, if ((flags & PROMPT_INCREMENTAL) && *tmp != '\0') { xasprintf(&cp, "=%s", tmp); - c->prompt_callbackfn(c->prompt_data, cp, 0); + c->prompt_inputcb(c, c->prompt_data, cp, 0); free(cp); } @@ -707,8 +706,8 @@ status_prompt_clear(struct client *c) if (c->prompt_string == NULL) return; - if (c->prompt_freefn != NULL && c->prompt_data != NULL) - c->prompt_freefn(c->prompt_data); + if (c->prompt_freecb != NULL && c->prompt_data != NULL) + c->prompt_freecb(c->prompt_data); free(c->prompt_string); c->prompt_string = NULL; @@ -995,7 +994,7 @@ status_prompt_key(struct client *c, key_code key) if (key >= '0' && key <= '9') goto append_key; s = utf8_tocstr(c->prompt_buffer); - c->prompt_callbackfn(c->prompt_data, s, 1); + c->prompt_inputcb(c, c->prompt_data, s, 1); status_prompt_clear(c); free(s); return (1); @@ -1276,13 +1275,13 @@ process_key: s = utf8_tocstr(c->prompt_buffer); if (*s != '\0') status_prompt_add_history(s); - if (c->prompt_callbackfn(c->prompt_data, s, 1) == 0) + if (c->prompt_inputcb(c, c->prompt_data, s, 1) == 0) status_prompt_clear(c); free(s); break; case '\033': /* Escape */ case '\003': /* C-c */ - if (c->prompt_callbackfn(c->prompt_data, NULL, 1) == 0) + if (c->prompt_inputcb(c, c->prompt_data, NULL, 1) == 0) status_prompt_clear(c); break; case '\022': /* C-r */ @@ -1330,7 +1329,7 @@ append_key: s = utf8_tocstr(c->prompt_buffer); if (strlen(s) != 1) status_prompt_clear(c); - else if (c->prompt_callbackfn(c->prompt_data, s, 1) == 0) + else if (c->prompt_inputcb(c, c->prompt_data, s, 1) == 0) status_prompt_clear(c); free(s); } @@ -1340,7 +1339,7 @@ changed: if (c->prompt_flags & PROMPT_INCREMENTAL) { s = utf8_tocstr(c->prompt_buffer); xasprintf(&cp, "%c%s", prefix, s); - c->prompt_callbackfn(c->prompt_data, cp, 0); + c->prompt_inputcb(c, c->prompt_data, cp, 0); free(cp); free(s); } @@ -2335,7 +2335,7 @@ abc123 Commands which set options are as follows: .Bl -tag -width Ds .It Xo Ic set-option -.Op Fl agoqsuw +.Op Fl aFgoqsuw .Op Fl t Ar target-session | Ar target-window .Ar option Ar value .Xc @@ -2351,6 +2351,8 @@ otherwise a session option. If .Fl g is given, the global session or window option is set. +.Fl F +expands formats in the option value. The .Fl u flag unsets an option, so a session inherits the option from the global @@ -2901,7 +2903,7 @@ The default is .Ql \ -_@ . .El .It Xo Ic set-window-option -.Op Fl agoqu +.Op Fl aFgoqu .Op Fl t Ar target-window .Ar option Ar value .Xc @@ -2909,6 +2911,7 @@ The default is Set a window option. The .Fl a , +.Fl F , .Fl g , .Fl o , .Fl q @@ -405,6 +405,7 @@ enum tty_code_code { TTYC_SS, /* set cursor style, Ss */ TTYC_TC, /* 24-bit "true" colour, Tc */ TTYC_TSL, /* to_status_line, tsl */ + TTYC_U8, TTYC_VPA, /* row_address, cv */ TTYC_XENL, /* eat_newline_glitch, xn */ TTYC_XT, /* xterm(1)-compatible title, XT */ @@ -676,6 +677,7 @@ struct screen_write_ctx { struct screen_write_collect_item *item; struct screen_write_collect_line *list; u_int scrolled; + u_int bg; u_int cells; u_int written; @@ -796,6 +798,7 @@ struct window_pane { struct event modetimer; time_t modelast; u_int modeprefix; + char *searchstr; TAILQ_ENTRY(window_pane) entry; RB_ENTRY(window_pane) tree_entry; @@ -1285,6 +1288,8 @@ struct cmd_entry { }; /* Client connection. */ +typedef int (*prompt_input_cb)(struct client *, void *, const char *, int); +typedef void (*prompt_free_cb)(void *); struct client { const char *name; struct tmuxpeer *peer; @@ -1349,11 +1354,13 @@ struct client { #define CLIENT_STATUSFORCE 0x80000 #define CLIENT_DOUBLECLICK 0x100000 #define CLIENT_TRIPLECLICK 0x200000 +#define CLIENT_SIZECHANGED 0x400000 int flags; struct key_table *keytable; struct event identify_timer; - void (*identify_callback)(struct client *, struct window_pane *); + void (*identify_callback)(struct client *, + struct window_pane *); void *identify_callback_data; char *message_string; @@ -1364,8 +1371,8 @@ struct client { char *prompt_string; struct utf8_data *prompt_buffer; size_t prompt_index; - int (*prompt_callbackfn)(void *, const char *, int); - void (*prompt_freefn)(void *); + prompt_input_cb prompt_inputcb; + prompt_free_cb prompt_freecb; void *prompt_data; u_int prompt_hindex; enum { PROMPT_ENTRY, PROMPT_COMMAND } prompt_mode; @@ -1624,7 +1631,7 @@ void environ_put(struct environ *, const char *); void environ_unset(struct environ *, const char *); void environ_update(struct options *, struct environ *, struct environ *); void environ_push(struct environ *); -void environ_log(struct environ *, const char *); +void printflike(2, 3) environ_log(struct environ *, const char *, ...); struct environ *environ_for_session(struct session *, int); /* tty.c */ @@ -1702,6 +1709,7 @@ int tty_term_flag(struct tty_term *, enum tty_code_code); const char *tty_term_describe(struct tty_term *, enum tty_code_code); /* tty-acs.c */ +int tty_acs_needed(struct tty *); const char *tty_acs_get(struct tty *, u_char); /* tty-keys.c */ @@ -1805,8 +1813,8 @@ void key_bindings_add(const char *, key_code, int, struct cmd_list *); void key_bindings_remove(const char *, key_code); void key_bindings_remove_table(const char *); void key_bindings_init(void); -void key_bindings_dispatch(struct key_binding *, struct client *, - struct mouse_event *, struct cmd_find_state *); +void key_bindings_dispatch(struct key_binding *, struct cmdq_item *, + struct client *, struct mouse_event *, struct cmd_find_state *); /* key-string.c */ key_code key_string_lookup_string(const char *); @@ -1888,7 +1896,7 @@ void printflike(2, 3) status_message_set(struct client *, const char *, ...); void status_message_clear(struct client *); int status_message_redraw(struct client *); void status_prompt_set(struct client *, const char *, const char *, - int (*)(void *, const char *, int), void (*)(void *), void *, int); + prompt_input_cb, prompt_free_cb, void *, int); void status_prompt_clear(struct client *); int status_prompt_redraw(struct client *); int status_prompt_key(struct client *, key_code); @@ -1933,7 +1941,7 @@ void grid_destroy(struct grid *); int grid_compare(struct grid *, struct grid *); void grid_collect_history(struct grid *, u_int); void grid_scroll_history(struct grid *, u_int); -void grid_scroll_history_region(struct grid *, u_int, u_int); +void grid_scroll_history_region(struct grid *, u_int, u_int, u_int); void grid_clear_history(struct grid *); const struct grid_line *grid_peek_line(struct grid *, u_int); void grid_get_cell(struct grid *, u_int, u_int, struct grid_cell *); @@ -1958,8 +1966,8 @@ void grid_view_set_cells(struct grid *, u_int, u_int, const struct grid_cell *, const char *, size_t); void grid_view_clear_history(struct grid *, u_int); void grid_view_clear(struct grid *, u_int, u_int, u_int, u_int, u_int); -void grid_view_scroll_region_up(struct grid *, u_int, u_int); -void grid_view_scroll_region_down(struct grid *, u_int, u_int); +void grid_view_scroll_region_up(struct grid *, u_int, u_int, u_int); +void grid_view_scroll_region_down(struct grid *, u_int, u_int, u_int); void grid_view_insert_lines(struct grid *, u_int, u_int, u_int); void grid_view_insert_lines_region(struct grid *, u_int, u_int, u_int, u_int); @@ -2006,10 +2014,10 @@ void screen_write_clearline(struct screen_write_ctx *, u_int); void screen_write_clearendofline(struct screen_write_ctx *, u_int); void screen_write_clearstartofline(struct screen_write_ctx *, u_int); void screen_write_cursormove(struct screen_write_ctx *, u_int, u_int); -void screen_write_reverseindex(struct screen_write_ctx *); +void screen_write_reverseindex(struct screen_write_ctx *, u_int); void screen_write_scrollregion(struct screen_write_ctx *, u_int, u_int); -void screen_write_linefeed(struct screen_write_ctx *, int); -void screen_write_scrollup(struct screen_write_ctx *, u_int); +void screen_write_linefeed(struct screen_write_ctx *, int, u_int); +void screen_write_scrollup(struct screen_write_ctx *, u_int, u_int); void screen_write_carriagereturn(struct screen_write_ctx *); void screen_write_clearendofscreen(struct screen_write_ctx *, u_int); void screen_write_clearstartofscreen(struct screen_write_ctx *, u_int); @@ -2180,7 +2188,6 @@ void window_copy_vadd(struct window_pane *, const char *, va_list); void window_copy_pageup(struct window_pane *, int); void window_copy_start_drag(struct client *, struct mouse_event *); int window_copy_scroll_position(struct window_pane *); -const char *window_copy_search_string(struct window_pane *); /* window-choose.c */ extern const struct window_mode window_choose_mode; @@ -74,23 +74,48 @@ tty_acs_cmp(const void *key, const void *value) return (ch - entry->key); } +/* Should this terminal use ACS instead of UTF-8 line drawing? */ +int +tty_acs_needed(struct tty *tty) +{ + if (tty == NULL) + return (0); + + /* + * If the U8 flag is present, it marks whether a terminal supports + * UTF-8 and ACS together. + * + * If it is present and zero, we force ACS - this gives users a way to + * turn off UTF-8 line drawing. + * + * If it is nonzero, we can fall through to the default and use UTF-8 + * line drawing on UTF-8 terminals. + */ + if (tty_term_has(tty->term, TTYC_U8) && + tty_term_number(tty->term, TTYC_U8) == 0) + return (1); + + if (tty->flags & TTY_UTF8) + return (0); + return (1); +} + /* Retrieve ACS to output as a string. */ const char * tty_acs_get(struct tty *tty, u_char ch) { - struct tty_acs_entry *entry; + struct tty_acs_entry *entry; - /* If not a UTF-8 terminal, use the ACS set. */ - if (tty != NULL && !(tty->flags & TTY_UTF8)) { + /* Use the ACS set instead of UTF-8 if needed. */ + if (tty_acs_needed(tty)) { if (tty->term->acs[ch][0] == '\0') return (NULL); return (&tty->term->acs[ch][0]); } /* Otherwise look up the UTF-8 translation. */ - entry = bsearch(&ch, - tty_acs_table, nitems(tty_acs_table), sizeof tty_acs_table[0], - tty_acs_cmp); + entry = bsearch(&ch, tty_acs_table, nitems(tty_acs_table), + sizeof tty_acs_table[0], tty_acs_cmp); if (entry == NULL) return (NULL); return (entry->string); @@ -257,6 +257,7 @@ static const struct tty_term_code_entry tty_term_codes[] = { [TTYC_TC] = { TTYCODE_FLAG, "Tc" }, [TTYC_TSL] = { TTYCODE_STRING, "tsl" }, [TTYC_VPA] = { TTYCODE_STRING, "vpa" }, + [TTYC_U8] = { TTYCODE_NUMBER, "U8" }, [TTYC_XENL] = { TTYCODE_FLAG, "xenl" }, [TTYC_XT] = { TTYCODE_FLAG, "XT" }, }; @@ -71,8 +71,6 @@ static void tty_default_colours(struct grid_cell *, static void tty_default_attributes(struct tty *, const struct window_pane *, u_int); -#define tty_use_acs(tty) \ - (tty_term_has((tty)->term, TTYC_ACSC) && !((tty)->flags & TTY_UTF8)) #define tty_use_margin(tty) \ ((tty)->term_type == TTY_VT420) @@ -278,7 +276,8 @@ tty_open(struct tty *tty, char **cause) void tty_start_tty(struct tty *tty) { - struct termios tio; + struct client *c = tty->client; + struct termios tio; if (tty->fd != -1 && tcgetattr(tty->fd, &tty->tio) == 0) { setblocking(tty->fd, 0); @@ -299,10 +298,14 @@ tty_start_tty(struct tty *tty) tty_putcode(tty, TTYC_SMCUP); tty_putcode(tty, TTYC_SMKX); - if (tty_use_acs(tty)) - tty_putcode(tty, TTYC_ENACS); tty_putcode(tty, TTYC_CLEAR); + if (tty_acs_needed(tty)) { + log_debug("%s: using capabilities for ACS", c->name); + tty_putcode(tty, TTYC_ENACS); + } else + log_debug("%s: using UTF-8 for ACS", c->name); + tty_putcode(tty, TTYC_CNORM); if (tty_term_has(tty->term, TTYC_KMOUS)) tty_puts(tty, "\033[?1000l\033[?1002l\033[?1006l\033[?1005l"); @@ -351,7 +354,7 @@ tty_stop_tty(struct tty *tty) return; tty_raw(tty, tty_term_string2(tty->term, TTYC_CSR, 0, ws.ws_row - 1)); - if (tty_use_acs(tty)) + if (tty_acs_needed(tty)) tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS)); tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0)); tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX)); @@ -754,6 +757,115 @@ tty_redraw_region(struct tty *tty, const struct tty_ctx *ctx) } } +static void +tty_clear_line(struct tty *tty, const struct window_pane *wp, u_int py, + u_int px, u_int nx, u_int bg) +{ + log_debug("%s: %u at %u,%u", __func__, nx, px, py); + + /* Nothing to clear. */ + if (nx == 0) + return; + + /* If genuine BCE is available, can try escape sequences. */ + if (!tty_fake_bce(tty, wp, bg)) { + /* Off the end of the line, use EL if available. */ + if (px + nx >= tty->sx && tty_term_has(tty->term, TTYC_EL)) { + tty_cursor(tty, px, py); + tty_putcode(tty, TTYC_EL); + return; + } + + /* At the start of the line. Use EL1. */ + if (px == 0 && tty_term_has(tty->term, TTYC_EL1)) { + tty_cursor(tty, px + nx - 1, py); + tty_putcode(tty, TTYC_EL1); + return; + } + + /* Section of line. Use ECH if possible. */ + if (tty_term_has(tty->term, TTYC_ECH)) { + tty_cursor(tty, px, py); + tty_putcode1(tty, TTYC_ECH, nx); + return; + } + } + + /* Couldn't use an escape sequence, use spaces. */ + tty_cursor(tty, px, py); + tty_repeat_space(tty, nx); +} + +static void +tty_clear_area(struct tty *tty, const struct window_pane *wp, u_int py, + u_int ny, u_int px, u_int nx, u_int bg) +{ + u_int yy; + char tmp[64]; + + log_debug("%s: %u,%u at %u,%u", __func__, nx, ny, px, py); + + /* Nothing to clear. */ + if (nx == 0 || ny == 0) + return; + + /* If genuine BCE is available, can try escape sequences. */ + if (!tty_fake_bce(tty, wp, bg)) { + /* Use ED if clearing off the bottom of the terminal. */ + if (px == 0 && + px + nx >= tty->sx && + py + ny >= tty->sy && + tty_term_has(tty->term, TTYC_ED)) { + tty_cursor(tty, 0, py); + tty_putcode(tty, TTYC_ED); + return; + } + + /* + * On VT420 compatible terminals we can use DECFRA if the + * background colour isn't default (because it doesn't work + * after SGR 0). + */ + if (tty->term_type == TTY_VT420 && bg != 8) { + xsnprintf(tmp, sizeof tmp, "\033[32;%u;%u;%u;%u$x", + py + 1, px + 1, py + ny, px + nx); + tty_puts(tty, tmp); + return; + } + + /* Full lines can be scrolled away to clear them. */ + if (px == 0 && + px + nx >= tty->sx && + ny > 2 && + tty_term_has(tty->term, TTYC_CSR) && + tty_term_has(tty->term, TTYC_INDN)) { + tty_region(tty, py, py + ny - 1); + tty_margin_off(tty); + tty_putcode1(tty, TTYC_INDN, ny); + return; + } + + /* + * If margins are supported, can just scroll the area off to + * clear it. + */ + if (nx > 2 && + ny > 2 && + tty_term_has(tty->term, TTYC_CSR) && + tty_use_margin(tty) && + tty_term_has(tty->term, TTYC_INDN)) { + tty_region(tty, py, py + ny - 1); + tty_margin(tty, px, px + nx - 1); + tty_putcode1(tty, TTYC_INDN, ny); + return; + } + } + + /* Couldn't use an escape sequence, loop over the lines. */ + for (yy = py; yy < py + ny; yy++) + tty_clear_line(tty, wp, yy, px, nx, bg); +} + void tty_draw_pane(struct tty *tty, const struct window_pane *wp, u_int py, u_int ox, u_int oy) @@ -766,7 +878,7 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp, struct screen *s, u_int py, u_int ox, u_int oy) { struct grid_cell gc, last; - u_int i, j, sx, width; + u_int i, j, sx, nx, width; int flags, cleared = 0; char buf[512]; size_t len; @@ -861,16 +973,10 @@ tty_draw_line(struct tty *tty, const struct window_pane *wp, tty_putn(tty, buf, len, width); } - if (!cleared && sx < tty->sx) { + nx = screen_size_x(s) - sx; + if (!cleared && sx < tty->sx && nx != 0) { tty_default_attributes(tty, wp, 8); - tty_cursor(tty, ox + sx, oy + py); - if (sx != screen_size_x(s) && - ox + screen_size_x(s) >= tty->sx && - tty_term_has(tty->term, TTYC_EL) && - !tty_fake_bce(tty, wp, 8)) - tty_putcode(tty, TTYC_EL); - else - tty_repeat_space(tty, screen_size_x(s) - sx); + tty_clear_line(tty, wp, oy + py, ox + sx, nx, 8); } tty->flags = (tty->flags & ~TTY_NOCURSOR) | flags; @@ -1018,73 +1124,54 @@ void tty_cmd_clearline(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; - struct screen *s = wp->screen; - u_int sx = screen_size_x(s); + u_int nx, py = ctx->yoff + ctx->ocy; tty_default_attributes(tty, wp, ctx->bg); - tty_cursor_pane(tty, ctx, 0, ctx->ocy); - - if (tty_pane_full_width(tty, ctx) && - !tty_fake_bce(tty, wp, ctx->bg) && - tty_term_has(tty->term, TTYC_EL)) - tty_putcode(tty, TTYC_EL); - else - tty_repeat_space(tty, sx); + nx = screen_size_x(wp->screen); + tty_clear_line(tty, wp, py, ctx->xoff, nx, ctx->bg); } void tty_cmd_clearendofline(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; - struct screen *s = wp->screen; - u_int sx = screen_size_x(s); + u_int nx, py = ctx->yoff + ctx->ocy; tty_default_attributes(tty, wp, ctx->bg); - tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - - if (tty_pane_full_width(tty, ctx) && - tty_term_has(tty->term, TTYC_EL) && - !tty_fake_bce(tty, wp, ctx->bg)) - tty_putcode(tty, TTYC_EL); - else - tty_repeat_space(tty, sx - ctx->ocx); + nx = screen_size_x(wp->screen) - ctx->ocx; + tty_clear_line(tty, wp, py, ctx->xoff + ctx->ocx, nx, ctx->bg); } void tty_cmd_clearstartofline(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; + u_int py = ctx->yoff + ctx->ocy; tty_default_attributes(tty, wp, ctx->bg); - if (ctx->xoff == 0 && - tty_term_has(tty->term, TTYC_EL1) && - !tty_fake_bce(tty, ctx->wp, ctx->bg)) { - tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - tty_putcode(tty, TTYC_EL1); - } else { - tty_cursor_pane(tty, ctx, 0, ctx->ocy); - tty_repeat_space(tty, ctx->ocx + 1); - } + tty_clear_line(tty, wp, py, ctx->xoff, ctx->ocx + 1, ctx->bg); } void tty_cmd_reverseindex(struct tty *tty, const struct tty_ctx *ctx) { + struct window_pane *wp = ctx->wp; + if (ctx->ocy != ctx->orupper) return; if (!tty_pane_full_width(tty, ctx) || - tty_fake_bce(tty, ctx->wp, 8) || + tty_fake_bce(tty, wp, 8) || !tty_term_has(tty->term, TTYC_CSR) || !tty_term_has(tty->term, TTYC_RI)) { tty_redraw_region(tty, ctx); return; } - tty_attributes(tty, &grid_default_cell, ctx->wp); + tty_default_attributes(tty, wp, ctx->bg); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_margin_off(tty); @@ -1108,7 +1195,7 @@ tty_cmd_linefeed(struct tty *tty, const struct tty_ctx *ctx) return; } - tty_attributes(tty, &grid_default_cell, wp); + tty_default_attributes(tty, wp, ctx->bg); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_margin_pane(tty, ctx); @@ -1130,7 +1217,7 @@ void tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; - u_int i, lines; + u_int i; if ((!tty_pane_full_width(tty, ctx) && !tty_use_margin(tty)) || tty_fake_bce(tty, wp, 8) || @@ -1139,142 +1226,86 @@ tty_cmd_scrollup(struct tty *tty, const struct tty_ctx *ctx) return; } - tty_attributes(tty, &grid_default_cell, wp); + tty_default_attributes(tty, wp, ctx->bg); tty_region_pane(tty, ctx, ctx->orupper, ctx->orlower); tty_margin_pane(tty, ctx); - /* - * Konsole has a bug where it will ignore SU if the parameter is more - * than the height of the scroll region. Clamping the parameter doesn't - * hurt in any case. - */ - lines = tty->rlower - tty->rupper; - if (lines > ctx->num) - lines = ctx->num; - - if (lines == 1 || !tty_term_has(tty->term, TTYC_INDN)) { + if (ctx->num == 1 || !tty_term_has(tty->term, TTYC_INDN)) { tty_cursor(tty, tty->rright, tty->rlower); - for (i = 0; i < lines; i++) + for (i = 0; i < ctx->num; i++) tty_putc(tty, '\n'); } else - tty_putcode1(tty, TTYC_INDN, lines); + tty_putcode1(tty, TTYC_INDN, ctx->num); } void tty_cmd_clearendofscreen(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; - struct screen *s = wp->screen; - u_int i, j; - u_int sx = screen_size_x(s), sy = screen_size_y(s); + u_int px, py, nx, ny; tty_default_attributes(tty, wp, ctx->bg); - tty_region_pane(tty, ctx, 0, sy - 1); + tty_region_pane(tty, ctx, 0, screen_size_y(wp->screen) - 1); tty_margin_off(tty); - if (tty_pane_full_width(tty, ctx) && - ctx->yoff + wp->sy >= tty->sy - 1 && - status_at_line(tty->client) <= 0 && - tty_term_has(tty->term, TTYC_ED)) { - tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - tty_putcode(tty, TTYC_ED); - } else if (tty_pane_full_width(tty, ctx) && - tty_term_has(tty->term, TTYC_EL) && - !tty_fake_bce(tty, wp, ctx->bg)) { - tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - tty_putcode(tty, TTYC_EL); - if (ctx->ocy != sy - 1) { - tty_cursor_pane(tty, ctx, 0, ctx->ocy + 1); - for (i = ctx->ocy + 1; i < sy; i++) { - tty_putcode(tty, TTYC_EL); - if (i == sy - 1) - continue; - tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1); - tty->cy++; - } - } - } else { - tty_cursor_pane(tty, ctx, ctx->ocx, ctx->ocy); - tty_repeat_space(tty, sx - ctx->ocx); - for (j = ctx->ocy + 1; j < sy; j++) { - tty_cursor_pane(tty, ctx, 0, j); - tty_repeat_space(tty, sx); - } - } + px = ctx->xoff; + nx = screen_size_x(wp->screen); + py = ctx->yoff + ctx->ocy + 1; + ny = screen_size_y(wp->screen) - ctx->ocy - 1; + + tty_clear_area(tty, wp, py, ny, px, nx, ctx->bg); + + px = ctx->xoff + ctx->ocx; + nx = screen_size_x(wp->screen) - ctx->ocx; + py = ctx->yoff + ctx->ocy; + + tty_clear_line(tty, wp, py, px, nx, ctx->bg); } void tty_cmd_clearstartofscreen(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; - struct screen *s = wp->screen; - u_int i, j; - u_int sx = screen_size_x(s), sy = screen_size_y(s); + u_int px, py, nx, ny; tty_default_attributes(tty, wp, ctx->bg); - tty_region_pane(tty, ctx, 0, sy - 1); + tty_region_pane(tty, ctx, 0, screen_size_y(wp->screen) - 1); tty_margin_off(tty); - if (tty_pane_full_width(tty, ctx) && - tty_term_has(tty->term, TTYC_EL) && - !tty_fake_bce(tty, wp, ctx->bg)) { - tty_cursor_pane(tty, ctx, 0, 0); - for (i = 0; i < ctx->ocy; i++) { - tty_putcode(tty, TTYC_EL); - tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1); - tty->cy++; - } - } else { - tty_cursor_pane(tty, ctx, 0, 0); - for (j = 0; j < ctx->ocy; j++) { - tty_cursor_pane(tty, ctx, 0, j); - tty_repeat_space(tty, sx); - } - } - tty_cursor_pane(tty, ctx, 0, ctx->ocy); - tty_repeat_space(tty, ctx->ocx + 1); + px = ctx->xoff; + nx = screen_size_x(wp->screen); + py = ctx->yoff; + ny = ctx->ocy - 1; + + tty_clear_area(tty, wp, py, ny, px, nx, ctx->bg); + + px = ctx->xoff; + nx = ctx->ocx + 1; + py = ctx->yoff + ctx->ocy; + + tty_clear_line(tty, wp, py, px, nx, ctx->bg); } void tty_cmd_clearscreen(struct tty *tty, const struct tty_ctx *ctx) { struct window_pane *wp = ctx->wp; - struct screen *s = wp->screen; - u_int i, j; - u_int sx = screen_size_x(s), sy = screen_size_y(s); + u_int px, py, nx, ny; tty_default_attributes(tty, wp, ctx->bg); - tty_region_pane(tty, ctx, 0, sy - 1); + tty_region_pane(tty, ctx, 0, screen_size_y(wp->screen) - 1); tty_margin_off(tty); - if (tty_pane_full_width(tty, ctx) && - ctx->yoff + wp->sy >= tty->sy - 1 && - status_at_line(tty->client) <= 0 && - tty_term_has(tty->term, TTYC_ED)) { - tty_cursor_pane(tty, ctx, 0, 0); - tty_putcode(tty, TTYC_ED); - } else if (tty_pane_full_width(tty, ctx) && - tty_term_has(tty->term, TTYC_EL) && - !tty_fake_bce(tty, wp, ctx->bg)) { - tty_cursor_pane(tty, ctx, 0, 0); - for (i = 0; i < sy; i++) { - tty_putcode(tty, TTYC_EL); - if (i != sy - 1) { - tty_emulate_repeat(tty, TTYC_CUD, TTYC_CUD1, 1); - tty->cy++; - } - } - } else { - tty_cursor_pane(tty, ctx, 0, 0); - for (j = 0; j < sy; j++) { - tty_cursor_pane(tty, ctx, 0, j); - tty_repeat_space(tty, sx); - } - } + px = ctx->xoff; + nx = screen_size_x(wp->screen); + py = ctx->yoff; + ny = screen_size_y(wp->screen); + + tty_clear_area(tty, wp, py, ny, px, nx, ctx->bg); } void @@ -1389,7 +1420,7 @@ tty_reset(struct tty *tty) struct grid_cell *gc = &tty->cell; if (!grid_cells_equal(gc, &grid_default_cell)) { - if ((gc->attr & GRID_ATTR_CHARSET) && tty_use_acs(tty)) + if ((gc->attr & GRID_ATTR_CHARSET) && tty_acs_needed(tty)) tty_putcode(tty, TTYC_RMACS); tty_putcode(tty, TTYC_SGR0); memcpy(gc, &grid_default_cell, sizeof *gc); @@ -1739,7 +1770,7 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc, tty_putcode(tty, TTYC_INVIS); if (changed & GRID_ATTR_STRIKETHROUGH) tty_putcode(tty, TTYC_SMXX); - if ((changed & GRID_ATTR_CHARSET) && tty_use_acs(tty)) + if ((changed & GRID_ATTR_CHARSET) && tty_acs_needed(tty)) tty_putcode(tty, TTYC_SMACS); } diff --git a/window-copy.c b/window-copy.c index 8424bfa6..6d1a9f69 100644 --- a/window-copy.c +++ b/window-copy.c @@ -208,8 +208,13 @@ window_copy_init(struct window_pane *wp) data->rectflag = 0; data->scroll_exit = 0; - data->searchtype = WINDOW_COPY_OFF; - data->searchstr = NULL; + if (wp->searchstr != NULL) { + data->searchtype = WINDOW_COPY_SEARCHUP; + data->searchstr = xstrdup(wp->searchstr); + } else { + data->searchtype = WINDOW_COPY_OFF; + data->searchstr = NULL; + } data->searchmark = NULL; data->searchx = data->searchy = data->searcho = -1; @@ -316,7 +321,7 @@ window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap) * (so it's on a new line). */ screen_write_carriagereturn(&back_ctx); - screen_write_linefeed(&back_ctx, 0); + screen_write_linefeed(&back_ctx, 0, 8); } else data->backing_written = 1; old_cy = backing->cy; @@ -1134,6 +1139,9 @@ window_copy_search(struct window_pane *wp, int direction, int moveflag) u_int fx, fy, endline; int wrapflag, cis, found; + free(wp->searchstr); + wp->searchstr = xstrdup(data->searchstr); + fx = data->cx; fy = screen_hsize(data->backing) - data->oy + data->cy; @@ -2482,16 +2490,3 @@ window_copy_drag_update(__unused struct client *c, struct mouse_event *m) if (window_copy_update_selection(wp, 1)) window_copy_redraw_selection(wp, old_cy); } - -const char * -window_copy_search_string(struct window_pane *wp) -{ - struct window_copy_mode_data *data; - - if (wp->mode != &window_copy_mode) - return (""); - data = wp->modedata; - if (data->searchtype == WINDOW_COPY_OFF || data->searchstr == NULL) - return (""); - return (data->searchstr); -} @@ -828,6 +828,7 @@ static void window_pane_destroy(struct window_pane *wp) { window_pane_reset_mode(wp); + free(wp->searchstr); if (wp->fd != -1) { #ifdef HAVE_UTEMPTER |