diff --git a/CHANGES b/CHANGES index 621e645c..0776468d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,7 @@ 21 November 2007 +* Make command output (eg list-keys) go to a scrollable window similar to + scroll mode. * Redo screen redrawing so it is a) readable b) split into utility functions that can be used outside screen.c. Use these to make scroll mode only redraw what it has to which gets rid of irritating flickering status box and @@ -245,4 +247,4 @@ (including mutt, emacs). No status bar yet and no key remapping or other customisation. -$Id: CHANGES,v 1.78 2007-11-21 18:24:49 nicm Exp $ +$Id: CHANGES,v 1.79 2007-11-21 19:44:04 nicm Exp $ diff --git a/Makefile b/Makefile index 9d6e04e4..d3fb19c5 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.45 2007-11-21 13:11:41 nicm Exp $ +# $Id: Makefile,v 1.46 2007-11-21 19:44:04 nicm Exp $ .SUFFIXES: .c .o .y .h .PHONY: clean update-index.html upload-index.html @@ -27,7 +27,7 @@ SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \ cmd-link-window.c cmd-unlink-window.c cmd-next-window.c \ cmd-swap-window.c cmd-rename-session.c cmd-kill-session.c \ cmd-switch-client.c cmd-has-session.c cmd-scroll-mode.c \ - window-scroll.c + window-scroll.c window-more.c CC?= cc INCDIRS+= -I. -I- -I/usr/local/include diff --git a/key-bindings.c b/key-bindings.c index f17f5c86..5f13dd60 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -1,4 +1,4 @@ -/* $Id: key-bindings.c,v 1.18 2007-11-21 13:11:41 nicm Exp $ */ +/* $Id: key-bindings.c,v 1.19 2007-11-21 19:44:05 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -160,56 +160,18 @@ key_bindings_error(struct cmd_ctx *ctx, const char *fmt, ...) void printflike2 key_bindings_print(struct cmd_ctx *ctx, const char *fmt, ...) { - static u_int line; - struct client *c = ctx->client; - struct screen *s = &c->session->curw->window->screen; - struct hdr hdr; + struct window *w = ctx->session->curw->window; va_list ap; - char *msg; - size_t size; - u_int i, sx, sy; - sx = screen_size_x(s); - sy = screen_size_y(s); - - buffer_ensure(c->out, sizeof hdr); - buffer_add(c->out, sizeof hdr); - size = BUFFER_USED(c->out); - - if (line == 2 * sy || !(c->flags & CLIENT_HOLD)) { - input_store_zero(c->out, CODE_CURSOROFF); - for (i = 0; i < sy; i++) { - input_store_two(c->out, CODE_CURSORMOVE, i + 1, 1); - input_store_zero(c->out, CODE_CLEARLINE); - } - input_store_two(c->out, CODE_CURSORMOVE, 1, 1); - input_store_two(c->out, CODE_ATTRIBUTES, 0, 0x88); - - line = 0; - c->flags |= CLIENT_HOLD; - } - if (line >= sy) { - input_store_two(c->out, CODE_CURSORMOVE, line - sy + 1, sx / 2); - } - line++; + if (w->mode == NULL) { + w->mode = &window_more_mode; + w->mode->init(w); + } else if (w->mode != &window_more_mode) + return; va_start(ap, fmt); - xvasprintf(&msg, fmt, ap); + window_more_vadd(w, fmt, ap); va_end(ap); - if (strlen(msg) > sx / 2) - msg[sx / 2] = '\0'; - - buffer_write(c->out, msg, strlen(msg)); - if (line != sy && line != 2 * sy) { - input_store8(c->out, '\r'); - input_store8(c->out, '\n'); - } - xfree(msg); - - size = BUFFER_USED(c->out) - size; - hdr.type = MSG_DATA; - hdr.size = size; - memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); } void @@ -238,4 +200,7 @@ key_bindings_dispatch(int key, struct client *c) ctx.flags = CMD_KEY; cmd_exec(bd->cmd, &ctx); + + if (c->session->curw->window->mode == &window_more_mode) + server_redraw_window_all(c->session->curw->window); } diff --git a/tmux.h b/tmux.h index 31057f10..96632eac 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.88 2007-11-21 18:24:49 nicm Exp $ */ +/* $Id: tmux.h,v 1.89 2007-11-21 19:44:05 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -815,6 +815,11 @@ void window_key(struct window *, int); /* window-scroll.c */ extern const struct window_mode window_scroll_mode; +/* window-more.c */ +extern const struct window_mode window_more_mode; +void window_more_vadd(struct window *, const char *, va_list); +void printflike2 window_more_add(struct window *, const char *, ...); + /* session.c */ extern struct sessions sessions; void session_cancelbell(struct session *, struct winlink *); diff --git a/window-more.c b/window-more.c new file mode 100644 index 00000000..2dd657ec --- /dev/null +++ b/window-more.c @@ -0,0 +1,294 @@ +/* $Id: window-more.c,v 1.1 2007-11-21 19:44:05 nicm Exp $ */ + +/* + * Copyright (c) 2007 Nicholas Marriott + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include + +#include "tmux.h" + +void window_more_init(struct window *); +void window_more_resize(struct window *, u_int, u_int); +void window_more_draw(struct window *, struct buffer *, u_int, u_int); +void window_more_key(struct window *, int); + +void window_more_draw_position(struct window *, struct screen_draw_ctx *); +void window_more_draw_line(struct window *, struct screen_draw_ctx *, u_int); + +void window_more_up_1(struct window *); +void window_more_down_1(struct window *); + +const struct window_mode window_more_mode = { + window_more_init, + window_more_resize, + window_more_draw, + window_more_key +}; + +struct window_more_mode_data { + ARRAY_DECL(, char *) list; + u_int top; +}; + +void +window_more_vadd(struct window *w, const char *fmt, va_list ap) +{ + struct window_more_mode_data *data = w->modedata; + char *s; + + xvasprintf(&s, fmt, ap); + ARRAY_ADD(&data->list, s); +} + +void +window_more_add(struct window *w, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + window_more_vadd(w, fmt, ap); + va_end(ap); +} + +void +window_more_init(struct window *w) +{ + struct window_more_mode_data *data; + + w->modedata = data = xmalloc(sizeof *data); + ARRAY_INIT(&data->list); + data->top = 0; +} + +void +window_more_resize(unused struct window *w, unused u_int sx, unused u_int sy) +{ +} + +void +window_more_draw_position(struct window *w, struct screen_draw_ctx *ctx) +{ + struct window_more_mode_data *data = w->modedata; + char *ptr, buf[32]; + size_t len; + char *line; + size_t n; + + len = xsnprintf( + buf, sizeof buf, "[%u/%u]", data->top, ARRAY_LENGTH(&data->list)); + if (len <= screen_size_x(ctx->s)) + ptr = buf; + else { + ptr = buf + len - screen_size_x(ctx->s); + len -= len - screen_size_x(ctx->s); + } + + screen_draw_move(ctx, 0, 0); + + if (data->top < ARRAY_LENGTH(&data->list)) { + line = ARRAY_ITEM(&data->list, data->top); + n = strlen(line); + if (n > screen_size_x(ctx->s) - len) + n = screen_size_x(ctx->s) - len; + buffer_write(ctx->b, line, n); + } else + n = 0; + for (; n < screen_size_x(ctx->s) - len; n++) + input_store8(ctx->b, SCREEN_DEFDATA); + + screen_draw_move(ctx, screen_size_x(ctx->s) - len, 0); + screen_draw_set_attributes(ctx, 0, status_colour); + buffer_write(ctx->b, buf, len); +} + +void +window_more_draw_line(struct window *w, struct screen_draw_ctx *ctx, u_int py) +{ + struct window_more_mode_data *data = w->modedata; + char *line; + size_t n; + u_int p; + + screen_draw_move(ctx, 0, py); + screen_draw_set_attributes(ctx, SCREEN_DEFATTR, SCREEN_DEFCOLR); + + p = data->top + py; + if (p >= ARRAY_LENGTH(&data->list)) { + input_store_zero(ctx->b, CODE_CLEARLINE); + return; + } + + line = ARRAY_ITEM(&data->list, p); + n = strlen(line); + if (n > screen_size_x(ctx->s)) + n = screen_size_x(ctx->s); + buffer_write(ctx->b, line, n); + for (; n < screen_size_x(ctx->s); n++) + input_store8(ctx->b, SCREEN_DEFDATA); +} + +void +window_more_draw(struct window *w, struct buffer *b, u_int py, u_int ny) +{ + struct screen *s = &w->screen; + struct screen_draw_ctx ctx; + u_int i; + + screen_draw_start(&ctx, s, b, 0, 0); + + for (i = py; i < py + ny; i++) { + if (i == 0) + continue; + window_more_draw_line(w, &ctx, i); + } + if (py == 0) + window_more_draw_position(w, &ctx); + + screen_draw_stop(&ctx); + input_store_zero(b, CODE_CURSOROFF); +} + +void +window_more_key(struct window *w, int key) +{ + struct window_more_mode_data *data = w->modedata; + u_int top, sy; + + sy = screen_size_y(&w->screen); + + top = data->top; + + switch (key) { + case 'Q': + case 'q': + w->mode = NULL; + xfree(w->modedata); + + recalculate_sizes(); + server_redraw_window_all(w); + return; + case 'k': + case 'K': + case KEYC_UP: + window_more_up_1(w); + return; + case 'j': + case 'J': + case KEYC_DOWN: + window_more_down_1(w); + return; + case '\025': /* C-u */ + case KEYC_PPAGE: + if (data->top < sy) + data->top = 0; + else + data->top -= sy; + break; + case '\006': /* C-f */ + case KEYC_NPAGE: + if (data->top + sy > ARRAY_LENGTH(&data->list)) + data->top = ARRAY_LENGTH(&data->list); + else + data->top += sy; + break; + } + if (top != data->top) + server_redraw_window_all(w); +} + +void +window_more_up_1(struct window *w) +{ + struct window_more_mode_data *data = w->modedata; + struct screen *s = &w->screen; + struct screen_draw_ctx ctx; + struct client *c; + u_int i; + struct hdr hdr; + size_t size; + + if (data->top == 0) + return; + data->top--; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + if (!session_has(c->session, w)) + continue; + + buffer_ensure(c->out, sizeof hdr); + buffer_add(c->out, sizeof hdr); + size = BUFFER_USED(c->out); + + screen_draw_start(&ctx, s, c->out, 0, 0); + screen_draw_move(&ctx, 0, 0); + input_store_one(c->out, CODE_INSERTLINE, 1); + window_more_draw_position(w, &ctx); + window_more_draw_line(w, &ctx, 1); + screen_draw_stop(&ctx); + input_store_zero(c->out, CODE_CURSOROFF); + + size = BUFFER_USED(c->out) - size; + hdr.type = MSG_DATA; + hdr.size = size; + memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); + } +} + +void +window_more_down_1(struct window *w) +{ + struct window_more_mode_data *data = w->modedata; + struct screen *s = &w->screen; + struct screen_draw_ctx ctx; + struct client *c; + u_int i; + struct hdr hdr; + size_t size; + + if (data->top >= ARRAY_LENGTH(&data->list)) + return; + data->top++; + + for (i = 0; i < ARRAY_LENGTH(&clients); i++) { + c = ARRAY_ITEM(&clients, i); + if (c == NULL || c->session == NULL) + continue; + if (!session_has(c->session, w)) + continue; + + buffer_ensure(c->out, sizeof hdr); + buffer_add(c->out, sizeof hdr); + size = BUFFER_USED(c->out); + + screen_draw_start(&ctx, s, c->out, 0, 0); + screen_draw_move(&ctx, 0, 0); + input_store_one(c->out, CODE_DELETELINE, 1); + window_more_draw_line(w, &ctx, screen_last_y(s)); + window_more_draw_position(w, &ctx); + screen_draw_stop(&ctx); + input_store_zero(c->out, CODE_CURSOROFF); + + size = BUFFER_USED(c->out) - size; + hdr.type = MSG_DATA; + hdr.size = size; + memcpy(BUFFER_IN(c->out) - size - sizeof hdr, &hdr, sizeof hdr); + } +} diff --git a/window-scroll.c b/window-scroll.c index f1ba54e0..c9ded460 100644 --- a/window-scroll.c +++ b/window-scroll.c @@ -1,4 +1,4 @@ -/* $Id: window-scroll.c,v 1.7 2007-11-21 18:24:49 nicm Exp $ */ +/* $Id: window-scroll.c,v 1.8 2007-11-21 19:44:05 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -149,14 +149,14 @@ window_scroll_key(struct window *w, int key) case KEYC_DOWN: window_scroll_down_1(w); return; - case '\025': + case '\025': /* C-u */ case KEYC_PPAGE: if (data->oy + sy > data->size) data->oy = data->size; else data->oy += sy; break; - case '\006': + case '\006': /* C-f */ case KEYC_NPAGE: if (data->oy < sy) data->oy = 0; @@ -198,7 +198,7 @@ window_scroll_up_1(struct window *w) screen_draw_move(&ctx, 0, 0); input_store_one(c->out, CODE_INSERTLINE, 1); window_scroll_draw_position(w, &ctx); - screen_draw_line(&ctx, 1); /* nuke old position */ + screen_draw_line(&ctx, 1); /* nuke old position display */ screen_draw_stop(&ctx); input_store_zero(c->out, CODE_CURSOROFF);