mirror of
https://github.com/tmux/tmux.git
synced 2025-03-24 14:58:47 +00:00
Add support for popups to control mode
This commit is contained in:
parent
ef68debc8d
commit
5fcda70d0c
@ -432,7 +432,15 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
||||
w = tty->sx;
|
||||
if (h > tty->sy)
|
||||
h = tty->sy;
|
||||
if (!cmd_display_menu_get_position(tc, item, args, &px, &py, w, h))
|
||||
if (tc->flags & CLIENT_CONTROL) {
|
||||
/* Control clients may not have a window size, so provide a reasonable default so popups can still work. */
|
||||
if (w == 0)
|
||||
w = 80;
|
||||
if (h == 0)
|
||||
h = 25;
|
||||
px = 0;
|
||||
py = 0;
|
||||
} else if (!cmd_display_menu_get_position(tc, item, args, &px, &py, w, h))
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
value = args_get(args, 'b');
|
||||
@ -485,7 +493,7 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
||||
else if (args_has(args, 'E'))
|
||||
flags |= POPUP_CLOSEEXIT;
|
||||
if (popup_display(flags, lines, item, px, py, w, h, env, shellcmd, argc,
|
||||
argv, cwd, title, tc, s, style, border_style, NULL, NULL) != 0) {
|
||||
argv, cwd, title, tc, s, style, border_style, NULL, NULL, target->wp) != 0) {
|
||||
cmd_free_argv(argc, argv);
|
||||
if (env != NULL)
|
||||
environ_free(env);
|
||||
@ -498,5 +506,7 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
||||
free(cwd);
|
||||
free(title);
|
||||
cmd_free_argv(argc, argv);
|
||||
if (tc->flags & CLIENT_CONTROL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
return (CMD_RETURN_WAIT);
|
||||
}
|
||||
|
@ -260,3 +260,19 @@ control_notify_paste_buffer_deleted(const char *name)
|
||||
control_write(c, "%%paste-buffer-deleted %s", name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_popup(struct client *c, int status, char *buf, size_t len, int wp)
|
||||
{
|
||||
struct evbuffer *message = evbuffer_new();
|
||||
|
||||
if (message == NULL)
|
||||
fatalx("out of memory");
|
||||
evbuffer_add_printf(message, "%%popup %d", status);
|
||||
if (wp != -1)
|
||||
evbuffer_add_printf(message, " %u", wp);
|
||||
evbuffer_add_printf(message, " : ");
|
||||
control_escape(message, buf, len);
|
||||
control_write_buffer(c, message);
|
||||
evbuffer_free(message);
|
||||
}
|
||||
|
87
control.c
87
control.c
@ -43,7 +43,9 @@
|
||||
*/
|
||||
struct control_block {
|
||||
size_t size;
|
||||
/* exactly one of `line` and `buffer` will be nonnull */
|
||||
char *line;
|
||||
struct evbuffer *buffer;
|
||||
uint64_t t;
|
||||
|
||||
TAILQ_ENTRY(control_block) entry;
|
||||
@ -225,7 +227,10 @@ control_free_sub(struct control_state *cs, struct control_sub *csub)
|
||||
static void
|
||||
control_free_block(struct control_state *cs, struct control_block *cb)
|
||||
{
|
||||
free(cb->line);
|
||||
if (cb->line != NULL)
|
||||
free(cb->line);
|
||||
if (cb->buffer != NULL)
|
||||
evbuffer_free(cb->buffer);
|
||||
TAILQ_REMOVE(&cs->all_blocks, cb, all_entry);
|
||||
free(cb);
|
||||
}
|
||||
@ -401,13 +406,63 @@ control_vwrite(struct client *c, const char *fmt, va_list ap)
|
||||
free(s);
|
||||
}
|
||||
|
||||
static void
|
||||
control_vwrite_buffer(struct client *c, struct evbuffer *buffer)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
|
||||
log_debug("%s: %s: writing buffer", __func__, c->name);
|
||||
|
||||
bufferevent_write_buffer(cs->write_event, buffer);
|
||||
bufferevent_write(cs->write_event, "\n", 1);
|
||||
|
||||
bufferevent_enable(cs->write_event, EV_WRITE);
|
||||
}
|
||||
|
||||
/* Frees line and buffer after using them asynchronously. */
|
||||
static void
|
||||
control_enqueue(struct client *c, struct control_state *cs, char *line, struct evbuffer *buffer)
|
||||
{
|
||||
struct control_block *cb = xcalloc(1, sizeof *cb);
|
||||
|
||||
if (line != NULL) {
|
||||
log_debug("%s: %s: storing line: %s", __func__, c->name, cb->line);
|
||||
cb->line = line;
|
||||
} else {
|
||||
log_debug("%s: %s: storing buffer", __func__, c->name);
|
||||
cb->buffer = buffer;
|
||||
}
|
||||
|
||||
TAILQ_INSERT_TAIL(&cs->all_blocks, cb, all_entry);
|
||||
cb->t = get_timer();
|
||||
|
||||
bufferevent_enable(cs->write_event, EV_WRITE);
|
||||
}
|
||||
|
||||
void
|
||||
control_write_buffer(struct client *c, struct evbuffer *buffer)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_block *cb;
|
||||
va_list ap;
|
||||
|
||||
if (TAILQ_EMPTY(&cs->all_blocks)) {
|
||||
control_vwrite_buffer(c, buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
control_enqueue(c, cs, NULL, buffer);
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* Write a line. */
|
||||
void
|
||||
control_write(struct client *c, const char *fmt, ...)
|
||||
{
|
||||
struct control_state *cs = c->control_state;
|
||||
struct control_block *cb;
|
||||
va_list ap;
|
||||
char *line;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
@ -417,13 +472,8 @@ control_write(struct client *c, const char *fmt, ...)
|
||||
return;
|
||||
}
|
||||
|
||||
cb = xcalloc(1, sizeof *cb);
|
||||
xvasprintf(&cb->line, fmt, ap);
|
||||
TAILQ_INSERT_TAIL(&cs->all_blocks, cb, all_entry);
|
||||
cb->t = get_timer();
|
||||
|
||||
log_debug("%s: %s: storing line: %s", __func__, c->name, cb->line);
|
||||
bufferevent_enable(cs->write_event, EV_WRITE);
|
||||
xvasprintf(&line, fmt, ap);
|
||||
control_enqueue(c, cs, line, NULL);
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
@ -604,6 +654,17 @@ control_flush_all_blocks(struct client *c)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_escape(struct evbuffer *message, char *s, size_t size)
|
||||
{
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
if (s[i] < ' ' || s[i] == '\\')
|
||||
evbuffer_add_printf(message, "\\%03o", s[i]);
|
||||
else
|
||||
evbuffer_add_printf(message, "%c", s[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Append data to buffer. */
|
||||
static struct evbuffer *
|
||||
control_append_data(struct client *c, struct control_pane *cp, uint64_t age,
|
||||
@ -611,7 +672,6 @@ control_append_data(struct client *c, struct control_pane *cp, uint64_t age,
|
||||
{
|
||||
u_char *new_data;
|
||||
size_t new_size;
|
||||
u_int i;
|
||||
|
||||
if (message == NULL) {
|
||||
message = evbuffer_new();
|
||||
@ -628,12 +688,7 @@ control_append_data(struct client *c, struct control_pane *cp, uint64_t age,
|
||||
new_data = window_pane_get_new_data(wp, &cp->offset, &new_size);
|
||||
if (new_size < size)
|
||||
fatalx("not enough data: %zu < %zu", new_size, size);
|
||||
for (i = 0; i < size; i++) {
|
||||
if (new_data[i] < ' ' || new_data[i] == '\\')
|
||||
evbuffer_add_printf(message, "\\%03o", new_data[i]);
|
||||
else
|
||||
evbuffer_add_printf(message, "%c", new_data[i]);
|
||||
}
|
||||
control_escape(message, new_data, size);
|
||||
window_pane_update_used_data(wp, &cp->offset, size);
|
||||
return (message);
|
||||
}
|
||||
|
64
popup.c
64
popup.c
@ -28,6 +28,7 @@
|
||||
|
||||
struct popup_data {
|
||||
struct client *c;
|
||||
int wp;
|
||||
struct cmdq_item *item;
|
||||
int flags;
|
||||
char *title;
|
||||
@ -614,6 +615,47 @@ popup_job_update_cb(struct job *job)
|
||||
evbuffer_drain(evb, size);
|
||||
}
|
||||
|
||||
// NOTE TO REVIEWER: This is a copy of cmd_capture_pane_append. I think we'd want a shared implementation but I don't know where it should go.
|
||||
static char *
|
||||
popup_append(char *buf, size_t *len, char *line, size_t linelen)
|
||||
{
|
||||
buf = xrealloc(buf, *len + linelen + 1);
|
||||
memcpy(buf + *len, line, linelen);
|
||||
*len += linelen;
|
||||
return (buf);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_notify_control(struct client *c, int status, struct screen *s, int wp)
|
||||
{
|
||||
char *buf = NULL;
|
||||
struct grid_cell *gc = NULL;
|
||||
int sx = screen_size_x(s);
|
||||
int sy = screen_size_y(s);
|
||||
char *line;
|
||||
size_t linelen;
|
||||
size_t len = 0;
|
||||
int i;
|
||||
struct grid *gd = s->grid;
|
||||
const struct grid_line *gl;
|
||||
|
||||
for (i = 0; i < sy; i++) {
|
||||
line = grid_string_cells(gd, 0, i, sx, &gc, GRID_STRING_WITH_SEQUENCES, s);
|
||||
linelen = strlen(line);
|
||||
|
||||
buf = popup_append(buf, &len, line, linelen);
|
||||
|
||||
gl = grid_peek_line(gd, i);
|
||||
if (!(gl->flags & GRID_LINE_WRAPPED))
|
||||
buf[len++] = '\n';
|
||||
|
||||
free(line);
|
||||
}
|
||||
|
||||
control_notify_popup(c, status, buf, len, wp);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_job_complete_cb(struct job *job)
|
||||
{
|
||||
@ -629,8 +671,10 @@ popup_job_complete_cb(struct job *job)
|
||||
pd->status = 0;
|
||||
pd->job = NULL;
|
||||
|
||||
if ((pd->flags & POPUP_CLOSEEXIT) ||
|
||||
((pd->flags & POPUP_CLOSEEXITZERO) && pd->status == 0))
|
||||
if (pd->c->flags & CLIENT_CONTROL)
|
||||
popup_notify_control(pd->c, pd->status, &pd->s, pd->wp);
|
||||
else if ((pd->flags & POPUP_CLOSEEXIT) ||
|
||||
((pd->flags & POPUP_CLOSEEXITZERO) && pd->status == 0))
|
||||
server_client_clear_overlay(pd->c);
|
||||
}
|
||||
|
||||
@ -639,7 +683,7 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
|
||||
u_int py, u_int sx, u_int sy, struct environ *env, const char *shellcmd,
|
||||
int argc, char **argv, const char *cwd, const char *title, struct client *c,
|
||||
struct session *s, const char *style, const char *border_style,
|
||||
popup_close_cb cb, void *arg)
|
||||
popup_close_cb cb, void *arg, struct window_pane *wp)
|
||||
{
|
||||
struct popup_data *pd;
|
||||
u_int jx, jy;
|
||||
@ -664,10 +708,14 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
|
||||
jx = sx - 2;
|
||||
jy = sy - 2;
|
||||
}
|
||||
if (c->tty.sx < sx || c->tty.sy < sy)
|
||||
if (!(c->flags & CLIENT_CONTROL) && (c->tty.sx < sx || c->tty.sy < sy))
|
||||
return (-1);
|
||||
|
||||
pd = xcalloc(1, sizeof *pd);
|
||||
if (wp != NULL)
|
||||
pd->wp = wp->id;
|
||||
else
|
||||
pd->wp = -1;
|
||||
pd->item = item;
|
||||
pd->flags = flags;
|
||||
if (title != NULL)
|
||||
@ -723,8 +771,10 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
|
||||
JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE|JOB_DEFAULTSHELL, jx, jy);
|
||||
pd->ictx = input_init(NULL, job_get_event(pd->job), &pd->palette);
|
||||
|
||||
server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb,
|
||||
popup_draw_cb, popup_key_cb, popup_free_cb, popup_resize_cb, pd);
|
||||
if (!(c->flags & CLIENT_CONTROL)) {
|
||||
server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb,
|
||||
popup_draw_cb, popup_key_cb, popup_free_cb, popup_resize_cb, pd);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -811,7 +861,7 @@ popup_editor(struct client *c, const char *buf, size_t len,
|
||||
xasprintf(&cmd, "%s %s", editor, path);
|
||||
if (popup_display(POPUP_INTERNAL|POPUP_CLOSEEXIT, BOX_LINES_DEFAULT,
|
||||
NULL, px, py, sx, sy, NULL, cmd, 0, NULL, _PATH_TMP, NULL, c, NULL,
|
||||
NULL, NULL, popup_editor_close_cb, pe) != 0) {
|
||||
NULL, NULL, popup_editor_close_cb, pe, NULL) != 0) {
|
||||
popup_editor_free(pe);
|
||||
free(cmd);
|
||||
return (-1);
|
||||
|
5
tmux.h
5
tmux.h
@ -3379,11 +3379,13 @@ struct window_pane_offset *control_pane_offset(struct client *,
|
||||
struct window_pane *, int *);
|
||||
void control_reset_offsets(struct client *);
|
||||
void printflike(2, 3) control_write(struct client *, const char *, ...);
|
||||
void control_write_buffer(struct client *c, struct evbuffer *buffer);
|
||||
void control_write_output(struct client *, struct window_pane *);
|
||||
int control_all_done(struct client *);
|
||||
void control_add_sub(struct client *, const char *, enum control_sub_type,
|
||||
int, const char *);
|
||||
void control_remove_sub(struct client *, const char *);
|
||||
void control_escape(struct evbuffer *, char *, size_t);
|
||||
|
||||
/* control-notify.c */
|
||||
void control_notify_pane_mode_changed(int);
|
||||
@ -3400,6 +3402,7 @@ void control_notify_session_closed(struct session *);
|
||||
void control_notify_session_window_changed(struct session *);
|
||||
void control_notify_paste_buffer_changed(const char *);
|
||||
void control_notify_paste_buffer_deleted(const char *);
|
||||
void control_notify_popup(struct client *c, int status, char *buf, size_t len, int wp);
|
||||
|
||||
/* session.c */
|
||||
extern struct sessions sessions;
|
||||
@ -3531,7 +3534,7 @@ int popup_display(int, enum box_lines, struct cmdq_item *, u_int,
|
||||
u_int, u_int, u_int, struct environ *, const char *, int,
|
||||
char **, const char *, const char *, struct client *,
|
||||
struct session *, const char *, const char *,
|
||||
popup_close_cb, void *);
|
||||
popup_close_cb, void *, struct window_pane *);
|
||||
int popup_editor(struct client *, const char *, size_t,
|
||||
popup_finish_edit_cb, void *);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user