Merge copy mode and output mode, dropping the latter. Idea and code from

Micah Cowan.
pull/1/head
Nicholas Marriott 2010-04-06 21:35:44 +00:00
parent f81190a793
commit ac9daf92d7
12 changed files with 222 additions and 401 deletions

View File

@ -37,7 +37,7 @@ SRCS= attributes.c cfg.c client.c clock.c \
resize.c screen-redraw.c screen-write.c screen.c session.c status.c \
server-fn.c server.c server-client.c server-window.c \
tmux.c tty-keys.c tty-term.c tty.c utf8.c \
window-choose.c window-clock.c window-copy.c window-more.c window.c \
window-choose.c window-clock.c window-copy.c window.c \
xterm-keys.c xmalloc.c
CDIAGFLAGS+= -Wno-long-long -Wall -W -Wnested-externs -Wformat=2

View File

@ -63,6 +63,7 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_ctx *ctx)
return (-1);
window_pane_set_mode(wp, &window_copy_mode);
window_copy_init_from_pane(wp);
if (wp->mode == &window_copy_mode && cmd_check_flag(data->chflags, 'u'))
window_copy_pageup(wp);

View File

@ -287,10 +287,11 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
*/
if (cfg_finished && !ARRAY_EMPTY(&cfg_causes)) {
wp = s->curw->window->active;
window_pane_set_mode(wp, &window_more_mode);
window_pane_set_mode(wp, &window_copy_mode);
window_copy_init_for_output(wp);
for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
cause = ARRAY_ITEM(&cfg_causes, i);
window_more_add(wp, "%s", cause);
window_copy_add(wp, "%s", cause);
xfree(cause);
}
ARRAY_FREE(&cfg_causes);

41
grid.c
View File

