mirror of
https://github.com/tmux/tmux.git
synced 2026-04-06 07:38:33 +00:00
Merge.
This commit is contained in:
12
Makefile.am
12
Makefile.am
@@ -240,9 +240,19 @@ dist_tmux_SOURCES += image.c image-sixel.c
|
||||
endif
|
||||
|
||||
if NEED_FUZZING
|
||||
check_PROGRAMS = fuzz/input-fuzzer
|
||||
check_PROGRAMS = \
|
||||
fuzz/input-fuzzer \
|
||||
fuzz/cmd-parse-fuzzer \
|
||||
fuzz/format-fuzzer \
|
||||
fuzz/style-fuzzer
|
||||
fuzz_input_fuzzer_LDFLAGS = $(FUZZING_LIBS)
|
||||
fuzz_input_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS)
|
||||
fuzz_cmd_parse_fuzzer_LDFLAGS = $(FUZZING_LIBS)
|
||||
fuzz_cmd_parse_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS)
|
||||
fuzz_format_fuzzer_LDFLAGS = $(FUZZING_LIBS)
|
||||
fuzz_format_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS)
|
||||
fuzz_style_fuzzer_LDFLAGS = $(FUZZING_LIBS)
|
||||
fuzz_style_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS)
|
||||
endif
|
||||
|
||||
# Install tmux.1 in the right format.
|
||||
|
||||
@@ -93,7 +93,7 @@ cmd_list_keys_get_table_width(struct key_binding **l, u_int n)
|
||||
}
|
||||
|
||||
static struct key_binding **
|
||||
cmd_get_root_and_prefix(u_int *n, struct sort_criteria *sort_crit)
|
||||
cmd_list_keys_get_root_and_prefix(u_int *n, struct sort_criteria *sort_crit)
|
||||
{
|
||||
const char *tables[] = { "prefix", "root" };
|
||||
struct key_table *t;
|
||||
@@ -119,7 +119,7 @@ cmd_get_root_and_prefix(u_int *n, struct sort_criteria *sort_crit)
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_filter_key_list(int filter_notes, int filter_key, key_code only,
|
||||
cmd_list_keys_filter_key_list(int filter_notes, int filter_key, key_code only,
|
||||
struct key_binding **l, u_int *n)
|
||||
{
|
||||
key_code key;
|
||||
@@ -137,10 +137,10 @@ cmd_filter_key_list(int filter_notes, int filter_key, key_code only,
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_format_add_key_binding(struct format_tree *ft,
|
||||
cmd_list_keys_format_add_key_binding(struct format_tree *ft,
|
||||
const struct key_binding *bd, const char *prefix)
|
||||
{
|
||||
const char *s;
|
||||
char *s;
|
||||
|
||||
if (bd->flags & KEY_BINDING_REPEAT)
|
||||
format_add(ft, "key_repeat", "1");
|
||||
@@ -155,12 +155,12 @@ cmd_format_add_key_binding(struct format_tree *ft,
|
||||
format_add(ft, "key_prefix", "%s", prefix);
|
||||
format_add(ft, "key_table", "%s", bd->tablename);
|
||||
|
||||
s = key_string_lookup_key(bd->key, 0);
|
||||
format_add(ft, "key_string", "%s", s);
|
||||
format_add(ft, "key_string", "%s", key_string_lookup_key(bd->key, 0));
|
||||
|
||||
s = cmd_list_print(bd->cmdlist,
|
||||
CMD_LIST_PRINT_ESCAPED|CMD_LIST_PRINT_NO_GROUPS);
|
||||
s = cmd_list_print(bd->cmdlist, CMD_LIST_PRINT_ESCAPED|
|
||||
CMD_LIST_PRINT_NO_GROUPS);
|
||||
format_add(ft, "key_command", "%s", s);
|
||||
free(s);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
@@ -213,14 +213,16 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (table)
|
||||
l = sort_get_key_bindings_table(table, &n, &sort_crit);
|
||||
else if (notes_only)
|
||||
l = cmd_get_root_and_prefix(&n, &sort_crit);
|
||||
l = cmd_list_keys_get_root_and_prefix(&n, &sort_crit);
|
||||
else
|
||||
l = sort_get_key_bindings(&n, &sort_crit);
|
||||
|
||||
filter_notes = notes_only && !args_has(args, 'a');
|
||||
filter_key = only != KEYC_UNKNOWN;
|
||||
if (filter_notes || filter_key)
|
||||
cmd_filter_key_list(filter_notes, filter_key, only, l, &n);
|
||||
if (filter_notes || filter_key) {
|
||||
cmd_list_keys_filter_key_list(filter_notes, filter_key, only, l,
|
||||
&n);
|
||||
}
|
||||
if (single)
|
||||
n = 1;
|
||||
|
||||
@@ -232,7 +234,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
|
||||
format_add(ft, "key_table_width", "%u",
|
||||
cmd_list_keys_get_table_width(l, n));
|
||||
for (i = 0; i < n; i++) {
|
||||
cmd_format_add_key_binding(ft, l[i], prefix);
|
||||
cmd_list_keys_format_add_key_binding(ft, l[i], prefix);
|
||||
|
||||
line = format_expand(ft, template);
|
||||
if ((single && tc != NULL) || n == 1)
|
||||
|
||||
2
cmd.c
2
cmd.c
@@ -313,6 +313,8 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
|
||||
|
||||
if (argc == 0)
|
||||
return (0);
|
||||
if (argc < 0 || argc > 1000)
|
||||
return (-1);
|
||||
*argv = xcalloc(argc, sizeof **argv);
|
||||
|
||||
buf[len - 1] = '\0';
|
||||
|
||||
@@ -49,6 +49,7 @@ format_is_type(struct format_range *fr, struct style *sy)
|
||||
case STYLE_RANGE_NONE:
|
||||
case STYLE_RANGE_LEFT:
|
||||
case STYLE_RANGE_RIGHT:
|
||||
case STYLE_RANGE_CONTROL:
|
||||
return (1);
|
||||
case STYLE_RANGE_PANE:
|
||||
case STYLE_RANGE_WINDOW:
|
||||
@@ -1065,6 +1066,10 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
|
||||
log_debug("%s: range user|%u at %u-%u", __func__,
|
||||
sr->argument, sr->start, sr->end);
|
||||
break;
|
||||
case STYLE_RANGE_CONTROL:
|
||||
log_debug("%s: range control|%u at %u-%u", __func__,
|
||||
sr->argument, sr->start, sr->end);
|
||||
break;
|
||||
}
|
||||
format_free_range(&frs, fr);
|
||||
}
|
||||
@@ -1116,7 +1121,7 @@ format_width(const char *expanded)
|
||||
/*
|
||||
* 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
|
||||
* format_draw function will actually do the escaping.
|
||||
*/
|
||||
char *
|
||||
format_trim_left(const char *expanded, u_int limit)
|
||||
|
||||
96
format.c
96
format.c
@@ -84,6 +84,12 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
|
||||
return (strcmp(fj1->cmd, fj2->cmd));
|
||||
}
|
||||
|
||||
/* Maimum pad and trim width. */
|
||||
#define FORMAT_MAX_WIDTH 10000
|
||||
|
||||
/* Maimum repeat size. */
|
||||
#define FORMAT_MAX_REPEAT 10000
|
||||
|
||||
/* Format modifiers. */
|
||||
#define FORMAT_TIMESTRING 0x1
|
||||
#define FORMAT_BASENAME 0x2
|
||||
@@ -1009,7 +1015,7 @@ static void *
|
||||
format_cb_pane_flags(struct format_tree *ft)
|
||||
{
|
||||
if (ft->wp != NULL)
|
||||
return (xstrdup(window_pane_printable_flags(ft->wp, 1)));
|
||||
return (xstrdup(window_pane_printable_flags(ft->wp)));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
@@ -1344,6 +1350,8 @@ format_cb_mouse_status_range(struct format_tree *ft)
|
||||
return (xstrdup("session"));
|
||||
case STYLE_RANGE_USER:
|
||||
return (xstrdup(sr->string));
|
||||
case STYLE_RANGE_CONTROL:
|
||||
return (xstrdup("control"));
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
@@ -1378,6 +1386,18 @@ format_cb_alternate_saved_y(struct format_tree *ft)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for bracket_paste_flag. */
|
||||
static void *
|
||||
format_cb_bracket_paste_flag(struct format_tree *ft)
|
||||
{
|
||||
if (ft->wp != NULL && ft->wp->screen != NULL) {
|
||||
if (ft->wp->screen->mode & MODE_BRACKETPASTE)
|
||||
return (xstrdup("1"));
|
||||
return (xstrdup("0"));
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for buffer_name. */
|
||||
static void *
|
||||
format_cb_buffer_name(struct format_tree *ft)
|
||||
@@ -1616,9 +1636,13 @@ format_cb_client_user(struct format_tree *ft)
|
||||
struct passwd *pw;
|
||||
|
||||
if (ft->c != NULL) {
|
||||
if (ft->c->user != NULL)
|
||||
return (xstrdup(ft->c->user));
|
||||
uid = proc_get_peer_uid(ft->c->peer);
|
||||
if (uid != (uid_t)-1 && (pw = getpwuid(uid)) != NULL)
|
||||
return (xstrdup(pw->pw_name));
|
||||
if (uid != (uid_t)-1 && (pw = getpwuid(uid)) != NULL) {
|
||||
ft->c->user = xstrdup(pw->pw_name);
|
||||
return (xstrdup(ft->c->user));
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
@@ -2288,6 +2312,38 @@ format_cb_pane_pipe_pid(struct format_tree *ft)
|
||||
return (value);
|
||||
}
|
||||
|
||||
/* Callback for pane_pb_progress. */
|
||||
static void *
|
||||
format_cb_pane_pb_progress(struct format_tree *ft)
|
||||
{
|
||||
char *value = NULL;
|
||||
|
||||
if (ft->wp != NULL)
|
||||
xasprintf(&value, "%d", ft->wp->base.progress_bar.progress);
|
||||
return (value);
|
||||
}
|
||||
|
||||
/* Callback for pane_pb_state. */
|
||||
static void *
|
||||
format_cb_pane_pb_state(struct format_tree *ft)
|
||||
{
|
||||
if (ft->wp != NULL) {
|
||||
switch (ft->wp->base.progress_bar.state) {
|
||||
case PROGRESS_BAR_HIDDEN:
|
||||
return xstrdup("hidden");
|
||||
case PROGRESS_BAR_NORMAL:
|
||||
return xstrdup("normal");
|
||||
case PROGRESS_BAR_ERROR:
|
||||
return xstrdup("error");
|
||||
case PROGRESS_BAR_INDETERMINATE:
|
||||
return xstrdup("indeterminate");
|
||||
case PROGRESS_BAR_PAUSED:
|
||||
return xstrdup("paused");
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_right. */
|
||||
static void *
|
||||
format_cb_pane_right(struct format_tree *ft)
|
||||
@@ -3063,10 +3119,13 @@ format_cb_uid(__unused struct format_tree *ft)
|
||||
static void *
|
||||
format_cb_user(__unused struct format_tree *ft)
|
||||
{
|
||||
static char *cached;
|
||||
struct passwd *pw;
|
||||
|
||||
if ((pw = getpwuid(getuid())) != NULL)
|
||||
return (xstrdup(pw->pw_name));
|
||||
if (cached == NULL && (pw = getpwuid(getuid())) != NULL)
|
||||
cached = xstrdup(pw->pw_name);
|
||||
if (cached != NULL)
|
||||
return (xstrdup(cached));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
@@ -3101,6 +3160,9 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "alternate_saved_y", FORMAT_TABLE_STRING,
|
||||
format_cb_alternate_saved_y
|
||||
},
|
||||
{ "bracket_paste_flag", FORMAT_TABLE_STRING,
|
||||
format_cb_bracket_paste_flag
|
||||
},
|
||||
{ "buffer_created", FORMAT_TABLE_TIME,
|
||||
format_cb_buffer_created
|
||||
},
|
||||
@@ -3395,6 +3457,12 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "pane_path", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_path
|
||||
},
|
||||
{ "pane_pb_progress", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_pb_progress
|
||||
},
|
||||
{ "pane_pb_state", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_pb_state
|
||||
},
|
||||
{ "pane_pid", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_pid
|
||||
},
|
||||
@@ -4256,6 +4324,8 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
||||
/* Skip any separator character. */
|
||||
if (*cp == ';')
|
||||
cp++;
|
||||
if (*cp == '\0')
|
||||
break;
|
||||
|
||||
/* Check single character modifiers with no arguments. */
|
||||
if (strchr("labcdnwETSWPL!<>", cp[0]) != NULL &&
|
||||
@@ -4816,7 +4886,7 @@ format_replace_expression(struct format_modifier *mexp,
|
||||
|
||||
/* The third argument may be precision. */
|
||||
if (argc >= 3) {
|
||||
prec = strtonum(mexp->argv[2], INT_MIN, INT_MAX, &errstr);
|
||||
prec = strtonum(mexp->argv[2], INT_MIN + 1, INT_MAX, &errstr);
|
||||
if (errstr != NULL) {
|
||||
format_log(es, "expression precision %s: %s", errstr,
|
||||
mexp->argv[2]);
|
||||
@@ -4961,8 +5031,8 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
||||
case '=':
|
||||
if (fm->argc < 1)
|
||||
break;
|
||||
limit = strtonum(fm->argv[0], INT_MIN, INT_MAX,
|
||||
&errstr);
|
||||
limit = strtonum(fm->argv[0], -FORMAT_MAX_WIDTH,
|
||||
FORMAT_MAX_WIDTH, &errstr);
|
||||
if (errstr != NULL)
|
||||
limit = 0;
|
||||
if (fm->argc >= 2 && fm->argv[1] != NULL)
|
||||
@@ -4971,8 +5041,8 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
||||
case 'p':
|
||||
if (fm->argc < 1)
|
||||
break;
|
||||
width = strtonum(fm->argv[0], INT_MIN, INT_MAX,
|
||||
&errstr);
|
||||
width = strtonum(fm->argv[0], -FORMAT_MAX_WIDTH,
|
||||
FORMAT_MAX_WIDTH, &errstr);
|
||||
if (errstr != NULL)
|
||||
width = 0;
|
||||
break;
|
||||
@@ -5195,7 +5265,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
||||
format_log(es, "repeat syntax error: %s", copy);
|
||||
goto fail;
|
||||
}
|
||||
nrep = strtonum(right, 1, 10000, &errstr);
|
||||
nrep = strtonum(right, 1, FORMAT_MAX_REPEAT, &errstr);
|
||||
if (errstr != NULL)
|
||||
value = xstrdup("");
|
||||
else {
|
||||
@@ -5390,6 +5460,7 @@ done:
|
||||
if (marker != NULL && strcmp(new, value) != 0) {
|
||||
free(value);
|
||||
xasprintf(&value, "%s%s", new, marker);
|
||||
free(new);
|
||||
} else {
|
||||
free(value);
|
||||
value = new;
|
||||
@@ -5400,6 +5471,7 @@ done:
|
||||
if (marker != NULL && strcmp(new, value) != 0) {
|
||||
free(value);
|
||||
xasprintf(&value, "%s%s", marker, new);
|
||||
free(new);
|
||||
} else {
|
||||
free(value);
|
||||
value = new;
|
||||
@@ -5512,7 +5584,7 @@ format_expand1(struct format_expand_state *es, const char *fmt)
|
||||
buf[off++] = *fmt++;
|
||||
continue;
|
||||
}
|
||||
if (*fmt++ == '\0')
|
||||
if (*++fmt == '\0')
|
||||
break;
|
||||
|
||||
ch = (u_char)*fmt++;
|
||||
|
||||
83
fuzz/cmd-parse-fuzzer.c
Normal file
83
fuzz/cmd-parse-fuzzer.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (c) 2026 David Korczynski <david@adalogics.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Fuzz the tmux command parser (cmd_parse_from_buffer).
|
||||
*
|
||||
* This exercises:
|
||||
* - cmd-parse.y (yacc grammar, lexer, command building)
|
||||
* - cmd.c (command lookup and validation)
|
||||
* - arguments.c (argument parsing and flag handling)
|
||||
* - cmd-find.c (target resolution)
|
||||
* - options.c (option name lookups during parsing)
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
struct event_base *libevent;
|
||||
|
||||
int
|
||||
LLVMFuzzerTestOneInput(const u_char *data, size_t size)
|
||||
{
|
||||
struct cmd_parse_input pi;
|
||||
struct cmd_parse_result *pr;
|
||||
|
||||
if (size > 2048 || size == 0)
|
||||
return 0;
|
||||
|
||||
memset(&pi, 0, sizeof pi);
|
||||
pi.flags = CMD_PARSE_QUIET;
|
||||
|
||||
pr = cmd_parse_from_buffer(data, size, &pi);
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_SUCCESS:
|
||||
cmd_list_free(pr->cmdlist);
|
||||
break;
|
||||
case CMD_PARSE_ERROR:
|
||||
free(pr->error);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
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();
|
||||
socket_path = xstrdup("dummy");
|
||||
|
||||
return 0;
|
||||
}
|
||||
133
fuzz/cmd-parse-fuzzer.dict
Normal file
133
fuzz/cmd-parse-fuzzer.dict
Normal file
@@ -0,0 +1,133 @@
|
||||
# tmux command names
|
||||
"set-option"
|
||||
"bind-key"
|
||||
"unbind-key"
|
||||
"send-keys"
|
||||
"new-session"
|
||||
"new-window"
|
||||
"split-window"
|
||||
"select-window"
|
||||
"select-pane"
|
||||
"kill-pane"
|
||||
"kill-window"
|
||||
"kill-session"
|
||||
"kill-server"
|
||||
"list-sessions"
|
||||
"list-windows"
|
||||
"list-panes"
|
||||
"list-keys"
|
||||
"list-buffers"
|
||||
"list-clients"
|
||||
"list-commands"
|
||||
"attach-session"
|
||||
"detach-client"
|
||||
"switch-client"
|
||||
"rename-session"
|
||||
"rename-window"
|
||||
"resize-pane"
|
||||
"resize-window"
|
||||
"display-message"
|
||||
"display-menu"
|
||||
"display-popup"
|
||||
"display-panes"
|
||||
"copy-mode"
|
||||
"paste-buffer"
|
||||
"capture-pane"
|
||||
"save-buffer"
|
||||
"load-buffer"
|
||||
"set-buffer"
|
||||
"delete-buffer"
|
||||
"show-buffer"
|
||||
"choose-buffer"
|
||||
"choose-tree"
|
||||
"choose-client"
|
||||
"if-shell"
|
||||
"run-shell"
|
||||
"source-file"
|
||||
"command-prompt"
|
||||
"confirm-before"
|
||||
"pipe-pane"
|
||||
"wait-for"
|
||||
"set-environment"
|
||||
"show-environment"
|
||||
"set-hook"
|
||||
"show-hooks"
|
||||
"show-messages"
|
||||
"show-options"
|
||||
"set-window-option"
|
||||
"show-window-options"
|
||||
"clear-history"
|
||||
"clock-mode"
|
||||
"find-window"
|
||||
"join-pane"
|
||||
"move-pane"
|
||||
"break-pane"
|
||||
"swap-pane"
|
||||
"swap-window"
|
||||
"move-window"
|
||||
"link-window"
|
||||
"unlink-window"
|
||||
"rotate-window"
|
||||
"next-window"
|
||||
"previous-window"
|
||||
"last-window"
|
||||
"last-pane"
|
||||
"next-layout"
|
||||
"previous-layout"
|
||||
"select-layout"
|
||||
"customize-mode"
|
||||
"refresh-client"
|
||||
"suspend-client"
|
||||
"lock-client"
|
||||
"lock-server"
|
||||
"lock-session"
|
||||
"respawn-pane"
|
||||
"respawn-window"
|
||||
"start-server"
|
||||
"server-access"
|
||||
"send-prefix"
|
||||
"clear-prompt-history"
|
||||
"show-prompt-history"
|
||||
|
||||
# Common flags and syntax
|
||||
"-t"
|
||||
"-s"
|
||||
"-g"
|
||||
"-w"
|
||||
"-p"
|
||||
"-a"
|
||||
"-o"
|
||||
"-q"
|
||||
"-u"
|
||||
"-F"
|
||||
"-f"
|
||||
"-b"
|
||||
"-d"
|
||||
"-e"
|
||||
"-n"
|
||||
"-r"
|
||||
|
||||
# Targets and option names
|
||||
"status"
|
||||
"default"
|
||||
"mouse"
|
||||
"on"
|
||||
"off"
|
||||
"vi"
|
||||
"emacs"
|
||||
"set -g"
|
||||
"set -s"
|
||||
"setw"
|
||||
"bind"
|
||||
"unbind"
|
||||
|
||||
# Syntax elements
|
||||
"{"
|
||||
"}"
|
||||
";"
|
||||
"#{"
|
||||
"%if"
|
||||
"%elif"
|
||||
"%else"
|
||||
"%endif"
|
||||
"%hidden"
|
||||
2
fuzz/cmd-parse-fuzzer.options
Normal file
2
fuzz/cmd-parse-fuzzer.options
Normal file
@@ -0,0 +1,2 @@
|
||||
[libfuzzer]
|
||||
max_len = 2048
|
||||
88
fuzz/format-fuzzer.c
Normal file
88
fuzz/format-fuzzer.c
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2026 David Korczynski <david@adalogics.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Fuzz the tmux format string expander (format_expand).
|
||||
*
|
||||
* This exercises:
|
||||
* - format.c (format parsing, modifier chains, conditionals, math, regex)
|
||||
* - colour.c (colour name and RGB parsing within formats)
|
||||
* - utf8.c (UTF-8 width calculations in format padding)
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
struct event_base *libevent;
|
||||
|
||||
int
|
||||
LLVMFuzzerTestOneInput(const u_char *data, size_t size)
|
||||
{
|
||||
struct format_tree *ft;
|
||||
char *buf, *expanded;
|
||||
|
||||
if (size > 2048 || size == 0)
|
||||
return 0;
|
||||
|
||||
/* Null-terminate the input for format_expand. */
|
||||
buf = malloc(size + 1);
|
||||
if (buf == NULL)
|
||||
return 0;
|
||||
memcpy(buf, data, size);
|
||||
buf[size] = '\0';
|
||||
|
||||
ft = format_create(NULL, NULL, 0, FORMAT_NOJOBS);
|
||||
format_add(ft, "session_name", "%s", "fuzz-session");
|
||||
format_add(ft, "window_index", "%d", 0);
|
||||
format_add(ft, "window_name", "%s", "fuzz-window");
|
||||
format_add(ft, "pane_index", "%d", 0);
|
||||
format_add(ft, "pane_id", "%s", "%%0");
|
||||
format_add(ft, "host", "%s", "fuzzhost");
|
||||
format_add(ft, "pane_width", "%d", 80);
|
||||
format_add(ft, "pane_height", "%d", 25);
|
||||
|
||||
expanded = format_expand(ft, buf);
|
||||
free(expanded);
|
||||
format_free(ft);
|
||||
|
||||
free(buf);
|
||||
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();
|
||||
socket_path = xstrdup("dummy");
|
||||
|
||||
return 0;
|
||||
}
|
||||
71
fuzz/format-fuzzer.dict
Normal file
71
fuzz/format-fuzzer.dict
Normal file
@@ -0,0 +1,71 @@
|
||||
# Format expansion syntax
|
||||
"#{"
|
||||
"}"
|
||||
"#{?"
|
||||
"#{=="
|
||||
"#{!="
|
||||
"#{<"
|
||||
"#{>"
|
||||
"#{m:"
|
||||
"#{C:"
|
||||
"#{s/"
|
||||
"#{t:"
|
||||
"#{T:"
|
||||
"#{E:"
|
||||
"#{S:"
|
||||
"#{W:"
|
||||
"#{P:"
|
||||
"##"
|
||||
|
||||
# Common format modifiers
|
||||
"b:"
|
||||
"d:"
|
||||
"q:"
|
||||
"l:"
|
||||
"e:"
|
||||
"t:"
|
||||
"p:"
|
||||
"w:"
|
||||
"n:"
|
||||
"a:"
|
||||
"=:"
|
||||
"||"
|
||||
"&&"
|
||||
","
|
||||
"#{e|"
|
||||
"#{p-1:"
|
||||
"#{=/10/...:"
|
||||
|
||||
# Format variables
|
||||
"session_name"
|
||||
"window_index"
|
||||
"window_name"
|
||||
"pane_index"
|
||||
"pane_id"
|
||||
"host"
|
||||
"pane_width"
|
||||
"pane_height"
|
||||
"pane_current_command"
|
||||
"pane_pid"
|
||||
"session_id"
|
||||
"window_id"
|
||||
"client_name"
|
||||
"version"
|
||||
"line"
|
||||
|
||||
# Conditionals
|
||||
"#{?pane_active,"
|
||||
",}"
|
||||
"#{?#{==:"
|
||||
|
||||
# Math and comparison
|
||||
"#{e|+:"
|
||||
"#{e|-:"
|
||||
"#{e|*:"
|
||||
"#{e|/:"
|
||||
"#{e|%:"
|
||||
|
||||
# Nested
|
||||
"#{="
|
||||
"#{"
|
||||
"#{l:"
|
||||
2
fuzz/format-fuzzer.options
Normal file
2
fuzz/format-fuzzer.options
Normal file
@@ -0,0 +1,2 @@
|
||||
[libfuzzer]
|
||||
max_len = 2048
|
||||
79
fuzz/style-fuzzer.c
Normal file
79
fuzz/style-fuzzer.c
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2026 David Korczynski <david@adalogics.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Fuzz the tmux style parser (style_parse).
|
||||
*
|
||||
* This exercises:
|
||||
* - style.c (style string parsing, alignment, ranges)
|
||||
* - colour.c (colour name, RGB, and indexed colour parsing)
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
struct event_base *libevent;
|
||||
|
||||
int
|
||||
LLVMFuzzerTestOneInput(const u_char *data, size_t size)
|
||||
{
|
||||
struct style sy;
|
||||
struct grid_cell gc;
|
||||
char *buf;
|
||||
|
||||
if (size > 512 || size == 0)
|
||||
return 0;
|
||||
|
||||
/* Null-terminate the input for style_parse. */
|
||||
buf = malloc(size + 1);
|
||||
if (buf == NULL)
|
||||
return 0;
|
||||
memcpy(buf, data, size);
|
||||
buf[size] = '\0';
|
||||
|
||||
memset(&gc, 0, sizeof gc);
|
||||
style_set(&sy, &gc);
|
||||
|
||||
style_parse(&sy, &gc, buf);
|
||||
|
||||
free(buf);
|
||||
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();
|
||||
socket_path = xstrdup("dummy");
|
||||
|
||||
return 0;
|
||||
}
|
||||
73
fuzz/style-fuzzer.dict
Normal file
73
fuzz/style-fuzzer.dict
Normal file
@@ -0,0 +1,73 @@
|
||||
# Style attributes
|
||||
"default"
|
||||
"ignore"
|
||||
"nodefaults"
|
||||
"bright"
|
||||
"bold"
|
||||
"dim"
|
||||
"underscore"
|
||||
"blink"
|
||||
"reverse"
|
||||
"hidden"
|
||||
"italics"
|
||||
"overline"
|
||||
"strikethrough"
|
||||
"double-underscore"
|
||||
"curly-underscore"
|
||||
"dotted-underscore"
|
||||
"dashed-underscore"
|
||||
"nobright"
|
||||
"nobold"
|
||||
"nodim"
|
||||
"nounderscore"
|
||||
"noblink"
|
||||
"noreverse"
|
||||
"nohidden"
|
||||
"noitalics"
|
||||
"nooverline"
|
||||
"nostrikethrough"
|
||||
|
||||
# Colours
|
||||
"fg="
|
||||
"bg="
|
||||
"us="
|
||||
"fill="
|
||||
"colour0"
|
||||
"colour255"
|
||||
"red"
|
||||
"green"
|
||||
"blue"
|
||||
"yellow"
|
||||
"cyan"
|
||||
"magenta"
|
||||
"white"
|
||||
"black"
|
||||
|
||||
# RGB and hex
|
||||
"#ff0000"
|
||||
"#00ff00"
|
||||
"#0000ff"
|
||||
|
||||
# Alignment and ranges
|
||||
"align=left"
|
||||
"align=centre"
|
||||
"align=right"
|
||||
"align=absolute-centre"
|
||||
"list=on"
|
||||
"list=focus"
|
||||
"list=left-marker"
|
||||
"list=right-marker"
|
||||
"range=left"
|
||||
"range=right"
|
||||
"range=pane"
|
||||
"range=window"
|
||||
"range=session"
|
||||
"range=user"
|
||||
|
||||
# Width and padding
|
||||
"width="
|
||||
"pad="
|
||||
|
||||
# Delimiters
|
||||
","
|
||||
" "
|
||||
2
fuzz/style-fuzzer.options
Normal file
2
fuzz/style-fuzzer.options
Normal file
@@ -0,0 +1,2 @@
|
||||
[libfuzzer]
|
||||
max_len = 512
|
||||
10
grid.c
10
grid.c
@@ -200,7 +200,7 @@ grid_adjust_lines(struct grid *gd, u_int lines)
|
||||
|
||||
/* Copy default into a cell. */
|
||||
static void
|
||||
grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg)
|
||||
grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg, int moved)
|
||||
{
|
||||
struct grid_line *gl = &gd->linedata[py];
|
||||
struct grid_cell_entry *gce = &gl->celldata[px];
|
||||
@@ -209,7 +209,7 @@ grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg)
|
||||
int had_extd = (gce->flags & GRID_FLAG_EXTENDED);
|
||||
|
||||
memcpy(gce, &grid_cleared_entry, sizeof *gce);
|
||||
if (had_extd && old_offset < gl->extdsize) {
|
||||
if (!moved && had_extd && old_offset < gl->extdsize) {
|
||||
gce->flags |= GRID_FLAG_EXTENDED;
|
||||
gce->offset = old_offset;
|
||||
gee = grid_extended_cell(gl, gce, &grid_cleared_cell);
|
||||
@@ -515,7 +515,7 @@ grid_expand_line(struct grid *gd, u_int py, u_int sx, u_int bg)
|
||||
(sx - gl->cellsize) * sizeof *gl->celldata);
|
||||
}
|
||||
for (xx = gl->cellsize; xx < sx; xx++)
|
||||
grid_clear_cell(gd, xx, py, bg);
|
||||
grid_clear_cell(gd, xx, py, bg, 0);
|
||||
gl->cellsize = sx;
|
||||
}
|
||||
|
||||
@@ -683,7 +683,7 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny, u_int bg)
|
||||
|
||||
grid_expand_line(gd, yy, px + ox, 8); /* default bg first */
|
||||
for (xx = px; xx < px + ox; xx++)
|
||||
grid_clear_cell(gd, xx, yy, bg);
|
||||
grid_clear_cell(gd, xx, yy, bg, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -777,7 +777,7 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx,
|
||||
for (xx = px; xx < px + nx; xx++) {
|
||||
if (xx >= dx && xx < dx + nx)
|
||||
continue;
|
||||
grid_clear_cell(gd, xx, py, bg);
|
||||
grid_clear_cell(gd, xx, py, bg, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -487,9 +487,9 @@ static void
|
||||
sixel_print_add(char **buf, size_t *len, size_t *used, const char *s,
|
||||
size_t slen)
|
||||
{
|
||||
if (*used + slen >= *len + 1) {
|
||||
while (*used + slen >= *len + 1) {
|
||||
*buf = xreallocarray(*buf, 2, *len);
|
||||
(*len) *= 2;
|
||||
*buf = xrealloc(*buf, *len);
|
||||
}
|
||||
memcpy(*buf + *used, s, slen);
|
||||
(*used) += slen;
|
||||
|
||||
@@ -673,8 +673,7 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key)
|
||||
}
|
||||
|
||||
/* Ignore internal function key codes. */
|
||||
if ((key >= KEYC_BASE && key < KEYC_BASE_END) ||
|
||||
(key >= KEYC_USER && key < KEYC_USER_END)) {
|
||||
if (KEYC_IS_USER(key) || KEYC_IS_SPECIAL(key) || KEYC_IS_MOUSE(key)) {
|
||||
log_debug("%s: ignoring key 0x%llx", __func__, key);
|
||||
return (0);
|
||||
}
|
||||
|
||||
57
input.c
57
input.c
@@ -164,6 +164,7 @@ 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_9(struct input_ctx *, const char *);
|
||||
static void input_osc_10(struct input_ctx *, const char *);
|
||||
static void input_osc_11(struct input_ctx *, const char *);
|
||||
static void input_osc_12(struct input_ctx *, const char *);
|
||||
@@ -2673,6 +2674,9 @@ input_exit_osc(struct input_ctx *ictx)
|
||||
case 8:
|
||||
input_osc_8(ictx, p);
|
||||
break;
|
||||
case 9:
|
||||
input_osc_9(ictx, p);
|
||||
break;
|
||||
case 10:
|
||||
input_osc_10(ictx, p);
|
||||
break;
|
||||
@@ -2941,6 +2945,57 @@ bad:
|
||||
free(id);
|
||||
}
|
||||
|
||||
/* Helper to handle setting the progress bar and redrawing. */
|
||||
static void
|
||||
input_set_progress_bar(struct input_ctx *ictx, enum progress_bar_state state,
|
||||
int p)
|
||||
{
|
||||
screen_set_progress_bar(ictx->ctx.s, state, p);
|
||||
if (ictx->wp != NULL) {
|
||||
server_redraw_window_borders(ictx->wp->window);
|
||||
server_status_window(ictx->wp->window);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle the OSC 9;4 sequence for progress bars. */
|
||||
static void
|
||||
input_osc_9(struct input_ctx *ictx, const char *p)
|
||||
{
|
||||
const char *pb = p;
|
||||
enum progress_bar_state state;
|
||||
int progress = 0;
|
||||
|
||||
if (*pb++ != '4')
|
||||
return;
|
||||
if (*pb == '\0' || (*pb == ';' && pb[1] == '\0'))
|
||||
return;
|
||||
|
||||
if (*pb++ != ';')
|
||||
return;
|
||||
if (*pb < '0' || *pb > '4')
|
||||
goto bad;
|
||||
state = *pb++ - '0';
|
||||
|
||||
if (*pb == '\0' || (*pb == ';' && pb[1] == '\0')) {
|
||||
input_set_progress_bar(ictx, state, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (*pb++ != ';')
|
||||
goto bad;
|
||||
while (*pb >= '0' && *pb <= '9') {
|
||||
if (progress > 100)
|
||||
goto bad;
|
||||
progress = progress * 10 + *pb++ - '0';
|
||||
}
|
||||
if (*pb != '\0' || progress < 0 || progress > 100)
|
||||
goto bad;
|
||||
input_set_progress_bar(ictx, state, progress);
|
||||
return;
|
||||
|
||||
bad:
|
||||
log_debug("bad OSC 9;4 %s", p);
|
||||
}
|
||||
|
||||
/* Handle the OSC 10 sequence for setting and querying foreground colour. */
|
||||
static void
|
||||
@@ -3151,7 +3206,7 @@ input_osc_52_parse(struct input_ctx *ictx, const char *p, u_char **out,
|
||||
return (0);
|
||||
}
|
||||
|
||||
len = (strlen(end) / 4) * 3;
|
||||
len = ((strlen(end) + 3) / 4) * 3;
|
||||
if (len == 0)
|
||||
return (0);
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ key_string_search_table(const char *string)
|
||||
return (key_string_table[i].key);
|
||||
}
|
||||
|
||||
if (sscanf(string, "User%u", &user) == 1 && user < KEYC_NUSER)
|
||||
if (sscanf(string, "User%u", &user) == 1 && user <= KEYC_NUSER)
|
||||
return (KEYC_USER + user);
|
||||
|
||||
return (KEYC_UNKNOWN);
|
||||
@@ -418,7 +418,7 @@ key_string_lookup_key(key_code key, int with_flags)
|
||||
s = "MouseMoveBorder";
|
||||
goto append;
|
||||
}
|
||||
if (key >= KEYC_USER && key < KEYC_USER_END) {
|
||||
if (KEYC_IS_USER(key)) {
|
||||
snprintf(tmp, sizeof tmp, "User%u", (u_int)(key - KEYC_USER));
|
||||
strlcat(out, tmp, sizeof out);
|
||||
goto out;
|
||||
|
||||
@@ -91,7 +91,7 @@ static const char *options_table_window_size_list[] = {
|
||||
"largest", "smallest", "manual", "latest", NULL
|
||||
};
|
||||
static const char *options_table_remain_on_exit_list[] = {
|
||||
"off", "on", "failed", "keypress", NULL
|
||||
"off", "on", "failed", "key", NULL
|
||||
};
|
||||
static const char *options_table_destroy_unattached_list[] = {
|
||||
"off", "on", "keep-last", "keep-group", NULL
|
||||
@@ -1429,8 +1429,9 @@ const struct options_table_entry options_table[] = {
|
||||
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
||||
.choices = options_table_remain_on_exit_list,
|
||||
.default_num = 0,
|
||||
.text = "Whether panes should remain ('on') or be automatically "
|
||||
"killed ('off' or 'failed') when the program inside exits."
|
||||
.text = "Whether panes should remain ('on'), remain until a key is "
|
||||
"pressed ('key') or be automatically killed ('off' or "
|
||||
"'failed') when the program inside exits."
|
||||
},
|
||||
|
||||
{ .name = "remain-on-exit-format",
|
||||
|
||||
4
regsub.c
4
regsub.c
@@ -41,7 +41,7 @@ regsub_expand(char **buf, ssize_t *len, const char *with, const char *text,
|
||||
u_int i;
|
||||
|
||||
for (cp = with; *cp != '\0'; cp++) {
|
||||
if (*cp == '\\') {
|
||||
if (cp[0] == '\\' && cp[1] != '\0') {
|
||||
cp++;
|
||||
if (*cp >= '0' && *cp <= '9') {
|
||||
i = *cp - '0';
|
||||
@@ -68,6 +68,8 @@ regsub(const char *pattern, const char *with, const char *text, int flags)
|
||||
|
||||
if (*text == '\0')
|
||||
return (xstrdup(""));
|
||||
if (*pattern == '\0')
|
||||
return (xstrdup(text));
|
||||
if (regcomp(&r, pattern, flags) != 0)
|
||||
return (NULL);
|
||||
|
||||
|
||||
@@ -602,6 +602,7 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp,
|
||||
struct grid_cell gc;
|
||||
const char *fmt, *border_opt;
|
||||
struct format_tree *ft;
|
||||
struct style_line_entry *sle = &wp->border_status_line;
|
||||
char *expanded;
|
||||
int pane_status = rctx->pane_status, sb_w = 0;
|
||||
int pane_scrollbars = rctx->pane_scrollbars;
|
||||
@@ -660,12 +661,15 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp,
|
||||
gc.attr &= ~GRID_ATTR_CHARSET;
|
||||
|
||||
screen_write_cursormove(&ctx, 0, 0, 0);
|
||||
format_draw(&ctx, &gc, width, expanded, NULL, 0);
|
||||
screen_write_stop(&ctx);
|
||||
style_ranges_free(&sle->ranges);
|
||||
format_draw(&ctx, &gc, width, expanded, &sle->ranges, 0);
|
||||
|
||||
free(expanded);
|
||||
screen_write_stop(&ctx);
|
||||
format_free(ft);
|
||||
|
||||
free(sle->expanded);
|
||||
sle->expanded = expanded;
|
||||
|
||||
if (grid_compare(wp->status_screen.grid, old.grid) == 0) {
|
||||
screen_free(&old);
|
||||
return (0);
|
||||
|
||||
19
screen.c
19
screen.c
@@ -131,6 +131,7 @@ screen_reinit(struct screen *s)
|
||||
image_free_all(s);
|
||||
#endif
|
||||
|
||||
screen_set_progress_bar(s, PROGRESS_BAR_HIDDEN, 0);
|
||||
screen_reset_hyperlinks(s);
|
||||
}
|
||||
|
||||
@@ -296,6 +297,19 @@ screen_pop_title(struct screen *s)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the progress bar state and progress. The progress will not be updated
|
||||
* if p is negative.
|
||||
*/
|
||||
void
|
||||
screen_set_progress_bar(struct screen *s, enum progress_bar_state pbs, int p)
|
||||
{
|
||||
s->progress_bar.state = pbs;
|
||||
if (p >= 0 && pbs != PROGRESS_BAR_INDETERMINATE)
|
||||
s->progress_bar.progress = p;
|
||||
}
|
||||
|
||||
|
||||
/* Resize screen with options. */
|
||||
void
|
||||
screen_resize_cursor(struct screen *s, u_int sx, u_int sy, int reflow,
|
||||
@@ -772,8 +786,9 @@ screen_mode_to_string(int mode)
|
||||
return (tmp);
|
||||
}
|
||||
|
||||
/* Convert screen to a string. */
|
||||
const char *
|
||||
screen_print(struct screen *s)
|
||||
screen_print(struct screen *s, int line)
|
||||
{
|
||||
static char *buf;
|
||||
static size_t len = 16384;
|
||||
@@ -789,6 +804,8 @@ screen_print(struct screen *s)
|
||||
buf = xmalloc(len);
|
||||
|
||||
for (y = 0; y < screen_hsize(s) + s->grid->sy; y++) {
|
||||
if (line >= 0 && y != (u_int)line)
|
||||
continue;
|
||||
n = snprintf(buf + last, len - last, "%.4d \"", y);
|
||||
if (n <= 0 || (u_int)n >= len - last)
|
||||
goto out;
|
||||
|
||||
1551
server-client.c
1551
server-client.c
File diff suppressed because it is too large
Load Diff
@@ -339,14 +339,13 @@ server_destroy_pane(struct window_pane *wp, int notify)
|
||||
switch (remain_on_exit) {
|
||||
case 0:
|
||||
break;
|
||||
case 3: /* keypress — fall through to draw remain-on-exit-format message */
|
||||
/* FALLTHROUGH */
|
||||
case 2:
|
||||
if (remain_on_exit == 2 &&
|
||||
WIFEXITED(wp->status) && WEXITSTATUS(wp->status) == 0)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
case 1:
|
||||
case 3:
|
||||
if (wp->flags & PANE_STATUSDRAWN)
|
||||
return;
|
||||
wp->flags |= PANE_STATUSDRAWN;
|
||||
|
||||
1
sort.c
1
sort.c
@@ -505,6 +505,7 @@ sort_get_panes_session(struct session *s, u_int *n,
|
||||
|
||||
i = 0;
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
w = wl->window;
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if (lsz <= i) {
|
||||
lsz += 100;
|
||||
|
||||
27
status.c
27
status.c
@@ -284,27 +284,10 @@ struct style_range *
|
||||
status_get_range(struct client *c, u_int x, u_int y)
|
||||
{
|
||||
struct status_line *sl = &c->status;
|
||||
struct style_range *sr;
|
||||
|
||||
if (y >= nitems(sl->entries))
|
||||
return (NULL);
|
||||
TAILQ_FOREACH(sr, &sl->entries[y].ranges, entry) {
|
||||
if (x >= sr->start && x < sr->end)
|
||||
return (sr);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Free all ranges. */
|
||||
static void
|
||||
status_free_ranges(struct style_ranges *srs)
|
||||
{
|
||||
struct style_range *sr, *sr1;
|
||||
|
||||
TAILQ_FOREACH_SAFE(sr, srs, entry, sr1) {
|
||||
TAILQ_REMOVE(srs, sr, entry);
|
||||
free(sr);
|
||||
}
|
||||
return (style_ranges_get_range(&sl->entries[y].ranges, x));
|
||||
}
|
||||
|
||||
/* Save old status line. */
|
||||
@@ -341,7 +324,7 @@ status_init(struct client *c)
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < nitems(sl->entries); i++)
|
||||
TAILQ_INIT(&sl->entries[i].ranges);
|
||||
style_ranges_init(&sl->entries[i].ranges);
|
||||
|
||||
screen_init(&sl->screen, c->tty.sx, 1, 0);
|
||||
sl->active = &sl->screen;
|
||||
@@ -355,7 +338,7 @@ status_free(struct client *c)
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < nitems(sl->entries); i++) {
|
||||
status_free_ranges(&sl->entries[i].ranges);
|
||||
style_ranges_free(&sl->entries[i].ranges);
|
||||
free((void *)sl->entries[i].expanded);
|
||||
}
|
||||
|
||||
@@ -374,7 +357,7 @@ int
|
||||
status_redraw(struct client *c)
|
||||
{
|
||||
struct status_line *sl = &c->status;
|
||||
struct status_line_entry *sle;
|
||||
struct style_line_entry *sle;
|
||||
struct session *s = c->session;
|
||||
struct screen_write_ctx ctx;
|
||||
struct grid_cell gc;
|
||||
@@ -454,7 +437,7 @@ status_redraw(struct client *c)
|
||||
screen_write_putc(&ctx, &gc, ' ');
|
||||
screen_write_cursormove(&ctx, 0, i, 0);
|
||||
|
||||
status_free_ranges(&sle->ranges);
|
||||
style_ranges_free(&sle->ranges);
|
||||
format_draw(&ctx, &gc, width, expanded, &sle->ranges,
|
||||
0);
|
||||
|
||||
|
||||
47
style.c
47
style.c
@@ -137,6 +137,15 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
|
||||
sy->range_type = STYLE_RANGE_RIGHT;
|
||||
sy->range_argument = 0;
|
||||
style_set_range_string(sy, "");
|
||||
} else if (strcasecmp(tmp + 6, "control") == 0) {
|
||||
if (found == NULL)
|
||||
goto error;
|
||||
n = strtonum(found, 0, 9, &errstr);
|
||||
if (errstr != NULL)
|
||||
goto error;
|
||||
sy->range_type = STYLE_RANGE_CONTROL;
|
||||
sy->range_argument = n;
|
||||
style_set_range_string(sy, "");
|
||||
} else if (strcasecmp(tmp + 6, "pane") == 0) {
|
||||
if (found == NULL)
|
||||
goto error;
|
||||
@@ -426,8 +435,10 @@ style_copy(struct style *dst, struct style *src)
|
||||
memcpy(dst, src, sizeof *dst);
|
||||
}
|
||||
|
||||
/* Set scrollbar style from an option. */
|
||||
void
|
||||
style_set_scrollbar_style_from_option(struct style *sb_style, struct options *oo)
|
||||
style_set_scrollbar_style_from_option(struct style *sb_style,
|
||||
struct options *oo)
|
||||
{
|
||||
struct style *sy;
|
||||
|
||||
@@ -446,3 +457,37 @@ style_set_scrollbar_style_from_option(struct style *sb_style, struct options *oo
|
||||
utf8_set(&sb_style->gc.data, PANE_SCROLLBARS_CHARACTER);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize style ranges. */
|
||||
void
|
||||
style_ranges_init(struct style_ranges *srs)
|
||||
{
|
||||
TAILQ_INIT(srs);
|
||||
}
|
||||
|
||||
/* Free style ranges. */
|
||||
void
|
||||
style_ranges_free(struct style_ranges *srs)
|
||||
{
|
||||
struct style_range *sr, *sr1;
|
||||
|
||||
TAILQ_FOREACH_SAFE(sr, srs, entry, sr1) {
|
||||
TAILQ_REMOVE(srs, sr, entry);
|
||||
free(sr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get range for position from style ranges. */
|
||||
struct style_range *
|
||||
style_ranges_get_range(struct style_ranges *srs, u_int x)
|
||||
{
|
||||
struct style_range *sr;
|
||||
|
||||
if (srs == NULL)
|
||||
return (NULL);
|
||||
TAILQ_FOREACH(sr, srs, entry) {
|
||||
if (x >= sr->start && x < sr->end)
|
||||
return (sr);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
31
tmux.1
31
tmux.1
@@ -5769,7 +5769,7 @@ uses when the colour with that index is requested.
|
||||
The index may be from zero to 255.
|
||||
.Pp
|
||||
.It Xo Ic remain\-on\-exit
|
||||
.Op Ic on | off | failed | keypress
|
||||
.Op Ic on | off | failed | key
|
||||
.Xc
|
||||
A pane with this flag set is not destroyed when the program running in it
|
||||
exits.
|
||||
@@ -5777,9 +5777,8 @@ If set to
|
||||
.Ic failed ,
|
||||
then only when the program exit status is not zero.
|
||||
If set to
|
||||
.Ic keypress ,
|
||||
the pane stays open and closes when the user presses any key (other than
|
||||
a mouse button or paste).
|
||||
.Ic key ,
|
||||
the pane stays open and closes when a key is pressed.
|
||||
The pane may be reactivated with the
|
||||
.Ic respawn\-pane
|
||||
command.
|
||||
@@ -6013,8 +6012,13 @@ and a location suffix, one of the following:
|
||||
.It Li "ScrollbarSlider" Ta "the scrollbar slider"
|
||||
.It Li "ScrollbarUp" Ta "above the scrollbar slider"
|
||||
.It Li "ScrollbarDown" Ta "below the scrollbar slider"
|
||||
.It Li "ControlN" Ta "on control range N"
|
||||
.El
|
||||
.Pp
|
||||
See the
|
||||
.Sx STYLES
|
||||
section for information on control ranges.
|
||||
.Pp
|
||||
The following mouse events are available:
|
||||
.Bl -column "MouseDown1" "MouseDrag1" "WheelDown" -offset indent
|
||||
.It Li "WheelUp" Ta "WheelDown" Ta ""
|
||||
@@ -6475,6 +6479,7 @@ The following variables are available, where appropriate:
|
||||
.It Li "alternate_on" Ta "" Ta "1 if pane is in alternate screen"
|
||||
.It Li "alternate_saved_x" Ta "" Ta "Saved cursor X in alternate screen"
|
||||
.It Li "alternate_saved_y" Ta "" Ta "Saved cursor Y in alternate screen"
|
||||
.It Li "bracket_paste_flag" Ta "" Ta "Pane bracketed paste flag"
|
||||
.It Li "buffer_created" Ta "" Ta "Time buffer created"
|
||||
.It Li "buffer_full" Ta "" Ta "Full buffer content"
|
||||
.It Li "buffer_name" Ta "" Ta "Name of buffer"
|
||||
@@ -6600,6 +6605,8 @@ The following variables are available, where appropriate:
|
||||
.It Li "pane_pid" Ta "" Ta "PID of first process in pane"
|
||||
.It Li "pane_pipe" Ta "" Ta "1 if pane is being piped"
|
||||
.It Li "pane_pipe_pid" Ta "" Ta "PID of pipe process, if any"
|
||||
.It Li "pane_pb_state" Ta "" Ta "Pane progress bar state, one of hidden, normal, error, indeterminate, paused (can be set by application)"
|
||||
.It Li "pane_pb_progress" Ta "" Ta "Pane progress bar progress percentage (can be set by application)"
|
||||
.It Li "pane_right" Ta "" Ta "Right of pane"
|
||||
.It Li "pane_search_string" Ta "" Ta "Last search string in copy mode"
|
||||
.It Li "pane_start_command" Ta "" Ta "Command pane started with"
|
||||
@@ -6828,6 +6835,7 @@ replaces the previous saved default).
|
||||
.Ic range=window|X ,
|
||||
.Ic range=pane|X ,
|
||||
.Ic range=user|X ,
|
||||
.Ic range=control|N ,
|
||||
.Ic norange
|
||||
.Xc
|
||||
Mark a range for mouse events in the
|
||||
@@ -6874,6 +6882,19 @@ will be available in the
|
||||
format variable.
|
||||
.Ql X
|
||||
must be at most 15 bytes in length.
|
||||
.Pp
|
||||
.Ic range=control|N
|
||||
is a set of ranges for users to define custom behavior.
|
||||
.Ql N
|
||||
can be 0 through 9.
|
||||
When a mouse event occurs in the
|
||||
.Ic range=control|N
|
||||
range, the
|
||||
.Ql ControlN
|
||||
key binding is triggered.
|
||||
See
|
||||
.Sx MOUSE SUPPORT
|
||||
for details.
|
||||
.It Ic set\-default
|
||||
Set the current colours and attributes as the default, overwriting any previous
|
||||
default.
|
||||
@@ -7403,7 +7424,7 @@ If
|
||||
is not given, the
|
||||
.Ic display\-time
|
||||
option is used; a delay of zero waits for a key press.
|
||||
.Ql N
|
||||
.Fl N
|
||||
ignores key presses and closes only after the delay expires.
|
||||
If
|
||||
.Fl C
|
||||
|
||||
299
tmux.h
299
tmux.h
@@ -129,18 +129,6 @@ struct winlink;
|
||||
#define VISUAL_ON 1
|
||||
#define VISUAL_BOTH 2
|
||||
|
||||
/* No key or unknown key. */
|
||||
#define KEYC_NONE 0x000ff000000000ULL
|
||||
#define KEYC_UNKNOWN 0x000fe000000000ULL
|
||||
|
||||
/*
|
||||
* Base for special (that is, not Unicode) keys. An enum must be at most a
|
||||
* signed int, so these are based in the highest Unicode PUA.
|
||||
*/
|
||||
#define KEYC_BASE 0x0000000010e000ULL
|
||||
#define KEYC_USER 0x0000000010f000ULL
|
||||
#define KEYC_USER_END (KEYC_USER + KEYC_NUSER)
|
||||
|
||||
/* Key modifier bits. */
|
||||
#define KEYC_META 0x00100000000000ULL
|
||||
#define KEYC_CTRL 0x00200000000000ULL
|
||||
@@ -156,45 +144,122 @@ struct winlink;
|
||||
#define KEYC_SENT 0x40000000000000ULL
|
||||
|
||||
/* Masks for key bits. */
|
||||
#define KEYC_MASK_MODIFIERS 0x00f00000000000ULL
|
||||
#define KEYC_MASK_TYPE 0x0000ff00000000ULL
|
||||
#define KEYC_MASK_MODIFIERS 0x00ff0000000000ULL
|
||||
#define KEYC_MASK_FLAGS 0xff000000000000ULL
|
||||
#define KEYC_MASK_KEY 0x000fffffffffffULL
|
||||
#define KEYC_MASK_KEY 0x0000ffffffffffULL
|
||||
|
||||
/* Available user keys. */
|
||||
#define KEYC_NUSER 1000
|
||||
#define KEYC_NUSER 1000
|
||||
#define KEYC_SHIFT_TYPE(t) ((unsigned long long)(t) << 32)
|
||||
#define KEYC_IS_TYPE(k, t) (((k) & KEYC_MASK_TYPE) == KEYC_SHIFT_TYPE(t))
|
||||
enum key_code_type {
|
||||
KEYC_TYPE_UNICODE,
|
||||
KEYC_TYPE_USER,
|
||||
KEYC_TYPE_FUNCTION,
|
||||
KEYC_TYPE_MOUSEMOVE,
|
||||
KEYC_TYPE_MOUSEDOWN,
|
||||
KEYC_TYPE_MOUSEUP,
|
||||
KEYC_TYPE_MOUSEDRAG,
|
||||
KEYC_TYPE_MOUSEDRAGEND,
|
||||
KEYC_TYPE_WHEELDOWN,
|
||||
KEYC_TYPE_WHEELUP,
|
||||
KEYC_TYPE_SECONDCLICK,
|
||||
KEYC_TYPE_DOUBLECLICK,
|
||||
KEYC_TYPE_TRIPLECLICK,
|
||||
KEYC_TYPE_NOTYPE /* end */
|
||||
};
|
||||
|
||||
/* Is this a mouse key? */
|
||||
#define KEYC_IS_MOUSE(key) \
|
||||
(((key) & KEYC_MASK_KEY) >= KEYC_MOUSE && \
|
||||
((key) & KEYC_MASK_KEY) < KEYC_BSPACE)
|
||||
enum key_code_mouse_location {
|
||||
KEYC_MOUSE_LOCATION_PANE,
|
||||
KEYC_MOUSE_LOCATION_STATUS,
|
||||
KEYC_MOUSE_LOCATION_STATUS_LEFT,
|
||||
KEYC_MOUSE_LOCATION_STATUS_RIGHT,
|
||||
KEYC_MOUSE_LOCATION_STATUS_DEFAULT,
|
||||
KEYC_MOUSE_LOCATION_BORDER,
|
||||
KEYC_MOUSE_LOCATION_SCROLLBAR_UP,
|
||||
KEYC_MOUSE_LOCATION_SCROLLBAR_SLIDER,
|
||||
KEYC_MOUSE_LOCATION_SCROLLBAR_DOWN,
|
||||
KEYC_MOUSE_LOCATION_CONTROL0, /* keep order */
|
||||
KEYC_MOUSE_LOCATION_CONTROL1,
|
||||
KEYC_MOUSE_LOCATION_CONTROL2,
|
||||
KEYC_MOUSE_LOCATION_CONTROL3,
|
||||
KEYC_MOUSE_LOCATION_CONTROL4,
|
||||
KEYC_MOUSE_LOCATION_CONTROL5,
|
||||
KEYC_MOUSE_LOCATION_CONTROL6,
|
||||
KEYC_MOUSE_LOCATION_CONTROL7,
|
||||
KEYC_MOUSE_LOCATION_CONTROL8,
|
||||
KEYC_MOUSE_LOCATION_CONTROL9,
|
||||
KEYC_MOUSE_LOCATION_NOWHERE /* end */
|
||||
};
|
||||
|
||||
/* Is this a Unicode key? */
|
||||
#define KEYC_IS_UNICODE(key) \
|
||||
(((key) & KEYC_MASK_KEY) > 0x7f && \
|
||||
(((key) & KEYC_MASK_KEY) < KEYC_BASE || \
|
||||
((key) & KEYC_MASK_KEY) >= KEYC_BASE_END) && \
|
||||
(((key) & KEYC_MASK_KEY) < KEYC_USER || \
|
||||
((key) & KEYC_MASK_KEY) >= KEYC_USER_END))
|
||||
(((key) & KEYC_MASK_TYPE) == KEYC_SHIFT_TYPE(KEYC_TYPE_UNICODE) && \
|
||||
((key) & KEYC_MASK_KEY) > 0x7f)
|
||||
|
||||
/* Is this a user key? */
|
||||
#define KEYC_IS_USER(key) \
|
||||
(((key) & KEYC_MASK_TYPE) == KEYC_SHIFT_TYPE(KEYC_TYPE_USER))
|
||||
|
||||
/* Is this a function key? */
|
||||
#define KEYC_IS_SPECIAL(key) \
|
||||
(((key) & KEYC_MASK_TYPE) == KEYC_SHIFT_TYPE(KEYC_TYPE_FUNCTION))
|
||||
|
||||
/* Is this a mouse key? */
|
||||
#define KEYC_IS_MOUSE(key) \
|
||||
(((key) & KEYC_MASK_KEY) == KEYC_MOUSE || \
|
||||
(((key) & KEYC_MASK_TYPE) >= KEYC_SHIFT_TYPE(KEYC_TYPE_MOUSEMOVE) && \
|
||||
((key) & KEYC_MASK_TYPE) <= KEYC_SHIFT_TYPE(KEYC_TYPE_TRIPLECLICK)))
|
||||
|
||||
/* Is this a paste key? */
|
||||
#define KEYC_IS_PASTE(key) \
|
||||
(((key) & KEYC_MASK_KEY) == KEYC_PASTE_START || \
|
||||
((key) & KEYC_MASK_KEY) == KEYC_PASTE_END)
|
||||
(((key) & KEYC_MASK_TYPE) == KEYC_SHIFT_TYPE(KEYC_TYPE_FUNCTION) && \
|
||||
(((key) & KEYC_MASK_KEY) == KEYC_PASTE_START || \
|
||||
((key) & KEYC_MASK_KEY) == KEYC_PASTE_END))
|
||||
|
||||
/* Multiple click timeout. */
|
||||
#define KEYC_CLICK_TIMEOUT 300
|
||||
|
||||
/* Bit shift for mouse events. */
|
||||
#define KEYC_MOUSE_LOCATION_SHIFT 0
|
||||
#define KEYC_MOUSE_BUTTON_SHIFT 8
|
||||
|
||||
/* Mouse key codes. */
|
||||
#define KEYC_MOUSE_KEY(name) \
|
||||
KEYC_ ## name ## _PANE, \
|
||||
KEYC_ ## name ## _STATUS, \
|
||||
KEYC_ ## name ## _STATUS_LEFT, \
|
||||
KEYC_ ## name ## _STATUS_RIGHT, \
|
||||
KEYC_ ## name ## _STATUS_DEFAULT, \
|
||||
KEYC_ ## name ## _SCROLLBAR_UP, \
|
||||
KEYC_ ## name ## _SCROLLBAR_SLIDER, \
|
||||
KEYC_ ## name ## _SCROLLBAR_DOWN, \
|
||||
KEYC_ ## name ## _BORDER
|
||||
#define KEYC_MOUSE_KEYS(t) \
|
||||
KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, PANE), \
|
||||
KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, STATUS), \
|
||||
KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, STATUS_LEFT), \
|
||||
KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, STATUS_RIGHT), \
|
||||
KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, STATUS_DEFAULT), \
|
||||
KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, BORDER), \
|
||||
KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, SCROLLBAR_UP), \
|
||||
KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, SCROLLBAR_SLIDER), \
|
||||
KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, SCROLLBAR_DOWN), \
|
||||
KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL0), \
|
||||
KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL1), \
|
||||
KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL2), \
|
||||
KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL3), \
|
||||
KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL4), \
|
||||
KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL5), \
|
||||
KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL6), \
|
||||
KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL7), \
|
||||
KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL8), \
|
||||
KEYC_MOUSE_KEY(KEYC_ ## t, KEYC_TYPE_ ## t, CONTROL9)
|
||||
#define KEYC_MOUSE_KEY(p, t, l) \
|
||||
p ## _ ## l = KEYC_MAKE_MOUSE_KEY(t, 0, KEYC_MOUSE_LOCATION_ ## l), \
|
||||
p ## 1_ ## l = KEYC_MAKE_MOUSE_KEY(t, 1, KEYC_MOUSE_LOCATION_ ## l), \
|
||||
p ## 2_ ## l = KEYC_MAKE_MOUSE_KEY(t, 2, KEYC_MOUSE_LOCATION_ ## l), \
|
||||
p ## 3_ ## l = KEYC_MAKE_MOUSE_KEY(t, 3, KEYC_MOUSE_LOCATION_ ## l), \
|
||||
p ## 6_ ## l = KEYC_MAKE_MOUSE_KEY(t, 6, KEYC_MOUSE_LOCATION_ ## l), \
|
||||
p ## 7_ ## l = KEYC_MAKE_MOUSE_KEY(t, 7, KEYC_MOUSE_LOCATION_ ## l), \
|
||||
p ## 8_ ## l = KEYC_MAKE_MOUSE_KEY(t, 8, KEYC_MOUSE_LOCATION_ ## l), \
|
||||
p ## 9_ ## l = KEYC_MAKE_MOUSE_KEY(t, 9, KEYC_MOUSE_LOCATION_ ## l), \
|
||||
p ## 10_ ## l = KEYC_MAKE_MOUSE_KEY(t, 10, KEYC_MOUSE_LOCATION_ ## l), \
|
||||
p ## 11_ ## l = KEYC_MAKE_MOUSE_KEY(t, 11, KEYC_MOUSE_LOCATION_ ## l)
|
||||
#define KEYC_MAKE_MOUSE_KEY(t, b, l) \
|
||||
((KEYC_SHIFT_TYPE(t)) | \
|
||||
((unsigned long long)(b) << KEYC_MOUSE_BUTTON_SHIFT) | \
|
||||
((unsigned long long)(l) << KEYC_MOUSE_LOCATION_SHIFT))
|
||||
#define KEYC_MOUSE_STRING(name, s) \
|
||||
{ #s "Pane", KEYC_ ## name ## _PANE }, \
|
||||
{ #s "Status", KEYC_ ## name ## _STATUS }, \
|
||||
@@ -204,7 +269,17 @@ struct winlink;
|
||||
{ #s "ScrollbarUp", KEYC_ ## name ## _SCROLLBAR_UP }, \
|
||||
{ #s "ScrollbarSlider", KEYC_ ## name ## _SCROLLBAR_SLIDER }, \
|
||||
{ #s "ScrollbarDown", KEYC_ ## name ## _SCROLLBAR_DOWN }, \
|
||||
{ #s "Border", KEYC_ ## name ## _BORDER }
|
||||
{ #s "Border", KEYC_ ## name ## _BORDER }, \
|
||||
{ #s "Control0", KEYC_ ## name ## _CONTROL0 }, \
|
||||
{ #s "Control1", KEYC_ ## name ## _CONTROL1 }, \
|
||||
{ #s "Control2", KEYC_ ## name ## _CONTROL2 }, \
|
||||
{ #s "Control3", KEYC_ ## name ## _CONTROL3 }, \
|
||||
{ #s "Control4", KEYC_ ## name ## _CONTROL4 }, \
|
||||
{ #s "Control5", KEYC_ ## name ## _CONTROL5 }, \
|
||||
{ #s "Control6", KEYC_ ## name ## _CONTROL6 }, \
|
||||
{ #s "Control7", KEYC_ ## name ## _CONTROL7 }, \
|
||||
{ #s "Control8", KEYC_ ## name ## _CONTROL8 }, \
|
||||
{ #s "Control9", KEYC_ ## name ## _CONTROL9 }
|
||||
|
||||
/*
|
||||
* A single key. This can be ASCII or Unicode or one of the keys between
|
||||
@@ -250,8 +325,15 @@ enum {
|
||||
|
||||
/* Special key codes. */
|
||||
enum {
|
||||
/* User key code range. */
|
||||
KEYC_USER = KEYC_SHIFT_TYPE(KEYC_TYPE_USER),
|
||||
|
||||
/* Functional key code range. */
|
||||
KEYC_NONE = KEYC_SHIFT_TYPE(KEYC_TYPE_FUNCTION),
|
||||
KEYC_UNKNOWN,
|
||||
|
||||
/* Focus events. */
|
||||
KEYC_FOCUS_IN = KEYC_BASE,
|
||||
KEYC_FOCUS_IN,
|
||||
KEYC_FOCUS_OUT,
|
||||
|
||||
/* "Any" key, used if not found in key table. */
|
||||
@@ -261,77 +343,6 @@ enum {
|
||||
KEYC_PASTE_START,
|
||||
KEYC_PASTE_END,
|
||||
|
||||
/* Mouse keys. */
|
||||
KEYC_MOUSE, /* unclassified mouse event */
|
||||
KEYC_DRAGGING, /* dragging in progress */
|
||||
KEYC_DOUBLECLICK, /* double click complete */
|
||||
KEYC_MOUSE_KEY(MOUSEMOVE),
|
||||
KEYC_MOUSE_KEY(MOUSEDOWN1),
|
||||
KEYC_MOUSE_KEY(MOUSEDOWN2),
|
||||
KEYC_MOUSE_KEY(MOUSEDOWN3),
|
||||
KEYC_MOUSE_KEY(MOUSEDOWN6),
|
||||
KEYC_MOUSE_KEY(MOUSEDOWN7),
|
||||
KEYC_MOUSE_KEY(MOUSEDOWN8),
|
||||
KEYC_MOUSE_KEY(MOUSEDOWN9),
|
||||
KEYC_MOUSE_KEY(MOUSEDOWN10),
|
||||
KEYC_MOUSE_KEY(MOUSEDOWN11),
|
||||
KEYC_MOUSE_KEY(MOUSEUP1),
|
||||
KEYC_MOUSE_KEY(MOUSEUP2),
|
||||
KEYC_MOUSE_KEY(MOUSEUP3),
|
||||
KEYC_MOUSE_KEY(MOUSEUP6),
|
||||
KEYC_MOUSE_KEY(MOUSEUP7),
|
||||
KEYC_MOUSE_KEY(MOUSEUP8),
|
||||
KEYC_MOUSE_KEY(MOUSEUP9),
|
||||
KEYC_MOUSE_KEY(MOUSEUP10),
|
||||
KEYC_MOUSE_KEY(MOUSEUP11),
|
||||
KEYC_MOUSE_KEY(MOUSEDRAG1),
|
||||
KEYC_MOUSE_KEY(MOUSEDRAG2),
|
||||
KEYC_MOUSE_KEY(MOUSEDRAG3),
|
||||
KEYC_MOUSE_KEY(MOUSEDRAG6),
|
||||
KEYC_MOUSE_KEY(MOUSEDRAG7),
|
||||
KEYC_MOUSE_KEY(MOUSEDRAG8),
|
||||
KEYC_MOUSE_KEY(MOUSEDRAG9),
|
||||
KEYC_MOUSE_KEY(MOUSEDRAG10),
|
||||
KEYC_MOUSE_KEY(MOUSEDRAG11),
|
||||
KEYC_MOUSE_KEY(MOUSEDRAGEND1),
|
||||
KEYC_MOUSE_KEY(MOUSEDRAGEND2),
|
||||
KEYC_MOUSE_KEY(MOUSEDRAGEND3),
|
||||
KEYC_MOUSE_KEY(MOUSEDRAGEND6),
|
||||
KEYC_MOUSE_KEY(MOUSEDRAGEND7),
|
||||
KEYC_MOUSE_KEY(MOUSEDRAGEND8),
|
||||
KEYC_MOUSE_KEY(MOUSEDRAGEND9),
|
||||
KEYC_MOUSE_KEY(MOUSEDRAGEND10),
|
||||
KEYC_MOUSE_KEY(MOUSEDRAGEND11),
|
||||
KEYC_MOUSE_KEY(WHEELUP),
|
||||
KEYC_MOUSE_KEY(WHEELDOWN),
|
||||
KEYC_MOUSE_KEY(SECONDCLICK1),
|
||||
KEYC_MOUSE_KEY(SECONDCLICK2),
|
||||
KEYC_MOUSE_KEY(SECONDCLICK3),
|
||||
KEYC_MOUSE_KEY(SECONDCLICK6),
|
||||
KEYC_MOUSE_KEY(SECONDCLICK7),
|
||||
KEYC_MOUSE_KEY(SECONDCLICK8),
|
||||
KEYC_MOUSE_KEY(SECONDCLICK9),
|
||||
KEYC_MOUSE_KEY(SECONDCLICK10),
|
||||
KEYC_MOUSE_KEY(SECONDCLICK11),
|
||||
KEYC_MOUSE_KEY(DOUBLECLICK1),
|
||||
KEYC_MOUSE_KEY(DOUBLECLICK2),
|
||||
KEYC_MOUSE_KEY(DOUBLECLICK3),
|
||||
KEYC_MOUSE_KEY(DOUBLECLICK6),
|
||||
KEYC_MOUSE_KEY(DOUBLECLICK7),
|
||||
KEYC_MOUSE_KEY(DOUBLECLICK8),
|
||||
KEYC_MOUSE_KEY(DOUBLECLICK9),
|
||||
KEYC_MOUSE_KEY(DOUBLECLICK10),
|
||||
KEYC_MOUSE_KEY(DOUBLECLICK11),
|
||||
KEYC_MOUSE_KEY(TRIPLECLICK1),
|
||||
KEYC_MOUSE_KEY(TRIPLECLICK2),
|
||||
KEYC_MOUSE_KEY(TRIPLECLICK3),
|
||||
KEYC_MOUSE_KEY(TRIPLECLICK6),
|
||||
KEYC_MOUSE_KEY(TRIPLECLICK7),
|
||||
KEYC_MOUSE_KEY(TRIPLECLICK8),
|
||||
KEYC_MOUSE_KEY(TRIPLECLICK9),
|
||||
KEYC_MOUSE_KEY(TRIPLECLICK10),
|
||||
KEYC_MOUSE_KEY(TRIPLECLICK11),
|
||||
|
||||
/* Backspace key. */
|
||||
KEYC_BSPACE,
|
||||
|
||||
@@ -384,8 +395,22 @@ enum {
|
||||
KEYC_REPORT_DARK_THEME,
|
||||
KEYC_REPORT_LIGHT_THEME,
|
||||
|
||||
/* End of special keys. */
|
||||
KEYC_BASE_END
|
||||
/* Mouse state. */
|
||||
KEYC_MOUSE, /* unclassified mouse event */
|
||||
KEYC_DRAGGING, /* dragging in progress */
|
||||
KEYC_DOUBLECLICK, /* double click complete */
|
||||
|
||||
/* Mouse key code ranges. Must be at the end. */
|
||||
KEYC_MOUSE_KEYS(MOUSEMOVE),
|
||||
KEYC_MOUSE_KEYS(WHEELDOWN),
|
||||
KEYC_MOUSE_KEYS(WHEELUP),
|
||||
KEYC_MOUSE_KEYS(MOUSEDOWN),
|
||||
KEYC_MOUSE_KEYS(MOUSEUP),
|
||||
KEYC_MOUSE_KEYS(MOUSEDRAG),
|
||||
KEYC_MOUSE_KEYS(MOUSEDRAGEND),
|
||||
KEYC_MOUSE_KEYS(SECONDCLICK),
|
||||
KEYC_MOUSE_KEYS(DOUBLECLICK),
|
||||
KEYC_MOUSE_KEYS(TRIPLECLICK),
|
||||
};
|
||||
|
||||
/* Termcap codes. */
|
||||
@@ -880,7 +905,8 @@ enum style_range_type {
|
||||
STYLE_RANGE_PANE,
|
||||
STYLE_RANGE_WINDOW,
|
||||
STYLE_RANGE_SESSION,
|
||||
STYLE_RANGE_USER
|
||||
STYLE_RANGE_USER,
|
||||
STYLE_RANGE_CONTROL
|
||||
};
|
||||
struct style_range {
|
||||
enum style_range_type type;
|
||||
@@ -894,6 +920,12 @@ struct style_range {
|
||||
};
|
||||
TAILQ_HEAD(style_ranges, style_range);
|
||||
|
||||
/* Ranges connected with a status line. */
|
||||
struct style_line_entry {
|
||||
char *expanded;
|
||||
struct style_ranges ranges;
|
||||
};
|
||||
|
||||
/* Default style width and pad. */
|
||||
#define STYLE_WIDTH_DEFAULT -1
|
||||
#define STYLE_PAD_DEFAULT -1
|
||||
@@ -952,6 +984,20 @@ enum screen_cursor_style {
|
||||
SCREEN_CURSOR_BAR
|
||||
};
|
||||
|
||||
|
||||
/* Progress bar, OSC 9;4. */
|
||||
enum progress_bar_state {
|
||||
PROGRESS_BAR_HIDDEN = 0,
|
||||
PROGRESS_BAR_NORMAL = 1,
|
||||
PROGRESS_BAR_ERROR = 2,
|
||||
PROGRESS_BAR_INDETERMINATE = 3,
|
||||
PROGRESS_BAR_PAUSED = 4
|
||||
};
|
||||
struct progress_bar {
|
||||
enum progress_bar_state state;
|
||||
int progress;
|
||||
};
|
||||
|
||||
/* Virtual screen. */
|
||||
struct screen_sel;
|
||||
struct screen_titles;
|
||||
@@ -993,6 +1039,7 @@ struct screen {
|
||||
struct screen_write_cline *write_list;
|
||||
|
||||
struct hyperlinks *hyperlinks;
|
||||
struct progress_bar progress_bar;
|
||||
};
|
||||
|
||||
/* Screen write context. */
|
||||
@@ -1216,8 +1263,8 @@ struct window_pane {
|
||||
#define PANE_DROP 0x2
|
||||
#define PANE_FOCUSED 0x4
|
||||
#define PANE_VISITED 0x8
|
||||
/* 0x10 unused */
|
||||
/* 0x20 unused */
|
||||
#define PANE_ZOOMED 0x10
|
||||
#define PANE_FLOATING 0x20
|
||||
#define PANE_INPUTOFF 0x40
|
||||
#define PANE_CHANGED 0x80
|
||||
#define PANE_EXITED 0x100
|
||||
@@ -1228,9 +1275,7 @@ struct window_pane {
|
||||
#define PANE_THEMECHANGED 0x2000
|
||||
#define PANE_UNSEENCHANGES 0x4000
|
||||
#define PANE_REDRAWSCROLLBAR 0x8000
|
||||
#define PANE_FLOATING 0x10000
|
||||
#define PANE_MINIMISED 0x20000
|
||||
#define PANE_ZOOMED 0x40000
|
||||
#define PANE_SAVED_FLOAT 0x80000 /* saved_float_* fields are valid */
|
||||
|
||||
/* Last floating position/size, saved when the pane is tiled. */
|
||||
@@ -1268,6 +1313,7 @@ struct window_pane {
|
||||
struct grid_cell cached_active_gc;
|
||||
struct colour_palette palette;
|
||||
enum client_theme last_theme;
|
||||
struct style_line_entry border_status_line;
|
||||
|
||||
int pipe_fd;
|
||||
pid_t pipe_pid;
|
||||
@@ -1892,10 +1938,6 @@ struct cmd_entry {
|
||||
|
||||
/* Status line. */
|
||||
#define STATUS_LINES_LIMIT 5
|
||||
struct status_line_entry {
|
||||
char *expanded;
|
||||
struct style_ranges ranges;
|
||||
};
|
||||
struct status_line {
|
||||
struct event timer;
|
||||
|
||||
@@ -1904,7 +1946,7 @@ struct status_line {
|
||||
int references;
|
||||
|
||||
struct grid_cell style;
|
||||
struct status_line_entry entries[STATUS_LINES_LIMIT];
|
||||
struct style_line_entry entries[STATUS_LINES_LIMIT];
|
||||
};
|
||||
|
||||
/* Prompt type. */
|
||||
@@ -1969,6 +2011,7 @@ typedef void (*overlay_resize_cb)(struct client *, void *);
|
||||
struct client {
|
||||
const char *name;
|
||||
struct tmuxpeer *peer;
|
||||
const char *user;
|
||||
struct cmdq_list *queue;
|
||||
|
||||
struct client_windows windows;
|
||||
@@ -2009,7 +2052,7 @@ struct client {
|
||||
struct event repeat_timer;
|
||||
|
||||
struct event click_timer;
|
||||
int click_where;
|
||||
int click_loc;
|
||||
int click_wp;
|
||||
u_int click_button;
|
||||
struct mouse_event click_event;
|
||||
@@ -3312,6 +3355,7 @@ int screen_set_title(struct screen *, const char *);
|
||||
void screen_set_path(struct screen *, const char *);
|
||||
void screen_push_title(struct screen *);
|
||||
void screen_pop_title(struct screen *);
|
||||
void screen_set_progress_bar(struct screen *, enum progress_bar_state, int);
|
||||
void screen_resize(struct screen *, u_int, u_int, int);
|
||||
void screen_resize_cursor(struct screen *, u_int, u_int, int, int, int);
|
||||
void screen_set_selection(struct screen *, u_int, u_int, u_int, u_int,
|
||||
@@ -3324,7 +3368,7 @@ int screen_select_cell(struct screen *, struct grid_cell *,
|
||||
void screen_alternate_on(struct screen *, struct grid_cell *, int);
|
||||
void screen_alternate_off(struct screen *, struct grid_cell *, int);
|
||||
const char *screen_mode_to_string(int);
|
||||
const char *screen_print(struct screen *);
|
||||
const char *screen_print(struct screen *, int);
|
||||
|
||||
/* window.c */
|
||||
extern struct windows windows;
|
||||
@@ -3404,7 +3448,7 @@ int window_pane_exited(struct window_pane *);
|
||||
u_int window_pane_search(struct window_pane *, const char *, int,
|
||||
int);
|
||||
const char *window_printable_flags(struct winlink *, int);
|
||||
const char *window_pane_printable_flags(struct window_pane *, int);
|
||||
const char *window_pane_printable_flags(struct window_pane *);
|
||||
struct window_pane *window_pane_find_up(struct window_pane *);
|
||||
struct window_pane *window_pane_find_down(struct window_pane *);
|
||||
struct window_pane *window_pane_find_left(struct window_pane *);
|
||||
@@ -3435,6 +3479,8 @@ 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 *);
|
||||
struct style_range *window_pane_border_status_get_range(struct window_pane *,
|
||||
u_int, u_int);
|
||||
|
||||
/* layout.c */
|
||||
u_int layout_count_cells(struct layout_cell *);
|
||||
@@ -3756,6 +3802,9 @@ void style_set(struct style *, const struct grid_cell *);
|
||||
void style_copy(struct style *, struct style *);
|
||||
void style_set_scrollbar_style_from_option(struct style *,
|
||||
struct options *);
|
||||
void style_ranges_init(struct style_ranges *);
|
||||
void style_ranges_free(struct style_ranges *);
|
||||
struct style_range *style_ranges_get_range(struct style_ranges *, u_int);
|
||||
|
||||
/* spawn.c */
|
||||
struct winlink *spawn_window(struct spawn_context *, char **);
|
||||
|
||||
46
tty-draw.c
46
tty-draw.c
@@ -143,6 +143,14 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
|
||||
log_debug("%s: px=%u py=%u nx=%u atx=%u aty=%u", __func__, px, py, nx,
|
||||
atx, aty);
|
||||
|
||||
/* There is no point in drawing more than the end of the terminal. */
|
||||
if (atx >= tty->sx)
|
||||
return;
|
||||
if (atx + nx >= tty->sx)
|
||||
nx = tty->sx - atx;
|
||||
if (nx == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Clamp the width to cellsize - note this is not cellused, because
|
||||
* there may be empty background cells after it (from BCE).
|
||||
@@ -150,19 +158,24 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
|
||||
cellsize = grid_get_line(gd, gd->hsize + py)->cellsize;
|
||||
if (screen_size_x(s) > cellsize)
|
||||
ex = cellsize;
|
||||
else {
|
||||
else
|
||||
ex = screen_size_x(s);
|
||||
if (px > ex)
|
||||
return;
|
||||
if (px + nx > ex)
|
||||
nx = ex - px;
|
||||
}
|
||||
if (ex < nx)
|
||||
ex = nx;
|
||||
log_debug("%s: drawing %u-%u,%u (end %u) at %u,%u; defaults: fg=%d, "
|
||||
"bg=%d", __func__, px, px + nx, py, ex, atx, aty, defaults->fg,
|
||||
defaults->bg);
|
||||
|
||||
/* Turn off cursor while redrawing and reset region and margins. */
|
||||
flags = (tty->flags & TTY_NOCURSOR);
|
||||
tty->flags |= TTY_NOCURSOR;
|
||||
tty_update_mode(tty, tty->mode, s);
|
||||
tty_region_off(tty);
|
||||
tty_margin_off(tty);
|
||||
|
||||
/* Start with the default cell as the last cell. */
|
||||
memcpy(&last, &grid_default_cell, sizeof last);
|
||||
last.bg = defaults->bg;
|
||||
tty_default_attributes(tty, defaults, palette, 8, s->hyperlinks);
|
||||
|
||||
/*
|
||||
* If there is padding at the start, we must have truncated a wide
|
||||
* character. Clear it.
|
||||
@@ -195,7 +208,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
|
||||
log_debug("%s: clearing %u padding cells", __func__, cx);
|
||||
tty_draw_line_clear(tty, atx, aty, cx, defaults, bg, 0);
|
||||
if (cx == ex)
|
||||
return;
|
||||
goto out;
|
||||
atx += cx;
|
||||
px += cx;
|
||||
nx -= cx;
|
||||
@@ -209,18 +222,6 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
|
||||
wrapped = 1;
|
||||
}
|
||||
|
||||
/* Turn off cursor while redrawing and reset region and margins. */
|
||||
flags = (tty->flags & TTY_NOCURSOR);
|
||||
tty->flags |= TTY_NOCURSOR;
|
||||
tty_update_mode(tty, tty->mode, s);
|
||||
tty_region_off(tty);
|
||||
tty_margin_off(tty);
|
||||
|
||||
/* Start with the default cell as the last cell. */
|
||||
memcpy(&last, &grid_default_cell, sizeof last);
|
||||
last.bg = defaults->bg;
|
||||
tty_default_attributes(tty, defaults, palette, 8, s->hyperlinks);
|
||||
|
||||
/* Loop over each character in the range. */
|
||||
last_i = i = 0;
|
||||
len = 0;
|
||||
@@ -252,7 +253,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
|
||||
}
|
||||
|
||||
/* Work out the the empty width. */
|
||||
if (i >= ex)
|
||||
if (px >= ex || i >= ex - px)
|
||||
empty = 1;
|
||||
else if (gcp->bg != last.bg)
|
||||
empty = 0;
|
||||
@@ -331,6 +332,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
|
||||
i += gcp->data.width;
|
||||
}
|
||||
|
||||
out:
|
||||
tty->flags = (tty->flags & ~TTY_NOCURSOR)|flags;
|
||||
tty_update_mode(tty, tty->mode, s);
|
||||
}
|
||||
|
||||
@@ -474,23 +474,46 @@ tty_default_features(int *feat, const char *name, u_int version)
|
||||
#define TTY_FEATURES_BASE_MODERN_XTERM \
|
||||
"256,RGB,bpaste,clipboard,mouse,strikethrough,title"
|
||||
{ .name = "mintty",
|
||||
.features = TTY_FEATURES_BASE_MODERN_XTERM
|
||||
",ccolour,cstyle,extkeys,margins,overline,usstyle"
|
||||
.features = TTY_FEATURES_BASE_MODERN_XTERM ","
|
||||
"ccolour,"
|
||||
"cstyle,"
|
||||
"extkeys,"
|
||||
"margins,"
|
||||
"overline,"
|
||||
"usstyle"
|
||||
},
|
||||
{ .name = "tmux",
|
||||
.features = TTY_FEATURES_BASE_MODERN_XTERM
|
||||
",ccolour,cstyle,focus,overline,usstyle,hyperlinks"
|
||||
.features = TTY_FEATURES_BASE_MODERN_XTERM ","
|
||||
"ccolour,"
|
||||
"cstyle,"
|
||||
"extkeys,"
|
||||
"focus,"
|
||||
"overline,"
|
||||
"usstyle,"
|
||||
"hyperlinks"
|
||||
},
|
||||
{ .name = "rxvt-unicode",
|
||||
.features = "256,bpaste,ccolour,cstyle,mouse,title,ignorefkeys"
|
||||
.features = "256,"
|
||||
"bpaste,"
|
||||
"ccolour,"
|
||||
"cstyle,"
|
||||
"mouse,"
|
||||
"title,"
|
||||
"ignorefkeys"
|
||||
},
|
||||
{ .name = "iTerm2",
|
||||
.features = TTY_FEATURES_BASE_MODERN_XTERM
|
||||
",cstyle,extkeys,margins,usstyle,sync,osc7,hyperlinks"
|
||||
.features = TTY_FEATURES_BASE_MODERN_XTERM ","
|
||||
"cstyle,"
|
||||
"extkeys,"
|
||||
"margins,"
|
||||
"usstyle,"
|
||||
"sync,"
|
||||
"osc7,hyperlinks"
|
||||
},
|
||||
{ .name = "foot",
|
||||
.features = TTY_FEATURES_BASE_MODERN_XTERM
|
||||
",cstyle,extkeys"
|
||||
.features = TTY_FEATURES_BASE_MODERN_XTERM ","
|
||||
"cstyle,"
|
||||
"extkeys"
|
||||
},
|
||||
{ .name = "XTerm",
|
||||
/*
|
||||
@@ -498,8 +521,11 @@ tty_default_features(int *feat, const char *name, u_int version)
|
||||
* disabled so not set it here - they will be added if
|
||||
* secondary DA shows VT420.
|
||||
*/
|
||||
.features = TTY_FEATURES_BASE_MODERN_XTERM
|
||||
",ccolour,cstyle,extkeys,focus"
|
||||
.features = TTY_FEATURES_BASE_MODERN_XTERM ","
|
||||
"ccolour,"
|
||||
"cstyle,"
|
||||
"extkeys,"
|
||||
"focus"
|
||||
}
|
||||
};
|
||||
u_int i;
|
||||
|
||||
@@ -1383,7 +1383,7 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size)
|
||||
copy[end] = '\0';
|
||||
|
||||
/* Convert from base64. */
|
||||
needed = (end / 4) * 3;
|
||||
needed = ((end + 3) / 4) * 3;
|
||||
if (needed == 0) {
|
||||
free(copy);
|
||||
return (0);
|
||||
|
||||
@@ -1034,6 +1034,8 @@ window_copy_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
|
||||
|
||||
screen_resize(s, sx, sy, 0);
|
||||
cx = data->cx;
|
||||
if (data->oy > gd->hsize + data->cy)
|
||||
data->oy = gd->hsize + data->cy;
|
||||
cy = gd->hsize + data->cy - data->oy;
|
||||
reflow = (gd->sx != sx);
|
||||
if (reflow)
|
||||
@@ -2747,6 +2749,8 @@ window_copy_cmd_refresh_from_pane(struct window_copy_cmd_state *cs)
|
||||
|
||||
if (data->viewmode)
|
||||
return (WINDOW_COPY_CMD_NOTHING);
|
||||
if (data->oy > screen_hsize(data->backing))
|
||||
data->oy = screen_hsize(data->backing);
|
||||
oy_from_top = screen_hsize(data->backing) - data->oy;
|
||||
|
||||
screen_free(data->backing);
|
||||
@@ -3340,7 +3344,7 @@ window_copy_command(struct window_mode_entry *wme, struct client *c,
|
||||
enum window_copy_cmd_clear clear = WINDOW_COPY_CMD_CLEAR_NEVER;
|
||||
const char *command;
|
||||
u_int i, count = args_count(args);
|
||||
int keys;
|
||||
int keys, flags;
|
||||
char *error = NULL;
|
||||
|
||||
if (count == 0)
|
||||
@@ -3362,9 +3366,10 @@ window_copy_command(struct window_mode_entry *wme, struct client *c,
|
||||
action = WINDOW_COPY_CMD_NOTHING;
|
||||
for (i = 0; i < nitems(window_copy_cmd_table); i++) {
|
||||
if (strcmp(window_copy_cmd_table[i].command, command) == 0) {
|
||||
if (c->flags & CLIENT_READONLY &&
|
||||
(~window_copy_cmd_table[i].flags &
|
||||
WINDOW_COPY_CMD_FLAG_READONLY)) {
|
||||
flags = window_copy_cmd_table[i].flags;
|
||||
if (c != NULL &&
|
||||
c->flags & CLIENT_READONLY &&
|
||||
(~flags & WINDOW_COPY_CMD_FLAG_READONLY)) {
|
||||
status_message_set(c, -1, 1, 0, 0,
|
||||
"client is read-only");
|
||||
return;
|
||||
|
||||
48
window.c
48
window.c
@@ -653,10 +653,10 @@ struct window_pane *
|
||||
window_get_active_at(struct window *w, u_int x, u_int y)
|
||||
{
|
||||
struct window_pane *wp;
|
||||
int status, xoff, yoff;
|
||||
int pane_status, xoff, yoff;
|
||||
u_int sx, sy;
|
||||
|
||||
status = options_get_number(w->options, "pane-border-status");
|
||||
pane_status = options_get_number(w->options, "pane-border-status");
|
||||
|
||||
TAILQ_FOREACH(wp, &w->z_index, zentry) {
|
||||
if (!window_pane_visible(wp))
|
||||
@@ -667,7 +667,7 @@ window_get_active_at(struct window *w, u_int x, u_int y)
|
||||
right border. */
|
||||
if ((int)x < xoff || x > xoff + sx)
|
||||
continue;
|
||||
if (status == PANE_STATUS_TOP) {
|
||||
if (pane_status == PANE_STATUS_TOP) {
|
||||
if ((int)y < yoff - 1 || y > yoff + sy)
|
||||
continue;
|
||||
} else {
|
||||
@@ -678,8 +678,13 @@ window_get_active_at(struct window *w, u_int x, u_int y)
|
||||
/* Floating, include top or or left border. */
|
||||
if ((int)x < xoff - 1 || x > xoff + sx)
|
||||
continue;
|
||||
if ((int)y < yoff - 1 || y > yoff + sy)
|
||||
if (pane_status == PANE_STATUS_TOP) {
|
||||
if ((int)y <= yoff - 2 || y > yoff + sy - 1)
|
||||
continue;
|
||||
} else {
|
||||
if ((int)y < yoff - 1 || y > yoff + sy)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return (wp);
|
||||
}
|
||||
@@ -990,9 +995,8 @@ window_printable_flags(struct winlink *wl, int escape)
|
||||
{
|
||||
struct session *s = wl->session;
|
||||
static char flags[32];
|
||||
int pos;
|
||||
u_int pos = 0;
|
||||
|
||||
pos = 0;
|
||||
if (wl->flags & WINLINK_ACTIVITY) {
|
||||
flags[pos++] = '#';
|
||||
if (escape)
|
||||
@@ -1015,7 +1019,7 @@ window_printable_flags(struct winlink *wl, int escape)
|
||||
}
|
||||
|
||||
const char *
|
||||
window_pane_printable_flags(struct window_pane *wp, __unused int escape)
|
||||
window_pane_printable_flags(struct window_pane *wp)
|
||||
{
|
||||
static char flags[32];
|
||||
struct window *w = wp->window;
|
||||
@@ -1099,6 +1103,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
|
||||
window_pane_default_cursor(wp);
|
||||
|
||||
screen_init(&wp->status_screen, 1, 1, 0);
|
||||
style_ranges_init(&wp->border_status_line.ranges);
|
||||
|
||||
if (gethostname(host, sizeof host) == 0)
|
||||
screen_set_title(&wp->base, host);
|
||||
@@ -1151,6 +1156,7 @@ window_pane_destroy(struct window_pane *wp)
|
||||
free(wp->shell);
|
||||
cmd_free_argv(wp->argc, wp->argv);
|
||||
colour_palette_free(&wp->palette);
|
||||
style_ranges_free(&wp->border_status_line.ranges);
|
||||
free(wp);
|
||||
}
|
||||
|
||||
@@ -2121,3 +2127,31 @@ window_pane_send_theme_update(struct window_pane *wp)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct style_range *
|
||||
window_pane_border_status_get_range(struct window_pane *wp, u_int x, u_int y)
|
||||
{
|
||||
struct style_ranges *srs;
|
||||
struct window *w = wp->window;
|
||||
struct options *wo = w->options;
|
||||
u_int line;
|
||||
int pane_status;
|
||||
|
||||
if (wp == NULL)
|
||||
return (NULL);
|
||||
srs = &wp->border_status_line.ranges;
|
||||
|
||||
pane_status = options_get_number(wo, "pane-border-status");
|
||||
if (pane_status == PANE_STATUS_TOP)
|
||||
line = wp->yoff - 1;
|
||||
else if (pane_status == PANE_STATUS_BOTTOM)
|
||||
line = wp->yoff + wp->sy;
|
||||
if (pane_status == PANE_STATUS_OFF || line != y)
|
||||
return (NULL);
|
||||
|
||||
/*
|
||||
* The border formats start 2 off but that isn't reflected in
|
||||
* the stored bounds of the range.
|
||||
*/
|
||||
return (style_ranges_get_range(srs, x - wp->xoff - 2));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user