Merge branch 'master' into floating_panes

This commit is contained in:
Nicholas Marriott
2026-05-12 12:38:31 +01:00
41 changed files with 1075 additions and 254 deletions

View File

@@ -41,6 +41,10 @@ endif
AM_CPPFLAGS += -DDEBUG AM_CPPFLAGS += -DDEBUG
endif endif
AM_CPPFLAGS += -iquote. AM_CPPFLAGS += -iquote.
if IS_ASAN
AM_CFLAGS += -fsanitize=address
AM_LDFLAGS += -fsanitize=address
endif
endif endif
# Set flags for Solaris. # Set flags for Solaris.

View File

@@ -64,6 +64,7 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
struct session *s; struct session *s;
struct window_pane *wp = target->wp, *swp; struct window_pane *wp = target->wp, *swp;
u_int tty_ox, tty_oy, tty_sx, tty_sy; u_int tty_ox, tty_oy, tty_sx, tty_sy;
int line_numbers;
if (args_has(args, 'q')) { if (args_has(args, 'q')) {
window_pane_reset_mode_all(wp); window_pane_reset_mode_all(wp);
@@ -86,10 +87,15 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
swp = source->wp; swp = source->wp;
else else
swp = wp; swp = wp;
line_numbers = 1;
if (event != NULL && KEYC_IS_MOUSE(event->key))
line_numbers = 0;
if (!window_pane_set_mode(wp, swp, &window_copy_mode, NULL, args)) { if (!window_pane_set_mode(wp, swp, &window_copy_mode, NULL, args)) {
window_copy_set_line_numbers(wp, line_numbers);
if (args_has(args, 'M')) if (args_has(args, 'M'))
window_copy_start_drag(c, &event->m); window_copy_start_drag(c, &event->m);
} } else
window_copy_set_line_numbers(wp, line_numbers);
if (args_has(args, 'u')) if (args_has(args, 'u'))
window_copy_pageup(wp, 0); window_copy_pageup(wp, 0);
if (args_has(args, 'd')) if (args_has(args, 'd'))

View File

@@ -118,7 +118,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval, size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval,
item, &cause); item, &cause);
} else if (args_has(args, 'p')) { } else if (args_has(args, 'p')) {
size = args_strtonum_and_expand(args, 'l', 0, 100, item, size = args_strtonum_and_expand(args, 'p', 0, 100, item,
&cause); &cause);
if (cause == NULL) if (cause == NULL)
size = curval * size / 100; size = curval * size / 100;

View File

@@ -102,7 +102,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
tmp = args_get(args, 's'); tmp = args_get(args, 's');
if (tmp != NULL) { if (tmp != NULL) {
name = format_single(item, tmp, c, NULL, NULL, NULL); name = format_single(item, tmp, c, NULL, NULL, NULL);
newname = session_check_name(name); newname = clean_name(name, "#:.");
if (newname == NULL) { if (newname == NULL) {
cmdq_error(item, "invalid session: %s", name); cmdq_error(item, "invalid session: %s", name);
free(name); free(name);
@@ -142,7 +142,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
else if (groupwith != NULL) else if (groupwith != NULL)
prefix = xstrdup(groupwith->name); prefix = xstrdup(groupwith->name);
else { else {
prefix = session_check_name(group); prefix = clean_name(group, "#:.");
if (prefix == NULL) { if (prefix == NULL) {
cmdq_error(item, "invalid session group: %s", cmdq_error(item, "invalid session group: %s",
group); group);

View File

@@ -37,6 +37,8 @@ static void printflike(1,2) yyerror(const char *, ...);
static char *yylex_token(int); static char *yylex_token(int);
static char *yylex_format(void); static char *yylex_format(void);
#define CMD_PARSE_MAX_ENVIRON_LEN 16384
struct cmd_parse_scope { struct cmd_parse_scope {
int flag; int flag;
TAILQ_ENTRY (cmd_parse_scope) entry; TAILQ_ENTRY (cmd_parse_scope) entry;
@@ -232,6 +234,10 @@ assignment : EQUALS
flag = flag && scope->flag; flag = flag && scope->flag;
} }
if (strlen($1) > CMD_PARSE_MAX_ENVIRON_LEN) {
yyerror("environment variable is too long");
YYABORT;
}
if ((~flags & CMD_PARSE_PARSEONLY) && flag) if ((~flags & CMD_PARSE_PARSEONLY) && flag)
environ_put(global_environ, $1, 0); environ_put(global_environ, $1, 0);
free($1); free($1);
@@ -250,6 +256,10 @@ hidden_assignment : HIDDEN EQUALS
flag = flag && scope->flag; flag = flag && scope->flag;
} }
if (strlen($2) > CMD_PARSE_MAX_ENVIRON_LEN) {
yyerror("environment variable is too long");
YYABORT;
}
if ((~flags & CMD_PARSE_PARSEONLY) && flag) if ((~flags & CMD_PARSE_PARSEONLY) && flag)
environ_put(global_environ, $2, ENVIRON_HIDDEN); environ_put(global_environ, $2, ENVIRON_HIDDEN);
free($2); free($2);

View File

@@ -128,6 +128,8 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
sigprocmask(SIG_SETMASK, &oldset, NULL); sigprocmask(SIG_SETMASK, &oldset, NULL);
cmdq_error(item, "fork error: %s", strerror(errno)); cmdq_error(item, "fork error: %s", strerror(errno));
close(pipe_fd[0]);
close(pipe_fd[1]);
free(cmd); free(cmd);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
case 0: case 0:

View File

@@ -52,7 +52,7 @@ cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item)
char *newname, *tmp; char *newname, *tmp;
tmp = format_single_from_target(item, args_string(args, 0)); tmp = format_single_from_target(item, args_string(args, 0));
newname = session_check_name(tmp); newname = clean_name(tmp, "#:.");
if (newname == NULL) { if (newname == NULL) {
cmdq_error(item, "invalid session: %s", tmp); cmdq_error(item, "invalid session: %s", tmp);
free(tmp); free(tmp);

View File

@@ -198,8 +198,17 @@ cmd_run_shell_timer(__unused int fd, __unused short events, void* arg)
} }
if (job_run(cmd, 0, NULL, NULL, cdata->s, cdata->cwd, NULL, if (job_run(cmd, 0, NULL, NULL, cdata->s, cdata->cwd, NULL,
cmd_run_shell_callback, cmd_run_shell_free, cdata, cmd_run_shell_callback, cmd_run_shell_free, cdata,
cdata->flags, -1, -1) == NULL) cdata->flags, -1, -1) == NULL) {
if (cdata->item == NULL)
status_message_set(c, -1, 1, 0, 0,
"failed to run command: %s", cmd);
else {
cmdq_error(cdata->item,
"failed to run command: %s", cmd);
cmdq_continue(cdata->item);
}
cmd_run_shell_free(cdata); cmd_run_shell_free(cdata);
}
return; return;
} }

View File

@@ -463,6 +463,9 @@ int utf8proc_wctomb(char *, wchar_t);
#ifdef NEED_FUZZING #ifdef NEED_FUZZING
/* tmux.c */ /* tmux.c */
#define main __weak main #define main __weak main
#define regcomp(preg, pattern, cflags) (0)
#define regexec(preg, string, nmatch, pmatch, eflags) (REG_NOMATCH)
#define regfree(preg) ((void)0)
#endif #endif
/* getopt.c */ /* getopt.c */

View File

@@ -73,6 +73,15 @@ AC_ARG_ENABLE(
) )
AM_CONDITIONAL(IS_OPTIMIZED, test "x$enable_optimizations" = xyes) AM_CONDITIONAL(IS_OPTIMIZED, test "x$enable_optimizations" = xyes)
# Is this --enable-asan?
AC_ARG_ENABLE(
asan,
AS_HELP_STRING(--enable-asan, enable ASAN build flags),
,
enable_asan=no
)
AM_CONDITIONAL(IS_ASAN, test "x$enable_asan" = xyes)
# Is this a static build? # Is this a static build?
AC_ARG_ENABLE( AC_ARG_ENABLE(
static, static,

View File

@@ -207,10 +207,12 @@ control_free_sub(struct control_state *cs, struct control_sub *csub)
RB_FOREACH_SAFE(csp, control_sub_panes, &csub->panes, csp1) { RB_FOREACH_SAFE(csp, control_sub_panes, &csub->panes, csp1) {
RB_REMOVE(control_sub_panes, &csub->panes, csp); RB_REMOVE(control_sub_panes, &csub->panes, csp);
free(csp->last);
free(csp); free(csp);
} }
RB_FOREACH_SAFE(csw, control_sub_windows, &csub->windows, csw1) { RB_FOREACH_SAFE(csw, control_sub_windows, &csub->windows, csw1) {
RB_REMOVE(control_sub_windows, &csub->windows, csw); RB_REMOVE(control_sub_windows, &csub->windows, csw);
free(csw->last);
free(csw); free(csw);
} }
free(csub->last); free(csub->last);
@@ -298,6 +300,7 @@ control_reset_offsets(struct client *c)
struct control_pane *cp, *cp1; struct control_pane *cp, *cp1;
RB_FOREACH_SAFE(cp, control_panes, &cs->panes, cp1) { RB_FOREACH_SAFE(cp, control_panes, &cs->panes, cp1) {
control_discard_pane(c, cp);
RB_REMOVE(control_panes, &cs->panes, cp); RB_REMOVE(control_panes, &cs->panes, cp);
free(cp); free(cp);
} }
@@ -352,6 +355,9 @@ control_set_pane_off(struct client *c, struct window_pane *wp)
struct control_pane *cp; struct control_pane *cp;
cp = control_add_pane(c, wp); cp = control_add_pane(c, wp);
control_discard_pane(c, cp);
memcpy(&cp->offset, &wp->offset, sizeof cp->offset);
memcpy(&cp->queued, &wp->offset, sizeof cp->queued);
cp->flags |= CONTROL_PANE_OFF; cp->flags |= CONTROL_PANE_OFF;
} }

21
file.c
View File

@@ -804,7 +804,7 @@ file_read_cancel(struct client_files *files, struct imsg *imsg)
} }
/* Handle a write ready message (server). */ /* Handle a write ready message (server). */
void int
file_write_ready(struct client_files *files, struct imsg *imsg) file_write_ready(struct client_files *files, struct imsg *imsg)
{ {
struct msg_write_ready *msg = imsg->data; struct msg_write_ready *msg = imsg->data;
@@ -812,19 +812,20 @@ file_write_ready(struct client_files *files, struct imsg *imsg)
struct client_file find, *cf; struct client_file find, *cf;
if (msglen != sizeof *msg) if (msglen != sizeof *msg)
fatalx("bad MSG_WRITE_READY size"); return (-1);
find.stream = msg->stream; find.stream = msg->stream;
if ((cf = RB_FIND(client_files, files, &find)) == NULL) if ((cf = RB_FIND(client_files, files, &find)) == NULL)
return; return (0);
if (msg->error != 0) { if (msg->error != 0) {
cf->error = msg->error; cf->error = msg->error;
file_fire_done(cf); file_fire_done(cf);
} else } else
file_push(cf); file_push(cf);
return (0);
} }
/* Handle read data message (server). */ /* Handle read data message (server). */
void int
file_read_data(struct client_files *files, struct imsg *imsg) file_read_data(struct client_files *files, struct imsg *imsg)
{ {
struct msg_read_data *msg = imsg->data; struct msg_read_data *msg = imsg->data;
@@ -834,10 +835,10 @@ file_read_data(struct client_files *files, struct imsg *imsg)
size_t bsize = msglen - sizeof *msg; size_t bsize = msglen - sizeof *msg;
if (msglen < sizeof *msg) if (msglen < sizeof *msg)
fatalx("bad MSG_READ_DATA size"); return (-1);
find.stream = msg->stream; find.stream = msg->stream;
if ((cf = RB_FIND(client_files, files, &find)) == NULL) if ((cf = RB_FIND(client_files, files, &find)) == NULL)
return; return (0);
log_debug("file %d read %zu bytes", cf->stream, bsize); log_debug("file %d read %zu bytes", cf->stream, bsize);
if (cf->error == 0 && !cf->closed) { if (cf->error == 0 && !cf->closed) {
@@ -847,10 +848,11 @@ file_read_data(struct client_files *files, struct imsg *imsg)
} else } else
file_fire_read(cf); file_fire_read(cf);
} }
return (0);
} }
/* Handle a read done message (server). */ /* Handle a read done message (server). */
void int
file_read_done(struct client_files *files, struct imsg *imsg) file_read_done(struct client_files *files, struct imsg *imsg)
{ {
struct msg_read_done *msg = imsg->data; struct msg_read_done *msg = imsg->data;
@@ -858,12 +860,13 @@ file_read_done(struct client_files *files, struct imsg *imsg)
struct client_file find, *cf; struct client_file find, *cf;
if (msglen != sizeof *msg) if (msglen != sizeof *msg)
fatalx("bad MSG_READ_DONE size"); return (-1);
find.stream = msg->stream; find.stream = msg->stream;
if ((cf = RB_FIND(client_files, files, &find)) == NULL) if ((cf = RB_FIND(client_files, files, &find)) == NULL)
return; return (0);
log_debug("file %d read done", cf->stream); log_debug("file %d read done", cf->stream);
cf->error = msg->error; cf->error = msg->error;
file_fire_done(cf); file_fire_done(cf);
return (0);
} }

View File