@ -46,18 +46,9 @@ const struct grid_cell grid_default_cell = { 0, 0, 8, 8, ' ' };
gc, sizeof gd->linedata[py].utf8data[px]); \
} while (0)
int grid_check_x(struct grid *, u_int);
int grid_check_y(struct grid *, u_int);
#ifdef DEBUG
int
grid_check_x(struct grid *gd, u_int px)
{
if ((px) >= (gd)->sx)
log_fatalx("x out of range: %u", px);
return (0);
}
int
grid_check_y(struct grid *gd, u_int py)
{
@ -66,16 +57,6 @@ grid_check_y(struct grid *gd, u_int py)
return (0);
}
#else
int
grid_check_x(struct grid *gd, u_int px)
{
if ((px) >= (gd)->sx) {
log_debug("x out of range: %u", px);
return (-1);
}
return (0);
}
int
grid_check_y(struct grid *gd, u_int py)
{
@ -270,8 +251,6 @@ grid_expand_line_utf8(struct grid *gd, u_int py, u_int sx)
const struct grid_cell *
grid_peek_cell(struct grid *gd, u_int px, u_int py)
{
if (grid_check_x(gd, px) != 0)
return (&grid_default_cell);
if (grid_check_y(gd, py) != 0)
return (&grid_default_cell);
@ -284,8 +263,6 @@ grid_peek_cell(struct grid *gd, u_int px, u_int py)
struct grid_cell *
grid_get_cell(struct grid *gd, u_int px, u_int py)
{
if (grid_check_x(gd, px) != 0)
return (NULL);
if (grid_check_y(gd, py) != 0)
return (NULL);
@ -298,8 +275,6 @@ void
grid_set_cell(
struct grid *gd, u_int px, u_int py, const struct grid_cell *gc)
{
if (grid_check_x(gd, px) != 0)
return;
if (grid_check_y(gd, py) != 0)
return;
@ -311,8 +286,6 @@ grid_set_cell(
const struct grid_utf8 *
grid_peek_utf8(struct grid *gd, u_int px, u_int py)
{
if (grid_check_x(gd, px) != 0)
return (NULL);
if (grid_check_y(gd, py) != 0)
return (NULL);
@ -325,8 +298,6 @@ grid_peek_utf8(struct grid *gd, u_int px, u_int py)
struct grid_utf8 *
grid_get_utf8(struct grid *gd, u_int px, u_int py)
{
if (grid_check_x(gd, px) != 0)
return (NULL);
if (grid_check_y(gd, py) != 0)
return (NULL);
@ -339,8 +310,6 @@ void
grid_set_utf8(
struct grid *gd, u_int px, u_int py, const struct grid_utf8 *gc)
{
if (grid_check_x(gd, px) != 0)
return;
if (grid_check_y(gd, py) != 0)
return;
@ -364,10 +333,6 @@ grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny)
return;
}
if (grid_check_x(gd, px) != 0)
return;
if (grid_check_x(gd, px + nx - 1) != 0)
return;
if (grid_check_y(gd, py) != 0)
return;
if (grid_check_y(gd, py + ny - 1) != 0)
@ -465,12 +430,6 @@ grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx)
if (nx == 0 || px == dx)
return;
if (grid_check_x(gd, px) != 0)
return;
if (grid_check_x(gd, px + nx - 1) != 0)
return;
if (grid_check_x(gd, dx + nx - 1) != 0)
return;
if (grid_check_y(gd, py) != 0)
return;
gl = &gd->linedata[py];

View File

@ -211,12 +211,14 @@ key_bindings_print(struct cmd_ctx *ctx, const char *fmt, ...)
struct winlink *wl = ctx->curclient->session->curw;
va_list ap;
if (wl->window->active->mode != &window_more_mode)
if (wl->window->active->mode != &window_copy_mode) {
window_pane_reset_mode(wl->window->active);
window_pane_set_mode(wl->window->active, &window_more_mode);
window_pane_set_mode(wl->window->active, &window_copy_mode);
window_copy_init_for_output(wl->window->active);
}
va_start(ap, fmt);
window_more_vadd(wl->window->active, fmt, ap);
window_copy_vadd(wl->window->active, fmt, ap);
va_end(ap);
}

View File

@ -1009,13 +1009,14 @@ screen_write_cell(struct screen_write_ctx *ctx,
}
/* Check this will fit on the current line and wrap if not. */
if (s->cx > screen_size_x(s) - width) {
if ((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - width) {
screen_write_linefeed(ctx, 1);
s->cx = 0; /* carriage return */
}
/* Sanity checks. */
if (s->cx > screen_size_x(s) - 1 || s->cy > screen_size_y(s) - 1)
if (((s->mode & MODE_WRAP) && s->cx > screen_size_x(s) - 1)
|| s->cy > screen_size_y(s) - 1)
return;
/* Handle overwriting of UTF-8 characters. */

View File

@ -20,6 +20,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <vis.h>
#include "tmux.h"
@ -55,7 +56,7 @@ screen_reinit(struct screen *s)
s->rupper = 0;
s->rlower = screen_size_y(s) - 1;
s->mode = MODE_CURSOR;
s->mode = MODE_CURSOR | MODE_WRAP;
screen_reset_tabs(s);

View File

@ -182,10 +182,11 @@ server_start(char *path)
*/
if (!ARRAY_EMPTY(&sessions) && !ARRAY_EMPTY(&cfg_causes)) {
wp = ARRAY_FIRST(&sessions)->curw->window->active;
window_pane_set_mode(wp, &window_more_mode);
window_pane_set_mode(wp, &window_copy_mode);
window_copy_init_for_output(wp);
for (i = 0; i < ARRAY_LENGTH(&cfg_causes); i++) {
cause = ARRAY_ITEM(&cfg_causes, i);
window_more_add(wp, "%s", cause);
window_copy_add(wp, "%s", cause);
xfree(cause);
}
ARRAY_FREE(&cfg_causes);

26
tmux.1
View File

@ -586,14 +586,8 @@ A
.Nm
window may be in one of several modes.
The default permits direct access to the terminal attached to the window.
The others are:
.Bl -tag -width Ds
.It Em output mode
This is entered when a command which produces output, such as
.Ic list-keys ,
is executed from a key binding.
.It Em copy mode
This permits a section of a window or its history to be copied to a
The other is copy mode, which permits a section of a window or its
history to be copied to a
.Em paste buffer
for later insertion into another window.
This mode is entered with the
@ -601,7 +595,9 @@ This mode is entered with the
command, bound to
.Ql \&[
by default.
.El
It is also entered when a command that produces output, such as
.Ic list-keys ,
is executed from a key binding.
.Pp
The keys available depend on whether emacs or vi mode is selected
(see the
@ -699,7 +695,7 @@ and
.Em emacs-choice
for keys used when choosing from lists (such as produced by the
.Ic choose-window
command) or in output mode; and
command); and
.Em vi-copy
and
.Em emacs-copy
@ -714,7 +710,9 @@ and
The paste buffer key pastes the first line from the top paste buffer on the
stack.
.Pp
The mode commands are as follows:
The synopsis for the
.Ic copy-mode
command is:
.Bl -tag -width Ds
.It Xo Ic copy-mode
.Op Fl u
@ -2032,8 +2030,8 @@ command.
.It Xo Ic synchronize-panes
.Op Ic on | off
.Xc
Duplicate input to any pane to all other panes in the same window, except
for panes that are not in output mode.
Duplicate input to any pane to all other panes in the same window (only
for panes that are not in any special mode).
.Pp
.It Xo Ic alternate-screen
.Op Ic on | off
@ -2443,7 +2441,7 @@ option.
Execute
.Ar shell-command
in the background without creating a window.
After it finishes, any output to stdout is displayed in output mode.
After it finishes, any output to stdout is displayed in copy mode.
If the command doesn't return success, the exit status is also displayed.
.It Ic server-info
.D1 (alias: Ic info )

10
tmux.h
View File

@ -541,6 +541,7 @@ struct mode_key_table {
#define MODE_KCURSOR 0x4
#define MODE_KKEYPAD 0x8 /* set = application, clear = number */
#define MODE_MOUSE 0x10
#define MODE_WRAP 0x20 /* whether lines wrap */
/*
* A single UTF-8 character.
@ -1880,13 +1881,12 @@ extern const struct window_mode window_clock_mode;
/* window-copy.c */
extern const struct window_mode window_copy_mode;
void window_copy_init_from_pane(struct window_pane *);
void window_copy_init_for_output(struct window_pane *);
void window_copy_add(struct window_pane *, const char *, ...);
void window_copy_vadd(struct window_pane *, const char *, va_list);
void window_copy_pageup(struct window_pane *);
/* window-more.c */
extern const struct window_mode window_more_mode;
void window_more_add(struct window_pane *, const char *, ...);
void window_more_vadd(struct window_pane *, const char *, va_list);
/* window-choose.c */
extern const struct window_mode window_choose_mode;
void window_choose_vadd(

View File

@ -93,9 +93,28 @@ enum window_copy_input_type {
WINDOW_COPY_GOTOLINE,
};
/*
* Copy-mode's visible screen (the "screen" field) is filled from one of
* two sources: the original contents of the pane (used when we
* actually enter via the "copy-mode" command, to copy the contents of
* the current pane), or else a series of lines containing the output
* from an output-writing tmux command (such as any of the "show-*" or
* "list-*" commands).
*
* In either case, the full content of the copy-mode grid is pointed at
* by the "backing" field, and is copied into "screen" as needed (that
* is, when scrolling occurs). When copy-mode is backed by a pane,
* backing points directly at that pane's screen structure (&wp->base);
* when backed by a list of output-lines from a command, it points at
* a newly-allocated screen structure (which is deallocated when the
* mode ends).
*/
struct window_copy_mode_data {
struct screen screen;
struct screen *backing;
int backing_written; /* backing display has started */
struct mode_key_data mdata;
u_int oy;
@ -129,18 +148,18 @@ window_copy_init(struct window_pane *wp)
{
struct window_copy_mode_data *data;
struct screen *s;
struct screen_write_ctx ctx;
u_int i;
int keys;
wp->modedata = data = xmalloc(sizeof *data);
data->oy = 0;
data->cx = wp->base.cx;
data->cy = wp->base.cy;
data->cx = 0;
data->cy = 0;
data->lastcx = 0;
data->lastsx = 0;
data->backing_written = 0;
data->rectflag = 0;
data->inputtype = WINDOW_COPY_OFF;
@ -168,6 +187,26 @@ window_copy_init(struct window_pane *wp)
else
mode_key_init(&data->mdata, &mode_key_tree_vi_copy);
data->backing = NULL;
return (s);
}
void
window_copy_init_from_pane(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
u_int i;
if (wp->mode != &window_copy_mode)
fatalx("not in copy mode");
data->backing = &wp->base;
data->cx = data->backing->cx;
data->cy = data->backing->cy;
s->cx = data->cx;
s->cy = data->cy;
@ -176,8 +215,17 @@ window_copy_init(struct window_pane *wp)
window_copy_write_line(wp, &ctx, i);
screen_write_cursormove(&ctx, data->cx, data->cy);
screen_write_stop(&ctx);
}
return (s);
void
window_copy_init_for_output(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
data->backing = xmalloc(sizeof *data->backing);
screen_init(data->backing, screen_size_x(&wp->base),
screen_size_y(&wp->base), UINT_MAX);
data->backing->mode &= ~MODE_WRAP;
}
void
@ -192,11 +240,73 @@ window_copy_free(struct window_pane *wp)
xfree(data->searchstr);
xfree(data->inputstr);
if (data->backing != &wp->base) {
screen_free(data->backing);
xfree(data->backing);
}
screen_free(&data->screen);
xfree(data);
}
void
window_copy_add(struct window_pane *wp, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
window_copy_vadd(wp, fmt, ap);
va_end(ap);
}
void
window_copy_vadd(struct window_pane *wp, const char *fmt, va_list ap)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *backing = data->backing;
struct screen_write_ctx back_ctx, ctx;
struct grid_cell gc;
int utf8flag;
u_int old_hsize;
if (backing == &wp->base)
return;
utf8flag = options_get_number(&wp->window->options, "utf8");
memcpy(&gc, &grid_default_cell, sizeof gc);
old_hsize = screen_hsize(data->backing);
screen_write_start(&back_ctx, NULL, backing);
if (data->backing_written) {
/*
* On the second or later line, do a CRLF before writing
* (so it's on a new line).
*/
screen_write_carriagereturn(&back_ctx);
screen_write_linefeed(&back_ctx, 0);
} else
data->backing_written = 1;
screen_write_vnputs(&back_ctx, 0, &gc, utf8flag, fmt, ap);
screen_write_stop(&back_ctx);
data->oy += screen_hsize(data->backing) - old_hsize;
screen_write_start(&ctx, wp, &data->screen);
/*
* If the history has changed, draw the top line.
* (If there's any history at all, it has changed.)
*/
if (screen_hsize(data->backing))
window_copy_redraw_lines(wp, 0, 1);
/* Write the line, if it's visible. */
if (backing->cy + data->oy < screen_size_y(backing))
window_copy_redraw_lines(wp, backing->cy, 1);
screen_write_stop(&ctx);
}
void
window_copy_pageup(struct window_pane *wp)
{
@ -207,8 +317,8 @@ window_copy_pageup(struct window_pane *wp)
n = 1;
if (screen_size_y(s) > 2)
n = screen_size_y(s) - 2;
if (data->oy + n > screen_hsize(&wp->base))
data->oy = screen_hsize(&wp->base);
if (data->oy + n > screen_hsize(data->backing))
data->oy = screen_hsize(data->backing);
else
data->oy += n;
window_copy_update_selection(wp);
@ -223,6 +333,8 @@ window_copy_resize(struct window_pane *wp, u_int sx, u_int sy)
struct screen_write_ctx ctx;
screen_resize(s, sx, sy);
if (data->backing != &wp->base)
screen_resize(data->backing, sx, sy);
if (data->cy > sy - 1)
data->cy = sy - 1;
@ -329,8 +441,8 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
case MODEKEYCOPY_HALFPAGEUP:
n = screen_size_y(s) / 2;
for (; np != 0; np--) {
if (data->oy + n > screen_hsize(&wp->base))
data->oy = screen_hsize(&wp->base);
if (data->oy + n > screen_hsize(data->backing))
data->oy = screen_hsize(data->backing);
else
data->oy += n;
}
@ -369,7 +481,7 @@ window_copy_key(struct window_pane *wp, struct client *c, int key)
case MODEKEYCOPY_HISTORYTOP:
data->cx = 0;
data->cy = 0;
data->oy = screen_hsize(&wp->base);
data->oy = screen_hsize(data->backing);
window_copy_update_selection(wp);
window_copy_redraw_screen(wp);
break;
@ -665,8 +777,7 @@ void
window_copy_scroll_to(struct window_pane *wp, u_int px, u_int py)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &wp->base;
struct grid *gd = s->grid;
struct grid *gd = data->backing->grid;
u_int offset, gap;
data->cx = px;
@ -761,7 +872,7 @@ void
window_copy_search_up(struct window_pane *wp, const char *searchstr)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &wp->base, ss;
struct screen *s = data->backing, ss;
struct screen_write_ctx ctx;
struct grid *gd = s->grid, *sgd;
struct grid_cell gc;
@ -818,7 +929,7 @@ void
window_copy_search_down(struct window_pane *wp, const char *searchstr)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = &wp->base, ss;
struct screen *s = data->backing, ss;
struct screen_write_ctx ctx;
struct grid *gd = s->grid, *sgd;
struct grid_cell gc;
@ -878,7 +989,7 @@ window_copy_goto_line(struct window_pane *wp, const char *linestr)
const char *errstr;
u_int lineno;
lineno = strtonum(linestr, 0, screen_hsize(&wp->base), &errstr);
lineno = strtonum(linestr, 0, screen_hsize(data->backing), &errstr);
if (errstr != NULL)
return;
@ -906,7 +1017,7 @@ window_copy_write_line(
last = screen_size_y(s) - 1;
if (py == 0) {
size = xsnprintf(hdr, sizeof hdr,
"[%u/%u]", data->oy, screen_hsize(&wp->base));
"[%u/%u]", data->oy, screen_hsize(data->backing));
screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
screen_write_puts(ctx, &gc, "%s", hdr);
} else if (py == last && data->inputtype != WINDOW_COPY_OFF) {
@ -923,8 +1034,9 @@ window_copy_write_line(
size = 0;
screen_write_cursormove(ctx, xoff, py);
screen_write_copy(ctx, &wp->base, xoff, (screen_hsize(&wp->base) -
data->oy) + py, screen_size_x(s) - size, 1);
screen_write_copy(ctx, data->backing, xoff,
(screen_hsize(data->backing) - data->oy) + py,
screen_size_x(s) - size, 1);
if (py == data->cy && data->cx == screen_size_x(s)) {
memcpy(&gc, &grid_default_cell, sizeof gc);
@ -993,7 +1105,7 @@ window_copy_start_selection(struct window_pane *wp)
struct screen *s = &data->screen;
data->selx = data->cx;
data->sely = screen_hsize(&wp->base) + data->cy - data->oy;
data->sely = screen_hsize(data->backing) + data->cy - data->oy;
s->sel.flag = 1;
window_copy_update_selection(wp);
@ -1018,7 +1130,7 @@ window_copy_update_selection(struct window_pane *wp)
gc.attr |= options_get_number(oo, "mode-attr");
/* Find top of screen. */
ty = screen_hsize(&wp->base) - data->oy;
ty = screen_hsize(data->backing) - data->oy;
/* Adjust the selection. */
sx = data->selx;
@ -1079,7 +1191,7 @@ window_copy_copy_selection(struct window_pane *wp, struct client *c)
/* Find start and end. */
xx = data->cx;
yy = screen_hsize(&wp->base) + data->cy - data->oy;
yy = screen_hsize(data->backing) + data->cy - data->oy;
if (yy < data->sely || (yy == data->sely && xx < data->selx)) {
sx = xx; sy = yy;
ex = data->selx; ey = data->sely;
@ -1158,12 +1270,13 @@ void
window_copy_copy_line(struct window_pane *wp,
char **buf, size_t *off, u_int sy, u_int sx, u_int ex)
{
struct grid *gd = wp->base.grid;
const struct grid_cell *gc;
const struct grid_utf8 *gu;
struct grid_line *gl;
u_int i, xx, wrapped = 0;
size_t size;
struct window_copy_mode_data *data = wp->modedata;
struct grid *gd = data->backing->grid;
const struct grid_cell *gc;
const struct grid_utf8 *gu;
struct grid_line *gl;
u_int i, xx, wrapped = 0;
size_t size;
if (sx > ex)
return;
@ -1218,7 +1331,7 @@ window_copy_clear_selection(struct window_pane *wp)
screen_clear_selection(&data->screen);
py = screen_hsize(&wp->base) + data->cy - data->oy;
py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if (data->cx > px)
window_copy_update_cursor(wp, px, data->cy);
@ -1227,9 +1340,10 @@ window_copy_clear_selection(struct window_pane *wp)
int
window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set)
{
const struct grid_cell *gc;
struct window_copy_mode_data *data = wp->modedata;
const struct grid_cell *gc;
gc = grid_peek_cell(wp->base.grid, px, py);
gc = grid_peek_cell(data->backing->grid, px, py);
if (gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8))
return (0);
if (gc->data == 0x00 || gc->data == 0x7f)
@ -1240,8 +1354,10 @@ window_copy_in_set(struct window_pane *wp, u_int px, u_int py, const char *set)
u_int
window_copy_find_length(struct window_pane *wp, u_int py)
{
const struct grid_cell *gc;
u_int px;
struct window_copy_mode_data *data = wp->modedata;
struct screen *s = data->backing;
const struct grid_cell *gc;
u_int px;
/*
* If the pane has been resized, its grid can contain old overlong
@ -1249,11 +1365,11 @@ window_copy_find_length(struct window_pane *wp, u_int py)
* width of the grid, and screen_write_copy treats them as spaces, so
* ignore them here too.
*/
px = wp->base.grid->linedata[py].cellsize;
if (px > screen_size_x(&wp->base))
px = screen_size_x(&wp->base);
px = s->grid->linedata[py].cellsize;
if (px > screen_size_x(s))
px = screen_size_x(s);
while (px > 0) {
gc = grid_peek_cell(wp->base.grid, px - 1, py);
gc = grid_peek_cell(s->grid, px - 1, py);
if (gc->flags & GRID_FLAG_UTF8)
break;
if (gc->data != ' ')
@ -1281,11 +1397,11 @@ window_copy_cursor_back_to_indentation(struct window_pane *wp)
const struct grid_cell *gc;
px = 0;
py = screen_hsize(&wp->base) + data->cy - data->oy;
py = screen_hsize(data->backing) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
while (px < xx) {
gc = grid_peek_cell(wp->base.grid, px, py);
gc = grid_peek_cell(data->backing->grid, px, py);
if (gc->flags & GRID_FLAG_UTF8)
break;
if (gc->data != ' ')
@ -1302,21 +1418,22 @@ void
window_copy_cursor_end_of_line(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *base_s = &wp->base;
struct grid *gd = base_s->grid;
struct screen *back_s = data->backing;
struct grid *gd = back_s->grid;
u_int px, py;
py = screen_hsize(base_s) + data->cy - data->oy;
py = screen_hsize(back_s) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if (data->cx == px) {
if (data->screen.sel.flag && data->rectflag)
px = screen_size_x(&wp->base);
px = screen_size_x(back_s);
if (gd->linedata[py].flags & GRID_LINE_WRAPPED) {
while (py < gd->sy + gd->hsize &&
gd->linedata[py].flags & GRID_LINE_WRAPPED) {
window_copy_cursor_down(wp, 0);
py = screen_hsize(base_s) + data->cy - data->oy;
py = screen_hsize(back_s)
+ data->cy - data->oy;
}
px = window_copy_find_length(wp, py);
}
@ -1351,7 +1468,7 @@ window_copy_cursor_right(struct window_pane *wp)
if (data->screen.sel.flag && data->rectflag)
px = screen_size_x(&data->screen);
else {
py = screen_hsize(&wp->base) + data->cy - data->oy;
py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
}
@ -1372,7 +1489,7 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only)
struct screen *s = &data->screen;
u_int ox, oy, px, py;
oy = screen_hsize(&wp->base) + data->cy - data->oy;
oy = screen_hsize(data->backing) + data->cy - data->oy;
ox = window_copy_find_length(wp, oy);
if (ox != 0) {
data->lastcx = data->cx;
@ -1399,7 +1516,7 @@ window_copy_cursor_up(struct window_pane *wp, int scroll_only)
}
if (!data->screen.sel.flag || !data->rectflag) {
py = screen_hsize(&wp->base) + data->cy - data->oy;
py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if ((data->cx >= data->lastsx && data->cx != px) ||
data->cx > px)
@ -1414,7 +1531,7 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only)
struct screen *s = &data->screen;
u_int ox, oy, px, py;
oy = screen_hsize(&wp->base) + data->cy - data->oy;
oy = screen_hsize(data->backing) + data->cy - data->oy;
ox = window_copy_find_length(wp, oy);
if (ox != 0) {
data->lastcx = data->cx;
@ -1433,7 +1550,7 @@ window_copy_cursor_down(struct window_pane *wp, int scroll_only)
}
if (!data->screen.sel.flag || !data->rectflag) {
py = screen_hsize(&wp->base) + data->cy - data->oy;
py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if ((data->cx >= data->lastsx && data->cx != px) ||
data->cx > px)
@ -1445,16 +1562,16 @@ void
window_copy_cursor_jump(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *base_s = &wp->base;
struct screen *back_s = data->backing;
const struct grid_cell *gc;
uint px, py, xx;
px = data->cx + 1;
py = screen_hsize(base_s) + data->cy - data->oy;
py = screen_hsize(back_s) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
while (px < xx) {
gc = grid_peek_cell(base_s->grid, px, py);
gc = grid_peek_cell(back_s->grid, px, py);
if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0
&& gc->data == data->jumpchar) {
@ -1471,18 +1588,18 @@ void
window_copy_cursor_jump_back(struct window_pane *wp)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *base_s = &wp->base;
struct screen *back_s = data->backing;
const struct grid_cell *gc;
uint px, py;
px = data->cx;
py = screen_hsize(base_s) + data->cy - data->oy;
py = screen_hsize(back_s) + data->cy - data->oy;
if (px > 0)
px--;
for (;;) {
gc = grid_peek_cell(base_s->grid, px, py);
gc = grid_peek_cell(back_s->grid, px, py);
if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0
&& gc->data == data->jumpchar) {
@ -1501,14 +1618,14 @@ void
window_copy_cursor_next_word(struct window_pane *wp, const char *separators)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *base_s = &wp->base;
struct screen *back_s = data->backing;
u_int px, py, xx, yy;
int expected = 0;
px = data->cx;
py = screen_hsize(base_s) + data->cy - data->oy;
py = screen_hsize(back_s) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
yy = screen_hsize(base_s) + screen_size_y(base_s) - 1;
yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
/*
* First skip past any nonword characters and then any word characters.
@ -1526,7 +1643,7 @@ window_copy_cursor_next_word(struct window_pane *wp, const char *separators)
window_copy_cursor_down(wp, 0);
px = 0;
py = screen_hsize(base_s) + data->cy - data->oy;
py = screen_hsize(back_s) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
} else
px++;
@ -1543,14 +1660,14 @@ void
window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators)
{
struct window_copy_mode_data *data = wp->modedata;
struct screen *base_s = &wp->base;
struct screen *back_s = data->backing;
u_int px, py, xx, yy;
int expected = 1;
px = data->cx;
py = screen_hsize(base_s) + data->cy - data->oy;
py = screen_hsize(back_s) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
yy = screen_hsize(base_s) + screen_size_y(base_s) - 1;
yy = screen_hsize(back_s) + screen_size_y(back_s) - 1;
/*
* First skip past any word characters, then any nonword characters.
@ -1568,7 +1685,7 @@ window_copy_cursor_next_word_end(struct window_pane *wp, const char *separators)
window_copy_cursor_down(wp, 0);
px = 0;
py = screen_hsize(base_s) + data->cy - data->oy;
py = screen_hsize(back_s) + data->cy - data->oy;
xx = window_copy_find_length(wp, py);
} else
px++;
@ -1589,7 +1706,7 @@ window_copy_cursor_previous_word(struct window_pane *wp, const char *separators)
u_int px, py;
px = data->cx;
py = screen_hsize(&wp->base) + data->cy - data->oy;
py = screen_hsize(data->backing) + data->cy - data->oy;
/* Move back to the previous word character. */
for (;;) {
@ -1599,12 +1716,12 @@ window_copy_cursor_previous_word(struct window_pane *wp, const char *separators)
break;
} else {
if (data->cy == 0 &&
(screen_hsize(&wp->base) == 0 ||
data->oy >= screen_hsize(&wp->base) - 1))
(screen_hsize(data->backing) == 0 ||
data->oy >= screen_hsize(data->backing) - 1))
goto out;
window_copy_cursor_up(wp, 0);
py = screen_hsize(&wp->base) + data->cy - data->oy;
py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
}
}
@ -1657,11 +1774,11 @@ window_copy_scroll_down(struct window_pane *wp, u_int ny)
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
if (ny > screen_hsize(&wp->base))
if (ny > screen_hsize(data->backing))
return;
if (data->oy > screen_hsize(&wp->base) - ny)
ny = screen_hsize(&wp->base) - data->oy;
if (data->oy > screen_hsize(data->backing) - ny)
ny = screen_hsize(data->backing) - data->oy;
if (ny == 0)
return;
data->oy += ny;
@ -1688,7 +1805,7 @@ window_copy_rectangle_toggle(struct window_pane *wp)
data->rectflag = !data->rectflag;
py = screen_hsize(&wp->base) + data->cy - data->oy;
py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wp, py);
if (data->cx > px)
window_copy_update_cursor(wp, px, data->cy);

View File

@ -1,260 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
*
* 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 <sys/types.h>
#include <string.h>
#include "tmux.h"
struct screen *window_more_init(struct window_pane *);
void window_more_free(struct window_pane *);
void window_more_resize(struct window_pane *, u_int, u_int);
void window_more_key(struct window_pane *, struct client *, int);
void window_more_redraw_screen(struct window_pane *);
void window_more_write_line(
struct window_pane *, struct screen_write_ctx *, u_int);
void window_more_scroll_up(struct window_pane *);
void window_more_scroll_down(struct window_pane *);
const struct window_mode window_more_mode = {
window_more_init,
window_more_free,
window_more_resize,
window_more_key,
NULL,
NULL,
};
struct window_more_mode_data {
struct screen screen;
struct mode_key_data mdata;
ARRAY_DECL(, char *) list;
u_int top;
};
void
window_more_add(struct window_pane *wp, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
window_more_vadd(wp, fmt, ap);
va_end(ap);
}
void
window_more_vadd(struct window_pane *wp, const char *fmt, va_list ap)
{
struct window_more_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
char *msg;
u_int size;
xvasprintf(&msg, fmt, ap);
ARRAY_ADD(&data->list, msg);
screen_write_start(&ctx, wp, NULL);
size = ARRAY_LENGTH(&data->list) - 1;
if (size >= data->top && size <= data->top + screen_size_y(s) - 1) {
window_more_write_line(wp, &ctx, size - data->top);
if (size != data->top)
window_more_write_line(wp, &ctx, 0);
} else
window_more_write_line(wp, &ctx, 0);
screen_write_stop(&ctx);
}
struct screen *
window_more_init(struct window_pane *wp)
{
struct window_more_mode_data *data;
struct screen *s;
int keys;
wp->modedata = data = xmalloc(sizeof *data);
ARRAY_INIT(&data->list);
data->top = 0;
s = &data->screen;
screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
s->mode &= ~MODE_CURSOR;
keys = options_get_number(&wp->window->options, "mode-keys");
if (keys == MODEKEY_EMACS)
mode_key_init(&data->mdata, &mode_key_tree_emacs_choice);
else
mode_key_init(&data->mdata, &mode_key_tree_vi_choice);
return (s);
}
void
window_more_free(struct window_pane *wp)
{
struct window_more_mode_data *data = wp->modedata;
u_int i;
for (i = 0; i < ARRAY_LENGTH(&data->list); i++)
xfree(ARRAY_ITEM(&data->list, i));
ARRAY_FREE(&data->list);
screen_free(&data->screen);
xfree(data);
}
void
window_more_resize(struct window_pane *wp, u_int sx, u_int sy)
{
struct window_more_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
screen_resize(s, sx, sy);
window_more_redraw_screen(wp);
}
/* ARGSUSED */
void
window_more_key(struct window_pane *wp, unused struct client *c, int key)
{
struct window_more_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
switch (mode_key_lookup(&data->mdata, key)) {
case MODEKEYCHOICE_CANCEL:
window_pane_reset_mode(wp);
break;
case MODEKEYCHOICE_UP:
case MODEKEYCHOICE_SCROLLUP:
window_more_scroll_up(wp);
break;
case MODEKEYCHOICE_DOWN:
case MODEKEYCHOICE_SCROLLDOWN:
window_more_scroll_down(wp);
break;
case MODEKEYCHOICE_PAGEUP:
if (data->top < screen_size_y(s))
data->top = 0;
else
data->top -= screen_size_y(s);
window_more_redraw_screen(wp);
break;
case MODEKEYCHOICE_PAGEDOWN:
if (data->top + screen_size_y(s) > ARRAY_LENGTH(&data->list))
data->top = ARRAY_LENGTH(&data->list);
else
data->top += screen_size_y(s);
window_more_redraw_screen(wp);
break;
default:
break;
}
}
void
window_more_write_line(
struct window_pane *wp, struct screen_write_ctx *ctx, u_int py)
{
struct window_more_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct options *oo = &wp->window->options;
struct grid_cell gc;
char *msg, hdr[32];
size_t size;
int utf8flag;
utf8flag = options_get_number(&wp->window->options, "utf8");
memcpy(&gc, &grid_default_cell, sizeof gc);
if (py == 0) {
size = xsnprintf(hdr, sizeof hdr,
"[%u/%u]", data->top, ARRAY_LENGTH(&data->list));
screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
colour_set_fg(&gc, options_get_number(oo, "mode-fg"));
colour_set_bg(&gc, options_get_number(oo, "mode-bg"));
gc.attr |= options_get_number(oo, "mode-attr");
screen_write_puts(ctx, &gc, "%s", hdr);
memcpy(&gc, &grid_default_cell, sizeof gc);
} else
size = 0;
screen_write_cursormove(ctx, 0, py);
if (data->top + py < ARRAY_LENGTH(&data->list)) {
msg = ARRAY_ITEM(&data->list, data->top + py);
screen_write_nputs(
ctx, screen_size_x(s) - size, &gc, utf8flag, "%s", msg);
}
while (s->cx < screen_size_x(s) - size)
screen_write_putc(ctx, &gc, ' ');
}
void
window_more_redraw_screen(struct window_pane *wp)
{
struct window_more_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
u_int i;
screen_write_start(&ctx, wp, NULL);
for (i = 0; i < screen_size_y(s); i++)
window_more_write_line(wp, &ctx, i);
screen_write_stop(&ctx);
}
void
window_more_scroll_up(struct window_pane *wp)
{
struct window_more_mode_data *data = wp->modedata;
struct screen_write_ctx ctx;
if (data->top == 0)
return;
data->top--;
screen_write_start(&ctx, wp, NULL);
screen_write_cursormove(&ctx, 0, 0);
screen_write_insertline(&ctx, 1);
window_more_write_line(wp, &ctx, 0);
window_more_write_line(wp, &ctx, 1);
screen_write_stop(&ctx);
}
void
window_more_scroll_down(struct window_pane *wp)
{
struct window_more_mode_data *data = wp->modedata;
struct screen *s = &data->screen;
struct screen_write_ctx ctx;
if (data->top >= ARRAY_LENGTH(&data->list))
return;
data->top++;
screen_write_start(&ctx, wp, NULL);
screen_write_cursormove(&ctx, 0, 0);
screen_write_deleteline(&ctx, 1);
window_more_write_line(wp, &ctx, screen_size_y(s) - 1);
window_more_write_line(wp, &ctx, 0);
screen_write_stop(&ctx);
}