mirror of
https://github.com/tmux/tmux.git
synced 2024-11-18 10:28:54 +00:00
Merge branch 'obsd-master'
This commit is contained in:
commit
ba9f32b464
@ -157,6 +157,7 @@ cmd_if_shell_callback(struct job *job)
|
||||
}
|
||||
|
||||
cmdq1 = cmdq_new(cmdq->client);
|
||||
cmdq1->flags |= cmdq->flags & CMD_Q_NOHOOKS;
|
||||
cmdq1->emptyfn = cmd_if_shell_done;
|
||||
cmdq1->data = cdata;
|
||||
|
||||
|
44
cmd-queue.c
44
cmd-queue.c
@ -186,6 +186,9 @@ static enum cmd_retval
|
||||
cmdq_continue_one(struct cmd_q *cmdq)
|
||||
{
|
||||
struct cmd *cmd = cmdq->cmd;
|
||||
const char *name = cmd->entry->name;
|
||||
struct session *s;
|
||||
struct hooks *hooks;
|
||||
enum cmd_retval retval;
|
||||
char *tmp;
|
||||
int flags = !!(cmd->flags & CMD_CONTROL);
|
||||
@ -197,19 +200,51 @@ cmdq_continue_one(struct cmd_q *cmdq)
|
||||
cmdq->time = time(NULL);
|
||||
cmdq->number++;
|
||||
|
||||
if (~cmdq->flags & CMD_Q_REENTRY)
|
||||
cmdq_guard(cmdq, "begin", flags);
|
||||
|
||||
if (cmd_prepare_state(cmd, cmdq, NULL) != 0)
|
||||
if (cmd_prepare_state(cmd, cmdq, cmdq->parent) != 0)
|
||||
goto error;
|
||||
|
||||
if (~cmdq->flags & CMD_Q_NOHOOKS) {
|
||||
s = NULL;
|
||||
if (cmdq->state.tflag.s != NULL)
|
||||
s = cmdq->state.tflag.s;
|
||||
else if (cmdq->state.sflag.s != NULL)
|
||||
s = cmdq->state.sflag.s;
|
||||
else if (cmdq->state.c != NULL)
|
||||
s = cmdq->state.c->session;
|
||||
if (s != NULL)
|
||||
hooks = s->hooks;
|
||||
else
|
||||
hooks = global_hooks;
|
||||
|
||||
if (~cmdq->flags & CMD_Q_REENTRY) {
|
||||
cmdq->flags |= CMD_Q_REENTRY;
|
||||
if (hooks_wait(hooks, cmdq, NULL,
|
||||
"before-%s", name) == 0)
|
||||
return (CMD_RETURN_WAIT);
|
||||
if (cmd_prepare_state(cmd, cmdq, cmdq->parent) != 0)
|
||||
goto error;
|
||||
}
|
||||
} else
|
||||
hooks = NULL;
|
||||
cmdq->flags &= ~CMD_Q_REENTRY;
|
||||
|
||||
retval = cmd->entry->exec(cmd, cmdq);
|
||||
if (retval == CMD_RETURN_ERROR)
|
||||
goto error;
|
||||
|
||||
if (hooks != NULL && hooks_wait(hooks, cmdq, NULL,
|
||||
"after-%s", name) == 0)
|
||||
retval = CMD_RETURN_WAIT;
|
||||
cmdq_guard(cmdq, "end", flags);
|
||||
|
||||
return (retval);
|
||||
|
||||
error:
|
||||
cmdq_guard(cmdq, "error", flags);
|
||||
cmdq->flags &= ~CMD_Q_REENTRY;
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
@ -232,11 +267,18 @@ cmdq_continue(struct cmd_q *cmdq)
|
||||
if (empty)
|
||||
goto empty;
|
||||
|
||||
/*
|
||||
* If the command isn't in the middle of running hooks (due to
|
||||
* CMD_RETURN_WAIT), move onto the next command; otherwise, leave the
|
||||
* state of the queue as it is.
|
||||
*/
|
||||
if (~cmdq->flags & CMD_Q_REENTRY) {
|
||||
if (cmdq->item == NULL) {
|
||||
cmdq->item = TAILQ_FIRST(&cmdq->queue);
|
||||
cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
|
||||
} else
|
||||
cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
|
||||
}
|
||||
|
||||
do {
|
||||
while (cmdq->cmd != NULL) {
|
||||
|
@ -49,6 +49,7 @@ cmd_source_file_exec(struct cmd *self, struct cmd_q *cmdq)
|
||||
char *cause;
|
||||
|
||||
cmdq1 = cmdq_new(cmdq->client);
|
||||
cmdq1->flags |= cmdq->flags & CMD_Q_NOHOOKS;
|
||||
cmdq1->emptyfn = cmd_source_file_done;
|
||||
cmdq1->data = cmdq;
|
||||
|
||||
|
5
format.c
5
format.c
@ -485,6 +485,7 @@ struct format_tree *
|
||||
format_create(struct cmd_q *cmdq, int flags)
|
||||
{
|
||||
struct format_tree *ft;
|
||||
struct cmd *cmd;
|
||||
|
||||
if (!event_initialized(&format_job_event)) {
|
||||
evtimer_set(&format_job_event, format_job_timer, NULL);
|
||||
@ -503,6 +504,10 @@ format_create(struct cmd_q *cmdq, int flags)
|
||||
|
||||
if (cmdq != NULL && cmdq->cmd != NULL)
|
||||
format_add(ft, "command_name", "%s", cmdq->cmd->entry->name);
|
||||
if (cmdq != NULL && cmdq->parent != NULL) {
|
||||
cmd = cmdq->parent->cmd;
|
||||
format_add(ft, "command_hooked", "%s", cmd->entry->name);
|
||||
}
|
||||
|
||||
return (ft);
|
||||
}
|
||||
|
@ -64,11 +64,15 @@ screen_write_reset(struct screen_write_ctx *ctx)
|
||||
|
||||
/* Write character. */
|
||||
void
|
||||
screen_write_putc(struct screen_write_ctx *ctx, struct grid_cell *gc,
|
||||
screen_write_putc(struct screen_write_ctx *ctx, const struct grid_cell *gcp,
|
||||
u_char ch)
|
||||
{
|
||||
utf8_set(&gc->data, ch);
|
||||
screen_write_cell(ctx, gc);
|
||||
struct grid_cell gc;
|
||||
|
||||
memcpy(&gc, gcp, sizeof gc);
|
||||
|
||||
utf8_set(&gc.data, ch);
|
||||
screen_write_cell(ctx, &gc);
|
||||
}
|
||||
|
||||
/* Calculate string length, with embedded formatting. */
|
||||
@ -148,75 +152,74 @@ screen_write_strlen(const char *fmt, ...)
|
||||
|
||||
/* Write simple string (no UTF-8 or maximum length). */
|
||||
void
|
||||
screen_write_puts(struct screen_write_ctx *ctx, struct grid_cell *gc,
|
||||
screen_write_puts(struct screen_write_ctx *ctx, const struct grid_cell *gcp,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
screen_write_vnputs(ctx, -1, gc, fmt, ap);
|
||||
screen_write_vnputs(ctx, -1, gcp, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* Write string with length limit (-1 for unlimited). */
|
||||
void
|
||||
screen_write_nputs(struct screen_write_ctx *ctx, ssize_t maxlen,
|
||||
struct grid_cell *gc, const char *fmt, ...)
|
||||
const struct grid_cell *gcp, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
screen_write_vnputs(ctx, maxlen, gc, fmt, ap);
|
||||
screen_write_vnputs(ctx, maxlen, gcp, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
|
||||
struct grid_cell *gc, const char *fmt, va_list ap)
|
||||
const struct grid_cell *gcp, const char *fmt, va_list ap)
|
||||
{
|
||||
struct grid_cell gc;
|
||||
struct utf8_data *ud = &gc.data;
|
||||
char *msg;
|
||||
struct utf8_data ud;
|
||||
u_char *ptr;
|
||||
size_t left, size = 0;
|
||||
enum utf8_state more;
|
||||
|
||||
memcpy(&gc, gcp, sizeof gc);
|
||||
xvasprintf(&msg, fmt, ap);
|
||||
|
||||
ptr = msg;
|
||||
while (*ptr != '\0') {
|
||||
if (*ptr > 0x7f && utf8_open(&ud, *ptr) == UTF8_MORE) {
|
||||
if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) {
|
||||
ptr++;
|
||||
|
||||
left = strlen(ptr);
|
||||
if (left < (size_t)ud.size - 1)
|
||||
if (left < (size_t)ud->size - 1)
|
||||
break;
|
||||
while ((more = utf8_append(&ud, *ptr)) == UTF8_MORE)
|
||||
while ((more = utf8_append(ud, *ptr)) == UTF8_MORE)
|
||||
ptr++;
|
||||
ptr++;
|
||||
|
||||
if (more == UTF8_DONE) {
|
||||
if (maxlen > 0 &&
|
||||
size + ud.width > (size_t) maxlen) {
|
||||
if (more != UTF8_DONE)
|
||||
continue;
|
||||
if (maxlen > 0 && size + ud->width > (size_t)maxlen) {
|
||||
while (size < (size_t)maxlen) {
|
||||
screen_write_putc(ctx, gc, ' ');
|
||||
screen_write_putc(ctx, &gc, ' ');
|
||||
size++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
size += ud.width;
|
||||
|
||||
utf8_copy(&gc->data, &ud);
|
||||
screen_write_cell(ctx, gc);
|
||||
}
|
||||
size += ud->width;
|
||||
screen_write_cell(ctx, &gc);
|
||||
} else {
|
||||
if (maxlen > 0 && size + 1 > (size_t)maxlen)
|
||||
break;
|
||||
|
||||
if (*ptr == '\001')
|
||||
gc->attr ^= GRID_ATTR_CHARSET;
|
||||
gc.attr ^= GRID_ATTR_CHARSET;
|
||||
else if (*ptr > 0x1f && *ptr < 0x7f) {
|
||||
size++;
|
||||
screen_write_putc(ctx, gc, *ptr);
|
||||
screen_write_putc(ctx, &gc, *ptr);
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
@ -228,22 +231,22 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
|
||||
/* Write string, similar to nputs, but with embedded formatting (#[]). */
|
||||
void
|
||||
screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
|
||||
struct grid_cell *gc, const char *fmt, ...)
|
||||
const struct grid_cell *gcp, const char *fmt, ...)
|
||||
{
|
||||
struct grid_cell lgc;
|
||||
struct utf8_data ud;
|
||||
struct grid_cell gc;
|
||||
struct utf8_data *ud = &gc.data;
|
||||
va_list ap;
|
||||
char *msg;
|
||||
u_char *ptr, *last;
|
||||
size_t left, size = 0;
|
||||
enum utf8_state more;
|
||||
|
||||
memcpy(&gc, gcp, sizeof gc);
|
||||
|
||||
va_start(ap, fmt);
|
||||
xvasprintf(&msg, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
memcpy(&lgc, gc, sizeof lgc);
|
||||
|
||||
ptr = msg;
|
||||
while (*ptr != '\0') {
|
||||
if (ptr[0] == '#' && ptr[1] == '[') {
|
||||
@ -255,42 +258,39 @@ screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
|
||||
}
|
||||
*last = '\0';
|
||||
|
||||
style_parse(gc, &lgc, ptr);
|
||||
style_parse(gcp, &gc, ptr);
|
||||
ptr = last + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*ptr > 0x7f && utf8_open(&ud, *ptr) == UTF8_MORE) {
|
||||
if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) {
|
||||
ptr++;
|
||||
|
||||
left = strlen(ptr);
|
||||
if (left < (size_t)ud.size - 1)
|
||||
if (left < (size_t)ud->size - 1)
|
||||
break;
|
||||
while ((more = utf8_append(&ud, *ptr)) == UTF8_MORE)
|
||||
while ((more = utf8_append(ud, *ptr)) == UTF8_MORE)
|
||||
ptr++;
|
||||
ptr++;
|
||||
|
||||
if (more == UTF8_DONE) {
|
||||
if (maxlen > 0 &&
|
||||
size + ud.width > (size_t) maxlen) {
|
||||
if (more != UTF8_DONE)
|
||||
continue;
|
||||
if (maxlen > 0 && size + ud->width > (size_t)maxlen) {
|
||||
while (size < (size_t)maxlen) {
|
||||
screen_write_putc(ctx, gc, ' ');
|
||||
screen_write_putc(ctx, &gc, ' ');
|
||||
size++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
size += ud.width;
|
||||
|
||||
utf8_copy(&lgc.data, &ud);
|
||||
screen_write_cell(ctx, &lgc);
|
||||
}
|
||||
size += ud->width;
|
||||
screen_write_cell(ctx, &gc);
|
||||
} else {
|
||||
if (maxlen > 0 && size + 1 > (size_t)maxlen)
|
||||
break;
|
||||
|
||||
if (*ptr > 0x1f && *ptr < 0x7f) {
|
||||
size++;
|
||||
screen_write_putc(ctx, &lgc, *ptr);
|
||||
screen_write_putc(ctx, &gc, *ptr);
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
33
tmux.1
33
tmux.1
@ -3225,9 +3225,35 @@ shows only the option value, not the name.
|
||||
.Nm
|
||||
allows commands to run on various triggers, called
|
||||
.Em hooks .
|
||||
Each hook has a
|
||||
.Em name .
|
||||
The following hooks are available:
|
||||
Each
|
||||
.Nm
|
||||
command has a
|
||||
.Em before
|
||||
hook and an
|
||||
.Em after
|
||||
hook and there are a number of hooks not associated with commands.
|
||||
.Pp
|
||||
A command's before hook is run before the command is executed and its after
|
||||
hook is run afterwards, except when the command is run as part of a hook
|
||||
itself.
|
||||
Before hooks are named using the
|
||||
.Ql before-
|
||||
prefix and after hooks the
|
||||
.Ql after-
|
||||
prefix.
|
||||
For example, the following command adds a hook to select the even-vertical
|
||||
layout after every
|
||||
.Ic split-window :
|
||||
.Bd -literal -offset indent
|
||||
set-hook after-split-window "selectl even-vertical"
|
||||
.Ed
|
||||
.Pp
|
||||
Or to write when each new window is created to a file:
|
||||
.Bd -literal -offset indent
|
||||
set-hook before-new-window 'run "date >>/tmp/log"'
|
||||
.Ed
|
||||
.Pp
|
||||
In addition, the following hooks are available:
|
||||
.Bl -tag -width "XXXXXXXXXXXXXXXX"
|
||||
.It alert-activity
|
||||
Run when a window has activity.
|
||||
@ -3454,6 +3480,7 @@ The following variables are available, where appropriate:
|
||||
.It Li "client_tty" Ta "" Ta "Pseudo terminal of client"
|
||||
.It Li "client_utf8" Ta "" Ta "1 if client supports utf8"
|
||||
.It Li "client_width" Ta "" Ta "Width of client"
|
||||
.It Li "command_hooked" Ta "" Ta "Name of command hooked, if any"
|
||||
.It Li "command_name" Ta "" Ta "Name of command in use, if any"
|
||||
.It Li "cursor_flag" Ta "" Ta "Pane cursor flag"
|
||||
.It Li "cursor_x" Ta "" Ta "Cursor X position in pane"
|
||||
|
22
tmux.h
22
tmux.h
@ -62,15 +62,8 @@ struct tmuxproc;
|
||||
/* Automatic name refresh interval, in microseconds. Must be < 1 second. */
|
||||
#define NAME_INTERVAL 500000
|
||||
|
||||
/*
|
||||
* READ_SIZE is the maximum size of data to hold from a pty (the event high
|
||||
* watermark). READ_BACKOFF is the amount of data waiting to be output to a tty
|
||||
* before pty reads will be backed off. READ_TIME is how long to back off
|
||||
* before the next read (in microseconds) if a tty is above READ_BACKOFF.
|
||||
*/
|
||||
#define READ_SIZE 1024
|
||||
#define READ_BACKOFF 512
|
||||
#define READ_TIME 100
|
||||
/* The maximum amount of data to hold from a pty (the event high watermark). */
|
||||
#define READ_SIZE 128
|
||||
|
||||
/* Attribute to make gcc check printf-like arguments. */
|
||||
#define printflike(a, b) __attribute__ ((format (printf, a, b)))
|
||||
@ -891,7 +884,6 @@ struct window_pane {
|
||||
|
||||
int fd;
|
||||
struct bufferevent *event;
|
||||
struct event timer;
|
||||
|
||||
struct input_ctx *ictx;
|
||||
|
||||
@ -2036,15 +2028,15 @@ void screen_write_stop(struct screen_write_ctx *);
|
||||
void screen_write_reset(struct screen_write_ctx *);
|
||||
size_t printflike(1, 2) screen_write_cstrlen(const char *, ...);
|
||||
void printflike(4, 5) screen_write_cnputs(struct screen_write_ctx *,
|
||||
ssize_t, struct grid_cell *, const char *, ...);
|
||||
ssize_t, const struct grid_cell *, const char *, ...);
|
||||
size_t printflike(1, 2) screen_write_strlen(const char *, ...);
|
||||
void printflike(3, 4) screen_write_puts(struct screen_write_ctx *,
|
||||
struct grid_cell *, const char *, ...);
|
||||
const struct grid_cell *, const char *, ...);
|
||||
void printflike(4, 5) screen_write_nputs(struct screen_write_ctx *,
|
||||
ssize_t, struct grid_cell *, const char *, ...);
|
||||
ssize_t, const struct grid_cell *, const char *, ...);
|
||||
void screen_write_vnputs(struct screen_write_ctx *, ssize_t,
|
||||
struct grid_cell *, const char *, va_list);
|
||||
void screen_write_putc(struct screen_write_ctx *, struct grid_cell *,
|
||||
const struct grid_cell *, const char *, va_list);
|
||||
void screen_write_putc(struct screen_write_ctx *, const struct grid_cell *,
|
||||
u_char);
|
||||
void screen_write_copy(struct screen_write_ctx *, struct screen *, u_int,
|
||||
u_int, u_int, u_int);
|
||||
|
39
window.c
39
window.c
@ -777,9 +777,6 @@ window_pane_destroy(struct window_pane *wp)
|
||||
{
|
||||
window_pane_reset_mode(wp);
|
||||
|
||||
if (event_initialized(&wp->timer))
|
||||
evtimer_del(&wp->timer);
|
||||
|
||||
if (wp->fd != -1) {
|
||||
#ifdef HAVE_UTEMPTER
|
||||
utempter_remove_record(wp->fd);
|
||||
@ -931,35 +928,16 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv,
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
window_pane_timer_callback(__unused int fd, __unused short events, void *data)
|
||||
{
|
||||
window_pane_read_callback(NULL, data);
|
||||
}
|
||||
|
||||
void
|
||||
window_pane_read_callback(__unused struct bufferevent *bufev, void *data)
|
||||
{
|
||||
struct window_pane *wp = data;
|
||||
struct evbuffer *evb = wp->event->input;
|
||||
char *new_data;
|
||||
size_t new_size, available;
|
||||
struct client *c;
|
||||
struct timeval tv;
|
||||
size_t new_size;
|
||||
|
||||
if (event_initialized(&wp->timer))
|
||||
evtimer_del(&wp->timer);
|
||||
|
||||
log_debug("%%%u has %zu bytes", wp->id, EVBUFFER_LENGTH(evb));
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!tty_client_ready(c, wp))
|
||||
continue;
|
||||
|
||||
available = EVBUFFER_LENGTH(c->tty.event->output);
|
||||
if (available > READ_BACKOFF)
|
||||
goto start_timer;
|
||||
}
|
||||
log_debug("%%%u has %zu bytes (of %zu)", wp->id, EVBUFFER_LENGTH(evb),
|
||||
(size_t)READ_SIZE);
|
||||
|
||||
new_size = EVBUFFER_LENGTH(evb) - wp->pipe_off;
|
||||
if (wp->pipe_fd != -1 && new_size > 0) {
|
||||
@ -970,17 +948,6 @@ window_pane_read_callback(__unused struct bufferevent *bufev, void *data)
|
||||
input_parse(wp);
|
||||
|
||||
wp->pipe_off = EVBUFFER_LENGTH(evb);
|
||||
return;
|
||||
|
||||
start_timer:
|
||||
log_debug("%%%u backing off (%s %zu > %d)", wp->id, c->ttyname,
|
||||
available, READ_BACKOFF);
|
||||
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = READ_TIME;
|
||||
|
||||
evtimer_set(&wp->timer, window_pane_timer_callback, wp);
|
||||
evtimer_add(&wp->timer, &tv);
|
||||
}
|
||||
|
||||
void
|
||||
|
Loading…
Reference in New Issue
Block a user