Merge branch 'obsd-master'

This commit is contained in:
Thomas Adam 2016-04-29 16:01:12 +01:00
commit ba9f32b464
8 changed files with 146 additions and 111 deletions

View File

@ -157,6 +157,7 @@ cmd_if_shell_callback(struct job *job)
} }
cmdq1 = cmdq_new(cmdq->client); cmdq1 = cmdq_new(cmdq->client);
cmdq1->flags |= cmdq->flags & CMD_Q_NOHOOKS;
cmdq1->emptyfn = cmd_if_shell_done; cmdq1->emptyfn = cmd_if_shell_done;
cmdq1->data = cdata; cmdq1->data = cdata;

View File

@ -186,6 +186,9 @@ static enum cmd_retval
cmdq_continue_one(struct cmd_q *cmdq) cmdq_continue_one(struct cmd_q *cmdq)
{ {
struct cmd *cmd = cmdq->cmd; struct cmd *cmd = cmdq->cmd;
const char *name = cmd->entry->name;
struct session *s;
struct hooks *hooks;
enum cmd_retval retval; enum cmd_retval retval;
char *tmp; char *tmp;
int flags = !!(cmd->flags & CMD_CONTROL); int flags = !!(cmd->flags & CMD_CONTROL);
@ -197,19 +200,51 @@ cmdq_continue_one(struct cmd_q *cmdq)
cmdq->time = time(NULL); cmdq->time = time(NULL);
cmdq->number++; cmdq->number++;
if (~cmdq->flags & CMD_Q_REENTRY)
cmdq_guard(cmdq, "begin", flags); cmdq_guard(cmdq, "begin", flags);
if (cmd_prepare_state(cmd, cmdq, NULL) != 0) if (cmd_prepare_state(cmd, cmdq, cmdq->parent) != 0)
goto error; 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); retval = cmd->entry->exec(cmd, cmdq);
if (retval == CMD_RETURN_ERROR) if (retval == CMD_RETURN_ERROR)
goto error; goto error;
if (hooks != NULL && hooks_wait(hooks, cmdq, NULL,
"after-%s", name) == 0)
retval = CMD_RETURN_WAIT;
cmdq_guard(cmdq, "end", flags); cmdq_guard(cmdq, "end", flags);
return (retval); return (retval);
error: error:
cmdq_guard(cmdq, "error", flags); cmdq_guard(cmdq, "error", flags);
cmdq->flags &= ~CMD_Q_REENTRY;
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@ -232,11 +267,18 @@ cmdq_continue(struct cmd_q *cmdq)
if (empty) if (empty)
goto 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) { if (cmdq->item == NULL) {
cmdq->item = TAILQ_FIRST(&cmdq->queue); cmdq->item = TAILQ_FIRST(&cmdq->queue);
cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list); cmdq->cmd = TAILQ_FIRST(&cmdq->item->cmdlist->list);
} else } else
cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry); cmdq->cmd = TAILQ_NEXT(cmdq->cmd, qentry);
}
do { do {
while (cmdq->cmd != NULL) { while (cmdq->cmd != NULL) {

View File

@ -49,6 +49,7 @@ cmd_source_file_exec(struct cmd *self, struct cmd_q *cmdq)
char *cause; char *cause;
cmdq1 = cmdq_new(cmdq->client); cmdq1 = cmdq_new(cmdq->client);
cmdq1->flags |= cmdq->flags & CMD_Q_NOHOOKS;
cmdq1->emptyfn = cmd_source_file_done; cmdq1->emptyfn = cmd_source_file_done;
cmdq1->data = cmdq; cmdq1->data = cmdq;

View File

@ -485,6 +485,7 @@ struct format_tree *
format_create(struct cmd_q *cmdq, int flags) format_create(struct cmd_q *cmdq, int flags)
{ {
struct format_tree *ft; struct format_tree *ft;
struct cmd *cmd;
if (!event_initialized(&format_job_event)) { if (!event_initialized(&format_job_event)) {
evtimer_set(&format_job_event, format_job_timer, NULL); 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) if (cmdq != NULL && cmdq->cmd != NULL)
format_add(ft, "command_name", "%s", cmdq->cmd->entry->name); 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); return (ft);
} }

View File

@ -64,11 +64,15 @@ screen_write_reset(struct screen_write_ctx *ctx)
/* Write character. */ /* Write character. */
void 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) u_char ch)
{ {
utf8_set(&gc->data, ch); struct grid_cell gc;
screen_write_cell(ctx, gc);
memcpy(&gc, gcp, sizeof gc);
utf8_set(&gc.data, ch);
screen_write_cell(ctx, &gc);
} }
/* Calculate string length, with embedded formatting. */ /* 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). */ /* Write simple string (no UTF-8 or maximum length). */
void 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, ...) const char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
screen_write_vnputs(ctx, -1, gc, fmt, ap); screen_write_vnputs(ctx, -1, gcp, fmt, ap);
va_end(ap); va_end(ap);
} }
/* Write string with length limit (-1 for unlimited). */ /* Write string with length limit (-1 for unlimited). */
void void
screen_write_nputs(struct screen_write_ctx *ctx, ssize_t maxlen, 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_list ap;
va_start(ap, fmt); va_start(ap, fmt);
screen_write_vnputs(ctx, maxlen, gc, fmt, ap); screen_write_vnputs(ctx, maxlen, gcp, fmt, ap);
va_end(ap); va_end(ap);
} }
void void
screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen, 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; char *msg;
struct utf8_data ud;
u_char *ptr; u_char *ptr;
size_t left, size = 0; size_t left, size = 0;
enum utf8_state more; enum utf8_state more;
memcpy(&gc, gcp, sizeof gc);
xvasprintf(&msg, fmt, ap); xvasprintf(&msg, fmt, ap);
ptr = msg; ptr = msg;
while (*ptr != '\0') { while (*ptr != '\0') {
if (*ptr > 0x7f && utf8_open(&ud, *ptr) == UTF8_MORE) { if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) {
ptr++; ptr++;
left = strlen(ptr); left = strlen(ptr);
if (left < (size_t)ud.size - 1) if (left < (size_t)ud->size - 1)
break; break;
while ((more = utf8_append(&ud, *ptr)) == UTF8_MORE) while ((more = utf8_append(ud, *ptr)) == UTF8_MORE)
ptr++; ptr++;
ptr++; ptr++;
if (more == UTF8_DONE) { if (more != UTF8_DONE)
if (maxlen > 0 && continue;
size + ud.width > (size_t) maxlen) { if (maxlen > 0 && size + ud->width > (size_t)maxlen) {
while (size < (size_t)maxlen) { while (size < (size_t)maxlen) {
screen_write_putc(ctx, gc, ' '); screen_write_putc(ctx, &gc, ' ');
size++; size++;
} }
break; break;
} }
size += ud.width; size += ud->width;
screen_write_cell(ctx, &gc);
utf8_copy(&gc->data, &ud);
screen_write_cell(ctx, gc);
}
} else { } else {
if (maxlen > 0 && size + 1 > (size_t)maxlen) if (maxlen > 0 && size + 1 > (size_t)maxlen)
break; break;
if (*ptr == '\001') if (*ptr == '\001')
gc->attr ^= GRID_ATTR_CHARSET; gc.attr ^= GRID_ATTR_CHARSET;
else if (*ptr > 0x1f && *ptr < 0x7f) { else if (*ptr > 0x1f && *ptr < 0x7f) {
size++; size++;
screen_write_putc(ctx, gc, *ptr); screen_write_putc(ctx, &gc, *ptr);
} }
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 (#[]). */ /* Write string, similar to nputs, but with embedded formatting (#[]). */
void void
screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen, 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 grid_cell gc;
struct utf8_data ud; struct utf8_data *ud = &gc.data;
va_list ap; va_list ap;
char *msg; char *msg;
u_char *ptr, *last; u_char *ptr, *last;
size_t left, size = 0; size_t left, size = 0;
enum utf8_state more; enum utf8_state more;
memcpy(&gc, gcp, sizeof gc);
va_start(ap, fmt); va_start(ap, fmt);
xvasprintf(&msg, fmt, ap); xvasprintf(&msg, fmt, ap);
va_end(ap); va_end(ap);
memcpy(&lgc, gc, sizeof lgc);
ptr = msg; ptr = msg;
while (*ptr != '\0') { while (*ptr != '\0') {
if (ptr[0] == '#' && ptr[1] == '[') { if (ptr[0] == '#' && ptr[1] == '[') {
@ -255,42 +258,39 @@ screen_write_cnputs(struct screen_write_ctx *ctx, ssize_t maxlen,
} }
*last = '\0'; *last = '\0';
style_parse(gc, &lgc, ptr); style_parse(gcp, &gc, ptr);
ptr = last + 1; ptr = last + 1;
continue; continue;
} }
if (*ptr > 0x7f && utf8_open(&ud, *ptr) == UTF8_MORE) { if (*ptr > 0x7f && utf8_open(ud, *ptr) == UTF8_MORE) {
ptr++; ptr++;
left = strlen(ptr); left = strlen(ptr);
if (left < (size_t)ud.size - 1) if (left < (size_t)ud->size - 1)
break; break;
while ((more = utf8_append(&ud, *ptr)) == UTF8_MORE) while ((more = utf8_append(ud, *ptr)) == UTF8_MORE)
ptr++; ptr++;
ptr++; ptr++;
if (more == UTF8_DONE) { if (more != UTF8_DONE)
if (maxlen > 0 && continue;
size + ud.width > (size_t) maxlen) { if (maxlen > 0 && size + ud->width > (size_t)maxlen) {
while (size < (size_t)maxlen) { while (size < (size_t)maxlen) {
screen_write_putc(ctx, gc, ' '); screen_write_putc(ctx, &gc, ' ');
size++; size++;
} }
break; break;
} }
size += ud.width; size += ud->width;
screen_write_cell(ctx, &gc);
utf8_copy(&lgc.data, &ud);
screen_write_cell(ctx, &lgc);
}
} else { } else {
if (maxlen > 0 && size + 1 > (size_t)maxlen) if (maxlen > 0 && size + 1 > (size_t)maxlen)
break; break;
if (*ptr > 0x1f && *ptr < 0x7f) { if (*ptr > 0x1f && *ptr < 0x7f) {
size++; size++;
screen_write_putc(ctx, &lgc, *ptr); screen_write_putc(ctx, &gc, *ptr);
} }
ptr++; ptr++;
} }

33
tmux.1
View File

@ -3225,9 +3225,35 @@ shows only the option value, not the name.
.Nm .Nm
allows commands to run on various triggers, called allows commands to run on various triggers, called
.Em hooks . .Em hooks .
Each hook has a Each
.Em name . .Nm
The following hooks are available: 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" .Bl -tag -width "XXXXXXXXXXXXXXXX"
.It alert-activity .It alert-activity
Run when a window has 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_tty" Ta "" Ta "Pseudo terminal of client"
.It Li "client_utf8" Ta "" Ta "1 if client supports utf8" .It Li "client_utf8" Ta "" Ta "1 if client supports utf8"
.It Li "client_width" Ta "" Ta "Width of client" .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 "command_name" Ta "" Ta "Name of command in use, if any"
.It Li "cursor_flag" Ta "" Ta "Pane cursor flag" .It Li "cursor_flag" Ta "" Ta "Pane cursor flag"
.It Li "cursor_x" Ta "" Ta "Cursor X position in pane" .It Li "cursor_x" Ta "" Ta "Cursor X position in pane"

22
tmux.h
View File

@ -62,15 +62,8 @@ struct tmuxproc;
/* Automatic name refresh interval, in microseconds. Must be < 1 second. */ /* Automatic name refresh interval, in microseconds. Must be < 1 second. */
#define NAME_INTERVAL 500000 #define NAME_INTERVAL 500000
/* /* The maximum amount of data to hold from a pty (the event high watermark). */
* READ_SIZE is the maximum size of data to hold from a pty (the event high #define READ_SIZE 128
* 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
/* Attribute to make gcc check printf-like arguments. */ /* Attribute to make gcc check printf-like arguments. */
#define printflike(a, b) __attribute__ ((format (printf, a, b))) #define printflike(a, b) __attribute__ ((format (printf, a, b)))
@ -891,7 +884,6 @@ struct window_pane {
int fd; int fd;
struct bufferevent *event; struct bufferevent *event;
struct event timer;
struct input_ctx *ictx; struct input_ctx *ictx;
@ -2036,15 +2028,15 @@ void screen_write_stop(struct screen_write_ctx *);
void screen_write_reset(struct screen_write_ctx *); void screen_write_reset(struct screen_write_ctx *);
size_t printflike(1, 2) screen_write_cstrlen(const char *, ...); size_t printflike(1, 2) screen_write_cstrlen(const char *, ...);
void printflike(4, 5) screen_write_cnputs(struct screen_write_ctx *, 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 *, ...); size_t printflike(1, 2) screen_write_strlen(const char *, ...);
void printflike(3, 4) screen_write_puts(struct screen_write_ctx *, 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 *, 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, void screen_write_vnputs(struct screen_write_ctx *, ssize_t,
struct grid_cell *, const char *, va_list); const struct grid_cell *, const char *, va_list);
void screen_write_putc(struct screen_write_ctx *, struct grid_cell *, void screen_write_putc(struct screen_write_ctx *, const struct grid_cell *,
u_char); u_char);
void screen_write_copy(struct screen_write_ctx *, struct screen *, u_int, void screen_write_copy(struct screen_write_ctx *, struct screen *, u_int,
u_int, u_int, u_int); u_int, u_int, u_int);

View File

@ -777,9 +777,6 @@ window_pane_destroy(struct window_pane *wp)
{ {
window_pane_reset_mode(wp); window_pane_reset_mode(wp);
if (event_initialized(&wp->timer))
evtimer_del(&wp->timer);
if (wp->fd != -1) { if (wp->fd != -1) {
#ifdef HAVE_UTEMPTER #ifdef HAVE_UTEMPTER
utempter_remove_record(wp->fd); utempter_remove_record(wp->fd);
@ -931,35 +928,16 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv,
return (0); return (0);
} }
void
window_pane_timer_callback(__unused int fd, __unused short events, void *data)
{
window_pane_read_callback(NULL, data);
}
void void
window_pane_read_callback(__unused struct bufferevent *bufev, void *data) window_pane_read_callback(__unused struct bufferevent *bufev, void *data)
{ {
struct window_pane *wp = data; struct window_pane *wp = data;
struct evbuffer *evb = wp->event->input; struct evbuffer *evb = wp->event->input;
char *new_data; char *new_data;
size_t new_size, available; size_t new_size;
struct client *c;
struct timeval tv;
if (event_initialized(&wp->timer)) log_debug("%%%u has %zu bytes (of %zu)", wp->id, EVBUFFER_LENGTH(evb),
evtimer_del(&wp->timer); (size_t)READ_SIZE);
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;
}
new_size = EVBUFFER_LENGTH(evb) - wp->pipe_off; new_size = EVBUFFER_LENGTH(evb) - wp->pipe_off;
if (wp->pipe_fd != -1 && new_size > 0) { 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); input_parse(wp);
wp->pipe_off = EVBUFFER_LENGTH(evb); 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 void