1
0
mirror of https://github.com/tmux/tmux.git synced 2025-04-08 01:55:21 +00:00

Merge branch 'tmux:master' into issue-4412-choose-tree-format-prints-wrong-values

This commit is contained in:
Michael Grant 2025-03-21 09:30:17 -04:00 committed by GitHub
commit 86b6480081
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 680 additions and 266 deletions

View File

@ -1,3 +1,12 @@
---
name: Use this issue template
about: Please read https://github.com/tmux/tmux/blob/master/.github/CONTRIBUTING.md
title: ''
labels: ''
assignees: ''
---
### Issue description
Please read https://github.com/tmux/tmux/blob/master/.github/CONTRIBUTING.md

35
.gitignore vendored
View File

@ -1,23 +1,24 @@
*.o
*~
*.diff
*.patch
*.core
core
tags
*.dSYM
*.diff
*.o
*.patch
*.swp
*~
.deps/
compat/.dirstamp
aclocal.m4
autom4te.cache/
config.log
config.status
etc/
tmux
.dirstamp
Makefile
Makefile.in
configure
tmux.1.*
*.dSYM
aclocal.m4
autom4te.cache/
cmd-parse.c
compat/.dirstamp
config.log
config.status
configure
core
etc/
fuzz/*-fuzzer
.dirstamp
tags
tmux
tmux.1.*

32
SYNCING
View File

@ -1,17 +1,17 @@
Preamble
========
Tmux portable relies on repositories "tmux" and "tmux-openbsd".
Tmux portable relies on repositories "tmux" and "tmux-obsd".
Here's a description of them:
* "tmux" is the portable version, the one which contains code for other
operating systems, and autotools, etc., which isn't found or needed in the
OpenBSD base system.
* "tmux-openbsd" is the version of tmux in OpenBSD base system which provides
* "tmux-obsd" is the version of tmux in OpenBSD base system which provides
the basis of the portable tmux version.
Note: The "tmux-openbsd" repository is actually handled by "git cvsimport"
Note: The "tmux-obsd" repository is actually handled by "git cvsimport"
running at 15 minute intervals, so a commit made to OpenBSD's tmux CVS
repository will take at least that long to appear in this git repository.
(It might take longer, depending on the CVS mirror used to import the
@ -34,11 +34,11 @@ this information has ever been set before.
Cloning repositories
====================
This involves having both tmux and tmux-openbsd cloned, as in:
This involves having both tmux and tmux-obsd cloned, as in:
% cd /some/where/useful
% git clone https://github.com/tmux/tmux.git
% git clone https://github.com/ThomasAdam/tmux-openbsd.git
% git clone https://github.com/ThomasAdam/tmux-obsd.git
Note that you do not need additional checkouts to manage the sync -- an
existing clone of either repositories will suffice. So if you already have
@ -47,30 +47,30 @@ these checkouts existing, skip that.
Adding in git-remotes
=====================
Because the portable "tmux" git repository and the "tmux-openbsd"
Because the portable "tmux" git repository and the "tmux-obsd"
repository do not inherently share any history between each other, the
history has been faked between them. This "faking of history" is something
which has to be told to git for the purposes of comparing the "tmux" and
"tmux-openbsd" repositories for syncing. To do this, we must reference the
clone of the "tmux-openbsd" repository from the "tmux" repository, as
"tmux-obsd" repositories for syncing. To do this, we must reference the
clone of the "tmux-obsd" repository from the "tmux" repository, as
shown by the following command:
% cd /path/to/tmux
% git remote add obsd-tmux file:///path/to/tmux-openbsd
% git remote add obsd-tmux file:///path/to/tmux-obsd
So that now, the remote "obsd-tmux" can be used to reference branches and
commits from the "tmux-openbsd" repository, but from the context of the
commits from the "tmux-obsd" repository, but from the context of the
portable "tmux" repository, which makes sense because it's the "tmux"
repository which will have the updates applied to them.
Fetching updates
================
To ensure the latest commits from "tmux-openbsd" can be found from within
"tmux", we have to ensure the "master" branch from "tmux-openbsd" is
To ensure the latest commits from "tmux-obsd" can be found from within
"tmux", we have to ensure the "master" branch from "tmux-obsd" is
up-to-date first, and then reference that update in "tmux", as in:
% cd /path/to/tmux-openbsd
% cd /path/to/tmux-obsd
% git checkout master
% git pull
@ -82,9 +82,9 @@ Then back in "tmux":
Creating the necessary branches
===============================
Now that "tmux" can see commits and branches from "tmux-openbsd" by way
Now that "tmux" can see commits and branches from "tmux-obsd" by way
of the remote name "obsd-tmux", we can now create the master branch from
"tmux-openbsd" in the "tmux" repository:
"tmux-obsd" in the "tmux" repository:
% git checkout -b obsd-master obsd-tmux/master
@ -92,7 +92,7 @@ Adding in the fake history points
=================================
To tie both the "master" branch from "tmux" and the "obsd-master"
branch from "tmux-openbsd" together, the fake history points added to the
branch from "tmux-obsd" together, the fake history points added to the
"tmux" repository need to be added. To do this, we must add an
additional refspec line, as in:

View File

@ -315,11 +315,11 @@ alerts_set_message(struct winlink *wl, const char *type, const char *option)
if (visual == VISUAL_OFF)
continue;
if (c->session->curw == wl) {
status_message_set(c, -1, 1, 0, "%s in current window",
type);
status_message_set(c, -1, 1, 0, 0,
"%s in current window", type);
} else {
status_message_set(c, -1, 1, 0, "%s in window %d", type,
wl->idx);
status_message_set(c, -1, 1, 0, 0,
"%s in window %d", type, wl->idx);
}
}
}

View File

@ -266,8 +266,13 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
if (cmd_list_any_have(pr->cmdlist, CMD_STARTSERVER))
flags |= CLIENT_STARTSERVER;
cmd_list_free(pr->cmdlist);
} else
} else {
fprintf(stderr, "%s\n", pr->error);
args_free_values(values, argc);
free(values);
free(pr->error);
return 1;
}
args_free_values(values, argc);
free(values);
}

View File

@ -99,7 +99,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
w = wp->window = window_create(w->sx, w->sy, w->xpixel, w->ypixel);
options_set_parent(wp->options, w->options);
wp->flags |= PANE_STYLECHANGED;
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp;
w->latest = tc;

View File

@ -39,8 +39,8 @@ const struct cmd_entry cmd_capture_pane_entry = {
.name = "capture-pane",
.alias = "capturep",
.args = { "ab:CeE:JNpPqS:Tt:", 0, 0, NULL },
.usage = "[-aCeJNpPqT] " CMD_BUFFER_USAGE " [-E end-line] "
.args = { "ab:CeE:JMNpPqS:Tt:", 0, 0, NULL },
.usage = "[-aCeJMNpPqT] " CMD_BUFFER_USAGE " [-E end-line] "
"[-S start-line] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
@ -107,14 +107,16 @@ static char *
cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
struct window_pane *wp, size_t *len)
{
struct grid *gd;
const struct grid_line *gl;
struct grid_cell *gc = NULL;
int n, join_lines, flags = 0;
u_int i, sx, top, bottom, tmp;
char *cause, *buf, *line;
const char *Sflag, *Eflag;
size_t linelen;
struct grid *gd;
const struct grid_line *gl;
struct screen *s;
struct grid_cell *gc = NULL;
struct window_mode_entry *wme;
int n, join_lines, flags = 0;
u_int i, sx, top, bottom, tmp;
char *cause, *buf, *line;
const char *Sflag, *Eflag;
size_t linelen;
sx = screen_size_x(&wp->base);
if (args_has(args, 'a')) {
@ -126,8 +128,20 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
}
return (xstrdup(""));
}
} else
s = &wp->base;
} else if (args_has(args, 'M')) {
wme = TAILQ_FIRST(&wp->modes);
if (wme != NULL && wme->mode->get_screen != NULL) {
s = wme->mode->get_screen (wme);
gd = s->grid;
} else {
s = &wp->base;
gd = wp->base.grid;
}
} else {
s = &wp->base;
gd = wp->base.grid;
}
Sflag = args_get(args, 'S');
if (Sflag != NULL && strcmp(Sflag, "-") == 0)
@ -181,7 +195,7 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
buf = NULL;
for (i = top; i <= bottom; i++) {
line = grid_string_cells(gd, 0, i, sx, &gc, flags, wp->screen);
line = grid_string_cells(gd, 0, i, sx, &gc, flags, s);
linelen = strlen(line);
buf = cmd_capture_pane_append(buf, len, line, linelen);

View File

@ -41,7 +41,7 @@ const struct cmd_entry cmd_display_menu_entry = {
.args = { "b:c:C:H:s:S:MOt:T:x:y:", 1, -1, cmd_display_menu_args_parse },
.usage = "[-MO] [-b border-lines] [-c target-client] "
"[-C starting-choice] [-H selected-style] [-s style] "
"[-S border-style] " CMD_TARGET_PANE_USAGE "[-T title] "
"[-S border-style] " CMD_TARGET_PANE_USAGE " [-T title] "
"[-x position] [-y position] name key command ...",
.target = { 't', CMD_FIND_PANE, 0 },
@ -58,7 +58,7 @@ const struct cmd_entry cmd_display_popup_entry = {
.usage = "[-BCE] [-b border-lines] [-c target-client] "
"[-d start-directory] [-e environment] [-h height] "
"[-s style] [-S border-style] " CMD_TARGET_PANE_USAGE
"[-T title] [-w width] [-x position] [-y position] "
" [-T title] [-w width] [-x position] [-y position] "
"[shell-command]",
.target = { 't', CMD_FIND_PANE, 0 },

View File

@ -39,8 +39,8 @@ const struct cmd_entry cmd_display_message_entry = {
.name = "display-message",
.alias = "display",
.args = { "ac:d:lINpt:F:v", 0, 1, NULL },
.usage = "[-aIlNpv] [-c target-client] [-d delay] [-F format] "
.args = { "aCc:d:lINpt:F:v", 0, 1, NULL },
.usage = "[-aCIlNpv] [-c target-client] [-d delay] [-F format] "
CMD_TARGET_PANE_USAGE " [message]",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
@ -69,6 +69,7 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
const char *template;
char *msg, *cause;
int delay = -1, flags, Nflag = args_has(args, 'N');
int Cflag = args_has(args, 'C');
struct format_tree *ft;
u_int count = args_count(args);
struct evbuffer *evb;
@ -150,7 +151,7 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
server_client_print(tc, 0, evb);
evbuffer_free(evb);
} else if (tc != NULL)
status_message_set(tc, delay, 0, Nflag, "%s", msg);
status_message_set(tc, delay, 0, Nflag, Cflag, "%s", msg);
free(msg);
format_free(ft);

View File

@ -157,7 +157,7 @@ cmd_if_shell_callback(struct job *job)
if (cmdlist == NULL) {
if (cdata->item == NULL) {
*error = toupper((u_char)*error);
status_message_set(c, -1, 1, 0, "%s", error);
status_message_set(c, -1, 1, 0, 0, "%s", error);
} else
cmdq_error(cdata->item, "%s", error);
free(error);

View File

@ -149,7 +149,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
src_wp->window = dst_w;
options_set_parent(src_wp->options, dst_w->options);
src_wp->flags |= PANE_STYLECHANGED;
src_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
if (flags & SPAWN_BEFORE)
TAILQ_INSERT_BEFORE(dst_wp, src_wp, entry);
else

View File

@ -91,7 +91,7 @@ cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
struct key_binding *bd;
const char *key;
char *tmp, *note;
int found = 0;
int found = 0;
table = key_bindings_get_table(tablename, 0);
if (table == NULL)
@ -114,8 +114,8 @@ cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
note = xstrdup(bd->note);
tmp = utf8_padcstr(key, keywidth + 1);
if (args_has(args, '1') && tc != NULL) {
status_message_set(tc, -1, 1, 0, "%s%s%s", prefix, tmp,
note);
status_message_set(tc, -1, 1, 0, 0, "%s%s%s", prefix,
tmp, note);
} else
cmdq_print(item, "%s%s%s", prefix, tmp, note);
free(tmp);
@ -298,8 +298,8 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
free(cp);
if (args_has(args, '1') && tc != NULL) {
status_message_set(tc, -1, 1, 0, "bind-key %s",
tmp);
status_message_set(tc, -1, 1, 0, 0,
"bind-key %s", tmp);
} else
cmdq_print(item, "bind-key %s", tmp);
free(key);
@ -321,6 +321,31 @@ out:
return (CMD_RETURN_NORMAL);
}
static void
cmd_list_single_command(const struct cmd_entry *entry, struct format_tree *ft,
const char *template, struct cmdq_item *item)
{
const char *s;
char *line;
format_add(ft, "command_list_name", "%s", entry->name);
if (entry->alias != NULL)
s = entry->alias;
else
s = "";
format_add(ft, "command_list_alias", "%s", s);
if (entry->usage != NULL)
s = entry->usage;
else
s = "";
format_add(ft, "command_list_usage", "%s", s);
line = format_expand(ft, template);
if (*line != '\0')
cmdq_print(item, "%s", line);
free(line);
}
static enum cmd_retval
cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
{
@ -328,8 +353,8 @@ cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
const struct cmd_entry **entryp;
const struct cmd_entry *entry;
struct format_tree *ft;
const char *template, *s, *command;
char *line;
const char *template, *command;
char *cause;
if ((template = args_get(args, 'F')) == NULL) {
template = "#{command_list_name}"
@ -341,30 +366,19 @@ cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
format_defaults(ft, NULL, NULL, NULL, NULL);
command = args_string(args, 0);
for (entryp = cmd_table; *entryp != NULL; entryp++) {
entry = *entryp;
if (command != NULL &&
(strcmp(entry->name, command) != 0 &&
(entry->alias == NULL ||
strcmp(entry->alias, command) != 0)))
continue;
format_add(ft, "command_list_name", "%s", entry->name);
if (entry->alias != NULL)
s = entry->alias;
else
s = "";
format_add(ft, "command_list_alias", "%s", s);
if (entry->usage != NULL)
s = entry->usage;
else
s = "";
format_add(ft, "command_list_usage", "%s", s);
line = format_expand(ft, template);
if (*line != '\0')
cmdq_print(item, "%s", line);
free(line);
if (command == NULL) {
for (entryp = cmd_table; *entryp != NULL; entryp++)
cmd_list_single_command(*entryp, ft, template, item);
} else {
entry = cmd_find(command, &cause);
if (entry != NULL)
cmd_list_single_command(entry, ft, template, item);
else {
cmdq_error(item, "%s", cause);
free(cause);
format_free(ft);
return (CMD_RETURN_ERROR);
}
}
format_free(ft);

View File

@ -892,7 +892,7 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...)
c->retval = 1;
} else {
*msg = toupper((u_char) *msg);
status_message_set(c, -1, 1, 0, "%s", msg);
status_message_set(c, -1, 1, 0, 0, "%s", msg);
}
free(msg);

View File

@ -204,7 +204,7 @@ cmd_run_shell_timer(__unused int fd, __unused short events, void* arg)
if (cmdlist == NULL) {
if (cdata->item == NULL) {
*error = toupper((u_char)*error);
status_message_set(c, -1, 1, 0, "%s", error);
status_message_set(c, -1, 1, 0, 0, "%s", error);
} else
cmdq_error(cdata->item, "%s", error);
free(error);

View File

@ -149,12 +149,14 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
markedwp = marked_pane.wp;
if (lastwp != NULL) {
lastwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
lastwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
PANE_THEMECHANGED);
server_redraw_window_borders(lastwp->window);
server_status_window(lastwp->window);
}
if (markedwp != NULL) {
markedwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
markedwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
PANE_THEMECHANGED);
server_redraw_window_borders(markedwp->window);
server_status_window(markedwp->window);
}
@ -169,7 +171,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
}
options_set_string(oo, "window-active-style", 0, "%s", style);
wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|PANE_THEMECHANGED);
}
if (args_has(args, 'g')) {
cmdq_print(item, "%s", options_get_string(oo, "window-style"));

View File

@ -217,7 +217,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'R')) {
colour_palette_clear(&wp->palette);
input_reset(wp->ictx, 1);
wp->flags |= (PANE_STYLECHANGED|PANE_REDRAW);
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED|PANE_REDRAW);
}
if (count == 0) {

View File

@ -42,7 +42,7 @@ const struct cmd_entry cmd_split_window_entry = {
.args = { "bc:de:fF:hIl:p:Pt:vZ", 0, -1, NULL },
.usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] "
"[-F format] [-l size] " CMD_TARGET_PANE_USAGE
"[shell-command]",
" [shell-command]",
.target = { 't', CMD_FIND_PANE, 0 },

View File

@ -101,10 +101,10 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
src_wp->window = dst_w;
options_set_parent(src_wp->options, dst_w->options);
src_wp->flags |= PANE_STYLECHANGED;
src_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
dst_wp->window = src_w;
options_set_parent(dst_wp->options, src_w->options);
dst_wp->flags |= PANE_STYLECHANGED;
dst_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
sx = src_wp->sx; sy = src_wp->sy;
xoff = src_wp->xoff; yoff = src_wp->yoff;

2
cmd.c
View File

@ -444,7 +444,7 @@ cmd_get_alias(const char *name)
}
/* Look up a command entry by name. */
static const struct cmd_entry *
const struct cmd_entry *
cmd_find(const char *name, char **cause)
{
const struct cmd_entry **loop, *entry, *found = NULL;

View File

@ -182,6 +182,46 @@ colour_tostring(int c)
return ("invalid");
}
/* Convert background colour to theme. */
enum client_theme
colour_totheme(int c)
{
int r, g, b, brightness;
if (c == -1)
return (THEME_UNKNOWN);
if (c & COLOUR_FLAG_RGB) {
r = (c >> 16) & 0xff;
g = (c >> 8) & 0xff;
b = (c >> 0) & 0xff;
brightness = r + g + b;
if (brightness > 382)
return (THEME_LIGHT);
return (THEME_DARK);
}
if (c & COLOUR_FLAG_256)
return (colour_totheme(colour_256toRGB(c)));
switch (c) {
case 0:
case 90:
return (THEME_DARK);
case 7:
case 97:
return (THEME_LIGHT);
default:
if (c >= 0 && c <= 7)
return (colour_totheme(colour_256toRGB(c)));
if (c >= 90 && c <= 97)
return (colour_totheme(colour_256toRGB(8 + c - 90)));
break;
}
return (THEME_UNKNOWN);
}
/* Convert colour from string. */
int
colour_fromstring(const char *s)

