diff --git a/cmd-if-shell.c b/cmd-if-shell.c index da0220ca..15432919 100644 --- a/cmd-if-shell.c +++ b/cmd-if-shell.c @@ -37,8 +37,8 @@ void cmd_if_shell_free(void *); const struct cmd_entry cmd_if_shell_entry = { "if-shell", "if", - "bt:", 2, 3, - "[-b] " CMD_TARGET_PANE_USAGE " shell-command command [command]", + "bFt:", 2, 3, + "[-bF] " CMD_TARGET_PANE_USAGE " shell-command command [command]", 0, cmd_if_shell_exec }; @@ -56,7 +56,8 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct cmd_if_shell_data *cdata; - char *shellcmd; + char *shellcmd, *cmd, *cause; + struct cmd_list *cmdlist; struct client *c; struct session *s = NULL; struct winlink *wl = NULL; @@ -84,6 +85,26 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_q *cmdq) shellcmd = format_expand(ft, args->argv[0]); format_free(ft); + if (args_has(args, 'F')) { + cmd = NULL; + if (*shellcmd != '0' && *shellcmd != '\0') + cmd = args->argv[1]; + else if (args->argc == 3) + cmd = args->argv[2]; + if (cmd == NULL) + return (CMD_RETURN_NORMAL); + if (cmd_string_parse(cmd, &cmdlist, NULL, 0, &cause) != 0) { + if (cause != NULL) { + cmdq_error(cmdq, "%s", cause); + free(cause); + } + return (CMD_RETURN_ERROR); + } + cmdq_run(cmdq, cmdlist); + cmd_list_free(cmdlist); + return (CMD_RETURN_NORMAL); + } + cdata = xmalloc(sizeof *cdata); cdata->cmd_if = xstrdup(args->argv[1]); if (args->argc == 3) diff --git a/cmd-split-window.c b/cmd-split-window.c index f88b2f65..6b901254 100644 --- a/cmd-split-window.c +++ b/cmd-split-window.c @@ -36,8 +36,8 @@ enum cmd_retval cmd_split_window_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_split_window_entry = { "split-window", "splitw", - "c:dF:l:hp:Pt:v", 0, -1, - "[-dhvP] [-c start-directory] [-F format] [-p percentage|-l size] " + "bc:dF:l:hp:Pt:v", 0, -1, + "[-bdhvP] [-c start-directory] [-F format] [-p percentage|-l size] " CMD_TARGET_PANE_USAGE " [command]", 0, cmd_split_window_exec @@ -144,7 +144,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_q *cmdq) if (*shell == '\0' || areshell(shell)) shell = _PATH_BSHELL; - if ((lc = layout_split_pane(wp, type, size, 0)) == NULL) { + lc = layout_split_pane(wp, type, size, args_has(args, 'b')); + if (lc == NULL) { cause = xstrdup("pane too small"); goto error; } diff --git a/format.c b/format.c index e7fd3e1f..fff9a695 100644 --- a/format.c +++ b/format.c @@ -40,8 +40,26 @@ int format_replace(struct format_tree *, const char *, size_t, char **, char *format_get_command(struct window_pane *); void format_window_pane_tabs(struct format_tree *, struct window_pane *); +/* Entry in format tree. */ +struct format_entry { + char *key; + char *value; + + RB_ENTRY(format_entry) entry; +}; + +/* Tree of format entries. */ +struct format_tree { + struct window *w; + struct session *s; + + RB_HEAD(format_rb_tree, format_entry) tree; +}; + /* Format key-value replacement entry. */ -RB_GENERATE(format_tree, format_entry, entry, format_cmp); +int format_cmp(struct format_entry *, struct format_entry *); +RB_PROTOTYPE(format_rb_tree, format_entry, entry, format_cmp); +RB_GENERATE(format_rb_tree, format_entry, entry, format_cmp); /* Format tree comparison function. */ int @@ -117,8 +135,8 @@ format_create(void) struct format_tree *ft; char host[MAXHOSTNAMELEN], *ptr; - ft = xmalloc(sizeof *ft); - RB_INIT(ft); + ft = xcalloc(1, sizeof *ft); + RB_INIT(&ft->tree); if (gethostname(host, sizeof host) == 0) { format_add(ft, "host", "%s", host); @@ -134,14 +152,10 @@ format_create(void) void format_free(struct format_tree *ft) { - struct format_entry *fe, *fe_next; + struct format_entry *fe, *fe1; - fe_next = RB_MIN(format_tree, ft); - while (fe_next != NULL) { - fe = fe_next; - fe_next = RB_NEXT(format_tree, ft, fe); - - RB_REMOVE(format_tree, ft, fe); + RB_FOREACH_SAFE(fe, format_rb_tree, &ft->tree, fe1) { + RB_REMOVE(format_rb_tree, &ft->tree, fe); free(fe->value); free(fe->key); free(fe); @@ -165,7 +179,7 @@ format_add(struct format_tree *ft, const char *key, const char *fmt, ...) xvasprintf(&fe->value, fmt, ap); va_end(ap); - fe_now = RB_INSERT(format_tree, ft, fe); + fe_now = RB_INSERT(format_rb_tree, &ft->tree, fe); if (fe_now != NULL) { free(fe_now->value); fe_now->value = fe->value; @@ -179,9 +193,32 @@ const char * format_find(struct format_tree *ft, const char *key) { struct format_entry *fe, fe_find; + struct options_entry *o; + static char s[16]; + + o = options_find(&global_options, key); + if (o == NULL && ft->w != NULL) + o = options_find(&ft->w->options, key); + if (o == NULL) + o = options_find(&global_w_options, key); + if (o == NULL && ft->s != NULL) + o = options_find(&ft->s->options, key); + if (o == NULL) + o = options_find(&global_s_options, key); + if (o != NULL) { + switch (o->type) { + case OPTIONS_STRING: + return (o->str); + case OPTIONS_NUMBER: + snprintf(s, sizeof s, "%lld", o->num); + return (s); + case OPTIONS_STYLE: + return (style_tostring(&o->style)); + } + } fe_find.key = (char *) key; - fe = RB_FIND(format_tree, ft, &fe_find); + fe = RB_FIND(format_rb_tree, &ft->tree, &fe_find); if (fe == NULL) return (NULL); return (fe->value); @@ -206,7 +243,7 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen, copy[keylen] = '\0'; /* Is there a length limit or whatnot? */ - if (!islower((u_char) *copy) && *copy != '?') { + if (!islower((u_char) *copy) && *copy != '@' && *copy != '?') { while (*copy != ':' && *copy != '\0') { switch (*copy) { case '=': @@ -389,6 +426,8 @@ format_session(struct format_tree *ft, struct session *s) char *tim; time_t t; + ft->s = s; + format_add(ft, "session_name", "%s", s->name); format_add(ft, "session_windows", "%u", winlink_count(&s->windows)); format_add(ft, "session_width", "%u", s->sx); @@ -418,6 +457,9 @@ format_client(struct format_tree *ft, struct client *c) time_t t; struct session *s; + if (ft->s == NULL) + ft->s = c->session; + format_add(ft, "client_height", "%u", c->tty.sy); format_add(ft, "client_width", "%u", c->tty.sx); if (c->tty.path != NULL) @@ -463,6 +505,8 @@ format_window(struct format_tree *ft, struct window *w) { char *layout; + ft->w = w; + layout = layout_dump(w); format_add(ft, "window_id", "@%u", w->id); @@ -471,6 +515,8 @@ format_window(struct format_tree *ft, struct window *w) format_add(ft, "window_height", "%u", w->sy); format_add(ft, "window_layout", "%s", layout); format_add(ft, "window_panes", "%u", window_count_panes(w)); + format_add(ft, "window_zoomed_flag", "%u", + !!(w->flags & WINDOW_ZOOMED)); free(layout); } @@ -482,6 +528,9 @@ format_winlink(struct format_tree *ft, struct session *s, struct winlink *wl) struct window *w = wl->window; char *flags; + if (ft->w == NULL) + ft->w = wl->window; + flags = window_printable_flags(s, wl); format_window(ft, w); @@ -498,8 +547,6 @@ format_winlink(struct format_tree *ft, struct session *s, struct winlink *wl) !!(wl->flags & WINLINK_SILENCE)); format_add(ft, "window_last_flag", "%u", !!(wl == TAILQ_FIRST(&s->lastw))); - format_add(ft, "window_zoomed_flag", "%u", - !!(wl->flags & WINDOW_ZOOMED)); free(flags); } @@ -536,6 +583,9 @@ format_window_pane(struct format_tree *ft, struct window_pane *wp) u_int i, idx; char *cmd, *cwd; + if (ft->w == NULL) + ft->w = wp->window; + size = 0; for (i = 0; i < gd->hsize; i++) { gl = &gd->linedata[i]; diff --git a/grid-view.c b/grid-view.c index badabd56..078a0da4 100644 --- a/grid-view.c +++ b/grid-view.c @@ -184,7 +184,10 @@ grid_view_insert_cells(struct grid *gd, u_int px, u_int py, u_int nx) px = grid_view_x(gd, px); py = grid_view_y(gd, py); - sx = grid_view_x(gd, gd->sx); + if (gd->linedata[py].cellsize + nx < gd->sx) + sx = grid_view_x(gd, gd->linedata[py].cellsize + nx); + else + sx = grid_view_x(gd, gd->sx); if (px == sx - 1) grid_clear(gd, px, py, 1, 1); @@ -201,7 +204,9 @@ grid_view_delete_cells(struct grid *gd, u_int px, u_int py, u_int nx) px = grid_view_x(gd, px); py = grid_view_y(gd, py); - sx = grid_view_x(gd, gd->sx); + sx = grid_view_x(gd, gd->linedata[py].cellsize); + if (sx < px + nx) + sx = px + nx; grid_move_cells(gd, px, px + nx, py, sx - px - nx); grid_clear(gd, sx - nx, py, px + nx - (sx - nx), 1); diff --git a/log.c b/log.c index 250a1da2..066165e8 100644 --- a/log.c +++ b/log.c @@ -46,7 +46,7 @@ log_open(const char *path) if (log_file == NULL) return; - setlinebuf(log_file); + setvbuf(log_file, NULL, _IOLBF, 0); event_set_log_callback(log_event_cb); tzset(); diff --git a/resize.c b/resize.c index 73a728fa..9ad73c81 100644 --- a/resize.c +++ b/resize.c @@ -50,7 +50,7 @@ recalculate_sizes(void) struct window *w; struct window_pane *wp; u_int i, j, ssx, ssy, has, limit; - int flag, has_status, is_zoomed; + int flag, has_status, is_zoomed, forced; RB_FOREACH(s, sessions, &sessions) { has_status = options_get_number(&s->options, "status"); @@ -116,18 +116,26 @@ recalculate_sizes(void) if (ssx == UINT_MAX || ssy == UINT_MAX) continue; + forced = 0; limit = options_get_number(&w->options, "force-width"); - if (limit >= PANE_MINIMUM && ssx > limit) + if (limit >= PANE_MINIMUM && ssx > limit) { ssx = limit; + forced |= WINDOW_FORCEWIDTH; + } limit = options_get_number(&w->options, "force-height"); - if (limit >= PANE_MINIMUM && ssy > limit) + if (limit >= PANE_MINIMUM && ssy > limit) { ssy = limit; + forced |= WINDOW_FORCEHEIGHT; + } if (w->sx == ssx && w->sy == ssy) continue; log_debug("window size %u,%u (was %u,%u)", ssx, ssy, w->sx, w->sy); + w->flags &= ~(WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT); + w->flags |= forced; + is_zoomed = w->flags & WINDOW_ZOOMED; if (is_zoomed) window_unzoom(w); diff --git a/screen-redraw.c b/screen-redraw.c index a7f713a5..ef9e539d 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -278,8 +278,37 @@ screen_redraw_draw_borders(struct client *c, int status, u_int top) struct options *oo = &c->session->options; struct tty *tty = &c->tty; struct window_pane *wp; - struct grid_cell active_gc, other_gc; - u_int i, j, type; + struct grid_cell active_gc, other_gc, msg_gc; + u_int i, j, type, msgx = 0, msgy = 0; + int small, flags; + char msg[256]; + const char *tmp; + size_t msglen = 0; + + small = (tty->sy - status + top > w->sy) || (tty->sx > w->sx); + if (small) { + flags = w->flags & (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT); + if (flags == (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT)) + tmp = "force-width, force-height"; + else if (flags == WINDOW_FORCEWIDTH) + tmp = "force-width"; + else if (flags == WINDOW_FORCEHEIGHT) + tmp = "force-height"; + else + tmp = "a smaller client"; + xsnprintf(msg, sizeof msg, "(size %ux%u from %s)", + w->sx, w->sy, tmp); + msglen = strlen(msg); + + if (tty->sy - 1 - status + top > w->sy && tty->sx >= msglen) { + msgx = tty->sx - msglen; + msgy = tty->sy - 1 - status + top; + } else if (tty->sx - w->sx > msglen) { + msgx = tty->sx - msglen; + msgy = tty->sy - 1 - status + top; + } else + small = 0; + } style_apply(&other_gc, oo, "pane-border-style"); style_apply(&active_gc, oo, "pane-active-border-style"); @@ -290,6 +319,9 @@ screen_redraw_draw_borders(struct client *c, int status, u_int top) type = screen_redraw_check_cell(c, i, j, &wp); if (type == CELL_INSIDE) continue; + if (type == CELL_OUTSIDE && + small && i > msgx && j == msgy) + continue; if (screen_redraw_check_active(i, j, type, w, wp)) tty_attributes(tty, &active_gc); else @@ -298,6 +330,13 @@ screen_redraw_draw_borders(struct client *c, int status, u_int top) tty_putc(tty, CELL_BORDERS[type]); } } + + if (small) { + memcpy(&msg_gc, &grid_default_cell, sizeof msg_gc); + tty_attributes(tty, &msg_gc); + tty_cursor(tty, msgx, msgy); + tty_puts(tty, msg); + } } /* Draw the panes. */ diff --git a/tmux.1 b/tmux.1 index fb708ded..726f23a1 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1761,7 +1761,7 @@ is given and the selected window is already the current window, the command behaves like .Ic last-window . .It Xo Ic split-window -.Op Fl dhvP +.Op Fl bdhvP .Op Fl c Ar start-directory .Oo Fl l .Ar size | @@ -1785,6 +1785,10 @@ and .Fl p options specify the size of the new pane in lines (for vertical split) or in cells (for horizontal split), or as a percentage, respectively. +The +.Fl b +option causes the new pane to be created to the left of or above +.Ar target-pane . All other options have the same meaning as for the .Ic new-window command. @@ -3039,12 +3043,17 @@ and .Ql } , for example .Ql #{session_name} . -Some variables also have an shorter alias such as -.Ql #S . +The possible variables are listed in the table below, or the name of a +.Nm +option may be used for an option's value. +Some variables have a shorter alias such as +.Ql #S , +and .Ql ## is replaced by a single .Ql # . -Conditionals are also accepted by prefixing with +.Pp +Conditionals are available by prefixing with .Ql \&? and separating two alternatives with a comma; if the specified variable exists and is not zero, the first alternative @@ -3055,7 +3064,15 @@ will include the string .Ql attached if the session is attached and the string .Ql not attached -if it is unattached. +if it is unattached, or +.Ql #{?automatic-rename,yes,no} +will include +.Ql yes +if +.Ic automatic-rename +is enabled, or +.Ql no +if not. A limit may be placed on the length of the resultant string by prefixing it by an .Ql = , @@ -3577,7 +3594,7 @@ Miscellaneous commands are as follows: .It Ic clock-mode Op Fl t Ar target-pane Display a large clock. .It Xo Ic if-shell -.Op Fl b +.Op Fl bF .Op Fl t Ar target-pane .Ar shell-command command .Op Ar command @@ -3590,7 +3607,9 @@ if returns success or the second .Ar command otherwise. -Before being executed, shell-command is expanded using the rules specified in the +Before being executed, +.Ar shell-command +is expanded using the rules specified in the .Sx FORMATS section, including those relevant to .Ar target-pane . @@ -3598,6 +3617,13 @@ With .Fl b , .Ar shell-command is run in the background. +.Pp +If +.Fl F +is given, +.Ar shell-command +is not executed but considered success if neither empty nor zero (after formats +are expanded). .It Ic lock-server .D1 (alias: Ic lock ) Lock each client individually by running the command specified by the diff --git a/tmux.h b/tmux.h index 57077a65..61f2ca7c 100644 --- a/tmux.h +++ b/tmux.h @@ -944,7 +944,9 @@ struct window { #define WINDOW_ACTIVITY 0x2 #define WINDOW_REDRAW 0x4 #define WINDOW_SILENCE 0x8 -#define WINDOW_ZOOMED 0x10 +#define WINDOW_ZOOMED 0x1000 +#define WINDOW_FORCEWIDTH 0x2000 +#define WINDOW_FORCEHEIGHT 0x4000 #define WINDOW_ALERTFLAGS (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_SILENCE) struct options options; @@ -1457,15 +1459,6 @@ struct options_table_entry { const char *style; }; -/* Tree of format entries. */ -struct format_entry { - char *key; - char *value; - - RB_ENTRY(format_entry) entry; -}; -RB_HEAD(format_tree, format_entry); - /* Common command usages. */ #define CMD_TARGET_PANE_USAGE "[-t target-pane]" #define CMD_TARGET_WINDOW_USAGE "[-t target-window]" @@ -1509,8 +1502,7 @@ void cfg_print_causes(struct cmd_q *); void cfg_show_causes(struct session *); /* format.c */ -int format_cmp(struct format_entry *, struct format_entry *); -RB_PROTOTYPE(format_tree, format_entry, entry, format_cmp); +struct format_tree; struct format_tree *format_create(void); void format_free(struct format_tree *); void printflike(3, 4) format_add(struct format_tree *, const char *, @@ -2232,9 +2224,6 @@ struct window_choose_data *window_choose_add_window(struct window_pane *, struct window_choose_data *window_choose_add_session(struct window_pane *, struct client *, struct session *, const char *, const char *, u_int); -struct window_choose_data *window_choose_add_item(struct window_pane *, - struct client *, struct winlink *, const char *, - const char *, u_int); void window_choose_expand_all(struct window_pane *); void window_choose_collapse_all(struct window_pane *); void window_choose_set_current(struct window_pane *, u_int); diff --git a/window-choose.c b/window-choose.c index db092872..56016394 100644 --- a/window-choose.c +++ b/window-choose.c @@ -931,36 +931,6 @@ window_choose_add_session(struct window_pane *wp, struct client *c, return (wcd); } -struct window_choose_data * -window_choose_add_item(struct window_pane *wp, struct client *c, - struct winlink *wl, const char *template, const char *action, u_int idx) -{ - struct window_choose_data *wcd; - char *expanded; - - wcd = window_choose_data_create(TREE_OTHER, c, c->session); - wcd->idx = wl->idx; - - wcd->ft_template = xstrdup(template); - format_add(wcd->ft, "line", "%u", idx); - format_session(wcd->ft, wcd->start_session); - format_winlink(wcd->ft, wcd->start_session, wl); - format_window_pane(wcd->ft, wl->window->active); - - /* - * Interpolate action here, since the data we pass back is the expanded - * template itself. - */ - xasprintf(&expanded, "%s", format_expand(wcd->ft, wcd->ft_template)); - wcd->command = cmd_template_replace(action, expanded, 1); - free(expanded); - - window_choose_add(wp, wcd); - - return (wcd); - -} - struct window_choose_data * window_choose_add_window(struct window_pane *wp, struct client *c, struct session *s, struct winlink *wl, const char *template,