From 9d83c5e94827db0248226149cffee23296c851aa Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 3 Nov 2020 08:09:35 +0000 Subject: Expand menu and popup -x and -y as a format, from teo_paul1 at yahoo dot com in GitHub issue 2442. --- cmd-display-menu.c | 256 +++++++++++++++++++++++++++++++++++------------------ tmux.1 | 22 +++++ 2 files changed, 191 insertions(+), 87 deletions(-) diff --git a/cmd-display-menu.c b/cmd-display-menu.c index 205d1243..7115dc81 100644 --- a/cmd-display-menu.c +++ b/cmd-display-menu.c @@ -61,7 +61,7 @@ const struct cmd_entry cmd_display_popup_entry = { .exec = cmd_display_popup_exec }; -static void +static int cmd_display_menu_get_position(struct client *tc, struct cmdq_item *item, struct args *args, u_int *px, u_int *py, u_int w, u_int h) { @@ -71,44 +71,46 @@ cmd_display_menu_get_position(struct client *tc, struct cmdq_item *item, struct session *s = tc->session; struct winlink *wl = target->wl; struct window_pane *wp = target->wp; - struct style_ranges *ranges; - struct style_range *sr; + struct style_ranges *ranges = NULL; + struct style_range *sr = NULL; const char *xp, *yp; - u_int line, ox, oy, sx, sy, lines; - - lines = status_line_size(tc); - for (line = 0; line < lines; line++) { - ranges = &tc->status.entries[line].ranges; - TAILQ_FOREACH(sr, ranges, entry) { - if (sr->type == STYLE_RANGE_WINDOW) - break; - } - if (sr != NULL) - break; + char *p; + int top; + u_int line, ox, oy, sx, sy, lines, position; + long n; + struct format_tree *ft; + + /* + * Work out the position from the -x and -y arguments. This is the + * bottom-left position. + */ + + /* If the popup is too big, stop now. */ + if (w > tty->sx || h > tty->sy) + return (0); + + /* Create format with mouse position if any. */ + ft = format_create_from_target(item); + if (event->m.valid) { + format_add(ft, "popup_mouse_x", "%u", event->m.x); + format_add(ft, "popup_mouse_y", "%u", event->m.y); } - if (line == lines) - ranges = &tc->status.entries[0].ranges; - xp = args_get(args, 'x'); - if (xp == NULL || strcmp(xp, "C") == 0) - *px = (tty->sx - 1) / 2 - w / 2; - else if (strcmp(xp, "R") == 0) - *px = tty->sx - 1; - else if (strcmp(xp, "P") == 0) { - tty_window_offset(&tc->tty, &ox, &oy, &sx, &sy); - if (wp->xoff >= ox) - *px = wp->xoff - ox; - else - *px = 0; - } else if (strcmp(xp, "M") == 0) { - if (event->m.valid && event->m.x > w / 2) - *px = event->m.x - w / 2; + /* + * If there are any status lines, add this window position and the + * status line position. + */ + top = status_at_line(tc); + if (top != -1) { + lines = status_line_size(tc); + if (top == 0) + top = lines; else - *px = 0; - } else if (strcmp(xp, "W") == 0) { - if (status_at_line(tc) == -1) - *px = 0; - else { + top = 0; + position = options_get_number(s->options, "status-position"); + + for (line = 0; line < lines; line++) { + ranges = &tc->status.entries[line].ranges; TAILQ_FOREACH(sr, ranges, entry) { if (sr->type != STYLE_RANGE_WINDOW) continue; @@ -116,61 +118,137 @@ cmd_display_menu_get_position(struct client *tc, struct cmdq_item *item, break; } if (sr != NULL) - *px = sr->start; - else - *px = 0; + break; + } + if (line == lines) + ranges = &tc->status.entries[0].ranges; + + if (sr != NULL) { + format_add(ft, "popup_window_status_line_x", "%u", + sr->start); + if (position == 0) { + format_add(ft, "popup_window_status_line_y", + "%u", line + 1 + h); + } else { + format_add(ft, "popup_window_status_line_y", + "%u", tty->sy - lines + line); + } + } + + if (position == 0) + format_add(ft, "popup_status_line_y", "%u", lines + h); + else { + format_add(ft, "popup_status_line_y", "%u", + tty->sy - lines); } } else - *px = strtoul(xp, NULL, 10); - if ((*px) + w >= tty->sx) - *px = tty->sx - w; + top = 0; - yp = args_get(args, 'y'); - if (yp == NULL || strcmp(yp, "C") == 0) - *py = (tty->sy - 1) / 2 + h / 2; - else if (strcmp(yp, "P") == 0) { - tty_window_offset(&tc->tty, &ox, &oy, &sx, &sy); - if (wp->yoff + wp->sy >= oy) - *py = wp->yoff + wp->sy - oy; + /* Popup width and height. */ + format_add(ft, "popup_width", "%u", w); + format_add(ft, "popup_height", "%u", h); + + /* Position so popup is in the centre. */ + n = (long)(tty->sx - 1) / 2 - w / 2; + if (n < 0) + format_add(ft, "popup_centre_x", "%u", 0); + else + format_add(ft, "popup_centre_x", "%ld", n); + n = (tty->sy - 1) / 2 + h / 2; + if (n + h >= tty->sy) + format_add(ft, "popup_centre_y", "%u", tty->sy - h); + else + format_add(ft, "popup_centre_y", "%ld", n); + + /* Position of popup relative to mouse. */ + if (event->m.valid) { + n = (long)event->m.x - w / 2; + if (n < 0) + format_add(ft, "popup_mouse_centre_x", "%u", 0); else - *py = 0; - } else if (strcmp(yp, "M") == 0) { - if (event->m.valid) - *py = event->m.y + h; + format_add(ft, "popup_mouse_centre_x", "%ld", n); + n = event->m.y - h / 2; + if (n + h >= tty->sy) { + format_add(ft, "popup_mouse_centre_y", "%u", + tty->sy - h); + } else + format_add(ft, "popup_mouse_centre_y", "%ld", n); + n = (long)event->m.y + h; + if (n + h >= tty->sy) + format_add(ft, "popup_mouse_top", "%u", tty->sy - h); else - *py = 0; - } else if (strcmp(yp, "S") == 0) { - if (options_get_number(s->options, "status-position") == 0) { - if (lines != 0) - *py = lines + h; - else - *py = 0; - } else { - if (lines != 0) - *py = tty->sy - lines; - else - *py = tty->sy; - } - } else if (strcmp(yp, "W") == 0) { - if (options_get_number(s->options, "status-position") == 0) { - if (lines != 0) - *py = line + 1 + h; - else - *py = 0; - } else { - if (lines != 0) - *py = tty->sy - lines + line; - else - *py = tty->sy; - } - } else - *py = strtoul(yp, NULL, 10); - if (*py < h) - *py = 0; + format_add(ft, "popup_mouse_top", "%ld", n); + n = event->m.y - h; + if (n < 0) + format_add(ft, "popup_mouse_bottom", "%u", 0); + else + format_add(ft, "popup_mouse_bottom", "%ld", n); + } + + /* Position in pane. */ + tty_window_offset(&tc->tty, &ox, &oy, &sx, &sy); + n = top + wp->yoff - oy + h; + if (n >= tty->sy) + format_add(ft, "popup_pane_top", "%u", tty->sy - h); + else + format_add(ft, "popup_pane_top", "%ld", n); + format_add(ft, "popup_pane_bottom", "%u", top + wp->yoff + wp->sy - oy); + format_add(ft, "popup_pane_left", "%u", wp->xoff - ox); + n = (long)wp->xoff + wp->sx - ox - w; + if (n < 0) + format_add(ft, "popup_pane_right", "%u", 0); else - *py -= h; - if ((*py) + h >= tty->sy) - *py = tty->sy - h; + format_add(ft, "popup_pane_right", "%ld", n); + + /* Expand horizontal position. */ + xp = args_get(args, 'x'); + if (xp == NULL || strcmp(xp, "C") == 0) + xp = "#{popup_centre_x}"; + else if (strcmp(xp, "R") == 0) + xp = "#{popup_right}"; + else if (strcmp(xp, "P") == 0) + xp = "#{popup_pane_left}"; + else if (strcmp(xp, "M") == 0) + xp = "#{popup_mouse_centre_x}"; + else if (strcmp(xp, "W") == 0) + xp = "#{popup_window_status_line_x}"; + p = format_expand(ft, xp); + n = strtol(p, NULL, 10); + if (n + w >= tty->sx) + n = tty->sx - w; + else if (n < 0) + n = 0; + *px = n; + log_debug("%s: -x: %s = %s = %u", __func__, xp, p, *px); + free(p); + + /* Expand vertical position */ + yp = args_get(args, 'y'); + if (yp == NULL || strcmp(yp, "C") == 0) + yp = "#{popup_centre_y}"; + else if (strcmp(yp, "P") == 0) + yp = "#{popup_pane_bottom}"; + else if (strcmp(yp, "M") == 0) + yp = "#{popup_mouse_top}"; + else if (strcmp(yp, "S") == 0) + yp = "#{popup_status_line_y}"; + else if (strcmp(yp, "W") == 0) + yp = "#{popup_window_status_line_y}"; + p = format_expand(ft, yp); + n = strtol(p, NULL, 10); + if (n < h) + n = 0; + else + n -= h; + if (n + h >= tty->sy) + n = tty->sy - h; + else if (n < 0) + n = 0; + *py = n; + log_debug("%s: -y: %s = %s = %u", __func__, yp, p, *py); + free(p); + + return (1); } static enum cmd_retval @@ -226,8 +304,11 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item) menu_free(menu); return (CMD_RETURN_NORMAL); } - cmd_display_menu_get_position(tc, item, args, &px, &py, menu->width + 4, - menu->count + 2); + if (!cmd_display_menu_get_position(tc, item, args, &px, &py, + menu->width + 4, menu->count + 2)) { + menu_free(menu); + return (CMD_RETURN_NORMAL); + } if (args_has(args, 'O')) flags |= MENU_STAYOPEN; @@ -296,7 +377,8 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item) w = tty->sx - 1; if (h > tty->sy - 1) h = tty->sy - 1; - cmd_display_menu_get_position(tc, item, args, &px, &py, w, h); + if (!cmd_display_menu_get_position(tc, item, args, &px, &py, w, h)) + return (CMD_RETURN_NORMAL); value = args_get(args, 'd'); if (value != NULL) diff --git a/tmux.1 b/tmux.1 index 3d58b32f..0a71cc37 100644 --- a/tmux.1 +++ b/tmux.1 @@ -5388,6 +5388,28 @@ Both may be a row or column number, or one of the following special values: .It Li "S" Ta Fl y Ta "The line above or below the status line" .El .Pp +Or a format, which is expanded including the following additional variables: +.Bl -column "XXXXXXXXXXXXXXXXXXXXXXXXXX" -offset indent +.It Sy "Variable name" Ta Sy "Replaced with" +.It Li "popup_centre_x" Ta "Centered in the client" +.It Li "popup_centre_y" Ta "Centered in the client" +.It Li "popup_height" Ta "Height of menu or popup" +.It Li "popup_mouse_bottom" Ta "Bottom of at the mouse" +.It Li "popup_mouse_centre_x" Ta "Horizontal centre at the mouse" +.It Li "popup_mouse_centre_y" Ta "Vertical centre at the mouse" +.It Li "popup_mouse_top" Ta "Top at the mouse" +.It Li "popup_mouse_x" Ta "Mouse X position" +.It Li "popup_mouse_y" Ta "Mouse Y position" +.It Li "popup_pane_bottom" Ta "Bottom of the pane" +.It Li "popup_pane_left" Ta "Left of the pane" +.It Li "popup_pane_right" Ta "Right of the pane" +.It Li "popup_pane_top" Ta "Top of the pane" +.It Li "popup_status_line_y" Ta "Above or below the status line" +.It Li "popup_width" Ta "Width of menu or popup" +.It Li "popup_window_status_line_x" Ta "At the window position in status line" +.It Li "popup_window_status_line_y" Ta "At the status line showing the window" +.El +.Pp Each menu consists of items followed by a key shortcut shown in brackets. If the menu is too large to fit on the terminal, it is not displayed. Pressing the key shortcut chooses the corresponding item. -- cgit v1.2.3 From 572a6b21b5a4d4e9587ddfc933449bb89fafeab1 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 3 Nov 2020 08:41:24 +0000 Subject: Back to 3.3. --- CHANGES | 4 ++++ configure.ac | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 6f3944c7..8a438f81 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +CHANGES FROM 3.2 TO 3.3 + +XXX + CHANGES FROM 3.1c TO 3.2 * Fire focus events even when the pane is in a mode. diff --git a/configure.ac b/configure.ac index 768d3db3..93246fc8 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # configure.ac -AC_INIT([tmux], 3.2-rc3) +AC_INIT([tmux], next-3.3) AC_PREREQ([2.60]) AC_CONFIG_AUX_DIR(etc) -- cgit v1.2.3 From 1326529f99366e7d438364fd8727ec132a2f7433 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 9 Nov 2020 08:42:43 +0000 Subject: Remove some old debug logging. --- screen-write.c | 1 - 1 file changed, 1 deletion(-) diff --git a/screen-write.c b/screen-write.c index c9c61086..ab6a020c 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1551,7 +1551,6 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, TAILQ_FOREACH_SAFE(ci, &cl->items, entry, tmp) { screen_write_set_cursor(ctx, ci->x, y); if (ci->type == CLEAR_END) { - log_debug("XXX %u %u", ci->x, ci->bg); screen_write_initctx(ctx, &ttyctx, 1); ttyctx.bg = ci->bg; tty_write(tty_cmd_clearendofline, &ttyctx); -- cgit v1.2.3 From 72c46aa15e50ef6391ab3fe6e230ed3abc9485b0 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 9 Nov 2020 09:00:41 +0000 Subject: Add support for Haiku, from David Carlier. GitHub issue 2453. --- Makefile.am | 5 +++ compat.h | 4 +++ compat/forkpty-haiku.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++ configure.ac | 30 +++++++++++++----- osdep-haiku.c | 53 ++++++++++++++++++++++++++++++++ 5 files changed, 167 insertions(+), 7 deletions(-) create mode 100644 compat/forkpty-haiku.c create mode 100644 osdep-haiku.c diff --git a/Makefile.am b/Makefile.am index 91d641fd..7b84b1e9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 \ diff --git a/compat.h b/compat.h index b213336f..ec125ced 100644 --- a/compat.h +++ b/compat.h @@ -110,6 +110,10 @@ void warnx(const char *, ...); #define pledge(s, p) (0) #endif +#ifndef IMAXBEL +#define IMAXBEL 0 +#endif + #ifdef HAVE_STDINT_H #include #else diff --git a/compat/forkpty-haiku.c b/compat/forkpty-haiku.c new file mode 100644 index 00000000..6112164c --- /dev/null +++ b/compat/forkpty-haiku.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2008 Nicholas Marriott + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include +#include +#include + +#include "compat.h" + +void fatal(const char *, ...); +void fatalx(const char *, ...); + +pid_t +forkpty(int *master, char *name, struct termios *tio, struct winsize *ws) +{ + int slave = -1; + char *path; + pid_t pid; + + if ((*master = open("/dev/ptmx", O_RDWR|O_NOCTTY)) == -1) + return (-1); + if (grantpt(*master) != 0) + goto out; + if (unlockpt(*master) != 0) + goto out; + + if ((path = ptsname(*master)) == NULL) + goto out; + if (name != NULL) + strlcpy(name, path, TTY_NAME_MAX); + if ((slave = open(path, O_RDWR|O_NOCTTY)) == -1) + goto out; + + switch (pid = fork()) { + case -1: + goto out; + case 0: + close(*master); + + setsid(); + if (ioctl(slave, TIOCSCTTY, NULL) == -1) + fatal("ioctl failed"); + + if (tio != NULL && tcsetattr(slave, TCSAFLUSH, tio) == -1) + fatal("tcsetattr failed"); + if (ioctl(slave, TIOCSWINSZ, ws) == -1) + fatal("ioctl failed"); + + dup2(slave, 0); + dup2(slave, 1); + dup2(slave, 2); + if (slave > 2) + close(slave); + return (0); + } + + close(slave); + return (pid); + +out: + if (*master != -1) + close(*master); + if (slave != -1) + close(slave); + return (-1); +} diff --git a/configure.ac b/configure.ac index 93246fc8..cf621835 100644 --- a/configure.ac +++ b/configure.ac @@ -296,12 +296,25 @@ AC_TRY_LINK( found_b64_ntop=yes, found_b64_ntop=no ) +OLD_LIBS="$LIBS" if test "x$found_b64_ntop" = xno; then AC_MSG_RESULT(no) - AC_MSG_CHECKING(for b64_ntop with -lresolv) - OLD_LIBS="$LIBS" - LIBS="$LIBS -lresolv" + LIBS="$OLD_LIBS -lresolv" + AC_TRY_LINK( + [ + #include + #include + #include + ], + [b64_ntop(NULL, 0, NULL, 0);], + found_b64_ntop=yes, + found_b64_ntop=no + ) +fi +if test "x$found_b64_ntop" = xno; then + AC_MSG_CHECKING(for b64_ntop with -lnetwork) + LIBS="$OLD_LIBS -lnetwork" AC_TRY_LINK( [ #include @@ -312,16 +325,14 @@ if test "x$found_b64_ntop" = xno; then found_b64_ntop=yes, found_b64_ntop=no ) - if test "x$found_b64_ntop" = xno; then - LIBS="$OLD_LIBS" - AC_MSG_RESULT(no) - fi fi if test "x$found_b64_ntop" = xyes; then AC_DEFINE(HAVE_B64_NTOP) AC_MSG_RESULT(yes) else + LIBS="$OLD_LIBS" AC_LIBOBJ(base64) + AC_MSG_RESULT(no) fi # Look for networking libraries. @@ -656,6 +667,10 @@ case "$host_os" in AC_MSG_RESULT(cygwin) PLATFORM=cygwin ;; + *haiku*) + AC_MSG_RESULT(haiku) + PLATFORM=haiku + ;; *) AC_MSG_RESULT(unknown) PLATFORM=unknown @@ -671,6 +686,7 @@ AM_CONDITIONAL(IS_NETBSD, test "x$PLATFORM" = xnetbsd) AM_CONDITIONAL(IS_OPENBSD, test "x$PLATFORM" = xopenbsd) AM_CONDITIONAL(IS_SUNOS, test "x$PLATFORM" = xsunos) AM_CONDITIONAL(IS_HPUX, test "x$PLATFORM" = xhpux) +AM_CONDITIONAL(IS_HAIKU, test "x$PLATFORM" = xhaiku) AM_CONDITIONAL(IS_UNKNOWN, test "x$PLATFORM" = xunknown) # Save our CFLAGS/CPPFLAGS/LDFLAGS for the Makefile and restore the old user diff --git a/osdep-haiku.c b/osdep-haiku.c new file mode 100644 index 00000000..298dc05e --- /dev/null +++ b/osdep-haiku.c @@ -0,0 +1,53 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2009 Nicholas Marriott + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include +#include +#include + +#include "tmux.h" + +char * +osdep_get_name(int fd, __unused char *tty) +{ + pid_t tid; + team_info tinfo; + + if ((tid = tcgetpgrp(fd)) == -1) + return (NULL); + + if (get_team_info(tid, &tinfo) != B_OK) + return (NULL); + + /* Up to the first 64 characters. */ + return (xstrdup(tinfo.args)); +} + +char * +osdep_get_cwd(int fd) +{ + return (NULL); +} + +struct event_base * +osdep_event_init(void) +{ + return (event_init()); +} -- cgit v1.2.3 From 61e55fa50dc7119a8c88bb385e615a8e6c8d6a85 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 9 Nov 2020 09:10:10 +0000 Subject: Change how escaping is processed for formats so that ## and # can be used in styles. Also add a 'w' format modifier for the width. From Chas J Owens IV in GitHub issue 2389. --- format-draw.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- format.c | 40 ++++++++++++-- tmux.1 | 4 +- 3 files changed, 201 insertions(+), 17 deletions(-) diff --git a/format-draw.c b/format-draw.c index ec98ba95..e73c5df4 100644 --- a/format-draw.c +++ b/format-draw.c @@ -486,6 +486,18 @@ format_draw_right(struct screen_write_ctx *octx, u_int available, u_int ocx, focus_end, frs); } +/* Draw multiple characters. */ +static void +format_draw_many(struct screen_write_ctx *ctx, struct style *sy, char ch, + u_int n) +{ + u_int i; + + utf8_set(&sy->gc.data, ch); + for (i = 0; i < n; i++) + screen_write_cell(ctx, &sy->gc); +} + /* Draw a format to a screen. */ void format_draw(struct screen_write_ctx *octx, const struct grid_cell *base, @@ -509,10 +521,10 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base, size_t size = strlen(expanded); struct screen *os = octx->s, s[TOTAL]; struct screen_write_ctx ctx[TOTAL]; - u_int ocx = os->cx, ocy = os->cy, i, width[TOTAL]; + u_int ocx = os->cx, ocy = os->cy, n, i, width[TOTAL]; u_int map[] = { LEFT, LEFT, CENTRE, RIGHT }; int focus_start = -1, focus_end = -1; - int list_state = -1, fill = -1; + int list_state = -1, fill = -1, even; enum style_align list_align = STYLE_ALIGN_DEFAULT; struct grid_cell gc, current_default; struct style sy, saved_sy; @@ -547,6 +559,34 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base, */ cp = expanded; while (*cp != '\0') { + /* Handle sequences of #. */ + if (cp[0] == '#' && cp[1] != '[' && cp[1] != '\0') { + for (n = 1; cp[n] == '#'; n++) + /* nothing */; + if (cp[n] != '[') { + width[current] += n; + cp += n; + format_draw_many(&ctx[current], &sy, '#', n); + continue; + } + even = ((n % 2) == 0); + if (even) + cp += (n + 1); + else + cp += (n - 1); + if (sy.ignore) + continue; + format_draw_many(&ctx[current], &sy, '#', n / 2); + width[current] += (n / 2); + if (even) { + utf8_set(ud, '['); + screen_write_cell(&ctx[current], &sy.gc); + width[current]++; + } + continue; + } + + /* Is this not a style? */ if (cp[0] != '#' || cp[1] != '[' || sy.ignore) { /* See if this is a UTF-8 character. */ if ((more = utf8_open(ud, *cp)) == UTF8_MORE) { @@ -796,13 +836,33 @@ u_int format_width(const char *expanded) { const char *cp, *end; - u_int width = 0; + u_int n, width = 0; struct utf8_data ud; enum utf8_state more; cp = expanded; while (*cp != '\0') { - if (cp[0] == '#' && cp[1] == '[') { + if (*cp == '#') { + for (n = 1; cp[n] == '#'; n++) + /* nothing */; + if (cp[n] != '[') { + width += n; + cp += n; + continue; + } + width += (n / 2); /* one for each ## */ + + if ((n % 2) == 0) { + /* + * An even number of #s means that all #s are + * escaped, so not a style. + */ + width++; /* one for the [ */ + cp += (n + 1); + continue; + } + cp += (n - 1); /* point to the [ */ + end = format_skip(cp + 2, "]"); if (end == NULL) return (0); @@ -823,19 +883,57 @@ format_width(const char *expanded) return (width); } -/* Trim on the left, taking #[] into account. */ +/* + * Trim on the left, taking #[] into account. Note, we copy the whole set of + * unescaped #s, but only add their escaped size to width. This is because the + * format_draw function will actually do the escaping when it runs + */ char * format_trim_left(const char *expanded, u_int limit) { char *copy, *out; const char *cp = expanded, *end; - u_int width = 0; + u_int even, n, width = 0; struct utf8_data ud; enum utf8_state more; - out = copy = xmalloc(strlen(expanded) + 1); + out = copy = xcalloc(1, strlen(expanded) + 1); while (*cp != '\0') { - if (cp[0] == '#' && cp[1] == '[') { + if (width >= limit) + break; + if (*cp == '#') { + for (end = cp + 1; *end == '#'; end++) + /* nothing */; + n = end - cp; + if (*end != '[') { + if (n > limit - width) + n = limit - width; + memcpy(out, cp, n); + out += n; + width += n; + cp = end; + continue; + } + even = ((n % 2) == 0); + + n /= 2; + if (n > limit - width) + n = limit - width; + width += n; + n *= 2; + memcpy(out, cp, n); + out += n; + + if (even) { + if (width + 1 <= limit) { + *out++ = '['; + width++; + } + cp = end + 1; + continue; + } + cp = end - 1; + end = format_skip(cp + 2, "]"); if (end == NULL) break; @@ -873,7 +971,7 @@ format_trim_right(const char *expanded, u_int limit) { char *copy, *out; const char *cp = expanded, *end; - u_int width = 0, total_width, skip; + u_int width = 0, total_width, skip, old_n, even, n; struct utf8_data ud; enum utf8_state more; @@ -882,12 +980,64 @@ format_trim_right(const char *expanded, u_int limit) return (xstrdup(expanded)); skip = total_width - limit; - out = copy = xmalloc(strlen(expanded) + 1); + out = copy = xcalloc(1, strlen(expanded) + 1); while (*cp != '\0') { - if (cp[0] == '#' && cp[1] == '[') { + if (*cp == '#') { + for (end = cp + 1; *end == '#'; end++) + /* nothing */; + old_n = n = end - cp; + if (*end != '[') { + if (width <= skip) { + if (skip - width >= n) + n = 0; + else + n -= (skip - width); + } + if (n != 0) { + memcpy(out, cp, n); + out += n; + } + + /* + * The width always increases by the full + * amount even if we can't copy anything yet. + */ + width += old_n; + cp = end; + continue; + } + even = ((n % 2) == 0); + + n /= 2; + if (width <= skip) { + if (skip - width >= n) + n = 0; + else + n -= (skip - width); + } + if (n != 0) { + /* + * Copy the full amount because it hasn't been + * escaped yet. + */ + memcpy(out, cp, old_n); + out += old_n; + } + cp += old_n; + width += (old_n / 2) - even; + + if (even) { + if (width > skip) + *out++ = '['; + width++; + continue; + } + cp = end - 1; + end = format_skip(cp + 2, "]"); - if (end == NULL) + if (end == NULL) { break; + } memcpy(out, cp, end + 1 - cp); out += (end + 1 - cp); cp = end + 1; diff --git a/format.c b/format.c index 99efbc1c..91955259 100644 --- a/format.c +++ b/format.c @@ -98,6 +98,7 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2) #define FORMAT_PANES 0x200 #define FORMAT_PRETTY 0x400 #define FORMAT_LENGTH 0x800 +#define FORMAT_WIDTH 0x1000 /* Limit on recursion. */ #define FORMAT_LOOP_LIMIT 10 @@ -1671,7 +1672,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s, /* * Modifiers are a ; separated list of the forms: - * l,m,C,b,d,n,t,q,E,T,S,W,P,<,> + * l,m,C,b,d,n,t,w,q,E,T,S,W,P,<,> * =a * =/a * =/a/ @@ -1688,7 +1689,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s, cp++; /* Check single character modifiers with no arguments. */ - if (strchr("lbdnqETSWP<>", cp[0]) != NULL && + if (strchr("lbdnqwETSWP<>", cp[0]) != NULL && format_is_end(cp[1])) { format_add_modifier(&list, count, cp, 1, NULL, 0); cp++; @@ -2184,6 +2185,9 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen, if (errptr != NULL) width = 0; break; + case 'w': + modifiers |= FORMAT_WIDTH; + break; case 'e': if (fm->argc < 1 || fm->argc > 3) break; @@ -2456,13 +2460,19 @@ done: format_log(es, "applied padding width %d: %s", width, value); } - /* Replace with the length if needed. */ + /* Replace with the length or width if needed. */ if (modifiers & FORMAT_LENGTH) { xasprintf(&new, "%zu", strlen(value)); free(value); value = new; format_log(es, "replacing with length: %s", new); } + if (modifiers & FORMAT_WIDTH) { + xasprintf(&new, "%u", format_width(value)); + free(value); + value = new; + format_log(es, "replacing with width: %s", new); + } /* Expand the buffer and copy in the value. */ valuelen = strlen(value); @@ -2589,8 +2599,30 @@ format_expand1(struct format_expand_state *es, const char *fmt) break; fmt += n + 1; continue; - case '}': case '#': + /* + * If ##[ (with two or more #s), then it is a style and + * can be left for format_draw to handle. + */ + ptr = fmt; + n = 2; + while (*ptr == '#') { + ptr++; + n++; + } + if (*ptr == '[') { + format_log(es, "found #*%zu[", n); + while (len - off < n + 2) { + buf = xreallocarray(buf, 2, len); + len *= 2; + } + memcpy(buf + off, fmt - 2, n + 1); + off += n + 1; + fmt = ptr + 1; + continue; + } + /* FALLTHROUGH */ + case '}': case ',': format_log(es, "found #%c", ch); while (len - off < 2) { diff --git a/tmux.1 b/tmux.1 index 0a71cc37..37f6f165 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4591,7 +4591,9 @@ pads the string to a given width, for example will result in a width of at least 10 characters. A positive width pads on the left, a negative on the right. .Ql n -expands to the length of the variable, for example +expands to the length of the variable and +.Ql w +to its width when displayed, for example .Ql #{n:window_name} . .Pp Prefixing a time variable with -- cgit v1.2.3 From f1193b48910aed15a2c73cdb5784a26f2ea0f64c Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 9 Nov 2020 10:54:28 +0000 Subject: If mouse bits change, clear them all and set again to avoid problems with some bits implying others. GitHub issue 2458. --- tty.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/tty.c b/tty.c index bcbccca6..777b639b 100644 --- a/tty.c +++ b/tty.c @@ -694,28 +694,26 @@ tty_update_mode(struct tty *tty, int mode, struct screen *s) } if ((changed & ALL_MOUSE_MODES) && tty_term_has(tty->term, TTYC_KMOUS)) { - if ((mode & ALL_MOUSE_MODES) == 0) + /* + * If the mouse modes have changed, clear any that are set and + * apply again. There are differences in how terminals track + * the various bits. + */ + if (tty->mode & MODE_MOUSE_SGR) tty_puts(tty, "\033[?1006l"); - if ((changed & MODE_MOUSE_STANDARD) && - (~mode & MODE_MOUSE_STANDARD)) + if (tty->mode & MODE_MOUSE_STANDARD) tty_puts(tty, "\033[?1000l"); - if ((changed & MODE_MOUSE_BUTTON) && - (~mode & MODE_MOUSE_BUTTON)) + if (tty->mode & MODE_MOUSE_BUTTON) tty_puts(tty, "\033[?1002l"); - if ((changed & MODE_MOUSE_ALL) && - (~mode & MODE_MOUSE_ALL)) + if (tty->mode & MODE_MOUSE_ALL) tty_puts(tty, "\033[?1003l"); - if (mode & ALL_MOUSE_MODES) tty_puts(tty, "\033[?1006h"); - if ((changed & MODE_MOUSE_STANDARD) && - (mode & MODE_MOUSE_STANDARD)) + if (mode & MODE_MOUSE_STANDARD) tty_puts(tty, "\033[?1000h"); - if ((changed & MODE_MOUSE_BUTTON) && - (mode & MODE_MOUSE_BUTTON)) + if (mode & MODE_MOUSE_BUTTON) tty_puts(tty, "\033[?1002h"); - if ((changed & MODE_MOUSE_ALL) && - (mode & MODE_MOUSE_ALL)) + if (mode & MODE_MOUSE_ALL) tty_puts(tty, "\033[?1003h"); } if (changed & MODE_BRACKETPASTE) { -- cgit v1.2.3 From 3eb1519bd784076f63fed6678b88f918317a2124 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 9 Nov 2020 16:41:55 +0000 Subject: Scaffold for oss-fuzz, from Sergey Nizovtsev. --- .gitignore | 2 ++ Makefile.am | 6 ++++ compat.h | 8 +++++ configure.ac | 47 +++++++++++++++++++++++-- fuzz/input-fuzzer.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++ fuzz/input-fuzzer.dict | 8 +++++ fuzz/input-fuzzer.options | 2 ++ 7 files changed, 159 insertions(+), 3 deletions(-) create mode 100644 fuzz/input-fuzzer.c create mode 100644 fuzz/input-fuzzer.dict create mode 100644 fuzz/input-fuzzer.options diff --git a/.gitignore b/.gitignore index d01a0166..ec49a6de 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,5 @@ configure tmux.1.* *.dSYM cmd-parse.c +fuzz/*-fuzzer +.dirstamp diff --git a/Makefile.am b/Makefile.am index 7b84b1e9..b40e0944 100644 --- a/Makefile.am +++ b/Makefile.am @@ -202,6 +202,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 \ diff --git a/compat.h b/compat.h index ec125ced..6e26a02c 100644 --- a/compat.h +++ b/compat.h @@ -52,6 +52,9 @@ #ifndef __packed #define __packed __attribute__ ((__packed__)) #endif +#ifndef __weak +#define __weak __attribute__ ((__weak__)) +#endif #ifndef ECHOPRT #define ECHOPRT 0 @@ -395,6 +398,11 @@ int utf8proc_mbtowc(wchar_t *, const char *, size_t); int utf8proc_wctomb(char *, wchar_t); #endif +#ifdef NEED_FUZZING +/* tmux.c */ +#define main __weak main +#endif + /* getopt.c */ extern int BSDopterr; extern int BSDoptind; diff --git a/configure.ac b/configure.ac index cf621835..97010df4 100644 --- a/configure.ac +++ b/configure.ac @@ -21,6 +21,26 @@ SAVED_CFLAGS="$CFLAGS" SAVED_CPPFLAGS="$CPPFLAGS" SAVED_LDFLAGS="$LDFLAGS" +# Is this oss-fuzz build? +AC_ARG_ENABLE( + fuzzing, + AC_HELP_STRING(--enable-fuzzing, build fuzzers) +) +AC_ARG_VAR( + FUZZING_LIBS, + AC_HELP_STRING(libraries to link fuzzing targets with) +) + +# Set up convenient fuzzing defaults before initializing compiler. +if test "x$enable_fuzzing" = xyes; then + AC_DEFINE(NEED_FUZZING) + test "x$CC" == x && CC=clang + test "x$FUZZING_LIBS" == x && \ + FUZZING_LIBS="-fsanitize=fuzzer" + test "x$SAVED_CFLAGS" == x && \ + AM_CFLAGS="-g -fsanitize=fuzzer-no-link,address" +fi + # Set up the compiler in two different ways and say yes we may want to install. AC_PROG_CC AM_PROG_CC_C_O @@ -54,8 +74,11 @@ if test "x$enable_static" = xyes; then LDFLAGS="$AM_LDFLAGS $SAVED_LDFLAGS" fi +# Do we need fuzzers? +AM_CONDITIONAL(NEED_FUZZING, test "x$enable_fuzzing" = xyes) + # Is this gcc? -AM_CONDITIONAL(IS_GCC, test "x$GCC" = xyes) +AM_CONDITIONAL(IS_GCC, test "x$GCC" = xyes -a "x$enable_fuzzing" != xyes) # Is this Sun CC? AC_EGREP_CPP( @@ -117,8 +140,6 @@ AC_REPLACE_FUNCS([ \ getline \ getprogname \ memmem \ - recallocarray \ - reallocarray \ setenv \ setproctitle \ strcasestr \ @@ -130,6 +151,26 @@ AC_REPLACE_FUNCS([ \ ]) AC_FUNC_STRNLEN +# Clang sanitizers wrap reallocarray even if it isn't available on the target +# system. When compiled it always returns NULL and crashes the program. To +# detect this we need a more complicated test. +AC_MSG_CHECKING([for working reallocarray]) +AC_RUN_IFELSE([AC_LANG_PROGRAM( + [#include ], + [return (reallocarray(NULL, 1, 1) == NULL);] + )], + AC_MSG_RESULT(yes), + [AC_LIBOBJ(reallocarray) AC_MSG_RESULT([no])] +) +AC_MSG_CHECKING([for working recallocarray]) +AC_RUN_IFELSE([AC_LANG_PROGRAM( + [#include ], + [return (recallocarray(NULL, 1, 1, 1) == NULL);] + )], + AC_MSG_RESULT(yes), + [AC_LIBOBJ(recallocarray) AC_MSG_RESULT([no])] +) + # Look for clock_gettime. Must come before event_init. AC_SEARCH_LIBS(clock_gettime, rt) diff --git a/fuzz/input-fuzzer.c b/fuzz/input-fuzzer.c new file mode 100644 index 00000000..27f2be3d --- /dev/null +++ b/fuzz/input-fuzzer.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2020 Sergey Nizovtsev + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include "tmux.h" + +#define FUZZER_MAXLEN 512 +#define PANE_WIDTH 80 +#define PANE_HEIGHT 25 + +struct event_base *libevent; + +int +LLVMFuzzerTestOneInput(const unsigned char *data, size_t size) +{ + struct bufferevent *vpty[2]; + struct window *w; + struct window_pane *wp; + int error; + + /* + * Since AFL doesn't support -max_len paramenter we have to + * discard long inputs manually. + */ + if (size > FUZZER_MAXLEN) + return 0; + + w = window_create(PANE_WIDTH, PANE_HEIGHT, 0, 0); + wp = window_add_pane(w, NULL, 0, 0); + bufferevent_pair_new(libevent, BEV_OPT_CLOSE_ON_FREE, vpty); + wp->ictx = input_init(wp, vpty[0]); + window_add_ref(w, __func__); + + input_parse_buffer(wp, (u_char*) data, size); + while (cmdq_next(NULL) != 0) + ; + error = event_base_loop(libevent, EVLOOP_NONBLOCK); + if (error == -1) + errx(1, "event_base_loop failed"); + + assert(w->references == 1); + window_remove_ref(w, __func__); + + bufferevent_free(vpty[0]); + bufferevent_free(vpty[1]); + + return 0; +} + +int +LLVMFuzzerInitialize(__unused int *argc, __unused char ***argv) +{ + const struct options_table_entry *oe; + + global_environ = environ_create(); + global_options = options_create(NULL); + global_s_options = options_create(NULL); + global_w_options = options_create(NULL); + for (oe = options_table; oe->name != NULL; oe++) { + if (oe->scope & OPTIONS_TABLE_SERVER) + options_default(global_options, oe); + if (oe->scope & OPTIONS_TABLE_SESSION) + options_default(global_s_options, oe); + if (oe->scope & OPTIONS_TABLE_WINDOW) + options_default(global_w_options, oe); + } + libevent = osdep_event_init(); + + options_set_number(global_w_options, "monitor-bell", 0); + options_set_number(global_w_options, "allow-rename", 1); + options_set_number(global_options, "set-clipboard", 2); + + return 0; +} diff --git a/fuzz/input-fuzzer.dict b/fuzz/input-fuzzer.dict new file mode 100644 index 00000000..2091b970 --- /dev/null +++ b/fuzz/input-fuzzer.dict @@ -0,0 +1,8 @@ +"\x1b[" +"1000" +"2004" +"1049" +"38;2" +"100;" +"tmux;" +"rgb:00/00/00" diff --git a/fuzz/input-fuzzer.options b/fuzz/input-fuzzer.options new file mode 100644 index 00000000..5d468bc6 --- /dev/null +++ b/fuzz/input-fuzzer.options @@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 512 -- cgit v1.2.3 From bbab5b7a30717c4455f7725e6adc364f6c274e7d Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 10 Nov 2020 08:16:52 +0000 Subject: Allow previous-word to scroll onto the first line, noticed by Anindya Mukherjee. --- window-copy.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/window-copy.c b/window-copy.c index 1dc0c293..6dc03b34 100644 --- a/window-copy.c +++ b/window-copy.c @@ -4526,10 +4526,11 @@ window_copy_cursor_previous_word_pos(struct window_mode_entry *wme, const char *separators, int already, u_int *ppx, u_int *ppy) { struct window_copy_mode_data *data = wme->data; - u_int px, py; + u_int px, py, hsize; + hsize = screen_hsize(data->backing); px = data->cx; - py = screen_hsize(data->backing) + data->cy - data->oy; + py = hsize + data->cy - data->oy; /* Move back to the previous word character. */ if (already || window_copy_in_set(wme, px, py, separators)) { @@ -4542,9 +4543,7 @@ window_copy_cursor_previous_word_pos(struct window_mode_entry *wme, } else { if (py == 0 || (data->cy == 0 && - (screen_hsize(data->backing) == 0 || - data->oy >= - screen_hsize(data->backing) - 1))) + (hsize == 0 || data->oy > hsize - 1))) goto out; py--; @@ -4573,10 +4572,11 @@ window_copy_cursor_previous_word(struct window_mode_entry *wme, const char *separators, int already) { struct window_copy_mode_data *data = wme->data; - u_int px, py; + u_int px, py, hsize; + hsize = screen_hsize(data->backing); px = data->cx; - py = screen_hsize(data->backing) + data->cy - data->oy; + py = hsize + data->cy - data->oy; /* Move back to the previous word character. */ if (already || window_copy_in_set(wme, px, py, separators)) { @@ -4588,14 +4588,11 @@ window_copy_cursor_previous_word(struct window_mode_entry *wme, break; } else { if (data->cy == 0 && - (screen_hsize(data->backing) == 0 || - data->oy >= - screen_hsize(data->backing) - 1)) + (hsize == 0 || data->oy > hsize - 1)) goto out; window_copy_cursor_up(wme, 0); - py = screen_hsize(data->backing) + data->cy - - data->oy; + py = hsize + data->cy - data->oy; px = window_copy_find_length(wme, py); /* Stop if separator at EOL. */ -- cgit v1.2.3 From 0d28ee927421c46315bc0b47b5f8f49a8392efa4 Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 17 Nov 2020 08:13:35 +0000 Subject: Log missing keys when extended keys is on rather than fatal(). --- input-keys.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/input-keys.c b/input-keys.c index 224bcfa5..5cd43dc3 100644 --- a/input-keys.c +++ b/input-keys.c @@ -330,7 +330,8 @@ static struct input_key_entry input_key_defaults[] = { .data = "\033[2;_~" }, { .key = KEYC_DC|KEYC_BUILD_MODIFIERS, - .data = "\033[3;_~" } + .data = "\033[3;_~" + } }; static const key_code input_key_modifiers[] = { 0, @@ -557,7 +558,7 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key) modifier = '8'; break; default: - fatalx("invalid key modifiers: %llx", key); + goto missing; } xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", outkey, modifier); bufferevent_write(bev, tmp, strlen(tmp)); -- cgit v1.2.3 From bfdc4373d71895a5f454834da4b0bd92ab964dd4 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Tue, 17 Nov 2020 17:56:55 +0000 Subject: Update closefrom from OpenSSH for macOS code which is now needed. --- compat/closefrom.c | 94 ++++++++++++++++++++++++++++++++++++++++-------------- configure.ac | 4 ++- 2 files changed, 73 insertions(+), 25 deletions(-) diff --git a/compat/closefrom.c b/compat/closefrom.c index 7915cde4..28be3680 100644 --- a/compat/closefrom.c +++ b/compat/closefrom.c @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "compat.h" + #ifndef HAVE_CLOSEFROM #include @@ -44,8 +46,9 @@ # include # endif #endif - -#include "compat.h" +#if defined(HAVE_LIBPROC_H) +# include +#endif #ifndef OPEN_MAX # define OPEN_MAX 256 @@ -55,21 +58,73 @@ __unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $"; #endif /* lint */ +#ifndef HAVE_FCNTL_CLOSEM /* * Close all file descriptors greater than or equal to lowfd. */ +static void +closefrom_fallback(int lowfd) +{ + long fd, maxfd; + + /* + * Fall back on sysconf() or getdtablesize(). We avoid checking + * resource limits since it is possible to open a file descriptor + * and then drop the rlimit such that it is below the open fd. + */ +#ifdef HAVE_SYSCONF + maxfd = sysconf(_SC_OPEN_MAX); +#else + maxfd = getdtablesize(); +#endif /* HAVE_SYSCONF */ + if (maxfd < 0) + maxfd = OPEN_MAX; + + for (fd = lowfd; fd < maxfd; fd++) + (void) close((int) fd); +} +#endif /* HAVE_FCNTL_CLOSEM */ + #ifdef HAVE_FCNTL_CLOSEM void closefrom(int lowfd) { (void) fcntl(lowfd, F_CLOSEM, 0); } -#else +#elif defined(HAVE_LIBPROC_H) && defined(HAVE_PROC_PIDINFO) void closefrom(int lowfd) { - long fd, maxfd; -#if defined(HAVE_DIRFD) && defined(HAVE_PROC_PID) + int i, r, sz; + pid_t pid = getpid(); + struct proc_fdinfo *fdinfo_buf = NULL; + + sz = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); + if (sz == 0) + return; /* no fds, really? */ + else if (sz == -1) + goto fallback; + if ((fdinfo_buf = malloc(sz)) == NULL) + goto fallback; + r = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fdinfo_buf, sz); + if (r < 0 || r > sz) + goto fallback; + for (i = 0; i < r / (int)PROC_PIDLISTFD_SIZE; i++) { + if (fdinfo_buf[i].proc_fd >= lowfd) + close(fdinfo_buf[i].proc_fd); + } + free(fdinfo_buf); + return; + fallback: + free(fdinfo_buf); + closefrom_fallback(lowfd); + return; +} +#elif defined(HAVE_DIRFD) && defined(HAVE_PROC_PID) +void +closefrom(int lowfd) +{ + long fd; char fdpath[PATH_MAX], *endp; struct dirent *dent; DIR *dirp; @@ -77,7 +132,7 @@ closefrom(int lowfd) /* Check for a /proc/$$/fd directory. */ len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid()); - if (len > 0 && (size_t)len <= sizeof(fdpath) && (dirp = opendir(fdpath))) { + if (len > 0 && (size_t)len < sizeof(fdpath) && (dirp = opendir(fdpath))) { while ((dent = readdir(dirp)) != NULL) { fd = strtol(dent->d_name, &endp, 10); if (dent->d_name != endp && *endp == '\0' && @@ -85,25 +140,16 @@ closefrom(int lowfd) (void) close((int) fd); } (void) closedir(dirp); - } else -#endif - { - /* - * Fall back on sysconf() or getdtablesize(). We avoid checking - * resource limits since it is possible to open a file descriptor - * and then drop the rlimit such that it is below the open fd. - */ -#ifdef HAVE_SYSCONF - maxfd = sysconf(_SC_OPEN_MAX); -#else - maxfd = getdtablesize(); -#endif /* HAVE_SYSCONF */ - if (maxfd < 0) - maxfd = OPEN_MAX; - - for (fd = lowfd; fd < maxfd; fd++) - (void) close((int) fd); + return; } + /* /proc/$$/fd strategy failed, fall back to brute force closure */ + closefrom_fallback(lowfd); +} +#else +void +closefrom(int lowfd) +{ + closefrom_fallback(lowfd); } #endif /* !HAVE_FCNTL_CLOSEM */ #endif /* HAVE_CLOSEFROM */ diff --git a/configure.ac b/configure.ac index 97010df4..8dd00d79 100644 --- a/configure.ac +++ b/configure.ac @@ -99,6 +99,7 @@ AC_CHECK_HEADERS([ \ dirent.h \ fcntl.h \ inttypes.h \ + libproc.h \ libutil.h \ ndir.h \ paths.h \ @@ -124,7 +125,8 @@ AC_CHECK_FUNCS([ \ dirfd \ flock \ prctl \ - sysconf \ + proc_pidinfo \ + sysconf ]) # Check for functions with a compatibility implementation. -- cgit v1.2.3 From 76cfb5f471ac785b133cdfd6ec53a5097c0bdf3c Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 26 Nov 2020 09:19:10 +0000 Subject: Add -N flag to display-panes to ignore keys, GitHub issue 2473. --- cmd-display-panes.c | 15 +++++++++++---- tmux.1 | 5 +++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/cmd-display-panes.c b/cmd-display-panes.c index 352b2e4d..64efb89a 100644 --- a/cmd-display-panes.c +++ b/cmd-display-panes.c @@ -34,8 +34,8 @@ const struct cmd_entry cmd_display_panes_entry = { .name = "display-panes", .alias = "displayp", - .args = { "bd:t:", 0, 1 }, - .usage = "[-b] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]", + .args = { "bd:Nt:", 0, 1 }, + .usage = "[-bN] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]", .flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG, .exec = cmd_display_panes_exec @@ -284,8 +284,15 @@ cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item) else cdata->item = item; - server_client_set_overlay(tc, delay, NULL, NULL, cmd_display_panes_draw, - cmd_display_panes_key, cmd_display_panes_free, cdata); + if (args_has(args, 'N')) { + server_client_set_overlay(tc, delay, NULL, NULL, + cmd_display_panes_draw, NULL, cmd_display_panes_free, + cdata); + } else { + server_client_set_overlay(tc, delay, NULL, NULL, + cmd_display_panes_draw, cmd_display_panes_key, + cmd_display_panes_free, cdata); + } if (args_has(args, 'b')) return (CMD_RETURN_NORMAL); diff --git a/tmux.1 b/tmux.1 index 37f6f165..4cc4bfe4 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2098,7 +2098,7 @@ starts without the option information. This command works only if at least one client is attached. .It Xo .Ic display-panes -.Op Fl b +.Op Fl bN .Op Fl d Ar duration .Op Fl t Ar target-client .Op Ar template @@ -2111,7 +2111,8 @@ See the and .Ic display-panes-active-colour session options. -The indicator is closed when a key is pressed or +The indicator is closed when a key is pressed (unless +.Fl N is given) or .Ar duration milliseconds have passed. If -- cgit v1.2.3 From fd5c3e6122faea45d3eb44275424d78bc67b0ce2 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 26 Nov 2020 13:06:21 +0000 Subject: Fix check for vertical centre. --- cmd-display-menu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd-display-menu.c b/cmd-display-menu.c index 7115dc81..ae000abe 100644 --- a/cmd-display-menu.c +++ b/cmd-display-menu.c @@ -155,7 +155,7 @@ cmd_display_menu_get_position(struct client *tc, struct cmdq_item *item, else format_add(ft, "popup_centre_x", "%ld", n); n = (tty->sy - 1) / 2 + h / 2; - if (n + h >= tty->sy) + if (n >= tty->sy) format_add(ft, "popup_centre_y", "%u", tty->sy - h); else format_add(ft, "popup_centre_y", "%ld", n); -- cgit v1.2.3 From 33046ecee2090a7ff733097d1c05d377936b3e5f Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 30 Nov 2020 13:37:45 +0000 Subject: Ignore running command when checking for no-hooks flag if it is blocked. GitHub issue 2483. --- cmd-queue.c | 6 +++++- tmux.1 | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/cmd-queue.c b/cmd-queue.c index 36f1c9be..05f439f5 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -768,7 +768,11 @@ cmdq_running(struct client *c) { struct cmdq_list *queue = cmdq_get(c); - return (queue->item); + if (queue->item == NULL) + return (NULL); + if (queue->item->flags & CMDQ_WAITING) + return (NULL); + return (queue->item); } /* Print a guard line. */ diff --git a/tmux.1 b/tmux.1 index 4cc4bfe4..b3a74b0a 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2112,7 +2112,8 @@ and .Ic display-panes-active-colour session options. The indicator is closed when a key is pressed (unless -.Fl N is given) or +.Fl N +is given) or .Ar duration milliseconds have passed. If -- cgit v1.2.3 From 9a74bba007a60b93d1fdf68772e5cfb61b3558ff Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 1 Dec 2020 08:12:58 +0000 Subject: 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 and use it for the window_flags format variable so it doesn't end up escaping any following text. GitHub issue 2485. --- format-draw.c | 8 ++++++-- format.c | 32 +++++++++++++++++++++++++++++--- options-table.c | 4 ++-- tmux.1 | 7 ++++++- 4 files changed, 43 insertions(+), 8 deletions(-) diff --git a/format-draw.c b/format-draw.c index e73c5df4..67b961d9 100644 --- a/format-draw.c +++ b/format-draw.c @@ -563,13 +563,17 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base, if (cp[0] == '#' && cp[1] != '[' && cp[1] != '\0') { for (n = 1; cp[n] == '#'; n++) /* nothing */; + even = ((n % 2) == 0); if (cp[n] != '[') { - width[current] += n; cp += n; + if (even) + n = (n / 2); + else + n = (n / 2) + 1; + width[current] += n; format_draw_many(&ctx[current], &sy, '#', n); continue; } - even = ((n % 2) == 0); if (even) cp += (n + 1); else diff --git a/format.c b/format.c index 91955259..98dc4cb7 100644 --- a/format.c +++ b/format.c @@ -99,6 +99,7 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2) #define FORMAT_PRETTY 0x400 #define FORMAT_LENGTH 0x800 #define FORMAT_WIDTH 0x1000 +#define FORMAT_ESCAPE 0x2000 /* Limit on recursion. */ #define FORMAT_LOOP_LIMIT 10 @@ -1394,6 +1395,23 @@ format_quote(const char *s) return (out); } +/* Escape #s in string. */ +static char * +format_escape(const char *s) +{ + const char *cp; + char *out, *at; + + at = out = xmalloc(strlen(s) * 2 + 1); + for (cp = s; *cp != '\0'; cp++) { + if (*cp == '#') + *at++ = '#'; + *at++ = *cp; + } + *at = '\0'; + return (out); +} + /* Make a prettier time. */ static char * format_pretty_time(time_t t) @@ -1539,6 +1557,11 @@ found: found = xstrdup(format_quote(saved)); free(saved); } + if (modifiers & FORMAT_ESCAPE) { + saved = found; + found = xstrdup(format_escape(saved)); + free(saved); + } return (found); } @@ -1689,7 +1712,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s, cp++; /* Check single character modifiers with no arguments. */ - if (strchr("lbdnqwETSWP<>", cp[0]) != NULL && + if (strchr("lbdnwETSWP<>", cp[0]) != NULL && format_is_end(cp[1])) { format_add_modifier(&list, count, cp, 1, NULL, 0); cp++; @@ -1710,7 +1733,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s, } /* Now try single character with arguments. */ - if (strchr("mCst=pe", cp[0]) == NULL) + if (strchr("mCst=peq", cp[0]) == NULL) break; c = cp[0]; @@ -2216,7 +2239,10 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen, time_format = format_strip(fm->argv[1]); break; case 'q': - modifiers |= FORMAT_QUOTE; + if (fm->argc < 1) + modifiers |= FORMAT_QUOTE; + else if (strchr(fm->argv[0], 'e') != NULL) + modifiers |= FORMAT_ESCAPE; break; case 'E': modifiers |= FORMAT_EXPAND; diff --git a/options-table.c b/options-table.c index 2ae49d7a..56e1c895 100644 --- a/options-table.c +++ b/options-table.c @@ -1014,7 +1014,7 @@ const struct options_table_entry options_table[] = { { .name = "window-status-current-format", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_WINDOW, - .default_str = "#I:#W#{?window_flags,#{window_flags}, }", + .default_str = "#I:#W#{?window_flags,#{q/e:window_flags}, }", .text = "Format of the current window in the status line." }, @@ -1030,7 +1030,7 @@ const struct options_table_entry options_table[] = { { .name = "window-status-format", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_WINDOW, - .default_str = "#I:#W#{?window_flags,#{window_flags}, }", + .default_str = "#I:#W#{?window_flags,#{q/e:window_flags}, }", .text = "Format of windows in the status line, except the current " "window." }, diff --git a/tmux.1 b/tmux.1 index b3a74b0a..9d1021f3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4638,7 +4638,12 @@ of the variable respectively. .Ql q:\& will escape .Xr sh 1 -special characters. +special characters or with an +.Ql e +suffix, escape hash characters (so +.Ql # +becomes +.Ql ## ). .Ql E:\& will expand the format twice, for example .Ql #{E:status-left} -- cgit v1.2.3 From f0c1233d4f97b499dd51688b089ad7c485c14b2a Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 1 Dec 2020 10:48:03 +0000 Subject: Leave newlines inside multiline quotes. --- cmd-parse.y | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmd-parse.y b/cmd-parse.y index c8995d8b..7b42c621 100644 --- a/cmd-parse.y +++ b/cmd-parse.y @@ -1505,8 +1505,12 @@ yylex_token(int ch) state == NONE) break; - /* Spaces and comments inside quotes after \n are removed. */ + /* + * Spaces and comments inside quotes after \n are removed but + * the \n is left. + */ if (ch == '\n' && state != NONE) { + yylex_append1(&buf, &len, '\n'); while ((ch = yylex_getc()) == ' ' || ch == '\t') /* nothing */; if (ch != '#') -- cgit v1.2.3 From fd451aa7962f399250fd166f207451fcf4b9cb94 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 3 Dec 2020 07:12:11 +0000 Subject: Redraw any visible modes when status line changes so that formats like the pane title are updated. GitHub issue 2487. Also a man page fix from jmc. --- server-client.c | 24 ++++++++++++++++++++++++ tmux.1 | 2 +- tmux.h | 1 + tty.c | 4 ++-- window-buffer.c | 12 ++++++++++++ window-client.c | 12 ++++++++++++ window-tree.c | 12 ++++++++++++ 7 files changed, 64 insertions(+), 3 deletions(-) diff --git a/server-client.c b/server-client.c index 3e256a92..f85304a6 100644 --- a/server-client.c +++ b/server-client.c @@ -42,6 +42,7 @@ static void server_client_repeat_timer(int, short, void *); static void server_client_click_timer(int, short, void *); static void server_client_check_exit(struct client *); static void server_client_check_redraw(struct client *); +static void server_client_check_modes(struct client *); static void server_client_set_title(struct client *); static void server_client_reset_state(struct client *); static int server_client_assume_paste(struct session *); @@ -1355,6 +1356,7 @@ server_client_loop(void) TAILQ_FOREACH(c, &clients, entry) { server_client_check_exit(c); if (c->session != NULL) { + server_client_check_modes(c); server_client_check_redraw(c); server_client_reset_state(c); } @@ -1810,6 +1812,28 @@ server_client_redraw_timer(__unused int fd, __unused short events, log_debug("redraw timer fired"); } +/* + * Check if modes need to be updated. Only modes in the current window are + * updated and it is done when the status line is redrawn. + */ +static void +server_client_check_modes(struct client *c) +{ + struct window *w = c->session->curw->window; + struct window_pane *wp; + struct window_mode_entry *wme; + + if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED)) + return; + if (~c->flags & CLIENT_REDRAWSTATUS) + return; + TAILQ_FOREACH(wp, &w->panes, entry) { + wme = TAILQ_FIRST(&wp->modes); + if (wme != NULL && wme->mode->update != NULL) + wme->mode->update(wme); + } +} + /* Check for client redraws. */ static void server_client_check_redraw(struct client *c) diff --git a/tmux.1 b/tmux.1 index 9d1021f3..f9a9cdf3 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4643,7 +4643,7 @@ special characters or with an suffix, escape hash characters (so .Ql # becomes -.Ql ## ). +.Ql ## ) . .Ql E:\& will expand the format twice, for example .Ql #{E:status-left} diff --git a/tmux.h b/tmux.h index 1845775d..986eed00 100644 --- a/tmux.h +++ b/tmux.h @@ -887,6 +887,7 @@ struct window_mode { struct cmd_find_state *, struct args *); void (*free)(struct window_mode_entry *); void (*resize)(struct window_mode_entry *, u_int, u_int); + void (*update)(struct window_mode_entry *); void (*key)(struct window_mode_entry *, struct client *, struct session *, struct winlink *, key_code, struct mouse_event *); diff --git a/tty.c b/tty.c index 777b639b..fac7a99e 100644 --- a/tty.c +++ b/tty.c @@ -2447,7 +2447,7 @@ tty_check_fg(struct tty *tty, int *palette, struct grid_cell *gc) /* Is this a 256-colour colour? */ if (gc->fg & COLOUR_FLAG_256) { /* And not a 256 colour mode? */ - if (colours != 256) { + if (colours < 256) { gc->fg = colour_256to16(gc->fg); if (gc->fg & 8) { gc->fg &= 7; @@ -2500,7 +2500,7 @@ tty_check_bg(struct tty *tty, int *palette, struct grid_cell *gc) * palette. Bold background doesn't exist portably, so just * discard the bold bit if set. */ - if (colours != 256) { + if (colours < 256) { gc->bg = colour_256to16(gc->bg); if (gc->bg & 8) { gc->bg &= 7; diff --git a/window-buffer.c b/window-buffer.c index ae6f13ce..4599cbc5 100644 --- a/window-buffer.c +++ b/window-buffer.c @@ -31,6 +31,7 @@ static struct screen *window_buffer_init(struct window_mode_entry *, static void window_buffer_free(struct window_mode_entry *); static void window_buffer_resize(struct window_mode_entry *, u_int, u_int); +static void window_buffer_update(struct window_mode_entry *); static void window_buffer_key(struct window_mode_entry *, struct client *, struct session *, struct winlink *, key_code, struct mouse_event *); @@ -63,6 +64,7 @@ const struct window_mode window_buffer_mode = { .init = window_buffer_init, .free = window_buffer_free, .resize = window_buffer_resize, + .update = window_buffer_update, .key = window_buffer_key, }; @@ -335,6 +337,16 @@ window_buffer_resize(struct window_mode_entry *wme, u_int sx, u_int sy) mode_tree_resize(data->data, sx, sy); } +static void +window_buffer_update(struct window_mode_entry *wme) +{ + struct window_buffer_modedata *data = wme->data; + + mode_tree_build(data->data); + mode_tree_draw(data->data); + data->wp->flags |= PANE_REDRAW; +} + static void window_buffer_do_delete(void *modedata, void *itemdata, __unused struct client *c, __unused key_code key) diff --git a/window-client.c b/window-client.c index 5e02462b..ec3c646a 100644 --- a/window-client.c +++ b/window-client.c @@ -30,6 +30,7 @@ static struct screen *window_client_init(struct window_mode_entry *, static void window_client_free(struct window_mode_entry *); static void window_client_resize(struct window_mode_entry *, u_int, u_int); +static void window_client_update(struct window_mode_entry *); static void window_client_key(struct window_mode_entry *, struct client *, struct session *, struct winlink *, key_code, struct mouse_event *); @@ -59,6 +60,7 @@ const struct window_mode window_client_mode = { .init = window_client_init, .free = window_client_free, .resize = window_client_resize, + .update = window_client_update, .key = window_client_key, }; @@ -311,6 +313,16 @@ window_client_resize(struct window_mode_entry *wme, u_int sx, u_int sy) mode_tree_resize(data->data, sx, sy); } +static void +window_client_update(struct window_mode_entry *wme) +{ + struct window_client_modedata *data = wme->data; + + mode_tree_build(data->data); + mode_tree_draw(data->data); + data->wp->flags |= PANE_REDRAW; +} + static void window_client_do_detach(void *modedata, void *itemdata, __unused struct client *c, key_code key) diff --git a/window-tree.c b/window-tree.c index a687af16..1498b337 100644 --- a/window-tree.c +++ b/window-tree.c @@ -29,6 +29,7 @@ static struct screen *window_tree_init(struct window_mode_entry *, static void window_tree_free(struct window_mode_entry *); static void window_tree_resize(struct window_mode_entry *, u_int, u_int); +static void window_tree_update(struct window_mode_entry *); static void window_tree_key(struct window_mode_entry *, struct client *, struct session *, struct winlink *, key_code, struct mouse_event *); @@ -79,6 +80,7 @@ const struct window_mode window_tree_mode = { .init = window_tree_init, .free = window_tree_free, .resize = window_tree_resize, + .update = window_tree_update, .key = window_tree_key, }; @@ -937,6 +939,16 @@ window_tree_resize(struct window_mode_entry *wme, u_int sx, u_int sy) mode_tree_resize(data->data, sx, sy); } +static void +window_tree_update(struct window_mode_entry *wme) +{ + struct window_tree_modedata *data = wme->data; + + mode_tree_build(data->data); + mode_tree_draw(data->data); + data->wp->flags |= PANE_REDRAW; +} + static char * window_tree_get_target(struct window_tree_itemdata *item, struct cmd_find_state *fs) -- cgit v1.2.3 From ed786309ccc7ceb2077f658e689a5f35549bb2bc Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 7 Dec 2020 09:23:57 +0000 Subject: Do not clear the wrapped flag on linefeeds if it is already set - this does not appear to be what applications want. GitHub issue 2478 and 2414. --- screen-write.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/screen-write.c b/screen-write.c index ab6a020c..92f1aa39 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1240,8 +1240,6 @@ screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped, u_int bg) gl = grid_get_line(gd, gd->hsize + s->cy); if (wrapped) gl->flags |= GRID_LINE_WRAPPED; - else - gl->flags &= ~GRID_LINE_WRAPPED; log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy, s->rupper, s->rlower); -- cgit v1.2.3 From f6095cad993293ec0f1988c1f6ae22921f9d2b2e Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 7 Dec 2020 09:46:58 +0000 Subject: Do not include the status line size when working out the character for the pane status line. GitHub issue 2493. --- screen-redraw.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/screen-redraw.c b/screen-redraw.c index 50df2671..47c1a838 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -407,7 +407,7 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp, struct format_tree *ft; char *expanded; int pane_status = rctx->pane_status; - u_int width, i, cell_type, top, px, py; + u_int width, i, cell_type, px, py; struct screen_write_ctx ctx; struct screen old; @@ -432,16 +432,12 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp, screen_write_start(&ctx, &wp->status_screen); - if (rctx->statustop) - top = rctx->statuslines; - else - top = 0; for (i = 0; i < width; i++) { px = wp->xoff + 2 + i; if (rctx->pane_status == PANE_STATUS_TOP) - py = top + wp->yoff - 1; + py = wp->yoff - 1; else - py = top + wp->yoff + wp->sy; + py = wp->yoff + wp->sy; cell_type = screen_redraw_type_of_cell(c, px, py, pane_status); screen_redraw_border_set(wp, pane_lines, cell_type, &gc); screen_write_cell(&ctx, &gc); -- cgit v1.2.3 From 681c0d2bfbf22a51f90c977d0b3e91d30c23c11e Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Mon, 7 Dec 2020 12:12:40 +0000 Subject: Include compat.h after system headers, GitHub issue 2492. --- compat/closefrom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/closefrom.c b/compat/closefrom.c index 28be3680..be008239 100644 --- a/compat/closefrom.c +++ b/compat/closefrom.c @@ -14,8 +14,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "compat.h" - #ifn