View File

@ -638,9 +638,9 @@ else
AC_LIBOBJ(err)
fi
# Look for imsg_init in libutil.
AC_SEARCH_LIBS(imsg_init, util, found_imsg_init=yes, found_imsg_init=no)
if test "x$found_imsg_init" = xyes; then
# Look for imsg_add in libutil.
AC_SEARCH_LIBS(imsg_add, util, found_imsg_add=yes, found_imsg_add=no)
if test "x$found_imsg_add" = xyes; then
AC_DEFINE(HAVE_IMSG)
else
AC_LIBOBJ(imsg)

View File

@ -1544,6 +1544,23 @@ format_cb_client_written(struct format_tree *ft)
return (NULL);
}
/* Callback for client_theme. */
static void *
format_cb_client_theme(struct format_tree *ft)
{
if (ft->c != NULL) {
switch (ft->c->theme) {
case THEME_DARK:
return (xstrdup("dark"));
case THEME_LIGHT:
return (xstrdup("light"));
case THEME_UNKNOWN:
return (NULL);
}
}
return (NULL);
}
/* Callback for config_files. */
static void *
format_cb_config_files(__unused struct format_tree *ft)
@ -2881,6 +2898,9 @@ static const struct format_table_entry format_table[] = {
{ "client_termtype", FORMAT_TABLE_STRING,
format_cb_client_termtype
},
{ "client_theme", FORMAT_TABLE_STRING,
format_cb_client_theme
},
{ "client_tty", FORMAT_TABLE_STRING,
format_cb_client_tty
},

View File

@ -53,9 +53,15 @@ static struct input_key_entry input_key_defaults[] = {
{ .key = KEYC_PASTE_START,
.data = "\033[200~"
},
{ .key = KEYC_PASTE_START|KEYC_IMPLIED_META,
.data = "\033[200~"
},
{ .key = KEYC_PASTE_END,
.data = "\033[201~"
},
{ .key = KEYC_PASTE_END|KEYC_IMPLIED_META,
.data = "\033[201~"
},
/* Function keys. */
{ .key = KEYC_F1,
@ -307,6 +313,12 @@ static struct input_key_entry input_key_defaults[] = {
{ .key = KEYC_DC|KEYC_BUILD_MODIFIERS,
.data = "\033[3;_~"
},
{ .key = KEYC_REPORT_DARK_THEME,
.data = "\033[?997;1n"
},
{ .key = KEYC_REPORT_LIGHT_THEME,
.data = "\033[?997;2n"
},
};
static const key_code input_key_modifiers[] = {
0,

139
input.c
View File

@ -133,7 +133,7 @@ static void printflike(2, 3) input_reply(struct input_ctx *, const char *, ...);
static void input_set_state(struct input_ctx *,
const struct input_transition *);
static void input_reset_cell(struct input_ctx *);
static void input_report_current_theme(struct input_ctx *);
static void input_osc_4(struct input_ctx *, const char *);
static void input_osc_8(struct input_ctx *, const char *);
static void input_osc_10(struct input_ctx *, const char *);
@ -243,6 +243,7 @@ enum input_csi_type {
INPUT_CSI_DECSTBM,
INPUT_CSI_DL,
INPUT_CSI_DSR,
INPUT_CSI_DSR_PRIVATE,
INPUT_CSI_ECH,
INPUT_CSI_ED,
INPUT_CSI_EL,
@ -251,6 +252,7 @@ enum input_csi_type {
INPUT_CSI_IL,
INPUT_CSI_MODOFF,
INPUT_CSI_MODSET,
INPUT_CSI_QUERY_PRIVATE,
INPUT_CSI_RCP,
INPUT_CSI_REP,
INPUT_CSI_RM,
@ -259,8 +261,8 @@ enum input_csi_type {
INPUT_CSI_SD,
INPUT_CSI_SGR,
INPUT_CSI_SM,
INPUT_CSI_SM_PRIVATE,
INPUT_CSI_SM_GRAPHICS,
INPUT_CSI_SM_PRIVATE,
INPUT_CSI_SU,
INPUT_CSI_TBC,
INPUT_CSI_VPA,
@ -304,6 +306,8 @@ static const struct input_table_entry input_csi_table[] = {
{ 'm', ">", INPUT_CSI_MODSET },
{ 'n', "", INPUT_CSI_DSR },
{ 'n', ">", INPUT_CSI_MODOFF },
{ 'n', "?", INPUT_CSI_DSR_PRIVATE },
{ 'p', "?$", INPUT_CSI_QUERY_PRIVATE },
{ 'q', " ", INPUT_CSI_DECSCUSR },
{ 'q', ">", INPUT_CSI_XDA },
{ 'r', "", INPUT_CSI_DECSTBM },
@ -1531,6 +1535,20 @@ input_csi_dispatch(struct input_ctx *ictx)
if (n != -1)
screen_write_deleteline(sctx, n, bg);
break;
case INPUT_CSI_DSR_PRIVATE:
switch (input_get(ictx, 0, 0, 0)) {
case 996:
input_report_current_theme(ictx);
break;
}
break;
case INPUT_CSI_QUERY_PRIVATE:
switch (input_get(ictx, 0, 0, 0)) {
case 2031:
input_reply(ictx, "\033[?2031;2$y");
break;
}
break;
case INPUT_CSI_DSR:
switch (input_get(ictx, 0, 0, 0)) {
case -1:
@ -1781,6 +1799,9 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx)
case 2004:
screen_write_mode_clear(sctx, MODE_BRACKETPASTE);
break;
case 2031:
screen_write_mode_clear(sctx, MODE_THEME_UPDATES);
break;
default:
log_debug("%s: unknown '%c'", __func__, ictx->ch);
break;
@ -1876,6 +1897,9 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
case 2004:
screen_write_mode_set(sctx, MODE_BRACKETPASTE);
break;
case 2031:
screen_write_mode_set(sctx, MODE_THEME_UPDATES);
break;
default:
log_debug("%s: unknown '%c'", __func__, ictx->ch);
break;
@ -2697,84 +2721,6 @@ bad:
free(id);
}
/*
* Get a client with a foreground for the pane. There isn't much to choose
* between them so just use the first.
*/
static int
input_get_fg_client(struct window_pane *wp)
{
struct window *w = wp->window;
struct client *loop;
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->flags & CLIENT_UNATTACHEDFLAGS)
continue;
if (loop->session == NULL || !session_has(loop->session, w))
continue;
if (loop->tty.fg == -1)
continue;
return (loop->tty.fg);
}
return (-1);
}
/* Get a client with a background for the pane. */
static int
input_get_bg_client(struct window_pane *wp)
{
struct window *w = wp->window;
struct client *loop;
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->flags & CLIENT_UNATTACHEDFLAGS)
continue;
if (loop->session == NULL || !session_has(loop->session, w))
continue;
if (loop->tty.bg == -1)
continue;
return (loop->tty.bg);
}
return (-1);
}
/*
* If any control mode client exists that has provided a bg color, return it.
* Otherwise, return -1.
*/
static int
input_get_bg_control_client(struct window_pane *wp)
{
struct client *c;
if (wp->control_bg == -1)
return (-1);
TAILQ_FOREACH(c, &clients, entry) {
if (c->flags & CLIENT_CONTROL)
return (wp->control_bg);
}
return (-1);
}
/*
* If any control mode client exists that has provided a fg color, return it.
* Otherwise, return -1.
*/
static int
input_get_fg_control_client(struct window_pane *wp)
{
struct client *c;
if (wp->control_fg == -1)
return (-1);
TAILQ_FOREACH(c, &clients, entry) {
if (c->flags & CLIENT_CONTROL)
return (wp->control_fg);
}
return (-1);
}
/* Handle the OSC 10 sequence for setting and querying foreground colour. */
static void
@ -2787,11 +2733,11 @@ input_osc_10(struct input_ctx *ictx, const char *p)
if (strcmp(p, "?") == 0) {
if (wp == NULL)
return;
c = input_get_fg_control_client(wp);
c = window_pane_get_fg_control_client(wp);
if (c == -1) {
tty_default_colours(&defaults, wp);
if (COLOUR_DEFAULT(defaults.fg))
c = input_get_fg_client(wp);
c = window_pane_get_fg(wp);
else
c = defaults.fg;
}
@ -2832,20 +2778,12 @@ static void
input_osc_11(struct input_ctx *ictx, const char *p)
{
struct window_pane *wp = ictx->wp;
struct grid_cell defaults;
int c;
if (strcmp(p, "?") == 0) {
if (wp == NULL)
return;
c = input_get_bg_control_client(wp);
if (c == -1) {
tty_default_colours(&defaults, wp);
if (COLOUR_DEFAULT(defaults.bg))
c = input_get_bg_client(wp);
else
c = defaults.bg;
}
c = window_pane_get_bg(wp);
input_osc_colour_reply(ictx, 11, c);
return;
}
@ -2857,7 +2795,7 @@ input_osc_11(struct input_ctx *ictx, const char *p)
if (ictx->palette != NULL) {
ictx->palette->bg = c;
if (wp != NULL)
wp->flags |= PANE_STYLECHANGED;
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
screen_write_fullredraw(&ictx->ctx);
}
}
@ -2873,7 +2811,7 @@ input_osc_111(struct input_ctx *ictx, const char *p)
if (ictx->palette != NULL) {
ictx->palette->bg = 8;
if (wp != NULL)
wp->flags |= PANE_STYLECHANGED;
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
screen_write_fullredraw(&ictx->ctx);
}
}
@ -3064,3 +3002,18 @@ input_set_buffer_size(size_t buffer_size)
log_debug("%s: %lu -> %lu", __func__, input_buffer_size, buffer_size);
input_buffer_size = buffer_size;
}
static void
input_report_current_theme(struct input_ctx *ictx)
{
switch (window_pane_get_theme(ictx->wp)) {
case THEME_DARK:
input_reply(ictx, "\033[?997;1n");
break;
case THEME_LIGHT:
input_reply(ictx, "\033[?997;2n");
break;
case THEME_UNKNOWN:
break;
}
}

View File

@ -66,6 +66,7 @@ struct mode_tree_data {
u_int line_size;
u_int depth;
u_int maxdepth;
u_int width;
u_int height;
@ -196,6 +197,8 @@ mode_tree_build_lines(struct mode_tree_data *mtd,
int flat = 1;
mtd->depth = depth;
if (depth > mtd->maxdepth)
mtd->maxdepth = depth;
TAILQ_FOREACH(mti, mtl, entry) {
mtd->line_list = xreallocarray(mtd->line_list,
mtd->line_size + 1, sizeof *mtd->line_list);
@ -528,6 +531,7 @@ mode_tree_build(struct mode_tree_data *mtd)
TAILQ_INIT(&mtd->saved);
mode_tree_clear_lines(mtd);
mtd->maxdepth = 0;
mode_tree_build_lines(mtd, &mtd->children, 0);
if (mtd->line_list != NULL && tag == UINT64_MAX)
@ -658,7 +662,7 @@ mode_tree_draw(struct mode_tree_data *mtd)
char *text, *start, *key;
const char *tag, *symbol;
size_t size, n;
int keylen, pad;
int keylen, pad, namelen[mtd->maxdepth + 1];
if (mtd->line_size == 0)
return;
@ -682,6 +686,15 @@ mode_tree_draw(struct mode_tree_data *mtd)
keylen = mti->keylen + 3;
}
for (i = 0; i < mtd->maxdepth + 1; i++)
namelen[i] = 0;
for (i = 0; i < mtd->line_size; i++) {
line = &mtd->line_list[i];
mti = line->item;
if ((int)strlen(mti->name) > namelen[line->depth])
namelen[line->depth] = strlen(mti->name);
}
for (i = 0; i < mtd->line_size; i++) {
if (i < mtd->offset)
continue;
@ -731,8 +744,9 @@ mode_tree_draw(struct mode_tree_data *mtd)
tag = "*";
else
tag = "";
xasprintf(&text, "%-*s%s%s%s%s", keylen, key, start, mti->name,
tag, (mti->text != NULL) ? ": " : "" );
xasprintf(&text, "%-*s%s%*s%s%s", keylen, key, start,
namelen[line->depth], mti->name, tag,
(mti->text != NULL) ? ": " : "" );
width = utf8_cstrwidth(text);
if (width > w)
width = w;
@ -1297,7 +1311,7 @@ mode_tree_run_command(struct client *c, struct cmd_find_state *fs,
if (status == CMD_PARSE_ERROR) {
if (c != NULL) {
*error = toupper((u_char)*error);
status_message_set(c, -1, 1, 0, "%s", error);
status_message_set(c, -1, 1, 0, 0, "%s", error);
}
free(error);
}

View File

@ -1454,6 +1454,8 @@ const struct options_table_entry options_table[] = {
OPTIONS_TABLE_HOOK("client-focus-out", ""),
OPTIONS_TABLE_HOOK("client-resized", ""),
OPTIONS_TABLE_HOOK("client-session-changed", ""),
OPTIONS_TABLE_HOOK("client-light-theme", ""),
OPTIONS_TABLE_HOOK("client-dark-theme", ""),
OPTIONS_TABLE_HOOK("command-error", ""),
OPTIONS_TABLE_PANE_HOOK("pane-died", ""),
OPTIONS_TABLE_PANE_HOOK("pane-exited", ""),

View File

@ -1165,7 +1165,7 @@ options_push_changes(const char *name)
if (strcmp(name, "window-style") == 0 ||
strcmp(name, "window-active-style") == 0) {
RB_FOREACH(wp, window_pane_tree, &all_window_panes)
wp->flags |= PANE_STYLECHANGED;
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
}
if (strcmp(name, "pane-colours") == 0) {
RB_FOREACH(wp, window_pane_tree, &all_window_panes)

View File

@ -433,11 +433,15 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp,
const char *fmt;
struct format_tree *ft;
char *expanded;
int pane_status = rctx->pane_status;
int pane_status = rctx->pane_status, sb_w = 0;
int pane_scrollbars = rctx->pane_scrollbars;
u_int width, i, cell_type, px, py;
struct screen_write_ctx ctx;
struct screen old;
if (window_pane_show_scrollbar(wp, pane_scrollbars))
sb_w = wp->scrollbar_style.width + wp->scrollbar_style.pad;
ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS);
format_defaults(ft, c, c->session, c->session->curw, wp);
@ -451,7 +455,7 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp,
if (wp->sx < 4)
wp->status_size = width = 0;
else
wp->status_size = width = wp->sx - 4;
wp->status_size = width = wp->sx + sb_w - 2;
memcpy(&old, &wp->status_screen, sizeof old);
screen_init(&wp->status_screen, width, 1, 0);

View File

@ -56,11 +56,11 @@ static void server_client_set_title(struct client *);
static void server_client_set_path(struct client *);
static void server_client_reset_state(struct client *);
static void server_client_update_latest(struct client *);
static void server_client_dispatch(struct imsg *, void *);
static void server_client_dispatch_command(struct client *, struct imsg *);
static void server_client_dispatch_identify(struct client *, struct imsg *);
static void server_client_dispatch_shell(struct client *);
static void server_client_report_theme(struct client *, enum client_theme);
/* Compare client windows. */
static int
@ -152,6 +152,7 @@ server_client_clear_overlay(struct client *c)
c->overlay_draw = NULL;
c->overlay_key = NULL;
c->overlay_free = NULL;
c->overlay_resize = NULL;
c->overlay_data = NULL;
c->tty.flags &= ~(TTY_FREEZE|TTY_NOCURSOR);
@ -299,6 +300,7 @@ server_client_create(int fd)
c->tty.sx = 80;
c->tty.sy = 24;
c->theme = THEME_UNKNOWN;
status_init(c);
c->flags |= CLIENT_FOCUSED;
@ -400,6 +402,7 @@ server_client_set_session(struct client *c, struct session *s)
recalculate_sizes();
window_update_focus(s->curw->window);
session_update_activity(s, NULL);
session_theme_changed(s);
gettimeofday(&s->last_attached_time, NULL);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
s->curw->window->latest = c;
@ -2242,13 +2245,13 @@ out:
static int
server_client_is_bracket_paste(struct client *c, key_code key)
{
if (key == KEYC_PASTE_START) {
if ((key & KEYC_MASK_KEY) == KEYC_PASTE_START) {
c->flags |= CLIENT_BRACKETPASTING;
log_debug("%s: bracket paste on", c->name);
return (0);
}
if (key == KEYC_PASTE_END) {
if ((key & KEYC_MASK_KEY) == KEYC_PASTE_END) {
c->flags &= ~CLIENT_BRACKETPASTING;
log_debug("%s: bracket paste off", c->name);
return (0);
@ -2383,6 +2386,16 @@ server_client_key_callback(struct cmdq_item *item, void *data)
event->key = key;
}
/* Handle theme reporting keys. */
if (key == KEYC_REPORT_LIGHT_THEME) {
server_client_report_theme(c, THEME_LIGHT);
goto out;
}
if (key == KEYC_REPORT_DARK_THEME) {
server_client_report_theme(c, THEME_DARK);
goto out;
}
/* Find affected pane. */
if (!KEYC_IS_MOUSE(key) || cmd_find_from_mouse(&fs, m, 0) != 0)
cmd_find_from_client(&fs, c, 0);
@ -2673,6 +2686,12 @@ server_client_loop(void)
}
check_window_name(w);
}
/* Send theme updates. */
RB_FOREACH(w, windows, &windows) {
TAILQ_FOREACH(wp, &w->panes, entry)
window_pane_send_theme_update(wp);
}
}
/* Check if window needs to be resized. */
@ -3909,3 +3928,21 @@ out:
if (!parse)
free(msg);
}
static void
server_client_report_theme(struct client *c, enum client_theme theme)
{
if (theme == THEME_LIGHT) {
c->theme = THEME_LIGHT;
notify_client("client-light-theme", c);
} else {
c->theme = THEME_DARK;
notify_client("client-dark-theme", c);
}
/*
* Request foreground and background colour again. Don't forward 2031 to
* panes until a response is received.
*/
tty_puts(&c->tty, "\033]10;?\033\\\033]11;?\033\\");
}

View File

@ -751,3 +751,16 @@ session_renumber_windows(struct session *s)
RB_FOREACH_SAFE(wl, winlinks, &old_wins, wl1)
winlink_remove(&old_wins, wl);
}
/* Set the PANE_THEMECHANGED flag for every pane in this session. */
void
session_theme_changed(struct session *s)
{
struct window_pane *wp;
struct winlink *wl;
RB_FOREACH(wl, winlinks, &s->windows) {
TAILQ_FOREACH(wp, &wl->window->panes, entry)
wp->flags |= PANE_THEMECHANGED;
}
}

View File

@ -470,7 +470,7 @@ status_redraw(struct client *c)
/* Set a status line message. */
void
status_message_set(struct client *c, int delay, int ignore_styles,
int ignore_keys, const char *fmt, ...)
int ignore_keys, int no_freeze, const char *fmt, ...)
{
struct timeval tv;
va_list ap;
@ -514,7 +514,9 @@ status_message_set(struct client *c, int delay, int ignore_styles,
c->message_ignore_keys = ignore_keys;
c->message_ignore_styles = ignore_styles;
c->tty.flags |= (TTY_NOCURSOR|TTY_FREEZE);
if (!no_freeze)
c->tty.flags |= TTY_FREEZE;
c->tty.flags |= TTY_NOCURSOR;
c->flags |= CLIENT_REDRAWSTATUS;
}

25
tmux.1
View File

@ -2331,6 +2331,15 @@ repeats the last search and
does the same but reverses the direction (forward becomes backward and backward
becomes forward).
.Pp
The default incremental search key bindings,
.Ql C-r
and
.Ql C-s ,
are designed to emulate
.Xr emacs 1 .
When first pressed they allow a new search term to be entered; if pressed with
an empty search term they repeat the previously used search term.
.Pp
The
.Ql next-prompt
and
@ -2547,7 +2556,7 @@ but a different format may be specified with
.Fl F .
.Tg capturep
.It Xo Ic capture-pane
.Op Fl aAepPqCJN
.Op Fl aepPqCJMN
.Op Fl b Ar buffer-name
.Op Fl E Ar end-line
.Op Fl S Ar start-line
@ -2566,6 +2575,9 @@ is given, the alternate screen is used, and the history is not accessible.
If no alternate screen exists, an error will be returned unless
.Fl q
is given.
Similarly, if the pane is in a mode,
.Fl M
uses the screen for the mode.
If
.Fl e
is given, the output includes escape sequences for text and background
@ -5857,6 +5869,12 @@ with
.Ql bar/
throughout.
.Pp
Multiple modifiers may be separated with a semicolon (;) as in
.Ql #{T;=10:status-left} ,
which limits the resulting
.Xr strftime 3 -expanded
string to at most 10 characters.
.Pp
In addition, the last line of a shell command's output may be inserted using
.Ql #() .
For example,
@ -6744,7 +6762,7 @@ The following keys are available in menus:
.El
.Tg display
.It Xo Ic display-message
.Op Fl aIlNpv
.Op Fl aCIlNpv
.Op Fl c Ar target-client
.Op Fl d Ar delay
.Op Fl t Ar target-pane
@ -6767,6 +6785,9 @@ option is used; a delay of zero waits for a key press.
.Ql N
ignores key presses and closes only after the delay expires.
If
.Fl C
is given, the pane will continue to be updated while the message is displayed.
If
.Fl l
is given,
.Ar message

40
tmux.h
View File

@ -176,7 +176,8 @@ struct winlink;
/* Is this a paste key? */
#define KEYC_IS_PASTE(key) \
((key) == KEYC_PASTE_START || (key) == KEYC_PASTE_END)
(((key) & KEYC_MASK_KEY) == KEYC_PASTE_START || \
((key) & KEYC_MASK_KEY) == KEYC_PASTE_END)
/* Multiple click timeout. */
#define KEYC_CLICK_TIMEOUT 300
@ -377,6 +378,10 @@ enum {
KEYC_KP_ZERO,
KEYC_KP_PERIOD,
/* Theme reporting. */
KEYC_REPORT_DARK_THEME,
KEYC_REPORT_LIGHT_THEME,
/* End of special keys. */
KEYC_BASE_END
};
@ -644,6 +649,7 @@ enum tty_code_code {
#define MODE_CURSOR_VERY_VISIBLE 0x10000
#define MODE_CURSOR_BLINKING_SET 0x20000
#define MODE_KEYS_EXTENDED_2 0x40000
#define MODE_THEME_UPDATES 0x80000
#define ALL_MODES 0xffffff
#define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL)
@ -1090,6 +1096,7 @@ struct window_mode {
struct mouse_event *);
void (*formats)(struct window_mode_entry *,
struct format_tree *);
struct screen *(*get_screen)(struct window_mode_entry *);
};
/* Active window mode. */
@ -1154,8 +1161,9 @@ struct window_pane {
#define PANE_STATUSDRAWN 0x400
#define PANE_EMPTY 0x800
#define PANE_STYLECHANGED 0x1000
#define PANE_UNSEENCHANGES 0x2000
#define PANE_REDRAWSCROLLBAR 0x4000
#define PANE_THEMECHANGED 0x2000
#define PANE_UNSEENCHANGES 0x4000
#define PANE_REDRAWSCROLLBAR 0x8000
u_int sb_slider_y;
u_int sb_slider_h;
@ -1863,6 +1871,16 @@ struct overlay_ranges {
u_int nx[OVERLAY_MAX_RANGES];
};
/*
* Client theme, this is worked out from the background colour if not reported
* by terminal.
*/
enum client_theme {
THEME_UNKNOWN,
THEME_LIGHT,
THEME_DARK
};
/* Client connection. */
typedef int (*prompt_input_cb)(struct client *, void *, const char *, int);
typedef void (*prompt_free_cb)(void *);
@ -1922,6 +1940,7 @@ struct client {
struct mouse_event click_event;
struct status_line status;
enum client_theme theme;
#define CLIENT_TERMINAL 0x1
#define CLIENT_LOGIN 0x2
@ -2641,6 +2660,7 @@ int cmd_find_from_nothing(struct cmd_find_state *, int);
/* cmd.c */
extern const struct cmd_entry *cmd_table[];
const struct cmd_entry *cmd_find(const char *, char **);
void printflike(3, 4) cmd_log_argv(int, char **, const char *, ...);
void cmd_prepend_argv(int *, char ***, const char *);
void cmd_append_argv(int *, char ***, const char *);
@ -2890,7 +2910,7 @@ struct style_range *status_get_range(struct client *, u_int, u_int);
void status_init(struct client *);
void status_free(struct client *);
int status_redraw(struct client *);
void printflike(5, 6) status_message_set(struct client *, int, int, int,
void printflike(6, 7) status_message_set(struct client *, int, int, int, int,
const char *, ...);
void status_message_clear(struct client *);
int status_message_redraw(struct client *);
@ -2942,7 +2962,8 @@ int colour_join_rgb(u_char, u_char, u_char);
void colour_split_rgb(int, u_char *, u_char *, u_char *);
int colour_force_rgb(int);
const char *colour_tostring(int);
int colour_fromstring(const char *s);
enum client_theme colour_totheme(int);
int colour_fromstring(const char *);
int colour_256toRGB(int);
int colour_256to16(int);
int colour_byname(const char *);
@ -3243,6 +3264,13 @@ void window_set_fill_character(struct window *);
void window_pane_default_cursor(struct window_pane *);
int window_pane_mode(struct window_pane *);
int window_pane_show_scrollbar(struct window_pane *, int);
int window_pane_get_bg(struct window_pane *);
int window_pane_get_fg(struct window_pane *);
int window_pane_get_fg_control_client(struct window_pane *);
int window_pane_get_bg_control_client(struct window_pane *);
int window_get_bg_client(struct window_pane *);
enum client_theme window_pane_get_theme(struct window_pane *);
void window_pane_send_theme_update(struct window_pane *);
/* layout.c */
u_int layout_count_cells(struct layout_cell *);
@ -3440,11 +3468,11 @@ void session_group_synchronize_from(struct session *);
u_int session_group_count(struct session_group *);
u_int session_group_attached_count(struct session_group *);
void session_renumber_windows(struct session *);
void session_theme_changed(struct session *);
/* utf8.c */
enum utf8_state utf8_towc (const struct utf8_data *, wchar_t *);
enum utf8_state utf8_fromwc(wchar_t wc, struct utf8_data *);
int utf8_in_table(wchar_t, const wchar_t *, u_int);
void utf8_update_width_cache(void);
utf8_char utf8_build_one(u_char);
enum utf8_state utf8_from_data(const struct utf8_data *, utf8_char *);

View File

@ -208,11 +208,15 @@ static const struct tty_default_key_raw tty_default_raw_keys[] = {
{ "\033[O", KEYC_FOCUS_OUT },
/* Paste keys. */
{ "\033[200~", KEYC_PASTE_START },
{ "\033[201~", KEYC_PASTE_END },
{ "\033[200~", KEYC_PASTE_START|KEYC_IMPLIED_META },
{ "\033[201~", KEYC_PASTE_END|KEYC_IMPLIED_META },
/* Extended keys. */
{ "\033[1;5Z", '\011'|KEYC_CTRL|KEYC_SHIFT },
/* Theme reporting. */
{ "\033[?997;1n", KEYC_REPORT_DARK_THEME },
{ "\033[?997;2n", KEYC_REPORT_LIGHT_THEME },
};
/* Default xterm keys. */
@ -791,10 +795,12 @@ tty_keys_next(struct tty *tty)
switch (tty_keys_colours(tty, buf, len, &size, &tty->fg, &tty->bg)) {
case 0: /* yes */
key = KEYC_UNKNOWN;
session_theme_changed(tty->client->session);
goto complete_key;
case -1: /* no, or not valid */
break;
case 1: /* partial */
session_theme_changed(tty->client->session);
goto partial_key;
}
@ -931,6 +937,11 @@ partial_key:
delay = options_get_number(global_options, "escape-time");
if (delay == 0)
delay = 1;
if ((tty->flags & TTY_ALL_REQUEST_FLAGS) != TTY_ALL_REQUEST_FLAGS) {
log_debug("%s: increasing delay for active DA query", c->name);
if (delay < 500)
delay = 500;
}
tv.tv_sec = delay / 1000;
tv.tv_usec = (delay % 1000) * 1000L;

8
tty.c
View File

@ -356,6 +356,11 @@ tty_start_tty(struct tty *tty)
if (tty_term_has(tty->term, TTYC_ENBP))
tty_putcode(tty, TTYC_ENBP);
if (tty->term->flags & TERM_VT100LIKE) {
/* Subscribe to theme changes and request theme now. */
tty_puts(tty, "\033[?2031h\033[?996n");
}
evtimer_set(&tty->start_timer, tty_start_timer_callback, tty);
evtimer_add(&tty->start_timer, &tv);
@ -468,6 +473,9 @@ tty_stop_tty(struct tty *tty)
tty_raw(tty, tty_term_string(tty->term, TTYC_DSMG));
tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP));
if (tty->term->flags & TERM_VT100LIKE)
tty_raw(tty, "\033[?2031l");
setblocking(c->fd, 1);
}

View File

@ -40,6 +40,7 @@ static void window_copy_free(struct window_mode_entry *);
static void window_copy_resize(struct window_mode_entry *, u_int, u_int);
static void window_copy_formats(struct window_mode_entry *,
struct format_tree *);
static struct screen *window_copy_get_screen(struct window_mode_entry *);
static void window_copy_scroll1(struct window_mode_entry *,
struct window_pane *wp, int, u_int, int);
static void window_copy_pageup1(struct window_mode_entry *, int);
@ -160,6 +161,7 @@ const struct window_mode window_copy_mode = {
.key_table = window_copy_key_table,
.command = window_copy_command,
.formats = window_copy_formats,
.get_screen = window_copy_get_screen
};
const struct window_mode window_view_mode = {
@ -171,6 +173,7 @@ const struct window_mode window_view_mode = {
.key_table = window_copy_key_table,
.command = window_copy_command,
.formats = window_copy_formats,
.get_screen = window_copy_get_screen
};
enum {
@ -972,6 +975,14 @@ window_copy_formats(struct window_mode_entry *wme, struct format_tree *ft)
window_copy_cursor_hyperlink_cb);
}
static struct screen *
window_copy_get_screen(struct window_mode_entry *wme)
{
struct window_copy_mode_data *data = wme->data;
return (data->backing);
}
static void
window_copy_size_changed(struct window_mode_entry *wme)
{
@ -4252,6 +4263,8 @@ window_copy_match_at_cursor(struct window_copy_mode_data *data)
buf = xrealloc(buf, len + 2);
buf[len] = '\t';
len++;
} else if (gc.flags & GRID_FLAG_PADDING) {
/* nothing to do */
} else {
buf = xrealloc(buf, len + gc.data.size + 1);
memcpy(buf + len, gc.data.data, gc.data.size);

View File

@ -1000,7 +1000,7 @@ window_customize_set_option_callback(struct client *c, void *itemdata,
fail:
*cause = toupper((u_char)*cause);
status_message_set(c, -1, 1, 0, "%s", cause);
status_message_set(c, -1, 1, 0, 0, "%s", cause);
free(cause);
return (0);
}
@ -1203,7 +1203,7 @@ window_customize_set_command_callback(struct client *c, void *itemdata,
fail:
*error = toupper((u_char)*error);
status_message_set(c, -1, 1, 0, "%s", error);
status_message_set(c, -1, 1, 0, 0, "%s", error);
free(error);
return (0);
}

284
window.c
View File

@ -70,6 +70,8 @@ struct window_pane_input_data {
static struct window_pane *window_pane_create(struct window *, u_int, u_int,
u_int);
static void window_pane_destroy(struct window_pane *);
static void window_pane_full_size_offset(struct window_pane *wp,
u_int *xoff, u_int *yoff, u_int *sx, u_int *sy);
RB_GENERATE(windows, window, entry, window_cmp);
RB_GENERATE(winlinks, winlink, entry, winlink_cmp);
@ -591,34 +593,15 @@ struct window_pane *
window_get_active_at(struct window *w, u_int x, u_int y)
{
struct window_pane *wp;
int pane_scrollbars;
u_int sb_pos, sb_w, xoff, sx;
pane_scrollbars = options_get_number(w->options, "pane-scrollbars");
sb_pos = options_get_number(w->options, "pane-scrollbars-position");
u_int xoff, yoff, sx, sy;
TAILQ_FOREACH(wp, &w->panes, entry) {
if (!window_pane_visible(wp))
continue;
if (pane_scrollbars == PANE_SCROLLBARS_ALWAYS ||
(pane_scrollbars == PANE_SCROLLBARS_MODAL &&
window_pane_mode(wp) != WINDOW_PANE_NO_MODE)) {
sb_w = wp->scrollbar_style.width +
wp->scrollbar_style.pad;
} else
sb_w = 0;
if (sb_pos == PANE_SCROLLBARS_LEFT) {
xoff = wp->xoff - sb_w;
sx = wp->sx + sb_w;
} else { /* sb_pos == PANE_SCROLLBARS_RIGHT */
xoff = wp->xoff;
sx = wp->sx + sb_w;
}
window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy);
if (x < xoff || x > xoff + sx)
continue;
if (y < wp->yoff || y > wp->yoff + wp->sy)
if (y < yoff || y > yoff + sy)
continue;
return (wp);
}
@ -950,7 +933,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
wp = xcalloc(1, sizeof *wp);
wp->window = w;
wp->options = options_create(w->options);
wp->flags = PANE_STYLECHANGED;
wp->flags = (PANE_STYLECHANGED|PANE_THEMECHANGED);
wp->id = next_window_pane_id++;
RB_INSERT(window_pane_tree, &all_window_panes, wp);
@ -1359,6 +1342,36 @@ window_pane_choose_best(struct window_pane **list, u_int size)
return (best);
}
/*
* Get full size and offset of a window pane including the area of the
* scrollbars if they were visible but not including the border(s).
*/
static void
window_pane_full_size_offset(struct window_pane *wp, u_int *xoff, u_int *yoff,
u_int *sx, u_int *sy)
{
struct window *w = wp->window;
int pane_scrollbars;
u_int sb_w, sb_pos;
pane_scrollbars = options_get_number(w->options, "pane-scrollbars");
sb_pos = options_get_number(w->options, "pane-scrollbars-position");
if (window_pane_show_scrollbar(wp, pane_scrollbars))
sb_w = wp->scrollbar_style.width + wp->scrollbar_style.pad;
else
sb_w = 0;
if (sb_pos == PANE_SCROLLBARS_LEFT) {
*xoff = wp->xoff - sb_w;
*sx = wp->sx + sb_w;
} else { /* sb_pos == PANE_SCROLLBARS_RIGHT */
*xoff = wp->xoff;
*sx = wp->sx + sb_w;
}
*yoff = wp->yoff;
*sy = wp->sy;
}
/*
* Find the pane directly above another. We build a list of those adjacent to
* top edge and then choose the best.
@ -1370,6 +1383,7 @@ window_pane_find_up(struct window_pane *wp)
struct window_pane *next, *best, **list;
u_int edge, left, right, end, size;
int status, found;
u_int xoff, yoff, sx, sy;
if (wp == NULL)
return (NULL);
@ -1379,7 +1393,9 @@ window_pane_find_up(struct window_pane *wp)
list = NULL;
size = 0;
edge = wp->yoff;
window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy);
edge = yoff;
if (status == PANE_STATUS_TOP) {
if (edge == 1)
edge = w->sy + 1;
@ -1391,20 +1407,21 @@ window_pane_find_up(struct window_pane *wp)
edge = w->sy + 1;
}
left = wp->xoff;
right = wp->xoff + wp->sx;
left = xoff;
right = xoff + sx;
TAILQ_FOREACH(next, &w->panes, entry) {
window_pane_full_size_offset(next, &xoff, &yoff, &sx, &sy);
if (next == wp)
continue;
if (next->yoff + next->sy + 1 != edge)
if (yoff + sy + 1 != edge)
continue;
end = next->xoff + next->sx - 1;
end = xoff + sx - 1;
found = 0;
if (next->xoff < left && end > right)
if (xoff < left && end > right)
found = 1;
else if (next->xoff >= left && next->xoff <= right)
else if (xoff >= left && xoff <= right)
found = 1;
else if (end >= left && end <= right)
found = 1;
@ -1427,6 +1444,7 @@ window_pane_find_down(struct window_pane *wp)
struct window_pane *next, *best, **list;
u_int edge, left, right, end, size;
int status, found;
u_int xoff, yoff, sx, sy;
if (wp == NULL)
return (NULL);
@ -1436,7 +1454,9 @@ window_pane_find_down(struct window_pane *wp)
list = NULL;
size = 0;
edge = wp->yoff + wp->sy + 1;
window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy);
edge = yoff + sy + 1;
if (status == PANE_STATUS_TOP) {
if (edge >= w->sy)
edge = 1;
@ -1452,16 +1472,17 @@ window_pane_find_down(struct window_pane *wp)
right = wp->xoff + wp->sx;
TAILQ_FOREACH(next, &w->panes, entry) {
window_pane_full_size_offset(next, &xoff, &yoff, &sx, &sy);
if (next == wp)
continue;
if (next->yoff != edge)
if (yoff != edge)
continue;
end = next->xoff + next->sx - 1;
end = xoff + sx - 1;
found = 0;
if (next->xoff < left && end > right)
if (xoff < left && end > right)
found = 1;
else if (next->xoff >= left && next->xoff <= right)
else if (xoff >= left && xoff <= right)
found = 1;
else if (end >= left && end <= right)
found = 1;
@ -1484,6 +1505,7 @@ window_pane_find_left(struct window_pane *wp)
struct window_pane *next, *best, **list;
u_int edge, top, bottom, end, size;
int found;
u_int xoff, yoff, sx, sy;
if (wp == NULL)
return (NULL);
@ -1492,24 +1514,27 @@ window_pane_find_left(struct window_pane *wp)
list = NULL;
size = 0;
edge = wp->xoff;
window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy);
edge = xoff;
if (edge == 0)
edge = w->sx + 1;
top = wp->yoff;
bottom = wp->yoff + wp->sy;
top = yoff;
bottom = yoff + sy;
TAILQ_FOREACH(next, &w->panes, entry) {
window_pane_full_size_offset(next, &xoff, &yoff, &sx, &sy);
if (next == wp)
continue;
if (next->xoff + next->sx + 1 != edge)
if (xoff + sx + 1 != edge)
continue;
end = next->yoff + next->sy - 1;
end = yoff + sy - 1;
found = 0;
if (next->yoff < top && end > bottom)
if (yoff < top && end > bottom)
found = 1;
else if (next->yoff >= top && next->yoff <= bottom)
else if (yoff >= top && yoff <= bottom)
found = 1;
else if (end >= top && end <= bottom)
found = 1;
@ -1532,6 +1557,7 @@ window_pane_find_right(struct window_pane *wp)
struct window_pane *next, *best, **list;
u_int edge, top, bottom, end, size;
int found;
u_int xoff, yoff, sx, sy;
if (wp == NULL)
return (NULL);
@ -1540,7 +1566,9 @@ window_pane_find_right(struct window_pane *wp)
list = NULL;
size = 0;
edge = wp->xoff + wp->sx + 1;
window_pane_full_size_offset(wp, &xoff, &yoff, &sx, &sy);
edge = xoff + sx + 1;
if (edge >= w->sx)
edge = 0;
@ -1548,16 +1576,17 @@ window_pane_find_right(struct window_pane *wp)
bottom = wp->yoff + wp->sy;
TAILQ_FOREACH(next, &w->panes, entry) {
window_pane_full_size_offset(next, &xoff, &yoff, &sx, &sy);
if (next == wp)
continue;
if (next->xoff != edge)
if (xoff != edge)
continue;
end = next->yoff + next->sy - 1;
end = yoff + sy - 1;
found = 0;
if (next->yoff < top && end > bottom)
if (yoff < top && end > bottom)
found = 1;
else if (next->yoff >= top && next->yoff <= bottom)
else if (yoff >= top && yoff <= bottom)
found = 1;
else if (end >= top && end <= bottom)
found = 1;
@ -1723,6 +1752,8 @@ window_set_fill_character(struct window *w)
ud = utf8_fromcstr(value);
if (ud != NULL && ud[0].width == 1)
w->fill_character = ud;
else
free(ud);
}
}
@ -1756,3 +1787,162 @@ window_pane_show_scrollbar(struct window_pane *wp, int sb_option)
return (1);
return (0);
}
int
window_pane_get_bg(struct window_pane *wp)
{
int c;
struct grid_cell defaults;
c = window_pane_get_bg_control_client(wp);
if (c == -1) {
tty_default_colours(&defaults, wp);
if (COLOUR_DEFAULT(defaults.bg))
c = window_get_bg_client(wp);
else
c = defaults.bg;
}
return (c);
}
/* Get a client with a background for the pane. */
int
window_get_bg_client(struct window_pane *wp)
{
struct window *w = wp->window;
struct client *loop;
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->flags & CLIENT_UNATTACHEDFLAGS)
continue;
if (loop->session == NULL || !session_has(loop->session, w))
continue;
if (loop->tty.bg == -1)
continue;
return (loop->tty.bg);
}
return (-1);
}
/*
* If any control mode client exists that has provided a bg color, return it.
* Otherwise, return -1.
*/
int
window_pane_get_bg_control_client(struct window_pane *wp)
{
struct client *c;
if (wp->control_bg == -1)
return (-1);
TAILQ_FOREACH(c, &clients, entry) {
if (c->flags & CLIENT_CONTROL)
return (wp->control_bg);
}
return (-1);
}
/*
* Get a client with a foreground for the pane. There isn't much to choose
* between them so just use the first.
*/
int
window_pane_get_fg(struct window_pane *wp)
{
struct window *w = wp->window;
struct client *loop;
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->flags & CLIENT_UNATTACHEDFLAGS)
continue;
if (loop->session == NULL || !session_has(loop->session, w))
continue;
if (loop->tty.fg == -1)
continue;
return (loop->tty.fg);
}
return (-1);
}
/*
* If any control mode client exists that has provided a fg color, return it.
* Otherwise, return -1.
*/
int
window_pane_get_fg_control_client(struct window_pane *wp)
{
struct client *c;
if (wp->control_fg == -1)
return (-1);
TAILQ_FOREACH(c, &clients, entry) {
if (c->flags & CLIENT_CONTROL)
return (wp->control_fg);
}
return (-1);
}
enum client_theme
window_pane_get_theme(struct window_pane *wp)
{
struct window *w = wp->window;
struct client *loop;
enum client_theme theme;
int found_light = 0, found_dark = 0;
/*
* Derive theme from pane background color, if it's not the default
* colour.
*/
theme = colour_totheme(window_pane_get_bg(wp));
if (theme != THEME_UNKNOWN)
return (theme);
/* Try to find a client that has a theme. */
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->flags & CLIENT_UNATTACHEDFLAGS)
continue;
if (loop->session == NULL || !session_has(loop->session, w))
continue;
switch (loop->theme) {
case THEME_LIGHT:
found_light = 1;
break;
case THEME_DARK:
found_dark = 1;
break;
case THEME_UNKNOWN:
break;
}
}
if (found_dark && !found_light)
return (THEME_DARK);
if (found_light && !found_dark)
return (THEME_LIGHT);
return (THEME_UNKNOWN);
}
void
window_pane_send_theme_update(struct window_pane *wp)
{
if (~wp->flags & PANE_THEMECHANGED)
return;
if (~wp->screen->mode & MODE_THEME_UPDATES)
return;
switch (window_pane_get_theme(wp)) {
case THEME_LIGHT:
input_key_pane(wp, KEYC_REPORT_LIGHT_THEME, NULL);
break;
case THEME_DARK:
input_key_pane(wp, KEYC_REPORT_DARK_THEME, NULL);
break;
case THEME_UNKNOWN:
break;
}
wp->flags &= ~PANE_THEMECHANGED;
}