@@ -120,6 +120,9 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
/* Limit on recursion. */ /* Limit on recursion. */
#define FORMAT_LOOP_LIMIT 100 #define FORMAT_LOOP_LIMIT 100
/* Limit on time taken (milliseconds). */
#define FORMAT_TIME_LIMIT 100
/* Format expand flags. */ /* Format expand flags. */
#define FORMAT_EXPAND_TIME 0x1 #define FORMAT_EXPAND_TIME 0x1
#define FORMAT_EXPAND_NOJOBS 0x2 #define FORMAT_EXPAND_NOJOBS 0x2
@@ -169,9 +172,11 @@ RB_GENERATE_STATIC(format_entry_tree, format_entry, entry, format_entry_cmp);
struct format_expand_state { struct format_expand_state {
struct format_tree *ft; struct format_tree *ft;
u_int loop; u_int loop;
uint64_t start_time;
int flags;
time_t time; time_t time;
struct tm tm; struct tm tm;
int flags;
}; };
/* Format modifier. */ /* Format modifier. */
@@ -292,6 +297,7 @@ format_copy_state(struct format_expand_state *to,
to->time = from->time; to->time = from->time;
memcpy(&to->tm, &from->tm, sizeof to->tm); memcpy(&to->tm, &from->tm, sizeof to->tm);
to->flags = from->flags|flags; to->flags = from->flags|flags;
to->start_time = from->start_time;
} }
/* Format job update callback. */ /* Format job update callback. */
@@ -4155,15 +4161,33 @@ found:
return (found); return (found);
} }
/* Check if format has not taken too long. */
static int
format_check_time(struct format_expand_state *es)
{
uint64_t t = get_timer();
if (t - es->start_time < FORMAT_TIME_LIMIT)
return (1);
t -= es->start_time;
format_log(es, "reached time limit (%llu)", (unsigned long long)t);
return (0);
}
/* Unescape escaped characters. */ /* Unescape escaped characters. */
static char * static char *
format_unescape(const char *s) format_unescape(struct format_expand_state *es, const char *s)
{ {
char *out, *cp; char *out, *cp;
int brackets = 0; int brackets = 0;
cp = out = xmalloc(strlen(s) + 1); cp = out = xmalloc(strlen(s) + 1);
for (; *s != '\0'; s++) { for (; *s != '\0'; s++) {
if (!format_check_time(es)){
free(out);
return (xstrdup(""));
}
if (*s == '#' && s[1] == '{') if (*s == '#' && s[1] == '{')
brackets++; brackets++;
if (brackets == 0 && if (brackets == 0 &&
@@ -4182,13 +4206,17 @@ format_unescape(const char *s)
/* Remove escaped characters. */ /* Remove escaped characters. */
static char * static char *
format_strip(const char *s) format_strip(struct format_expand_state *es, const char *s)
{ {
char *out, *cp; char *out, *cp;
int brackets = 0; int brackets = 0;
cp = out = xmalloc(strlen(s) + 1); cp = out = xmalloc(strlen(s) + 1);
for (; *s != '\0'; s++) { for (; *s != '\0'; s++) {
if (!format_check_time(es)){
free(out);
return (xstrdup(""));
}
if (*s == '#' && s[1] == '{') if (*s == '#' && s[1] == '{')
brackets++; brackets++;
if (*s == '#' && strchr(",#{}:", s[1]) != NULL) { if (*s == '#' && strchr(",#{}:", s[1]) != NULL) {
@@ -4204,13 +4232,16 @@ format_strip(const char *s)
return (out); return (out);
} }
/* Skip until end. */ /* Skip until end. */
const char * static const char *
format_skip(const char *s, const char *end) format_skip1(struct format_expand_state *es, const char *s, const char *end)
{ {
int brackets = 0; int brackets = 0;
for (; *s != '\0'; s++) { for (; *s != '\0'; s++) {
if (es != NULL && !format_check_time(es))
return (NULL);
if (*s == '#' && s[1] == '{') if (*s == '#' && s[1] == '{')
brackets++; brackets++;
if (*s == '#' && if (*s == '#' &&
@@ -4229,6 +4260,13 @@ format_skip(const char *s, const char *end)
return (s); return (s);
} }
/* Skip until end. */
const char *
format_skip(const char *s, const char *end)
{
return (format_skip1(NULL, s, end));
}
/* Return left and right alternatives separated by commas. */ /* Return left and right alternatives separated by commas. */
static int static int
format_choose(struct format_expand_state *es, const char *s, char **left, format_choose(struct format_expand_state *es, const char *s, char **left,
@@ -4237,7 +4275,7 @@ format_choose(struct format_expand_state *es, const char *s, char **left,
const char *cp; const char *cp;
char *left0, *right0; char *left0, *right0;
cp = format_skip(s, ","); cp = format_skip1(es, s, ",");
if (cp == NULL) if (cp == NULL)
return (-1); return (-1);
left0 = xstrndup(s, cp - s); left0 = xstrndup(s, cp - s);
@@ -4368,7 +4406,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
/* Single argument with no wrapper character. */ /* Single argument with no wrapper character. */
if (!ispunct((u_char)cp[1]) || cp[1] == '-') { if (!ispunct((u_char)cp[1]) || cp[1] == '-') {
end = format_skip(cp + 1, ":;"); end = format_skip1(es, cp + 1, ":;");
if (end == NULL) if (end == NULL)
break; break;
@@ -4391,7 +4429,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
cp++; cp++;
break; break;
} }
end = format_skip(cp + 1, last); end = format_skip1(es, cp + 1, last);
if (end == NULL) if (end == NULL)
break; break;
cp++; cp++;
@@ -4505,7 +4543,7 @@ format_bool_op_n(struct format_expand_state *es, const char *fmt, int and)
cp1 = fmt; cp1 = fmt;
while (and ? result : !result) { while (and ? result : !result) {
cp2 = format_skip(cp1, ","); cp2 = format_skip1(es, cp1, ",");
if (cp2 == NULL) if (cp2 == NULL)
raw = xstrdup(cp1); raw = xstrdup(cp1);
@@ -5085,7 +5123,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
else if (fm->argc >= 2 && else if (fm->argc >= 2 &&
strchr(fm->argv[0], 'f') != NULL) { strchr(fm->argv[0], 'f') != NULL) {
free(time_format); free(time_format);
time_format = format_strip(fm->argv[1]); time_format = format_strip(es, fm->argv[1]);
} }
break; break;
case 'q': case 'q':
@@ -5201,7 +5239,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
/* Is this a literal string? */ /* Is this a literal string? */
if (modifiers & FORMAT_LITERAL) { if (modifiers & FORMAT_LITERAL) {
format_log(es, "literal string is '%s'", copy); format_log(es, "literal string is '%s'", copy);
value = format_unescape(copy); value = format_unescape(es, copy);
goto done; goto done;
} }
@@ -5277,6 +5315,12 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
else { else {
value = xstrdup(""); value = xstrdup("");
for (i = 0; i < nrep; i++) { for (i = 0; i < nrep; i++) {
if (!format_check_time(es)) {
free(right);
free(left);
free(value);
goto fail;
}
xasprintf(&new, "%s%s", value, left); xasprintf(&new, "%s%s", value, left);
free(value); free(value);
value = new; value = new;
@@ -5348,7 +5392,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
*/ */
cp = copy + 1; cp = copy + 1;
while (1) { while (1) {
cp2 = format_skip(cp, ","); cp2 = format_skip1(es, cp, ",");
if (cp2 == NULL) { if (cp2 == NULL) {
format_log(es, format_log(es,
"no condition matched in '%s'; using last " "no condition matched in '%s'; using last "
@@ -5383,7 +5427,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
} }
cp = cp2 + 1; cp = cp2 + 1;
cp2 = format_skip(cp, ","); cp2 = format_skip1(es, cp, ",");
if (format_true(found)) { if (format_true(found)) {
format_log(es, "condition '%s' is true", format_log(es, "condition '%s' is true",
condition); condition);
@@ -5551,7 +5595,7 @@ format_expand1(struct format_expand_state *es, const char *fmt)
int ch, brackets; int ch, brackets;
char expanded[8192]; char expanded[8192];
if (fmt == NULL || *fmt == '\0') if (fmt == NULL || *fmt == '\0' || !format_check_time(es))
return (xstrdup("")); return (xstrdup(""));
if (es->loop == FORMAT_LOOP_LIMIT) { if (es->loop == FORMAT_LOOP_LIMIT) {
@@ -5633,7 +5677,7 @@ format_expand1(struct format_expand_state *es, const char *fmt)
fmt += n + 1; fmt += n + 1;
continue; continue;
case '{': case '{':
ptr = format_skip((char *)fmt - 2, "}"); ptr = format_skip1(es, (char *)fmt - 2, "}");
if (ptr == NULL) if (ptr == NULL)
break; break;
n = ptr - fmt; n = ptr - fmt;
@@ -5656,7 +5700,7 @@ format_expand1(struct format_expand_state *es, const char *fmt)
n++; n++;
} }
if (*ptr == '[') { if (*ptr == '[') {
style_end = format_skip(fmt - 2, "]"); style_end = format_skip1(es, fmt - 2, "]");
format_log(es, "found #*%zu[", n); format_log(es, "found #*%zu[", n);
while (len - off < n + 2) { while (len - off < n + 2) {
buf = xreallocarray(buf, 2, len); buf = xreallocarray(buf, 2, len);
@@ -5720,6 +5764,7 @@ format_expand_time(struct format_tree *ft, const char *fmt)
memset(&es, 0, sizeof es); memset(&es, 0, sizeof es);
es.ft = ft; es.ft = ft;
es.flags = FORMAT_EXPAND_TIME; es.flags = FORMAT_EXPAND_TIME;
es.start_time = get_timer();
return (format_expand1(&es, fmt)); return (format_expand1(&es, fmt));
} }
@@ -5732,6 +5777,7 @@ format_expand(struct format_tree *ft, const char *fmt)
memset(&es, 0, sizeof es); memset(&es, 0, sizeof es);
es.ft = ft; es.ft = ft;
es.flags = 0; es.flags = 0;
es.start_time = get_timer();
return (format_expand1(&es, fmt)); return (format_expand1(&es, fmt));
} }

View File

@@ -122,19 +122,13 @@ sixel_set_pixel(struct sixel_image *si, u_int x, u_int y, u_int c)
static int static int
sixel_parse_write(struct sixel_image *si, u_int ch) sixel_parse_write(struct sixel_image *si, u_int ch)
{ {
struct sixel_line *sl;
u_int i; u_int i;
if (sixel_parse_expand_lines(si, si->dy + 6) != 0)
return (1);
sl = &si->lines[si->dy];
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++) {
if (sixel_parse_expand_line(si, sl, si->dx + 1) != 0) if (ch & (1 << i)) {
if (sixel_set_pixel(si, si->dx, si->dy + i, si->dc))
return (1); return (1);
if (ch & (1 << i)) }
sl->data[si->dx] = si->dc;
sl++;
} }
return (0); return (0);
} }

View File

@@ -53,14 +53,12 @@ image_log(struct image *im, const char* from, const char* fmt, ...)
static void static void
image_free(struct image *im) image_free(struct image *im)
{ {
struct screen *s = im->s;
image_log(im, __func__, NULL); image_log(im, __func__, NULL);
TAILQ_REMOVE(&all_images, im, all_entry); TAILQ_REMOVE(&all_images, im, all_entry);
all_images_count--; all_images_count--;
TAILQ_REMOVE(&s->images, im, entry); TAILQ_REMOVE(im->list, im, entry);
sixel_free(im->data); sixel_free(im->data);
free(im->fallback); free(im->fallback);
free(im); free(im);
@@ -137,7 +135,8 @@ image_store(struct screen *s, struct sixel_image *si)
image_fallback(&im->fallback, im->sx, im->sy); image_fallback(&im->fallback, im->sx, im->sy);
image_log(im, __func__, NULL); image_log(im, __func__, NULL);
TAILQ_INSERT_TAIL(&s->images, im, entry); im->list = &s->images;
TAILQ_INSERT_TAIL(im->list, im, entry);
TAILQ_INSERT_TAIL(&all_images, im, all_entry); TAILQ_INSERT_TAIL(&all_images, im, all_entry);
if (++all_images_count == MAX_IMAGE_COUNT) if (++all_images_count == MAX_IMAGE_COUNT)

View File

@@ -2663,13 +2663,10 @@ input_exit_osc(struct input_ctx *ictx)
input_osc_4(ictx, p); input_osc_4(ictx, p);
break; break;
case 7: case 7:
if (utf8_isvalid(p)) { if (screen_set_path(sctx->s, p) && wp != NULL) {
screen_set_path(sctx->s, p);
if (wp != NULL) {
server_redraw_window_borders(wp->window); server_redraw_window_borders(wp->window);
server_status_window(wp->window); server_status_window(wp->window);
} }
}
break; break;
case 8: case 8:
input_osc_8(ictx, p); input_osc_8(ictx, p);

View File

@@ -474,6 +474,10 @@ key_bindings_init(void)
"bind -n MouseDown1Status { if -F '#{&&:#{pane_active},#{!#{pane_minimised_flag}}}' { minimise-pane -t= } { switch-client -t= } }", "bind -n MouseDown1Status { if -F '#{&&:#{pane_active},#{!#{pane_minimised_flag}}}' { minimise-pane -t= } { switch-client -t= } }",
"bind -n C-MouseDown1Status { swap-window -t@ }", "bind -n C-MouseDown1Status { swap-window -t@ }",
/* Mouse button 1 down on default pane-border-format */
"bind -n MouseDown1Control9 { display-menu -t= -xM -yM -O -T 'Kill pane #{pane_index}?' 'Yes' 'y' { kill-pane -t= } 'No' 'n' {}}",
"bind -n MouseDown1Control8 { resize-pane -Z }",
/* Mouse wheel down on status line. */ /* Mouse wheel down on status line. */
"bind -n WheelDownStatus { next-window }", "bind -n WheelDownStatus { next-window }",
@@ -506,7 +510,7 @@ key_bindings_init(void)
"bind -Tcopy-mode C-b { send -X cursor-left }", "bind -Tcopy-mode C-b { send -X cursor-left }",
"bind -Tcopy-mode C-g { send -X clear-selection }", "bind -Tcopy-mode C-g { send -X clear-selection }",
"bind -Tcopy-mode C-k { send -X copy-pipe-end-of-line-and-cancel }", "bind -Tcopy-mode C-k { send -X copy-pipe-end-of-line-and-cancel }",
"bind -Tcopy-mode C-l { send -X cursor-centre-vertical }", "bind -Tcopy-mode C-l { send -X recentre-top-bottom }",
"bind -Tcopy-mode M-l { send -X cursor-centre-horizontal }", "bind -Tcopy-mode M-l { send -X cursor-centre-horizontal }",
"bind -Tcopy-mode C-n { send -X cursor-down }", "bind -Tcopy-mode C-n { send -X cursor-down }",
"bind -Tcopy-mode C-p { send -X cursor-up }", "bind -Tcopy-mode C-p { send -X cursor-up }",
@@ -515,6 +519,7 @@ key_bindings_init(void)
"bind -Tcopy-mode C-v { send -X page-down }", "bind -Tcopy-mode C-v { send -X page-down }",
"bind -Tcopy-mode C-w { send -X copy-pipe-and-cancel }", "bind -Tcopy-mode C-w { send -X copy-pipe-and-cancel }",
"bind -Tcopy-mode Escape { send -X cancel }", "bind -Tcopy-mode Escape { send -X cancel }",
"bind -Tcopy-mode C-[ { send -X cancel }",
"bind -Tcopy-mode Space { send -X page-down }", "bind -Tcopy-mode Space { send -X page-down }",
"bind -Tcopy-mode , { send -X jump-reverse }", "bind -Tcopy-mode , { send -X jump-reverse }",
"bind -Tcopy-mode \\; { send -X jump-again }", "bind -Tcopy-mode \\; { send -X jump-again }",
@@ -588,6 +593,7 @@ key_bindings_init(void)
"bind -Tcopy-mode-vi C-v { send -X rectangle-toggle }", "bind -Tcopy-mode-vi C-v { send -X rectangle-toggle }",
"bind -Tcopy-mode-vi C-y { send -X scroll-up }", "bind -Tcopy-mode-vi C-y { send -X scroll-up }",
"bind -Tcopy-mode-vi Escape { send -X clear-selection }", "bind -Tcopy-mode-vi Escape { send -X clear-selection }",
"bind -Tcopy-mode-vi C-[ { send -X clear-selection }",
"bind -Tcopy-mode-vi Space { send -X begin-selection }", "bind -Tcopy-mode-vi Space { send -X begin-selection }",
"bind -Tcopy-mode-vi '$' { send -X end-of-line }", "bind -Tcopy-mode-vi '$' { send -X end-of-line }",
"bind -Tcopy-mode-vi , { send -X jump-reverse }", "bind -Tcopy-mode-vi , { send -X jump-reverse }",

View File

@@ -183,13 +183,14 @@ layout_parse(struct window *w, const char *layout, char **cause)
struct window_pane *wp; struct window_pane *wp;
u_int npanes, ncells, sx = 0, sy = 0; u_int npanes, ncells, sx = 0, sy = 0;
u_short csum; u_short csum;
int n;
/* Check validity. */ /* Check validity. */
if (sscanf(layout, "%hx,", &csum) != 1) { if (sscanf(layout, "%hx,%n", &csum, &n) != 1 || n != 5) {
*cause = xstrdup("invalid layout"); *cause = xstrdup("invalid layout");
return (-1); return (-1);
} }
layout += 5; layout += n;
if (csum != layout_checksum(layout)) { if (csum != layout_checksum(layout)) {
*cause = xstrdup("invalid layout"); *cause = xstrdup("invalid layout");
return (-1); return (-1);

1
menu.c
View File

@@ -471,6 +471,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event)
case '\r': case '\r':
goto chosen; goto chosen;
case '\033': /* Escape */ case '\033': /* Escape */
case '['|KEYC_CTRL:
case 'c'|KEYC_CTRL: case 'c'|KEYC_CTRL:
case 'g'|KEYC_CTRL: case 'g'|KEYC_CTRL:
case 'q': case 'q':

View File

@@ -301,6 +301,8 @@ mode_tree_clear_tagged(struct mode_tree_list *mtl)
void void
mode_tree_up(struct mode_tree_data *mtd, int wrap) mode_tree_up(struct mode_tree_data *mtd, int wrap)
{ {
if (mtd->line_size == 0)
return;
if (mtd->current == 0) { if (mtd->current == 0) {
if (wrap) { if (wrap) {
mtd->current = mtd->line_size - 1; mtd->current = mtd->line_size - 1;
@@ -317,6 +319,8 @@ mode_tree_up(struct mode_tree_data *mtd, int wrap)
int int
mode_tree_down(struct mode_tree_data *mtd, int wrap) mode_tree_down(struct mode_tree_data *mtd, int wrap)
{ {
if (mtd->line_size == 0)
return (0);
if (mtd->current == mtd->line_size - 1) { if (mtd->current == mtd->line_size - 1) {
if (wrap) { if (wrap) {
mtd->current = 0; mtd->current = 0;
@@ -363,6 +367,8 @@ mode_tree_swap(struct mode_tree_data *mtd, int direction)
void * void *
mode_tree_get_current(struct mode_tree_data *mtd) mode_tree_get_current(struct mode_tree_data *mtd)
{ {
if (mtd->line_size == 0)
return (NULL);
return (mtd->line_list[mtd->current].item->itemdata); return (mtd->line_list[mtd->current].item->itemdata);
} }
@@ -433,6 +439,8 @@ mode_tree_set_current(struct mode_tree_data *mtd, uint64_t tag)
return (1); return (1);
} }
if (mtd->current >= mtd->line_size) { if (mtd->current >= mtd->line_size) {
if (mtd->line_size == 0)
return (0);
mtd->current = mtd->line_size - 1; mtd->current = mtd->line_size - 1;
if (mtd->current > mtd->height - 1) if (mtd->current > mtd->height - 1)
mtd->offset = mtd->current - mtd->height + 1; mtd->offset = mtd->current - mtd->height + 1;
@@ -1276,6 +1284,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
switch (*key) { switch (*key) {
case 'q': case 'q':
case '\033': /* Escape */ case '\033': /* Escape */
case '['|KEYC_CTRL:
case 'g'|KEYC_CTRL: case 'g'|KEYC_CTRL:
return (1); return (1);
case KEYC_F1: case KEYC_F1:

View File

@@ -166,7 +166,9 @@ parse_window_name(const char *in)
if (*name == '/') if (*name == '/')
name = basename(name); name = basename(name);
name = xstrdup(name); name = clean_name(name, "#");
free(copy); free(copy);
if (name == NULL)
return (xstrdup(""));
return (name); return (name);
} }

View File

@@ -108,6 +108,9 @@ static const char *options_table_extended_keys_format_list[] = {
static const char *options_table_allow_passthrough_list[] = { static const char *options_table_allow_passthrough_list[] = {
"off", "on", "all", NULL "off", "on", "all", NULL
}; };
static const char *options_table_copy_mode_line_numbers_list[] = {
"off", "default", "absolute", "relative", "hybrid", NULL
};
/* Status line format. */ /* Status line format. */
#define OPTIONS_TABLE_STATUS_FORMAT1 \ #define OPTIONS_TABLE_STATUS_FORMAT1 \
@@ -1176,7 +1179,7 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_str = "#[align=right]" .default_str = "#[align=right]"
"#{t/p:top_line_time}#{?#{e|>:#{top_line_time},0}, ,}" "#{t/p:top_line_time}#{?#{e|>:#{top_line_time},0}, ,}"
"[#{scroll_position}/#{history_size}]" "[#{copy_position}/#{copy_position_limit}]"
"#{?search_timed_out, (timed out)," "#{?search_timed_out, (timed out),"
"#{?search_count, (#{search_count}" "#{?search_count, (#{search_count}"
"#{?search_count_partial,+,} results),}}", "#{?search_count_partial,+,} results),}}",
@@ -1201,6 +1204,32 @@ const struct options_table_entry options_table[] = {
.text = "Style of selection in copy mode." .text = "Style of selection in copy mode."
}, },
{ .name = "copy-mode-current-line-number-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "fg=yellow",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of current line number in copy mode."
},
{ .name = "copy-mode-line-number-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "fg=white,dim",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of line numbers in copy mode."
},
{ .name = "copy-mode-line-numbers",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW,
.choices = options_table_copy_mode_line_numbers_list,
.default_num = 0,
.text = "Line number mode in copy mode."
},
{ .name = "fill-character", { .name = "fill-character",
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW, .scope = OPTIONS_TABLE_WINDOW,
@@ -1326,7 +1355,14 @@ const struct options_table_entry options_table[] = {
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_str = "#{?pane_active,#[reverse],}#{pane_index}#[default] " .default_str = "#{?pane_active,#[reverse],}#{pane_index}#[default] "
"\"#{pane_title}\"", "\"#{pane_title}\""
"#{?#{mouse},"
"#[align=right]"
"#[range=control|8]["
"#{?#{window_zoomed_flag},u,z}"
"]#[norange]"
"#[range=control|9][x]#[norange]"
",}",
.text = "Format of text in the pane status lines." .text = "Format of text in the pane status lines."
}, },
@@ -1473,6 +1509,28 @@ const struct options_table_entry options_table[] = {
"A value of 0 means no limit." "A value of 0 means no limit."
}, },
{ .name = "tree-mode-preview-format",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_str = "#{?pane_format,"
"#{pane_index}:#{pane_title},"
"#{window_index}:#{window_name}}",
.text = "Format of the preview indicator in tree mode."
},
{ .name = "tree-mode-preview-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "fg=#{?#{||:"
"#{&&:#{pane_format},#{pane_active}},"
"#{&&:#{window_format},#{window_active}}},"
"#{display-panes-active-colour},"
"#{display-panes-colour}}",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of preview indicator in tree mode."
},
{ .name = "window-active-style", { .name = "window-active-style",
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,

33
paste.c
View File

@@ -204,6 +204,7 @@ int
paste_rename(const char *oldname, const char *newname, char **cause) paste_rename(const char *oldname, const char *newname, char **cause)
{ {
struct paste_buffer *pb, *pb_new; struct paste_buffer *pb, *pb_new;
char *name;
if (cause != NULL) if (cause != NULL)
*cause = NULL; *cause = NULL;
@@ -219,23 +220,33 @@ paste_rename(const char *oldname, const char *newname, char **cause)
return (-1); return (-1);
} }
name = clean_name(newname, "");
if (name == NULL) {
if (cause != NULL)
xasprintf(cause, "invalid buffer name: %s", newname);
return (-1);
}
pb = paste_get_name(oldname); pb = paste_get_name(oldname);
if (pb == NULL) { if (pb == NULL) {
if (cause != NULL) if (cause != NULL)
xasprintf(cause, "no buffer %s", oldname); xasprintf(cause, "no buffer %s", oldname);
free(name);
return (-1); return (-1);
} }
pb_new = paste_get_name(newname); pb_new = paste_get_name(name);
if (pb_new == pb) if (pb_new == pb) {
free(name);
return (0); return (0);
}
if (pb_new != NULL) if (pb_new != NULL)
paste_free(pb_new); paste_free(pb_new);
RB_REMOVE(paste_name_tree, &paste_by_name, pb); RB_REMOVE(paste_name_tree, &paste_by_name, pb);
free(pb->name); free(pb->name);
pb->name = xstrdup(newname); pb->name = name;
if (pb->automatic) if (pb->automatic)
paste_num_automatic--; paste_num_automatic--;
@@ -244,7 +255,7 @@ paste_rename(const char *oldname, const char *newname, char **cause)
RB_INSERT(paste_name_tree, &paste_by_name, pb); RB_INSERT(paste_name_tree, &paste_by_name, pb);
notify_paste_buffer(oldname, 1); notify_paste_buffer(oldname, 1);
notify_paste_buffer(newname, 0); notify_paste_buffer(pb->name, 0);
return (0); return (0);
} }
@@ -257,6 +268,7 @@ int
paste_set(char *data, size_t size, const char *name, char **cause) paste_set(char *data, size_t size, const char *name, char **cause)
{ {
struct paste_buffer *pb, *old; struct paste_buffer *pb, *old;
char *newname;
if (cause != NULL) if (cause != NULL)
*cause = NULL; *cause = NULL;
@@ -276,9 +288,16 @@ paste_set(char *data, size_t size, const char *name, char **cause)
return (-1); return (-1);
} }
newname = clean_name(name, "");
if (newname == NULL) {
if (cause != NULL)
xasprintf(cause, "invalid buffer name: %s", name);
return (-1);
}
pb = xmalloc(sizeof *pb); pb = xmalloc(sizeof *pb);
pb->name = xstrdup(name); pb->name = newname;
pb->data = data; pb->data = data;
pb->size = size; pb->size = size;
@@ -288,13 +307,13 @@ paste_set(char *data, size_t size, const char *name, char **cause)
pb->created = time(NULL); pb->created = time(NULL);
if ((old = paste_get_name(name)) != NULL) if ((old = paste_get_name(pb->name)) != NULL)
paste_free(old); paste_free(old);
RB_INSERT(paste_name_tree, &paste_by_name, pb); RB_INSERT(paste_name_tree, &paste_by_name, pb);
RB_INSERT(paste_time_tree, &paste_by_time, pb); RB_INSERT(paste_time_tree, &paste_by_time, pb);
notify_paste_buffer(name, 0); notify_paste_buffer(pb->name, 0);
return (0); return (0);
} }

View File

@@ -90,7 +90,7 @@ You should see the Greek word 'kosme': "κόσμε"
2.3.2 U-0000E000 = ee 80 80 = "" | 2.3.2 U-0000E000 = ee 80 80 = "" |
2.3.3 U-0000FFFD = ef bf bd = "<22>" | 2.3.3 U-0000FFFD = ef bf bd = "<22>" |
2.3.4 U-0010FFFF = f4 8f bf bf = "􏿿" | 2.3.4 U-0010FFFF = f4 8f bf bf = "􏿿" |
2.3.5 U-00110000 = f4 90 80 80 = "<22>" | 2.3.5 U-00110000 = f4 90 80 80 = "<22><EFBFBD><EFBFBD><EFBFBD>" |
| |
3 Malformed sequences | 3 Malformed sequences |
| |

View File

@@ -36,6 +36,8 @@ struct screen_sel {
u_int ex; u_int ex;
u_int ey; u_int ey;
u_int clipx;
struct grid_cell cell; struct grid_cell cell;
}; };
@@ -245,19 +247,28 @@ screen_set_cursor_colour(struct screen *s, int colour)
int int
screen_set_title(struct screen *s, const char *title) screen_set_title(struct screen *s, const char *title)
{ {
if (!utf8_isvalid(title)) char *new_title;
new_title = clean_name(title, "#");
if (new_title == NULL)
return (0); return (0);
free(s->title); free(s->title);
s->title = xstrdup(title); s->title = new_title;
return (1); return (1);
} }
/* Set screen path. */ /* Set screen path. */
void int
screen_set_path(struct screen *s, const char *path) screen_set_path(struct screen *s, const char *path)
{ {
char *new_path;
new_path = clean_name(path, "#");
if (new_path == NULL)
return (0);
free(s->path); free(s->path);
utf8_stravis(&s->path, path, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL); s->path = new_path;
return (1);
} }
/* Push the current title onto the stack. */ /* Push the current title onto the stack. */
@@ -266,6 +277,16 @@ screen_push_title(struct screen *s)
{ {
struct screen_title_entry *title_entry; struct screen_title_entry *title_entry;
log_debug("%s: %u", __func__, s->ntitles);
while (s->ntitles >= 10) {
title_entry = TAILQ_LAST(s->titles, screen_titles);
free(title_entry->text);
TAILQ_REMOVE(s->titles, title_entry, entry);
free(title_entry);
s->ntitles--;
}
if (s->titles == NULL) { if (s->titles == NULL) {
s->titles = xmalloc(sizeof *s->titles); s->titles = xmalloc(sizeof *s->titles);
TAILQ_INIT(s->titles); TAILQ_INIT(s->titles);
@@ -273,6 +294,7 @@ screen_push_title(struct screen *s)
title_entry = xmalloc(sizeof *title_entry); title_entry = xmalloc(sizeof *title_entry);
title_entry->text = xstrdup(s->title); title_entry->text = xstrdup(s->title);
TAILQ_INSERT_HEAD(s->titles, title_entry, entry); TAILQ_INSERT_HEAD(s->titles, title_entry, entry);
s->ntitles++;
} }
/* /*
@@ -286,14 +308,15 @@ screen_pop_title(struct screen *s)
if (s->titles == NULL) if (s->titles == NULL)
return; return;
log_debug("%s: %u", __func__, s->ntitles);
title_entry = TAILQ_FIRST(s->titles); title_entry = TAILQ_FIRST(s->titles);
if (title_entry != NULL) { if (title_entry != NULL) {
screen_set_title(s, title_entry->text); free(s->title);
s->title = title_entry->text;
TAILQ_REMOVE(s->titles, title_entry, entry); TAILQ_REMOVE(s->titles, title_entry, entry);
free(title_entry->text);
free(title_entry); free(title_entry);
s->ntitles--;
} }
} }
@@ -456,7 +479,8 @@ screen_resize_y(struct screen *s, u_int sy, int eat_empty, u_int *cy)
/* Set selection. */ /* Set selection. */
void void
screen_set_selection(struct screen *s, u_int sx, u_int sy, screen_set_selection(struct screen *s, u_int sx, u_int sy,
u_int ex, u_int ey, u_int rectangle, int modekeys, struct grid_cell *gc) u_int ex, u_int ey, u_int rectangle, u_int clipx, int modekeys,
struct grid_cell *gc)
{ {
if (s->sel == NULL) if (s->sel == NULL)
s->sel = xcalloc(1, sizeof *s->sel); s->sel = xcalloc(1, sizeof *s->sel);
@@ -470,6 +494,7 @@ screen_set_selection(struct screen *s, u_int sx, u_int sy,
s->sel->sy = sy; s->sel->sy = sy;
s->sel->ex = ex; s->sel->ex = ex;
s->sel->ey = ey; s->sel->ey = ey;
s->sel->clipx = clipx;
} }
/* Clear selection. */ /* Clear selection. */
@@ -497,6 +522,8 @@ screen_check_selection(struct screen *s, u_int px, u_int py)
if (sel == NULL || sel->hidden) if (sel == NULL || sel->hidden)
return (0); return (0);
if (px < sel->clipx)
return (0);
if (sel->rectangle) { if (sel->rectangle) {
if (sel->sy < sel->ey) { if (sel->sy < sel->ey) {
@@ -649,6 +676,9 @@ void
screen_alternate_on(struct screen *s, struct grid_cell *gc, int cursor) screen_alternate_on(struct screen *s, struct grid_cell *gc, int cursor)
{ {
u_int sx, sy; u_int sx, sy;
#ifdef ENABLE_SIXEL
struct image *im;
#endif
if (SCREEN_IS_ALTERNATE(s)) if (SCREEN_IS_ALTERNATE(s))
return; return;
@@ -665,6 +695,8 @@ screen_alternate_on(struct screen *s, struct grid_cell *gc, int cursor)
#ifdef ENABLE_SIXEL #ifdef ENABLE_SIXEL
TAILQ_CONCAT(&s->saved_images, &s->images, entry); TAILQ_CONCAT(&s->saved_images, &s->images, entry);
TAILQ_FOREACH(im, &s->saved_images, entry)
im->list = &s->saved_images;
#endif #endif
grid_view_clear(s->grid, 0, 0, sx, sy, 8); grid_view_clear(s->grid, 0, 0, sx, sy, 8);
@@ -678,6 +710,9 @@ void
screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor) screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor)
{ {
u_int sx = screen_size_x(s), sy = screen_size_y(s); u_int sx = screen_size_x(s), sy = screen_size_y(s);
#ifdef ENABLE_SIXEL
struct image *im;
#endif
/* /*
* If the current size is different, temporarily resize to the old size * If the current size is different, temporarily resize to the old size
@@ -724,6 +759,8 @@ screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor)
#ifdef ENABLE_SIXEL #ifdef ENABLE_SIXEL
image_free_all(s); image_free_all(s);
TAILQ_CONCAT(&s->images, &s->saved_images, entry); TAILQ_CONCAT(&s->images, &s->saved_images, entry);
TAILQ_FOREACH(im, &s->images, entry)
im->list = &s->images;
#endif #endif
if (s->cx > screen_size_x(s) - 1) if (s->cx > screen_size_x(s) - 1)
@@ -762,6 +799,8 @@ screen_mode_to_string(int mode)
strlcat(tmp, "CURSOR_BLINKING,", sizeof tmp); strlcat(tmp, "CURSOR_BLINKING,", sizeof tmp);
if (mode & MODE_CURSOR_VERY_VISIBLE) if (mode & MODE_CURSOR_VERY_VISIBLE)
strlcat(tmp, "CURSOR_VERY_VISIBLE,", sizeof tmp); strlcat(tmp, "CURSOR_VERY_VISIBLE,", sizeof tmp);
if (mode & MODE_CURSOR_BLINKING_SET)
strlcat(tmp, "CURSOR_BLINKING_SET,", sizeof tmp);
if (mode & MODE_MOUSE_UTF8) if (mode & MODE_MOUSE_UTF8)
strlcat(tmp, "MOUSE_UTF8,", sizeof tmp); strlcat(tmp, "MOUSE_UTF8,", sizeof tmp);
if (mode & MODE_MOUSE_SGR) if (mode & MODE_MOUSE_SGR)
@@ -782,6 +821,9 @@ screen_mode_to_string(int mode)
strlcat(tmp, "KEYS_EXTENDED_2,", sizeof tmp); strlcat(tmp, "KEYS_EXTENDED_2,", sizeof tmp);
if (mode & MODE_THEME_UPDATES) if (mode & MODE_THEME_UPDATES)
strlcat(tmp, "THEME_UPDATES,", sizeof tmp); strlcat(tmp, "THEME_UPDATES,", sizeof tmp);
if (mode & MODE_SYNC)
strlcat(tmp, "SYNC,", sizeof tmp);
if (*tmp != '\0')
tmp[strlen(tmp) - 1] = '\0'; tmp[strlen(tmp) - 1] = '\0';
return (tmp); return (tmp);
} }

View File

@@ -41,6 +41,7 @@ static void server_client_check_redraw(struct client *);
static void server_client_check_modes(struct client *); static void server_client_check_modes(struct client *);
static void server_client_set_title(struct client *); static void server_client_set_title(struct client *);
static void server_client_set_path(struct client *); static void server_client_set_path(struct client *);
static void server_client_set_progress_bar(struct client *);
static void server_client_reset_state(struct client *); static void server_client_reset_state(struct client *);
static void server_client_update_latest(struct client *); static void server_client_update_latest(struct client *);
static void server_client_dispatch(struct imsg *, void *); static void server_client_dispatch(struct imsg *, void *);
@@ -2142,6 +2143,7 @@ server_client_check_redraw(struct client *c)
server_client_set_title(c); server_client_set_title(c);
server_client_set_path(c); server_client_set_path(c);
} }
server_client_set_progress_bar(c);
screen_redraw_screen(c); screen_redraw_screen(c);
} }
@@ -2208,6 +2210,23 @@ server_client_set_path(struct client *c)
} }
} }
/* Set client progress bar. */
static void
server_client_set_progress_bar(struct client *c)
{
struct session *s = c->session;
struct progress_bar *pane_pb;
if (s->curw == NULL)
return;
pane_pb = &s->curw->window->active->base.progress_bar;
if (pane_pb->state == c->progress_bar.state &&
pane_pb->progress == c->progress_bar.progress)
return;
memcpy(&c->progress_bar, pane_pb, sizeof c->progress_bar);
tty_set_progress_bar(&c->tty, &c->progress_bar);
}
/* Dispatch message from client. */ /* Dispatch message from client. */
static void static void
server_client_dispatch(struct imsg *imsg, void *arg) server_client_dispatch(struct imsg *imsg, void *arg)
@@ -2302,13 +2321,16 @@ server_client_dispatch(struct imsg *imsg, void *arg)
goto bad; goto bad;
break; break;
case MSG_WRITE_READY: case MSG_WRITE_READY:
file_write_ready(&c->files, imsg); if (file_write_ready(&c->files, imsg) != 0)
goto bad;
break; break;
case MSG_READ: case MSG_READ:
file_read_data(&c->files, imsg); if (file_read_data(&c->files, imsg) != 0)
goto bad;
break; break;
case MSG_READ_DONE: case MSG_READ_DONE:
file_read_done(&c->files, imsg); if (file_read_done(&c->files, imsg) != 0)
goto bad;
break; break;
} }

View File

@@ -229,24 +229,6 @@ session_destroy(struct session *s, int notify, const char *from)
session_remove_ref(s, __func__); session_remove_ref(s, __func__);
} }
/* Sanitize session name. */
char *
session_check_name(const char *name)
{
char *copy, *cp, *new_name;
if (*name == '\0')
return (NULL);
copy = xstrdup(name);
for (cp = copy; *cp != '\0'; cp++) {
if (*cp == ':' || *cp == '.')
*cp = '_';
}
utf8_stravis(&new_name, copy, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL);
free(copy);
return (new_name);
}
/* Lock session if it has timed out. */ /* Lock session if it has timed out. */
static void static void
session_lock_timer(__unused int fd, __unused short events, void *arg) session_lock_timer(__unused int fd, __unused short events, void *arg)

View File

@@ -82,6 +82,7 @@ spawn_window(struct spawn_context *sc, char **cause)
struct winlink *wl; struct winlink *wl;
int idx = sc->idx; int idx = sc->idx;
u_int sx, sy, xpixel, ypixel; u_int sx, sy, xpixel, ypixel;
char *name;
spawn_log(__func__, sc); spawn_log(__func__, sc);
@@ -180,8 +181,11 @@ spawn_window(struct spawn_context *sc, char **cause)
if (~sc->flags & SPAWN_RESPAWN) { if (~sc->flags & SPAWN_RESPAWN) {
free(w->name); free(w->name);
if (sc->name != NULL) { if (sc->name != NULL) {
w->name = format_single(item, sc->name, c, s, NULL, name = format_single(item, sc->name, c, s, NULL, NULL);
NULL); w->name = clean_name(name, "#");
free(name);
if (w->name == NULL)
w->name = xstrdup("");
options_set_number(w->options, "automatic-rename", 0); options_set_number(w->options, "automatic-rename", 0);
} else } else
w->name = default_window_name(w); w->name = default_window_name(w);

101
status.c
View File

@@ -689,10 +689,13 @@ status_prompt_set(struct client *c, struct cmd_find_state *fs,
server_client_clear_overlay(c); server_client_clear_overlay(c);
if (fs != NULL) if (fs != NULL) {
ft = format_create_from_state(NULL, c, fs); ft = format_create_from_state(NULL, c, fs);
else cmd_find_copy_state(&c->prompt_state, fs);
} else {
ft = format_create_defaults(NULL, c, NULL, NULL, NULL); ft = format_create_defaults(NULL, c, NULL, NULL, NULL);
cmd_find_clear_state(&c->prompt_state, 0);
}
if (input == NULL) if (input == NULL)
input = ""; input = "";
@@ -701,7 +704,6 @@ status_prompt_set(struct client *c, struct cmd_find_state *fs,
status_prompt_clear(c); status_prompt_clear(c);
status_push_screen(c); status_push_screen(c);
c->prompt_formats = ft;
c->prompt_string = xstrdup (msg); c->prompt_string = xstrdup (msg);
if (flags & PROMPT_NOFORMAT) if (flags & PROMPT_NOFORMAT)
@@ -737,6 +739,7 @@ status_prompt_set(struct client *c, struct cmd_find_state *fs,
if ((flags & PROMPT_SINGLE) && (flags & PROMPT_ACCEPT)) if ((flags & PROMPT_SINGLE) && (flags & PROMPT_ACCEPT))
cmdq_append(c, cmdq_get_callback(status_prompt_accept, c)); cmdq_append(c, cmdq_get_callback(status_prompt_accept, c));
format_free(ft);
} }
/* Remove status line prompt. */ /* Remove status line prompt. */
@@ -752,9 +755,6 @@ status_prompt_clear(struct client *c)
free(c->prompt_last); free(c->prompt_last);
c->prompt_last = NULL; c->prompt_last = NULL;
format_free(c->prompt_formats);
c->prompt_formats = NULL;
free(c->prompt_string); free(c->prompt_string);
c->prompt_string = NULL; c->prompt_string = NULL;
@@ -774,13 +774,19 @@ status_prompt_clear(struct client *c)
void void
status_prompt_update(struct client *c, const char *msg, const char *input) status_prompt_update(struct client *c, const char *msg, const char *input)
{ {
struct format_tree *ft;
char *tmp; char *tmp;
if (cmd_find_valid_state(&c->prompt_state))
ft = format_create_from_state(NULL, c, &c->prompt_state);
else
ft = format_create_defaults(NULL, c, NULL, NULL, NULL);
free(c->prompt_string); free(c->prompt_string);
c->prompt_string = xstrdup(msg); c->prompt_string = xstrdup(msg);
free(c->prompt_buffer); free(c->prompt_buffer);
tmp = format_expand_time(c->prompt_formats, input); tmp = format_expand_time(ft, input);
c->prompt_buffer = utf8_fromcstr(tmp); c->prompt_buffer = utf8_fromcstr(tmp);
c->prompt_index = utf8_strlen(c->prompt_buffer); c->prompt_index = utf8_strlen(c->prompt_buffer);
free(tmp); free(tmp);
@@ -788,6 +794,7 @@ status_prompt_update(struct client *c, const char *msg, const char *input)
memset(c->prompt_hindex, 0, sizeof c->prompt_hindex); memset(c->prompt_hindex, 0, sizeof c->prompt_hindex);
c->flags |= CLIENT_REDRAWSTATUS; c->flags |= CLIENT_REDRAWSTATUS;
format_free(ft);
} }
/* Redraw character. Return 1 if can continue redrawing, 0 otherwise. */ /* Redraw character. Return 1 if can continue redrawing, 0 otherwise. */
@@ -846,11 +853,13 @@ status_prompt_redraw(struct client *c)
struct status_line *sl = &c->status; struct status_line *sl = &c->status;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
struct session *s = c->session; struct session *s = c->session;
struct options *oo = s->options;
struct screen old_screen; struct screen old_screen;
u_int i, lines, offset, left, start, width, n; u_int i, lines, offset, left, start, width, n;
u_int pcursor, pwidth, promptline; u_int pcursor, pwidth, promptline;
u_int ax, aw; u_int ax, aw;
struct grid_cell gc; struct grid_cell gc;
struct format_tree *ft;
const char *msgfmt; const char *msgfmt;
char *expanded, *prompt, *tmp; char *expanded, *prompt, *tmp;
@@ -863,12 +872,17 @@ status_prompt_redraw(struct client *c)
lines = 1; lines = 1;
screen_init(sl->active, c->tty.sx, lines, 0); screen_init(sl->active, c->tty.sx, lines, 0);
if (cmd_find_valid_state(&c->prompt_state))
ft = format_create_from_state(NULL, c, &c->prompt_state);
else
ft = format_create_defaults(NULL, c, NULL, NULL, NULL);
n = options_get_number(s->options, "prompt-cursor-colour"); n = options_get_number(s->options, "prompt-cursor-colour");
sl->active->default_ccolour = n; sl->active->default_ccolour = n;
if (c->prompt_mode == PROMPT_COMMAND) if (c->prompt_mode == PROMPT_COMMAND)
n = options_get_number(s->options, "prompt-command-cursor-style"); n = options_get_number(oo, "prompt-command-cursor-style");
else else
n = options_get_number(s->options, "prompt-cursor-style"); n = options_get_number(oo, "prompt-cursor-style");
screen_set_cursor_style(n, &sl->active->default_cstyle, screen_set_cursor_style(n, &sl->active->default_cstyle,
&sl->active->default_mode); &sl->active->default_mode);
@@ -877,28 +891,29 @@ status_prompt_redraw(struct client *c)
promptline = lines - 1; promptline = lines - 1;
if (c->prompt_mode == PROMPT_COMMAND) if (c->prompt_mode == PROMPT_COMMAND)
style_apply(&gc, s->options, "message-command-style", NULL); style_apply(&gc, oo, "message-command-style", NULL);
else else
style_apply(&gc, s->options, "message-style", NULL); style_apply(&gc, oo, "message-style", NULL);
status_prompt_area(c, &ax, &aw); status_prompt_area(c, &ax, &aw);
tmp = utf8_tocstr(c->prompt_buffer); tmp = utf8_tocstr(c->prompt_buffer);
format_add(c->prompt_formats, "prompt-input", "%s", tmp); format_add(ft, "prompt-input", "%s", tmp);
prompt = format_expand_time(c->prompt_formats, c->prompt_string); prompt = format_expand_time(ft, c->prompt_string);
free(tmp); free(tmp);
/* /*
* Set #{message} to the prompt string and expand message-format. * Set #{message} to the prompt string and expand message-format.
* format_draw handles fill, alignment, and decorations in one call. * format_draw handles fill, alignment, and decorations in one call.
*/ */
format_add(c->prompt_formats, "message", "%s", prompt); format_add(ft, "message", "%s", prompt);
format_add(c->prompt_formats, "command_prompt", "%d", format_add(ft, "command_prompt", "%d",
c->prompt_mode == PROMPT_COMMAND); c->prompt_mode == PROMPT_COMMAND);
msgfmt = options_get_string(s->options, "message-format"); msgfmt = options_get_string(oo, "message-format");
expanded = format_expand_time(c->prompt_formats, msgfmt); expanded = format_expand_time(ft, msgfmt);
free(prompt);
start = format_width(prompt); start = format_width(expanded);
if (start > aw) if (start > aw)
start = aw; start = aw;
@@ -972,6 +987,49 @@ status_prompt_space(const struct utf8_data *ud)
return (*ud->data == ' '); return (*ud->data == ' ');
} }
static key_code
status_prompt_keypad_key(key_code key)
{
if (key & KEYC_MASK_MODIFIERS)
return (key);
switch (key) {
case KEYC_KP_SLASH:
return ('/');
case KEYC_KP_STAR:
return ('*');
case KEYC_KP_MINUS:
return ('-');
case KEYC_KP_SEVEN:
return ('7');
case KEYC_KP_EIGHT:
return ('8');
case KEYC_KP_NINE:
return ('9');
case KEYC_KP_PLUS:
return ('+');
case KEYC_KP_FOUR:
return ('4');
case KEYC_KP_FIVE:
return ('5');
case KEYC_KP_SIX:
return ('6');
case KEYC_KP_ONE:
return ('1');
case KEYC_KP_TWO:
return ('2');
case KEYC_KP_THREE:
return ('3');
case KEYC_KP_ENTER:
return ('\r');
case KEYC_KP_ZERO:
return ('0');
case KEYC_KP_PERIOD:
return ('.');
}
return (key);
}
/* /*
* Translate key from vi to emacs. Return 0 to drop key, 1 to process the key * Translate key from vi to emacs. Return 0 to drop key, 1 to process the key
* as an emacs key; return 2 to append to the buffer. * as an emacs key; return 2 to append to the buffer.
@@ -1010,6 +1068,7 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key)
*new_key = key; *new_key = key;
return (1); return (1);
case '\033': /* Escape */ case '\033': /* Escape */
case '['|KEYC_CTRL:
c->prompt_mode = PROMPT_COMMAND; c->prompt_mode = PROMPT_COMMAND;
if (c->prompt_index != 0) if (c->prompt_index != 0)
c->prompt_index--; c->prompt_index--;
@@ -1042,6 +1101,7 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key)
c->flags |= CLIENT_REDRAWSTATUS; c->flags |= CLIENT_REDRAWSTATUS;
return (0); return (0);
case '\033': /* Escape */ case '\033': /* Escape */
case '['|KEYC_CTRL:
return (0); return (0);
} }
@@ -1383,6 +1443,9 @@ status_prompt_key(struct client *c, key_code key)
} }
size = utf8_strlen(c->prompt_buffer); size = utf8_strlen(c->prompt_buffer);
key &= ~KEYC_MASK_FLAGS;
key = status_prompt_keypad_key(key);
if (c->prompt_flags & PROMPT_NUMERIC) { if (c->prompt_flags & PROMPT_NUMERIC) {
if (key >= '0' && key <= '9') if (key >= '0' && key <= '9')
goto append_key; goto append_key;
@@ -1392,7 +1455,6 @@ status_prompt_key(struct client *c, key_code key)
free(s); free(s);
return (1); return (1);
} }
key &= ~KEYC_MASK_FLAGS;
if (c->prompt_flags & (PROMPT_SINGLE|PROMPT_QUOTENEXT)) { if (c->prompt_flags & (PROMPT_SINGLE|PROMPT_QUOTENEXT)) {
if ((key & KEYC_MASK_KEY) == KEYC_BSPACE) if ((key & KEYC_MASK_KEY) == KEYC_BSPACE)
@@ -1607,6 +1669,7 @@ process_key:
free(s); free(s);
break; break;
case '\033': /* Escape */ case '\033': /* Escape */
case '['|KEYC_CTRL:
case 'c'|KEYC_CTRL: case 'c'|KEYC_CTRL:
case 'g'|KEYC_CTRL: case 'g'|KEYC_CTRL:
if (c->prompt_inputcb(c, c->prompt_data, NULL, 1) == 0) if (c->prompt_inputcb(c, c->prompt_data, NULL, 1) == 0)

91
tmux.1
View File

@@ -2228,6 +2228,11 @@ Turn off rectangle selection mode.
.Xc .Xc
Toggle rectangle selection mode. Toggle rectangle selection mode.
.It Xo .It Xo
.Ic recentre\-top\-bottom
(emacs : C-l)
.Xc
Cycles the current line between centre, top, and bottom.
.It Xo
.Ic refresh\-from\-pane .Ic refresh\-from\-pane
(vi: r) (vi: r)
(emacs: r) (emacs: r)
@@ -4664,6 +4669,8 @@ mouse sequences.
Supports the OSC 7 working directory extension. Supports the OSC 7 working directory extension.
.It overline .It overline
Supports the overline SGR attribute. Supports the overline SGR attribute.
.It progressbar
Supports the OSC 9;4 progress bar extension.
.It rectfill .It rectfill
Supports the DECFRA rectangle fill escape sequence. Supports the DECFRA rectangle fill escape sequence.
.It RGB .It RGB
@@ -5357,17 +5364,6 @@ section.
.It Ic copy\-mode\-position\-format Ar format .It Ic copy\-mode\-position\-format Ar format
Format of the position indicator in copy mode. Format of the position indicator in copy mode.
.Pp .Pp
.It Xo Ic mode\-keys
.Op Ic vi | emacs
.Xc
Use vi or emacs-style key bindings in copy mode.
The default is emacs, unless
.Ev VISUAL
or
.Ev EDITOR
contains
.Ql vi .
.Pp
.It Ic copy\-mode\-position\-style Ar style .It Ic copy\-mode\-position\-style Ar style
Set the style of the position indicator in copy mode. Set the style of the position indicator in copy mode.
For how to specify For how to specify
@@ -5384,6 +5380,63 @@ see the
.Sx STYLES .Sx STYLES
section. section.
.Pp .Pp
.It Ic copy\-mode\-current\-line\-number\-style Ar style
Set style of current line number in copy mode.
For how to specify
.Ar style ,
see the
.Sx STYLES
section.
.Pp
.It Ic copy\-mode\-line\-number\-style Ar style
Set style of line numbers in copy mode.
For how to specify
.Ar style ,
see the
.Sx STYLES
section.
.Pp
.It Xo Ic copy\-mode\-line\-numbers
.Op Ic off | default | absolute | relative | hybrid
.Xc
Show line numbers in copy mode.
.Ic off
hides line numbers,
.Ic default
shows line numbers matching the copy mode position indicator and
.Ic goto\-line ,
.Ic absolute
shows absolute line numbers,
.Ic relative
shows line numbers relative to the cursor, and
.Ic hybrid
shows the current line number as absolute and other line numbers as
relative.
With
.Ic off
or
.Ic default ,
the position indicator and
.Ic goto\-line
use the same numbering;
with
.Ic absolute ,
.Ic relative
and
.Ic hybrid ,
they use absolute line numbers.
.Pp
.It Xo Ic mode\-keys
.Op Ic vi | emacs
.Xc
Use vi or emacs-style key bindings in copy mode.
The default is emacs, unless
.Ev VISUAL
or
.Ev EDITOR
contains
.Ql vi .
.Pp
.It Ic mode\-style Ar style .It Ic mode\-style Ar style
Set window modes style. Set window modes style.
For how to specify For how to specify
@@ -5628,6 +5681,17 @@ A value of 0 (the default) means no limit.
When a limit is set, panes are arranged to not exceed this number of columns, When a limit is set, panes are arranged to not exceed this number of columns,
with additional panes stacked in extra rows. with additional panes stacked in extra rows.
.Pp .Pp
.It Ic tree\-mode\-preview\-format Ar format
Format of the preview indicator in tree mode.
.Pp
.It Ic tree\-mode\-preview\-style Ar style
Set the style of the preview indicator in tree mode.
For how to specify
.Ar style ,
see the
.Sx STYLES
section.
.Pp
.It Ic window\-status\-activity\-style Ar style .It Ic window\-status\-activity\-style Ar style
Set status line style for windows with an activity alert. Set status line style for windows with an activity alert.
For how to specify For how to specify
@@ -6533,6 +6597,8 @@ The following variables are available, where appropriate:
.It Li "copy_cursor_word" Ta "" Ta "Word under cursor in copy mode" .It Li "copy_cursor_word" Ta "" Ta "Word under cursor in copy mode"
.It Li "copy_cursor_x" Ta "" Ta "Cursor X position in copy mode" .It Li "copy_cursor_x" Ta "" Ta "Cursor X position in copy mode"
.It Li "copy_cursor_y" Ta "" Ta "Cursor Y position in copy mode" .It Li "copy_cursor_y" Ta "" Ta "Cursor Y position in copy mode"
.It Li "copy_position" Ta "" Ta "Position shown in the copy mode indicator"
.It Li "copy_position_limit" Ta "" Ta "Limit shown in the copy mode indicator"
.It Li "current_file" Ta "" Ta "Current configuration file" .It Li "current_file" Ta "" Ta "Current configuration file"
.It Li "cursor_character" Ta "" Ta "Character at cursor in pane" .It Li "cursor_character" Ta "" Ta "Character at cursor in pane"
.It Li "cursor_colour" Ta "" Ta "Cursor colour in pane" .It Li "cursor_colour" Ta "" Ta "Cursor colour in pane"
@@ -7493,7 +7559,6 @@ Display a popup running
when omitted) on when omitted) on
.Ar target\-client . .Ar target\-client .
A popup is a rectangular box drawn over the top of any panes. A popup is a rectangular box drawn over the top of any panes.
Panes are not updated while a popup is present.
If the command is run inside an existing popup, that popup is modified. If the command is run inside an existing popup, that popup is modified.
Only the Only the
.Fl b , .Fl b ,
@@ -8081,6 +8146,8 @@ $ printf \[aq]\e033[4 q\[aq]
If If
.Em Se .Em Se
is not set, \&Ss with argument 0 will be used to reset the cursor style instead. is not set, \&Ss with argument 0 will be used to reset the cursor style instead.
.It Em \&Spb
Set the state and progress for the OSC9;4 progress bar.
.It Em \&Swd .It Em \&Swd
Set the opening sequence for the working directory notification. Set the opening sequence for the working directory notification.
The sequence is terminated using the standard The sequence is terminated using the standard

17
tmux.c
View File

@@ -281,6 +281,23 @@ get_timer(void)
return ((ts.tv_sec * 1000ULL) + (ts.tv_nsec / 1000000ULL)); return ((ts.tv_sec * 1000ULL) + (ts.tv_nsec / 1000000ULL));
} }
char *
clean_name(const char *name, const char* forbid)
{
char *copy, *cp, *new_name;
if (*name == '\0' || !utf8_isvalid(name))
return (NULL);
copy = xstrdup(name);
for (cp = copy; *cp != '\0'; cp++) {
if (strchr(forbid, *cp) != NULL)
*cp = '_';
}
utf8_stravis(&new_name, copy, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL);
free(copy);
return (new_name);
}
const char * const char *
sig2name(int signo) sig2name(int signo)
{ {

23
tmux.h
View File

@@ -638,6 +638,7 @@ enum tty_code_code {
TTYC_SMUL, TTYC_SMUL,
TTYC_SMULX, TTYC_SMULX,
TTYC_SMXX, TTYC_SMXX,
TTYC_SPB,
TTYC_SXL, TTYC_SXL,
TTYC_SS, TTYC_SS,
TTYC_SWD, TTYC_SWD,
@@ -970,8 +971,10 @@ struct image {
u_int sx; u_int sx;
u_int sy; u_int sy;
TAILQ_ENTRY (image) all_entry; struct images *list;
TAILQ_ENTRY (image) entry; TAILQ_ENTRY (image) entry;
TAILQ_ENTRY (image) all_entry;
}; };
TAILQ_HEAD(images, image); TAILQ_HEAD(images, image);
#endif #endif
@@ -1005,6 +1008,7 @@ struct screen {
char *title; char *title;
char *path; char *path;
struct screen_titles *titles; struct screen_titles *titles;
u_int ntitles;
struct grid *grid; /* grid data */ struct grid *grid; /* grid data */
@@ -2035,6 +2039,7 @@ struct client {
char *title; char *title;
char *path; char *path;
const char *cwd; const char *cwd;
struct progress_bar progress_bar;
char *term_name; char *term_name;
int term_features; int term_features;
@@ -2144,8 +2149,8 @@ struct client {
struct event message_timer; struct event message_timer;
char *prompt_string; char *prompt_string;
struct format_tree *prompt_formats;
struct utf8_data *prompt_buffer; struct utf8_data *prompt_buffer;
struct cmd_find_state prompt_state;
char *prompt_last; char *prompt_last;
size_t prompt_index; size_t prompt_index;
prompt_input_cb prompt_inputcb; prompt_input_cb prompt_inputcb;
@@ -2380,6 +2385,7 @@ int checkshell(const char *);
void setblocking(int, int); void setblocking(int, int);
char *shell_argv0(const char *, int); char *shell_argv0(const char *, int);
uint64_t get_timer(void); uint64_t get_timer(void);
char *clean_name(const char *, const char *);
const char *sig2name(int); const char *sig2name(int);
const char *find_cwd(void); const char *find_cwd(void);
const char *find_home(void); const char *find_home(void);
@@ -2674,6 +2680,7 @@ void tty_repeat_requests(struct tty *, int);
void tty_stop_tty(struct tty *); void tty_stop_tty(struct tty *);
void tty_set_title(struct tty *, const char *); void tty_set_title(struct tty *, const char *);
void tty_set_path(struct tty *, const char *); void tty_set_path(struct tty *, const char *);
void tty_set_progress_bar(struct tty *, struct progress_bar *);
void tty_default_attributes(struct tty *, const struct grid_cell *, void tty_default_attributes(struct tty *, const struct grid_cell *,
struct colour_palette *, u_int, struct hyperlinks *); struct colour_palette *, u_int, struct hyperlinks *);
void tty_update_mode(struct tty *, int, struct screen *); void tty_update_mode(struct tty *, int, struct screen *);
@@ -3009,9 +3016,9 @@ void file_write_data(struct client_files *, struct imsg *);
void file_write_close(struct client_files *, struct imsg *); void file_write_close(struct client_files *, struct imsg *);
void file_read_open(struct client_files *, struct tmuxpeer *, struct imsg *, void file_read_open(struct client_files *, struct tmuxpeer *, struct imsg *,
int, int, client_file_cb, void *); int, int, client_file_cb, void *);
void file_write_ready(struct client_files *, struct imsg *); int file_write_ready(struct client_files *, struct imsg *);
void file_read_data(struct client_files *, struct imsg *); int file_read_data(struct client_files *, struct imsg *);
void file_read_done(struct client_files *, struct imsg *); int file_read_done(struct client_files *, struct imsg *);
void file_read_cancel(struct client_files *, struct imsg *); void file_read_cancel(struct client_files *, struct imsg *);
/* server.c */ /* server.c */
@@ -3353,14 +3360,14 @@ void screen_set_default_cursor(struct screen *, struct options *);
void screen_set_cursor_style(u_int, enum screen_cursor_style *, int *); void screen_set_cursor_style(u_int, enum screen_cursor_style *, int *);
void screen_set_cursor_colour(struct screen *, int); void screen_set_cursor_colour(struct screen *, int);
int screen_set_title(struct screen *, const char *); int screen_set_title(struct screen *, const char *);
void screen_set_path(struct screen *, const char *); int screen_set_path(struct screen *, const char *);
void screen_push_title(struct screen *); void screen_push_title(struct screen *);
void screen_pop_title(struct screen *); void screen_pop_title(struct screen *);
void screen_set_progress_bar(struct screen *, enum progress_bar_state, int); 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(struct screen *, u_int, u_int, int);
void screen_resize_cursor(struct screen *, u_int, u_int, int, 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, void screen_set_selection(struct screen *, u_int, u_int, u_int, u_int,
u_int, int, struct grid_cell *); u_int, u_int, int, struct grid_cell *);
void screen_clear_selection(struct screen *); void screen_clear_selection(struct screen *);
void screen_hide_selection(struct screen *); void screen_hide_selection(struct screen *);
int screen_check_selection(struct screen *, u_int, u_int); int screen_check_selection(struct screen *, u_int, u_int);
@@ -3605,6 +3612,7 @@ char *window_copy_get_line(struct window_pane *, u_int);
int window_copy_get_current_offset(struct window_pane *, u_int *, int window_copy_get_current_offset(struct window_pane *, u_int *,
u_int *); u_int *);
char *window_copy_get_hyperlink(struct window_pane *, u_int, u_int); char *window_copy_get_hyperlink(struct window_pane *, u_int, u_int);
void window_copy_set_line_numbers(struct window_pane *, int);
/* window-option.c */ /* window-option.c */
extern const struct window_mode window_customize_mode; extern const struct window_mode window_customize_mode;
@@ -3666,7 +3674,6 @@ struct session *session_create(const char *, const char *, const char *,
void session_destroy(struct session *, int, const char *); void session_destroy(struct session *, int, const char *);
void session_add_ref(struct session *, const char *); void session_add_ref(struct session *, const char *);
void session_remove_ref(struct session *, const char *); void session_remove_ref(struct session *, const char *);
char *session_check_name(const char *);
void session_update_activity(struct session *, struct timeval *); void session_update_activity(struct session *, struct timeval *);
struct session *session_next_session(struct session *, struct sort_criteria *); struct session *session_next_session(struct session *, struct sort_criteria *);
struct session *session_previous_session(struct session *, struct session *session_previous_session(struct session *,

View File

@@ -357,6 +357,17 @@ static const struct tty_feature tty_feature_sixel = {
TERM_SIXEL TERM_SIXEL
}; };
/* Terminal supports the OSC 9;4 progress bar. */
static const char *const tty_feature_progressbar_capabilities[] = {
"Spb=\\E]9;4;%p1%d;%p2%d\\E\\\\",
NULL
};
static const struct tty_feature tty_feature_progressbar = {
"progressbar",
tty_feature_progressbar_capabilities,
0
};
/* Available terminal features. */ /* Available terminal features. */
static const struct tty_feature *const tty_features[] = { static const struct tty_feature *const tty_features[] = {
&tty_feature_256, &tty_feature_256,
@@ -372,6 +383,7 @@ static const struct tty_feature *const tty_features[] = {
&tty_feature_mouse, &tty_feature_mouse,
&tty_feature_osc7, &tty_feature_osc7,
&tty_feature_overline, &tty_feature_overline,
&tty_feature_progressbar,
&tty_feature_rectfill, &tty_feature_rectfill,
&tty_feature_rgb, &tty_feature_rgb,
&tty_feature_sixel, &tty_feature_sixel,
@@ -490,7 +502,8 @@ tty_default_features(int *feat, const char *name, u_int version)
"focus," "focus,"
"overline," "overline,"
"usstyle," "usstyle,"
"hyperlinks" "hyperlinks,"
"progressbar"
}, },
{ .name = "rxvt-unicode", { .name = "rxvt-unicode",
.features = "256," .features = "256,"
@@ -508,13 +521,23 @@ tty_default_features(int *feat, const char *name, u_int version)
"margins," "margins,"
"usstyle," "usstyle,"
"sync," "sync,"
"osc7,hyperlinks" "osc7,"
"hyperlinks,"
"progressbar"
}, },
{ .name = "foot", { .name = "foot",
.features = TTY_FEATURES_BASE_MODERN_XTERM "," .features = TTY_FEATURES_BASE_MODERN_XTERM ","
"cstyle," "cstyle,"
"extkeys" "extkeys"
}, },
{ .name = "WezTerm",
.features = TTY_FEATURES_BASE_MODERN_XTERM ","
"ccolour,"
"cstyle,"
"extkeys,"
"focus,"
"usstyle"
},
{ .name = "XTerm", { .name = "XTerm",
/* /*
* xterm also supports DECSLRM and DECFRA, but they can be * xterm also supports DECSLRM and DECFRA, but they can be

View File

@@ -1640,6 +1640,8 @@ tty_keys_extended_device_attributes(struct tty *tty, const char *buf,
tty_default_features(features, "mintty", 0); tty_default_features(features, "mintty", 0);
else if (strncmp(tmp, "foot(", 5) == 0) else if (strncmp(tmp, "foot(", 5) == 0)
tty_default_features(features, "foot", 0); tty_default_features(features, "foot", 0);
else if (strncmp(tmp, "WezTerm ", 7) == 0)
tty_default_features(features, "WezTerm", 0);
log_debug("%s: received extended DA %.*s", c->name, (int)*size, buf); log_debug("%s: received extended DA %.*s", c->name, (int)*size, buf);
free(c->term_type); free(c->term_type);

View File

@@ -280,6 +280,7 @@ static const struct tty_term_code_entry tty_term_codes[] = {
[TTYC_SMULX] = { TTYCODE_STRING, "Smulx" }, [TTYC_SMULX] = { TTYCODE_STRING, "Smulx" },
[TTYC_SMUL] = { TTYCODE_STRING, "smul" }, [TTYC_SMUL] = { TTYCODE_STRING, "smul" },
[TTYC_SMXX] = { TTYCODE_STRING, "smxx" }, [TTYC_SMXX] = { TTYCODE_STRING, "smxx" },
[TTYC_SPB] = { TTYCODE_STRING, "Spb" },
[TTYC_SS] = { TTYCODE_STRING, "Ss" }, [TTYC_SS] = { TTYCODE_STRING, "Ss" },
[TTYC_SWD] = { TTYCODE_STRING, "Swd" }, [TTYC_SWD] = { TTYCODE_STRING, "Swd" },
[TTYC_SYNC] = { TTYCODE_STRING, "Sync" }, [TTYC_SYNC] = { TTYCODE_STRING, "Sync" },

7
tty.c
View File

@@ -3315,3 +3315,10 @@ tty_clipboard_query(struct tty *tty)
evtimer_add(&tty->clipboard_timer, &tv); evtimer_add(&tty->clipboard_timer, &tv);
} }
} }
void
tty_set_progress_bar(struct tty *tty, struct progress_bar *pb)
{
if (tty_term_has(tty->term, TTYC_SPB))
tty_putcode_ii(tty, TTYC_SPB, pb->state, pb->progress);
}

View File

@@ -279,6 +279,7 @@ window_clock_draw_screen(struct window_mode_entry *wme)
memcpy(&gc, &grid_default_cell, sizeof gc); memcpy(&gc, &grid_default_cell, sizeof gc);
gc.flags |= GRID_FLAG_NOPALETTE; gc.flags |= GRID_FLAG_NOPALETTE;
gc.bg = colour; gc.bg = colour;
gc.fg = colour;
for (ptr = tim; *ptr != '\0'; ptr++) { for (ptr = tim; *ptr != '\0'; ptr++) {
if (*ptr >= '0' && *ptr <= '9') if (*ptr >= '0' && *ptr <= '9')
idx = *ptr - '0'; idx = *ptr - '0';
@@ -299,7 +300,7 @@ window_clock_draw_screen(struct window_mode_entry *wme)
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
screen_write_cursormove(&ctx, x + i, y + j, 0); screen_write_cursormove(&ctx, x + i, y + j, 0);
if (window_clock_table[idx][j][i]) if (window_clock_table[idx][j][i])
screen_write_putc(&ctx, &gc, ' '); screen_write_putc(&ctx, &gc, '#');
} }
} }
x += 6; x += 6;

View File

@@ -52,6 +52,12 @@ static void window_copy_redraw_lines(struct window_mode_entry *, u_int,
u_int); u_int);
static void window_copy_redraw_screen(struct window_mode_entry *); static void window_copy_redraw_screen(struct window_mode_entry *);
static void window_copy_style_changed(struct window_mode_entry *); static void window_copy_style_changed(struct window_mode_entry *);
static int window_copy_line_number_mode(struct window_mode_entry *);
static int window_copy_line_number_is_absolute(struct window_mode_entry *);
static int window_copy_line_numbers_active(struct window_mode_entry *);
static u_int window_copy_line_number_width(struct window_mode_entry *);
static u_int window_copy_cursor_offset(struct window_mode_entry *, u_int, u_int);
static u_int window_copy_cursor_unoffset(struct window_mode_entry *, u_int, u_int);
static void window_copy_write_line(struct window_mode_entry *, static void window_copy_write_line(struct window_mode_entry *,
struct screen_write_ctx *, u_int); struct screen_write_ctx *, u_int);
static void window_copy_write_lines(struct window_mode_entry *, static void window_copy_write_lines(struct window_mode_entry *,
@@ -207,6 +213,14 @@ enum window_copy_cmd_clear {
WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
}; };
enum window_copy_line_numbers {
WINDOW_COPY_LINE_NUMBERS_OFF,
WINDOW_COPY_LINE_NUMBERS_DEFAULT,
WINDOW_COPY_LINE_NUMBERS_ABSOLUTE,
WINDOW_COPY_LINE_NUMBERS_RELATIVE,
WINDOW_COPY_LINE_NUMBERS_HYBRID,
};
struct window_copy_cmd_state { struct window_copy_cmd_state {
struct window_mode_entry *wme; struct window_mode_entry *wme;
struct args *args; struct args *args;
@@ -264,6 +278,7 @@ struct window_copy_mode_data {
int rectflag; /* in rectangle copy mode? */ int rectflag; /* in rectangle copy mode? */
int scroll_exit; /* exit on scroll to end? */ int scroll_exit; /* exit on scroll to end? */
int hide_position; /* hide position marker */ int hide_position; /* hide position marker */
int line_numbers;
enum { enum {
SEL_CHAR, /* select one char at a time */ SEL_CHAR, /* select one char at a time */
@@ -271,6 +286,13 @@ struct window_copy_mode_data {
SEL_LINE, /* select one line at a time */ SEL_LINE, /* select one line at a time */
} selflag; } selflag;
enum {
RECENTRE_TOP,
RECENTRE_MIDDLE,
RECENTRE_BOTTOM,
} recentre_state;
u_int recentre_line;
const char *separators; /* word separators */ const char *separators; /* word separators */
u_int dx; /* drag start position */ u_int dx; /* drag start position */
@@ -427,6 +449,7 @@ window_copy_common_init(struct window_mode_entry *wme)
data->jumptype = WINDOW_COPY_OFF; data->jumptype = WINDOW_COPY_OFF;
data->jumpchar = NULL; data->jumpchar = NULL;
data->line_numbers = 1;
screen_init(&data->screen, screen_size_x(base), screen_size_y(base), 0); screen_init(&data->screen, screen_size_x(base), screen_size_y(base), 0);
screen_set_default_cursor(&data->screen, global_w_options); screen_set_default_cursor(&data->screen, global_w_options);
@@ -463,9 +486,12 @@ window_copy_init(struct window_mode_entry *wme,
data->scroll_exit = args_has(args, 'e'); data->scroll_exit = args_has(args, 'e');
data->hide_position = args_has(args, 'H'); data->hide_position = args_has(args, 'H');
if (base->hyperlinks != NULL) if (base->hyperlinks != NULL) {
hyperlinks_free(data->screen.hyperlinks);
data->screen.hyperlinks = hyperlinks_copy(base->hyperlinks); data->screen.hyperlinks = hyperlinks_copy(base->hyperlinks);
data->screen.cx = data->cx; }
data->screen.cx = window_copy_cursor_offset(wme, data->cx,
screen_size_x(&data->screen));
data->screen.cy = data->cy; data->screen.cy = data->cy;
data->mx = data->cx; data->mx = data->cx;
data->my = screen_hsize(data->backing) + data->cy - data->oy; data->my = screen_hsize(data->backing) + data->cy - data->oy;
@@ -474,9 +500,13 @@ window_copy_init(struct window_mode_entry *wme,
screen_write_start(&ctx, &data->screen); screen_write_start(&ctx, &data->screen);
for (i = 0; i < screen_size_y(&data->screen); i++) for (i = 0; i < screen_size_y(&data->screen); i++)
window_copy_write_line(wme, &ctx, i); window_copy_write_line(wme, &ctx, i);
screen_write_cursormove(&ctx, data->cx, data->cy, 0); screen_write_cursormove(&ctx, window_copy_cursor_offset(wme, data->cx,
screen_size_x(&data->screen)), data->cy, 0);
screen_write_stop(&ctx); screen_write_stop(&ctx);
data->recentre_state = RECENTRE_MIDDLE;
data->recentre_line = 0;
return (&data->screen); return (&data->screen);
} }
@@ -491,6 +521,7 @@ window_copy_view_init(struct window_mode_entry *wme,
data = window_copy_common_init(wme); data = window_copy_common_init(wme);
data->viewmode = 1; data->viewmode = 1;
data->line_numbers = 0;
data->backing = xmalloc(sizeof *data->backing); data->backing = xmalloc(sizeof *data->backing);
screen_init(data->backing, sx, screen_size_y(base), UINT_MAX); screen_init(data->backing, sx, screen_size_y(base), UINT_MAX);
@@ -937,12 +968,22 @@ window_copy_formats(struct window_mode_entry *wme, struct format_tree *ft)
{ {
struct window_copy_mode_data *data = wme->data; struct window_copy_mode_data *data = wme->data;
u_int hsize = screen_hsize(data->backing); u_int hsize = screen_hsize(data->backing);
u_int position, limit;
struct grid_line *gl; struct grid_line *gl;
gl = grid_get_line(data->backing->grid, hsize - data->oy); gl = grid_get_line(data->backing->grid, hsize - data->oy);
format_add(ft, "top_line_time", "%llu", (unsigned long long)gl->time); format_add(ft, "top_line_time", "%llu", (unsigned long long)gl->time);
format_add(ft, "scroll_position", "%d", data->oy); format_add(ft, "scroll_position", "%d", data->oy);
if (window_copy_line_number_is_absolute(wme)) {
position = hsize - data->oy + 1;
limit = hsize + screen_size_y(data->backing);
} else {
position = data->oy;
limit = hsize;
}
format_add(ft, "copy_position", "%u", position);
format_add(ft, "copy_position_limit", "%u", limit);
format_add(ft, "rectangle_toggle", "%d", data->rectflag); format_add(ft, "rectangle_toggle", "%d", data->rectflag);
format_add(ft, "copy_cursor_x", "%d", data->cx); format_add(ft, "copy_cursor_x", "%d", data->cx);
@@ -2769,6 +2810,62 @@ window_copy_cmd_refresh_from_pane(struct window_copy_cmd_state *cs)
return (WINDOW_COPY_CMD_REDRAW); return (WINDOW_COPY_CMD_REDRAW);
} }
static enum window_copy_cmd_action
window_copy_cmd_recentre_top_bottom(struct window_copy_cmd_state *cs)
{
struct window_mode_entry *wme = cs->wme;
struct window_copy_mode_data *data = wme->data;
u_int cy = data->cy, oy = data->oy;
u_int sy = screen_size_y(&data->screen) - 1;
u_int sm = sy / 2, backing_row;
enum { MIDDLE, TOP, BOTTOM } target;
backing_row = screen_hsize(data->backing) + cy - data->oy;
if (data->recentre_line != backing_row) {
data->recentre_state = RECENTRE_MIDDLE;
data->recentre_line = backing_row;
}
switch (data->recentre_state) {
case RECENTRE_MIDDLE:
data->recentre_state = RECENTRE_TOP;
target = MIDDLE;
break;
case RECENTRE_TOP:
data->recentre_state = RECENTRE_BOTTOM;
target = TOP;
break;
case RECENTRE_BOTTOM:
default:
data->recentre_state = RECENTRE_MIDDLE;
target = BOTTOM;
break;
}
oy = data->oy;
switch (target) {
case MIDDLE:
if (cy < sm)
window_copy_scroll_down(wme, sm - cy);
else if (cy > sm)
window_copy_scroll_up(wme, cy - sm);
if (data->oy != oy)
data->cy = cy + (data->oy - oy);
break;
case TOP:
window_copy_scroll_up(wme, cy);
data->cy = cy - (oy - data->oy);
break;
case BOTTOM:
window_copy_scroll_down(wme, sy - cy);
data->cy = cy + (data->oy - oy);
break;
}
window_copy_update_selection(wme, 0, 0);
return (WINDOW_COPY_CMD_REDRAW);
}
static const struct { static const struct {
const char *command; const char *command;
u_int minargs; u_int minargs;
@@ -3153,6 +3250,12 @@ static const struct {
.clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY,
.f = window_copy_cmd_previous_word .f = window_copy_cmd_previous_word
}, },
{ .command = "recentre-top-bottom",
.args = { "", 0, 0, NULL },
.flags = WINDOW_COPY_CMD_FLAG_READONLY,
.clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,
.f = window_copy_cmd_recentre_top_bottom
},
{ .command = "rectangle-on", { .command = "rectangle-on",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0, NULL },
.flags = 0, .flags = 0,
@@ -4471,15 +4574,28 @@ window_copy_goto_line(struct window_mode_entry *wme, const char *linestr)
{ {
struct window_copy_mode_data *data = wme->data; struct window_copy_mode_data *data = wme->data;
const char *errstr; const char *errstr;
u_int hsize = screen_hsize(data->backing);
u_int line;
int lineno; int lineno;
lineno = strtonum(linestr, -1, INT_MAX, &errstr); lineno = strtonum(linestr, -1, INT_MAX, &errstr);
if (errstr != NULL) if (errstr != NULL)
return; return;
if (lineno < 0 || (u_int)lineno > screen_hsize(data->backing))
lineno = screen_hsize(data->backing);
if (window_copy_line_number_is_absolute(wme)) {
if (lineno <= 0)
line = 1;
else if ((u_int)lineno > hsize + 1)
line = hsize + 1;
else
line = lineno;
data->oy = hsize - (line - 1);
} else {
if (lineno < 0 || (u_int)lineno > hsize)
lineno = hsize;
data->oy = lineno; data->oy = lineno;
}
window_copy_update_selection(wme, 1, 0); window_copy_update_selection(wme, 1, 0);
window_copy_redraw_screen(wme); window_copy_redraw_screen(wme);
} }
@@ -4628,7 +4744,7 @@ window_copy_update_style(struct window_mode_entry *wme, u_int fx, u_int fy,
static void static void
window_copy_write_one(struct window_mode_entry *wme, window_copy_write_one(struct window_mode_entry *wme,
struct screen_write_ctx *ctx, u_int py, u_int fy, u_int nx, struct screen_write_ctx *ctx, u_int px, u_int py, u_int fy, u_int nx,
const struct grid_cell *mgc, const struct grid_cell *cgc, const struct grid_cell *mgc, const struct grid_cell *cgc,
const struct grid_cell *mkgc) const struct grid_cell *mkgc)
{ {
@@ -4637,7 +4753,7 @@ window_copy_write_one(struct window_mode_entry *wme,
struct grid_cell gc; struct grid_cell gc;
u_int fx; u_int fx;
screen_write_cursormove(ctx, 0, py, 0); screen_write_cursormove(ctx, px, py, 0);
for (fx = 0; fx < nx; fx++) { for (fx = 0; fx < nx; fx++) {
grid_get_cell(gd, fx, fy, &gc); grid_get_cell(gd, fx, fy, &gc);
if (fx + gc.data.width <= nx) { if (fx + gc.data.width <= nx) {
@@ -4648,6 +4764,116 @@ window_copy_write_one(struct window_mode_entry *wme,
} }
} }
static int
window_copy_line_number_mode(struct window_mode_entry *wme)
{
struct window_pane *wp = wme->wp;
struct window_copy_mode_data *data = wme->data;
struct options *oo = wp->window->options;
if (!data->line_numbers)
return (WINDOW_COPY_LINE_NUMBERS_OFF);
return (options_get_number(oo, "copy-mode-line-numbers"));
}
static int
window_copy_line_number_is_absolute(struct window_mode_entry *wme)
{
switch (window_copy_line_number_mode(wme)) {
case WINDOW_COPY_LINE_NUMBERS_ABSOLUTE:
case WINDOW_COPY_LINE_NUMBERS_RELATIVE:
case WINDOW_COPY_LINE_NUMBERS_HYBRID:
return (1);
case WINDOW_COPY_LINE_NUMBERS_OFF:
case WINDOW_COPY_LINE_NUMBERS_DEFAULT:
return (0);
}
fatalx("bad line number mode");
}
static int
window_copy_line_numbers_active(struct window_mode_entry *wme)
{
return (window_copy_line_number_mode(wme) !=
WINDOW_COPY_LINE_NUMBERS_OFF);
}
static u_int
window_copy_line_number_width(struct window_mode_entry *wme)
{
struct window_copy_mode_data *data = wme->data;
u_int lines, digits;
if (!window_copy_line_numbers_active(wme))
return (0);
lines = screen_hsize(data->backing) + screen_size_y(data->backing) + 1;
digits = 1;
while (lines >= 10) {
lines /= 10;
digits++;
}
if (digits < 3)
digits = 3;
return (digits + 1);
}
static u_int
window_copy_cursor_offset(struct window_mode_entry *wme, u_int cx, u_int sx)
{
u_int width = window_copy_line_number_width(wme);
u_int content;
if (width == 0)
return (cx);
if (width >= sx)
content = 1;
else
content = sx - width;
if (cx >= content)
return (sx - 1);
return (width + cx);
}
static u_int
window_copy_cursor_unoffset(struct window_mode_entry *wme, u_int vx, u_int sx)
{
u_int width = window_copy_line_number_width(wme);
u_int content;
if (width == 0)
return (vx);
if (width >= sx)
content = 1;
else
content = sx - width;
if (vx < width)
return (0);
vx -= width;
if (vx >= content)
return (content - 1);
return (vx);
}
void
window_copy_set_line_numbers(struct window_pane *wp, int enabled)
{
struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
struct window_copy_mode_data *data;
if (wme == NULL)
return;
if (wme->mode != &window_copy_mode)
return;
data = wme->data;
if (data == NULL)
return;
if (data->line_numbers == enabled)
return;
data->line_numbers = enabled;
window_copy_redraw_screen(wme);
}
int int
window_copy_get_current_offset(struct window_pane *wp, u_int *offset, window_copy_get_current_offset(struct window_pane *wp, u_int *offset,
u_int *size) u_int *size)
@@ -4673,12 +4899,23 @@ window_copy_write_line(struct window_mode_entry *wme,
struct window_copy_mode_data *data = wme->data; struct window_copy_mode_data *data = wme->data;
struct screen *s = &data->screen; struct screen *s = &data->screen;
struct options *oo = wp->window->options; struct options *oo = wp->window->options;
struct grid_cell gc, mgc, cgc, mkgc; struct grid_cell gc, mgc, cgc, mkgc, ln_gc, cur_ln_gc;
u_int sx = screen_size_x(s); u_int sx = screen_size_x(s);
u_int hsize = screen_hsize(data->backing); u_int hsize = screen_hsize(data->backing);
u_int width;
u_int absolute, line_number, content_sx;
const char *value; const char *value;
char *expanded; char *expanded;
struct format_tree *ft; struct format_tree *ft;
int current, mode;
width = window_copy_line_number_width(wme);
if (width >= sx)
content_sx = 1;
else if (width != 0)
content_sx = sx - width;
else
content_sx = sx;
ft = format_create_defaults(NULL, NULL, NULL, NULL, wp); ft = format_create_defaults(NULL, NULL, NULL, NULL, wp);
@@ -4690,24 +4927,52 @@ window_copy_write_line(struct window_mode_entry *wme,
cgc.flags |= GRID_FLAG_NOPALETTE; cgc.flags |= GRID_FLAG_NOPALETTE;
style_apply(&mkgc, oo, "copy-mode-mark-style", ft); style_apply(&mkgc, oo, "copy-mode-mark-style", ft);
mkgc.flags |= GRID_FLAG_NOPALETTE; mkgc.flags |= GRID_FLAG_NOPALETTE;
if (width != 0) {
style_apply(&ln_gc, oo, "copy-mode-line-number-style", ft);
ln_gc.flags |= GRID_FLAG_NOPALETTE;
style_apply(&cur_ln_gc, oo,
"copy-mode-current-line-number-style", ft);
cur_ln_gc.flags |= GRID_FLAG_NOPALETTE;
current = (py == data->cy);
absolute = hsize - data->oy + py + 1;
mode = window_copy_line_number_mode(wme);
if (mode == WINDOW_COPY_LINE_NUMBERS_DEFAULT) {
if (py < data->oy)
line_number = data->oy - py;
else
line_number = py - data->oy;
} else if (mode == WINDOW_COPY_LINE_NUMBERS_ABSOLUTE)
line_number = absolute;
else if (mode == WINDOW_COPY_LINE_NUMBERS_HYBRID && current)
line_number = absolute;
else if (py > data->cy)
line_number = py - data->cy;
else
line_number = data->cy - py;
screen_write_cursormove(ctx, 0, py, 0);
screen_write_nputs(ctx, width, current ? &cur_ln_gc : &ln_gc,
"%*u ", (int)width - 1, line_number);
}
window_copy_write_one(wme, ctx, py, hsize - data->oy + py, window_copy_write_one(wme, ctx, width, py, hsize - data->oy + py,
screen_size_x(s), &mgc, &cgc, &mkgc); content_sx, &mgc, &cgc, &mkgc);
if (py == 0 && s->rupper < s->rlower && !data->hide_position) { if (py == 0 && s->rupper < s->rlower && !data->hide_position) {
value = options_get_string(oo, "copy-mode-position-format"); value = options_get_string(oo, "copy-mode-position-format");
if (*value != '\0') { if (*value != '\0') {
expanded = format_expand(ft, value); expanded = format_expand(ft, value);
if (*expanded != '\0') { if (*expanded != '\0') {
screen_write_cursormove(ctx, 0, 0, 0); screen_write_cursormove(ctx, width, 0, 0);
format_draw(ctx, &gc, sx, expanded, NULL, 0); format_draw(ctx, &gc, content_sx, expanded,
NULL, 0);
} }
free(expanded); free(expanded);
} }
} }
if (py == data->cy && data->cx == screen_size_x(s)) { if (py == data->cy && data->cx >= content_sx) {
screen_write_cursormove(ctx, screen_size_x(s) - 1, py, 0); screen_write_cursormove(ctx, window_copy_cursor_offset(wme,
data->cx, screen_size_x(s)), py, 0);
screen_write_putc(ctx, &grid_default_cell, '$'); screen_write_putc(ctx, &grid_default_cell, '$');
} }
@@ -4757,13 +5022,28 @@ window_copy_redraw_lines(struct window_mode_entry *wme, u_int py, u_int ny)
{ {
struct window_pane *wp = wme->wp; struct window_pane *wp = wme->wp;
struct window_copy_mode_data *data = wme->data; struct window_copy_mode_data *data = wme->data;
struct screen *s = &data->screen;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
u_int i; u_int i;
if (window_copy_line_number_width(wme) != 0) {
screen_write_start(&ctx, &data->screen);
for (i = py; i < py + ny; i++)
window_copy_write_line(wme, &ctx, i);
screen_write_cursormove(&ctx,
window_copy_cursor_offset(wme, data->cx, screen_size_x(s)),
data->cy, 0);
screen_write_stop(&ctx);
wp->flags |= (PANE_REDRAW|PANE_REDRAWSCROLLBAR);
return;
}
screen_write_start_pane(&ctx, wp, NULL); screen_write_start_pane(&ctx, wp, NULL);
for (i = py; i < py + ny; i++) for (i = py; i < py + ny; i++)
window_copy_write_line(wme, &ctx, i); window_copy_write_line(wme, &ctx, i);
screen_write_cursormove(&ctx, data->cx, data->cy, 0); screen_write_cursormove(&ctx,
window_copy_cursor_offset(wme, data->cx, screen_size_x(s)), data->cy,
0);
screen_write_stop(&ctx); screen_write_stop(&ctx);
wp->flags |= PANE_REDRAWSCROLLBAR; wp->flags |= PANE_REDRAWSCROLLBAR;
@@ -4882,17 +5162,42 @@ window_copy_update_cursor(struct window_mode_entry *wme, u_int cx, u_int cy)
struct window_copy_mode_data *data = wme->data; struct window_copy_mode_data *data = wme->data;
struct screen *s = &data->screen; struct screen *s = &data->screen;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
u_int old_cx, old_cy; u_int old_cx, old_cy, width, content_sx;
old_cx = data->cx; old_cy = data->cy; old_cx = data->cx; old_cy = data->cy;
data->cx = cx; data->cy = cy; data->cx = cx; data->cy = cy;
if (window_copy_line_numbers_active(wme)) {
width = window_copy_line_number_width(wme);
if (s->sel != NULL || data->lineflag != LINE_SEL_NONE ||
old_cy != data->cy) {
window_copy_redraw_screen(wme);
return;
}
if (width >= screen_size_x(s))
content_sx = 1;
else
content_sx = screen_size_x(s) - width;
if (old_cx >= content_sx || data->cx >= content_sx) {
window_copy_redraw_screen(wme);
return;
}
screen_write_start_pane(&ctx, wp, NULL);
screen_write_cursormove(&ctx,
window_copy_cursor_offset(wme, data->cx, screen_size_x(s)),
data->cy, 0);
screen_write_stop(&ctx);
return;
}
if (old_cx == screen_size_x(s)) if (old_cx == screen_size_x(s))
window_copy_redraw_lines(wme, old_cy, 1); window_copy_redraw_lines(wme, old_cy, 1);
if (data->cx == screen_size_x(s)) if (data->cx == screen_size_x(s))
window_copy_redraw_lines(wme, data->cy, 1); window_copy_redraw_lines(wme, data->cy, 1);
else { else {
screen_write_start_pane(&ctx, wp, NULL); screen_write_start_pane(&ctx, wp, NULL);
screen_write_cursormove(&ctx, data->cx, data->cy, 0); screen_write_cursormove(&ctx,
window_copy_cursor_offset(wme, data->cx, screen_size_x(s)),
data->cy, 0);
screen_write_stop(&ctx); screen_write_stop(&ctx);
} }
} }
@@ -4967,7 +5272,7 @@ window_copy_set_selection(struct window_mode_entry *wme, int may_redraw,
struct screen *s = &data->screen; struct screen *s = &data->screen;
struct options *oo = wp->window->options; struct options *oo = wp->window->options;
struct grid_cell gc; struct grid_cell gc;
u_int sx, sy, cy, endsx, endsy; u_int sx, sy, cy, endsx, endsy, clipx;
int startrelpos, endrelpos; int startrelpos, endrelpos;
struct format_tree *ft; struct format_tree *ft;
@@ -4995,8 +5300,15 @@ window_copy_set_selection(struct window_mode_entry *wme, int may_redraw,
style_apply(&gc, oo, "copy-mode-selection-style", ft); style_apply(&gc, oo, "copy-mode-selection-style", ft);
gc.flags |= GRID_FLAG_NOPALETTE; gc.flags |= GRID_FLAG_NOPALETTE;
format_free(ft); format_free(ft);
clipx = window_copy_line_number_width(wme);
if (clipx >= screen_size_x(s))
clipx = screen_size_x(s) - 1;
if (window_copy_line_numbers_active(wme)) {
sx = window_copy_cursor_offset(wme, sx, screen_size_x(s));
endsx = window_copy_cursor_offset(wme, endsx, screen_size_x(s));
}
screen_set_selection(s, sx, sy, endsx, endsy, data->rectflag, screen_set_selection(s, sx, sy, endsx, endsy, data->rectflag,
data->modekeys, &gc); clipx, data->modekeys, &gc);
if (data->rectflag && may_redraw) { if (data->rectflag && may_redraw) {
/* /*
@@ -5152,12 +5464,20 @@ window_copy_copy_buffer(struct window_mode_entry *wme, const char *prefix,
{ {
struct window_pane *wp = wme->wp; struct window_pane *wp = wme->wp;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
int redraw = 0;
if (set_clip && if (set_clip &&
options_get_number(global_options, "set-clipboard") != 0) { options_get_number(global_options, "set-clipboard") != 0) {
if (window_copy_line_numbers_active(wme) &&
(wp->flags & PANE_REDRAW)) {
/* Clear PANE_REDRAW so clipboard write not skipped. */
redraw = PANE_REDRAW;
wp->flags &= ~PANE_REDRAW;
}
screen_write_start_pane(&ctx, wp, NULL); screen_write_start_pane(&ctx, wp, NULL);
screen_write_setselection(&ctx, "", buf, len); screen_write_setselection(&ctx, "", buf, len);
screen_write_stop(&ctx); screen_write_stop(&ctx);
wp->flags |= redraw;
notify_pane("pane-set-clipboard", wp); notify_pane("pane-set-clipboard", wp);
} }
@@ -5180,6 +5500,7 @@ window_copy_pipe_run(struct window_mode_entry *wme, struct session *s,
if (cmd != NULL && *cmd != '\0') { if (cmd != NULL && *cmd != '\0') {
job = job_run(cmd, 0, NULL, NULL, s, NULL, NULL, NULL, NULL, job = job_run(cmd, 0, NULL, NULL, s, NULL, NULL, NULL, NULL,
NULL, JOB_NOWAIT, -1, -1); NULL, JOB_NOWAIT, -1, -1);
if (job != NULL)
bufferevent_write(job_get_event(job), buf, *len); bufferevent_write(job_get_event(job), buf, *len);
} }
return (buf); return (buf);
@@ -5930,6 +6251,32 @@ window_copy_scroll_up(struct window_mode_entry *wme, u_int ny)
if (data->searchmark != NULL && !data->timeout) if (data->searchmark != NULL && !data->timeout)
window_copy_search_marks(wme, NULL, data->searchregex, 1); window_copy_search_marks(wme, NULL, data->searchregex, 1);
window_copy_update_selection(wme, 0, 0); window_copy_update_selection(wme, 0, 0);
if (window_copy_line_numbers_active(wme)) {
if (window_copy_line_number_mode(wme) !=
WINDOW_COPY_LINE_NUMBERS_ABSOLUTE) {
window_copy_redraw_screen(wme);
return;
}
screen_write_start(&ctx, &data->screen);
screen_write_cursormove(&ctx, 0, 0, 0);
screen_write_deleteline(&ctx, ny, 8);
window_copy_write_lines(wme, &ctx, screen_size_y(s) - ny, ny);
window_copy_write_line(wme, &ctx, 0);
if (screen_size_y(s) > 1)
window_copy_write_line(wme, &ctx, 1);
if (screen_size_y(s) > 3)
window_copy_write_line(wme, &ctx, screen_size_y(s) - 2);
if (s->sel != NULL && screen_size_y(s) > ny) {
window_copy_write_line(wme, &ctx,
screen_size_y(s) - ny - 1);
}
screen_write_cursormove(&ctx,
window_copy_cursor_offset(wme, data->cx, screen_size_x(s)),
data->cy, 0);
screen_write_stop(&ctx);
wp->flags |= (PANE_REDRAW|PANE_REDRAWSCROLLBAR);
return;
}
screen_write_start_pane(&ctx, wp, NULL); screen_write_start_pane(&ctx, wp, NULL);
screen_write_cursormove(&ctx, 0, 0, 0); screen_write_cursormove(&ctx, 0, 0, 0);
@@ -5942,7 +6289,9 @@ window_copy_scroll_up(struct window_mode_entry *wme, u_int ny)
window_copy_write_line(wme, &ctx, screen_size_y(s) - 2); window_copy_write_line(wme, &ctx, screen_size_y(s) - 2);
if (s->sel != NULL && screen_size_y(s) > ny) if (s->sel != NULL && screen_size_y(s) > ny)
window_copy_write_line(wme, &ctx, screen_size_y(s) - ny - 1); window_copy_write_line(wme, &ctx, screen_size_y(s) - ny - 1);
screen_write_cursormove(&ctx, data->cx, data->cy, 0); screen_write_cursormove(&ctx,
window_copy_cursor_offset(wme, data->cx, screen_size_x(s)), data->cy,
0);
screen_write_stop(&ctx); screen_write_stop(&ctx);
wp->flags |= PANE_REDRAWSCROLLBAR; wp->flags |= PANE_REDRAWSCROLLBAR;
} }
@@ -5967,6 +6316,27 @@ window_copy_scroll_down(struct window_mode_entry *wme, u_int ny)
if (data->searchmark != NULL && !data->timeout) if (data->searchmark != NULL && !data->timeout)
window_copy_search_marks(wme, NULL, data->searchregex, 1); window_copy_search_marks(wme, NULL, data->searchregex, 1);
window_copy_update_selection(wme, 0, 0); window_copy_update_selection(wme, 0, 0);
if (window_copy_line_numbers_active(wme)) {
if (window_copy_line_number_mode(wme) !=
WINDOW_COPY_LINE_NUMBERS_ABSOLUTE) {
window_copy_redraw_screen(wme);
return;
}
screen_write_start(&ctx, &data->screen);
screen_write_cursormove(&ctx, 0, 0, 0);
screen_write_insertline(&ctx, ny, 8);
window_copy_write_lines(wme, &ctx, 0, ny);
if (s->sel != NULL && screen_size_y(s) > ny)
window_copy_write_line(wme, &ctx, ny);
else if (ny == 1)
window_copy_write_line(wme, &ctx, 1);
screen_write_cursormove(&ctx,
window_copy_cursor_offset(wme, data->cx, screen_size_x(s)),
data->cy, 0);
screen_write_stop(&ctx);
wp->flags |= (PANE_REDRAW|PANE_REDRAWSCROLLBAR);
return;
}
screen_write_start_pane(&ctx, wp, NULL); screen_write_start_pane(&ctx, wp, NULL);
screen_write_cursormove(&ctx, 0, 0, 0); screen_write_cursormove(&ctx, 0, 0, 0);
@@ -5976,7 +6346,8 @@ window_copy_scroll_down(struct window_mode_entry *wme, u_int ny)
window_copy_write_line(wme, &ctx, ny); window_copy_write_line(wme, &ctx, ny);
else if (ny == 1) /* nuke position */ else if (ny == 1) /* nuke position */
window_copy_write_line(wme, &ctx, 1); window_copy_write_line(wme, &ctx, 1);
screen_write_cursormove(&ctx, data->cx, data->cy, 0); screen_write_cursormove(&ctx, window_copy_cursor_offset(wme, data->cx,
screen_size_x(s)), data->cy, 0);
screen_write_stop(&ctx); screen_write_stop(&ctx);
wp->flags |= PANE_REDRAWSCROLLBAR; wp->flags |= PANE_REDRAWSCROLLBAR;
} }
@@ -6004,6 +6375,7 @@ window_copy_move_mouse(struct mouse_event *m)
struct window_pane *wp; struct window_pane *wp;
struct window_mode_entry *wme; struct window_mode_entry *wme;
u_int x, y; u_int x, y;
struct window_copy_mode_data *data;
wp = cmd_mouse_pane(m, NULL, NULL); wp = cmd_mouse_pane(m, NULL, NULL);
if (wp == NULL) if (wp == NULL)
@@ -6017,6 +6389,8 @@ window_copy_move_mouse(struct mouse_event *m)
if (cmd_mouse_at(wp, m, &x, &y, 0) != 0) if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
return; return;
data = wme->data;
x = window_copy_cursor_unoffset(wme, x, screen_size_x(&data->screen));
window_copy_update_cursor(wme, x, y); window_copy_update_cursor(wme, x, y);
} }
@@ -6047,6 +6421,7 @@ window_copy_start_drag(struct client *c, struct mouse_event *m)
c->tty.mouse_drag_release = window_copy_drag_release; c->tty.mouse_drag_release = window_copy_drag_release;
data = wme->data; data = wme->data;
x = window_copy_cursor_unoffset(wme, x, screen_size_x(&data->screen));
yg = screen_hsize(data->backing) + y - data->oy; yg = screen_hsize(data->backing) + y - data->oy;
if (x < data->selrx || x > data->endselrx || yg != data->selry) if (x < data->selrx || x > data->endselrx || yg != data->selry)
data->selflag = SEL_CHAR; data->selflag = SEL_CHAR;
@@ -6104,6 +6479,7 @@ window_copy_drag_update(struct client *c, struct mouse_event *m)
if (cmd_mouse_at(wp, m, &x, &y, 0) != 0) if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
return; return;
x = window_copy_cursor_unoffset(wme, x, screen_size_x(&data->screen));
old_cx = data->cx; old_cx = data->cx;
old_cy = data->cy; old_cy = data->cy;
@@ -6141,6 +6517,8 @@ window_copy_drag_release(struct client *c, struct mouse_event *m)
return; return;
data = wme->data; data = wme->data;
if (window_copy_line_numbers_active(wme))
window_copy_drag_update(c, m);
evtimer_del(&data->dragtimer); evtimer_del(&data->dragtimer);
} }

View File

@@ -411,44 +411,49 @@ static void
window_tree_draw_label(struct screen_write_ctx *ctx, u_int px, u_int py, window_tree_draw_label(struct screen_write_ctx *ctx, u_int px, u_int py,
u_int sx, u_int sy, const struct grid_cell *gc, const char *label) u_int sx, u_int sy, const struct grid_cell *gc, const char *label)
{ {
size_t len; u_int width, ox, oy;
u_int ox, oy; char *new_label = NULL;
len = strlen(label); if (sx < 5 || sy < 3)
if (sx == 0 || sy == 1 || len > sx)
return; return;
ox = (sx - len + 1) / 2; width = format_width(label);
if (width > sx - 4) {
label = new_label = format_trim_left(label, sx - 4);
width = format_width(new_label);
}
if (width == 0)
return;
ox = (sx - width + 1) / 2;
oy = (sy + 1) / 2; oy = (sy + 1) / 2;
if (ox > 1 && ox + len < sx - 1 && sy >= 3) { screen_write_cursormove(ctx, px + ox - 2, py + oy - 1, 0);
screen_write_cursormove(ctx, px + ox - 1, py + oy - 1, 0); screen_write_box(ctx, width + 4, 3, BOX_LINES_DEFAULT,
screen_write_box(ctx, len + 2, 3, BOX_LINES_DEFAULT, NULL, NULL, NULL);
NULL); screen_write_cursormove(ctx, px + ox - 1, py + oy, 0);
} screen_write_clearcharacter(ctx, width + 2, 8);
screen_write_cursormove(ctx, px + ox, py + oy, 0); screen_write_cursormove(ctx, px + ox, py + oy, 0);
screen_write_puts(ctx, gc, "%s", label); format_draw(ctx, gc, width, label, NULL, 0);
free(new_label);
} }
static void static void
window_tree_draw_session(struct window_tree_modedata *data, struct session *s, window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
struct screen_write_ctx *ctx, u_int sx, u_int sy) struct screen_write_ctx *ctx, u_int sx, u_int sy)
{ {
struct options *oo = s->options;
struct winlink *wl; struct winlink *wl;
struct window *w; struct window *w;
u_int cx = ctx->s->cx, cy = ctx->s->cy; u_int cx = ctx->s->cx, cy = ctx->s->cy;
u_int loop, total, visible, each, width, offset; u_int loop, total, visible, each, width, offset;
u_int current, start, end, remaining, i; u_int current, start, end, remaining, i;
struct grid_cell gc; struct grid_cell gc;
int colour, active_colour, left, right; int left, right;
char *label; char *label;
const char *format;
struct format_tree *ft;
struct options *oo;
total = winlink_count(&s->windows); total = winlink_count(&s->windows);
memcpy(&gc, &grid_default_cell, sizeof gc);
colour = options_get_number(oo, "display-panes-colour");
active_colour = options_get_number(oo, "display-panes-active-colour");
if (sx / total < 24) { if (sx / total < 24) {
visible = sx / 24; visible = sx / 24;
if (visible == 0) if (visible == 0)
@@ -528,11 +533,13 @@ window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
continue; continue;
} }
w = wl->window; w = wl->window;
oo = w->options;
if (wl == s->curw) ft = format_create(NULL, NULL, FORMAT_WINDOW|w->id, 0);
gc.fg = active_colour; format_defaults(ft, NULL, s, wl, NULL);
else
gc.fg = colour; memcpy(&gc, &grid_default_cell, sizeof gc);
style_apply(&gc, oo, "tree-mode-preview-style", ft);
if (left) if (left)
offset = 3 + (i * each); offset = 3 + (i * each);
@@ -546,17 +553,19 @@ window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
screen_write_cursormove(ctx, cx + offset, cy, 0); screen_write_cursormove(ctx, cx + offset, cy, 0);
screen_write_preview(ctx, &w->active->base, width, sy); screen_write_preview(ctx, &w->active->base, width, sy);
xasprintf(&label, " %u:%s ", wl->idx, w->name); format = options_get_string(oo, "tree-mode-preview-format");
if (strlen(label) > width) { if (*format != '\0') {
free(label); label = format_expand(ft, format);
xasprintf(&label, " %u ", wl->idx); if (*label != '\0') {
window_tree_draw_label(ctx, cx + offset, cy,
width, sy, &gc, label);
} }
window_tree_draw_label(ctx, cx + offset, cy, width, sy, &gc,
label);
free(label); free(label);
}
if (loop != end - 1) { if (loop != end - 1) {
screen_write_cursormove(ctx, cx + offset + width, cy, 0); screen_write_cursormove(ctx, cx + offset + width, cy,
0);
screen_write_vline(ctx, sy, 0, 0); screen_write_vline(ctx, sy, 0, 0);
} }
loop++; loop++;
@@ -567,23 +576,22 @@ window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
static void static void
window_tree_draw_window(struct window_tree_modedata *data, struct session *s, window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
struct window *w, struct screen_write_ctx *ctx, u_int sx, u_int sy) struct winlink *wl, struct screen_write_ctx *ctx, u_int sx, u_int sy)
{ {
struct options *oo = s->options; struct window *w = wl->window;
struct window_pane *wp; struct window_pane *wp;
u_int cx = ctx->s->cx, cy = ctx->s->cy; u_int cx = ctx->s->cx, cy = ctx->s->cy;
u_int loop, total, visible, each, width, offset; u_int loop, total, visible, each, width, offset;
u_int current, start, end, remaining, i, pane_idx; u_int current, start, end, remaining, i;
struct grid_cell gc; struct grid_cell gc;
int colour, active_colour, left, right; int left, right;
char *label; char *label;
const char *format;
struct format_tree *ft;
struct options *oo;
total = window_count_panes(w, 1); total = window_count_panes(w, 1);
memcpy(&gc, &grid_default_cell, sizeof gc);
colour = options_get_number(oo, "display-panes-colour");
active_colour = options_get_number(oo, "display-panes-active-colour");
if (sx / total < 24) { if (sx / total < 24) {
visible = sx / 24; visible = sx / 24;
if (visible == 0) if (visible == 0)
@@ -662,11 +670,13 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
loop++; loop++;
continue; continue;
} }
oo = wp->options;
if (wp == w->active) ft = format_create(NULL, NULL, FORMAT_PANE|wp->id, 0);
gc.fg = active_colour; format_defaults(ft, NULL, s, wl, wp);
else
gc.fg = colour; memcpy(&gc, &grid_default_cell, sizeof gc);
style_apply(&gc, oo, "tree-mode-preview-style", ft);
if (left) if (left)
offset = 3 + (i * each); offset = 3 + (i * each);
@@ -680,15 +690,19 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
screen_write_cursormove(ctx, cx + offset, cy, 0); screen_write_cursormove(ctx, cx + offset, cy, 0);
screen_write_preview(ctx, &wp->base, width, sy); screen_write_preview(ctx, &wp->base, width, sy);
if (window_pane_index(wp, &pane_idx) != 0) format = options_get_string(oo, "tree-mode-preview-format");
pane_idx = loop; if (*format != '\0') {
xasprintf(&label, " %u ", pane_idx); label = format_expand(ft, format);
window_tree_draw_label(ctx, cx + offset, cy, each, sy, &gc, if (*label != '\0') {
label); window_tree_draw_label(ctx, cx + offset, cy,
width, sy, &gc, label);
}
free(label); free(label);
}
if (loop != end - 1) { if (loop != end - 1) {
screen_write_cursormove(ctx, cx + offset + width, cy, 0); screen_write_cursormove(ctx, cx + offset + width, cy,
0);
screen_write_vline(ctx, sy, 0, 0); screen_write_vline(ctx, sy, 0, 0);
} }
loop++; loop++;
@@ -703,10 +717,10 @@ window_tree_draw(void *modedata, void *itemdata, struct screen_write_ctx *ctx,
{ {
struct window_tree_itemdata *item = itemdata; struct window_tree_itemdata *item = itemdata;
struct session *sp; struct session *sp;
struct winlink *wlp; struct winlink *wl;
struct window_pane *wp; struct window_pane *wp;
window_tree_pull_item(item, &sp, &wlp, &wp); window_tree_pull_item(item, &sp, &wl, &wp);
if (wp == NULL) if (wp == NULL)
return; return;
@@ -717,7 +731,7 @@ window_tree_draw(void *modedata, void *itemdata, struct screen_write_ctx *ctx,
window_tree_draw_session(modedata, sp, ctx, sx, sy); window_tree_draw_session(modedata, sp, ctx, sx, sy);
break; break;
case WINDOW_TREE_WINDOW: case WINDOW_TREE_WINDOW:
window_tree_draw_window(modedata, sp, wlp->window, ctx, sx, sy); window_tree_draw_window(modedata, sp, wl, ctx, sx, sy);
break; break;
case WINDOW_TREE_PANE: case WINDOW_TREE_PANE:
screen_write_preview(ctx, &wp->base, sx, sy); screen_write_preview(ctx, &wp->base, sx, sy);

View File

@@ -407,10 +407,15 @@ window_remove_ref(struct window *w, const char *from)
void void
window_set_name(struct window *w, const char *new_name) window_set_name(struct window *w, const char *new_name)
{ {
char *name;
name = clean_name(new_name, "#");
if (name != NULL) {
free(w->name); free(w->name);
utf8_stravis(&w->name, new_name, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL); w->name = name;
notify_window("window-renamed", w); notify_window("window-renamed", w);
} }
}
void void
window_resize(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel) window_resize(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel)
@@ -2132,13 +2137,15 @@ struct style_range *
window_pane_border_status_get_range(struct window_pane *wp, u_int x, u_int y) window_pane_border_status_get_range(struct window_pane *wp, u_int x, u_int y)
{ {
struct style_ranges *srs; struct style_ranges *srs;
struct window *w = wp->window; struct window *w;
struct options *wo = w->options; struct options *wo;
u_int line; u_int line;
int pane_status; int pane_status;
if (wp == NULL) if (wp == NULL)
return (NULL); return (NULL);
w = wp->window;
wo = w->options;
srs = &wp->border_status_line.ranges; srs = &wp->border_status_line.ranges;
pane_status = options_get_number(wo, "pane-border-status"); pane_status = options_get_number(wo, "pane-border-status");