From efe557313aef555b415fa2ea2c9a50c4404ed788 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 25 Sep 2008 20:08:57 +0000 Subject: [PATCH] Internal screen data rewrite for better 256 colour/UTF-8 support. --- CHANGES | 12 +- GNUmakefile | 8 +- Makefile | 5 +- TODO | 125 +----- cmd-list-windows.c | 23 +- grid-view.c | 199 ++++++++++ grid.c | 353 +++++++++++++++++ input.c | 358 +++++++++-------- log.c | 5 +- screen-display.c | 477 ---------------------- screen-redraw.c | 122 +++--- screen-write.c | 955 +++++++++++++++++++++++---------------------- screen.c | 375 +++++------------- server-msg.c | 6 +- server.c | 28 +- status.c | 135 +++---- tmux.1 | 11 +- tmux.c | 12 +- tmux.h | 379 ++++++++---------- tty.c | 804 +++++++++++++++++++++++++------------- utf8.c | 139 +++---- window-copy.c | 262 +++++++------ window-more.c | 39 +- window-scroll.c | 63 +-- 24 files changed, 2474 insertions(+), 2421 deletions(-) create mode 100644 grid-view.c create mode 100644 grid.c delete mode 100644 screen-display.c diff --git a/CHANGES b/CHANGES index c55af603..c6f2dff6 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,13 @@ +25 September 2008 + +* Large internal rewrite to better support 256 colours and UTF-8. Screen data + is now stored as single two-way array of structures rather than as multiple + separate arrays. Also simplified a lot of code. + + Only external changes are three new flags, -2, -d and -u, which force tmux to + assume the terminal supports 256 colours, default colours (useful for + xterm-256color which lacks the AX flag), or UTF-8 respectively. + 10 September 2008 * Split off colour conversion code from screen code. @@ -664,4 +674,4 @@ (including mutt, emacs). No status bar yet and no key remapping or other customisation. -$Id: CHANGES,v 1.160 2008-09-10 18:59:29 nicm Exp $ +$Id: CHANGES,v 1.161 2008-09-25 20:08:51 nicm Exp $ diff --git a/GNUmakefile b/GNUmakefile index abc13121..b0e9dad3 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,4 +1,4 @@ -# $Id: GNUmakefile,v 1.39 2008-09-09 22:16:36 nicm Exp $ +# $Id: GNUmakefile,v 1.40 2008-09-25 20:08:51 nicm Exp $ .PHONY: clean @@ -12,7 +12,9 @@ DATE= $(shell date +%Y%m%d-%H%M) META?= \002 SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \ - xmalloc.c xmalloc-debug.c input.c input-keys.c screen.c screen-display.c \ + xmalloc.c xmalloc-debug.c input.c input-keys.c \ + screen.c screen-write.c screen-redraw.c \ + grid.c grid-view.c \ window.c session.c log.c client.c client-msg.c client-fn.c cfg.c \ key-string.c key-bindings.c resize.c arg.c mode-key.c \ cmd.c cmd-generic.c cmd-string.c \ @@ -31,7 +33,7 @@ SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \ cmd-list-commands.c cmd-move-window.c cmd-select-prompt.c \ cmd-respawn-window.c \ window-scroll.c window-more.c window-copy.c options.c paste.c \ - tty.c tty-keys.c tty-write.c screen-write.c screen-redraw.c utf8.c + tty.c tty-keys.c tty-write.c colour.c utf8.c CC?= gcc INCDIRS+= -I. -I- diff --git a/Makefile b/Makefile index 51334ace..2ada4b8d 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.74 2008-09-10 18:59:29 nicm Exp $ +# $Id: Makefile,v 1.75 2008-09-25 20:08:51 nicm Exp $ .SUFFIXES: .c .o .y .h .PHONY: clean update-index.html upload-index.html @@ -17,7 +17,8 @@ META?= \002 # C-b SRCS= tmux.c server.c server-msg.c server-fn.c buffer.c buffer-poll.c status.c \ xmalloc.c xmalloc-debug.c input.c input-keys.c \ - screen.c screen-display.c screen-write.c screen-redraw.c \ + screen.c screen-write.c screen-redraw.c \ + grid.c grid-view.c \ window.c session.c log.c client.c client-msg.c client-fn.c cfg.c \ key-string.c key-bindings.c resize.c arg.c mode-key.c \ cmd.c cmd-generic.c cmd-string.c \ diff --git a/TODO b/TODO index 54311a6f..ac90869c 100644 --- a/TODO +++ b/TODO @@ -41,127 +41,10 @@ -- For 0.5 -------------------------------------------------------------------- -XXX -screen contains grid - -screen_write <-- write to TTY and to screen using close-to-ANSI functions -screen_redraw <-- write areas of screen to TTY -grid_view <-- write to viewable area of grid -grid <-- manipulate grid and history - -XXX -grid_view has ox,oy -XXX - -- FINISH UTF8: fix copy and paste -- SPLIT u_short attr into attr,flags? -- maybe rethink backend data structure? - - utf8 can be 1-4 bytes - - most common is 1 bytes - - there can be double-width characters which take n bytes but 2 columns on screen - - they are not only drawn as two characters, they also require two backspaces to remove -- three operations: - - simultaneously update screen and ttys - - redraw screen or section of screen to ttys - - write to ttys without updating screen - ---- -NEED to be able to: - resize screen - apply ops to both screen and tty simultaneously - both when parsing input and when eg scrolling history - draw on the top of the screen without modifying it - display arbitrary parts of the history - redraw arbitrary parts of the visible screen ---- -NEVER need to draw into the history - -split off grid manip: - 16-bit characters - 8-bit flags - 8-bit attributes - 8-bit fg colour - 8-bit bg colour - -struct grid_data { - struct grid_cell **data; - int *sizes; - - int sx; - int sy; - - int hsize; - int hlimit; -}; -struct grid_cell { - u_short data; - u_char attr; - u_char flags; - u_char fg; - u_char bg; -}; -const struct grid_default_cell = { 0x20, 0, 0, 8, 8 }; - -; grid logically split from -; -hlimit to 0 and 0 to sy - -; ALWAYS fill with default - -const struct grid_cell *grid_get(int x, int y); -void grid_set(int x, int y, const struct grid_cell *cell); - -void grid_resize() -void grid_shift() /* shift lines into history */ - -struct grid_view { - int ox; - int oy; - - int sx; - int sy; - - struct grid_data *gdata; - struct grid_view *parent; -}; - -struct grid_cell *grid_view_get_cell(int x, int y) -void grid_view_set_cell(int x, int y, const struct grid_cell *cell); - -int grid_view_absolute_x(int x); -int grid_view_absolute_y(int y); - -int grid_view_relative_x(int x); -int grid_view_relative_y(int y); - -void grid_view_delete_lines(int y, int ny) -void grid_view_insert_lines(int y, int ny) -void grid_view_clear_lines(int y, int ny) -void grid_view_fill_lines(int y, int ny, const struct grid_cell *cell) - -void grid_view_delete_cells(int x, int y, int nx) -void grid_view_insert_cells(int x, int y, int nx) -void grid_view_clear_cells(int x, int y, int nx) -void grid_view_fill_cells(int x, int nx, const struct grid_cell *cell) - -void grid_view_clear_area(int x, int y, int nx, int ny) -void grid_view_fill_area(int x, int y, int nx, int ny, const struct grid_cell *cell) - ---- - -screen has two (both grid_view): - base and overlay - ---- -screen_write writes into overlay if it exists and then base, also optionally to tty -screen_draw draws overlay + base to display ---- - ---- - -Would it be better to just expand char to 16-bits and use it as an index only -for >2-byte characters? or - better - don't support entire UTF range? only the BMP? -this would get rid of UTF table and limits, but still leave double-width character annoyances -also would double memory usage +TODO -- 2 fix window-*.c + 3 resizing + 4 audit for leftover/unused code + 5 next phase of tidying ---- 21:09 < merdely> NicM: if I run 'tmux attach -t main' and there is no tmux session named main, start a new one. diff --git a/cmd-list-windows.c b/cmd-list-windows.c index d3cf24c0..d5ae16e2 100644 --- a/cmd-list-windows.c +++ b/cmd-list-windows.c @@ -1,4 +1,4 @@ -/* $Id: cmd-list-windows.c,v 1.23 2008-09-09 22:16:36 nicm Exp $ */ +/* $Id: cmd-list-windows.c,v 1.24 2008-09-25 20:08:52 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -48,6 +48,7 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) struct session *s; struct winlink *wl; struct window *w; + struct grid_data *gd; u_int i; unsigned long long size; const char *name; @@ -57,27 +58,23 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx) RB_FOREACH(wl, winlinks, &s->windows) { w = wl->window; + gd = w->base.grid; size = 0; - for (i = 0; i < w->base.hsize; i++) - size += w->base.grid_size[i] * 3; - size += w->base.hsize * (sizeof *w->base.grid_data); - size += w->base.hsize * (sizeof *w->base.grid_attr); - size += w->base.hsize * (sizeof *w->base.grid_fg); - size += w->base.hsize * (sizeof *w->base.grid_bg); - size += w->base.hsize * (sizeof *w->base.grid_size); - + for (i = 0; i < gd->hsize; i++) + size += gd->size[i] * sizeof **gd->data; + size += gd->hsize * (sizeof *gd->data); + size += gd->hsize * (sizeof *gd->size); + if (w->fd != -1) name = ttyname(w->fd); else name = ""; ctx->print(ctx, - "%d: %s \"%s\" (%s) [%ux%u] [history %u/%u, %llu bytes] " - "[UTF8 table %u/%u]", + "%d: %s \"%s\" (%s) [%ux%u] [history %u/%u, %llu bytes]", wl->idx, w->name, w->base.title, name, screen_size_x(&w->base), screen_size_y(&w->base), - w->base.hsize, w->base.hlimit, size, - ARRAY_LENGTH(&w->base.utf8_table.array), UTF8_LIMIT); + gd->hsize, gd->hlimit, size); } if (ctx->cmdclient != NULL) diff --git a/grid-view.c b/grid-view.c new file mode 100644 index 00000000..434a2d06 --- /dev/null +++ b/grid-view.c @@ -0,0 +1,199 @@ +/* $Id: grid-view.c,v 1.1 2008-09-25 20:08:52 nicm Exp $ */ + +/* + * Copyright (c) 2008 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" + +/* + * Grid view functions. These work using coordinates relative to the visible + * screen area. + */ + +#define grid_view_x(gd, x) (x) +#define grid_view_y(gd, y) ((gd)->hsize + (y)) + +/* Get cell for reading. */ +const struct grid_cell * +grid_view_peek_cell(struct grid_data *gd, u_int px, u_int py) +{ + return (grid_peek_cell(gd, grid_view_x(gd, px), grid_view_y(gd, py))); +} + +/* Get cell for writing. */ +struct grid_cell * +grid_view_get_cell(struct grid_data *gd, u_int px, u_int py) +{ + return (grid_get_cell(gd, grid_view_x(gd, px), grid_view_y(gd, py))); +} + +/* Set cell. */ +void +grid_view_set_cell( + struct grid_data *gd, u_int px, u_int py, const struct grid_cell *gc) +{ + grid_set_cell(gd, grid_view_x(gd, px), grid_view_y(gd, py), gc); +} + +/* Clear area. */ +void +grid_view_clear(struct grid_data *gd, u_int px, u_int py, u_int nx, u_int ny) +{ + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u, ny=%u", px, py, nx, ny); + + px = grid_view_x(gd, px); + py = grid_view_y(gd, py); + + grid_clear(gd, px, py, nx, ny); +} + +/* Fill area. */ +void +grid_view_fill(struct grid_data *gd, + const struct grid_cell *gc, u_int px, u_int py, u_int nx, u_int ny) +{ + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u, ny=%u", px, py, nx, ny); + + px = grid_view_x(gd, px); + py = grid_view_y(gd, py); + + grid_fill(gd, gc, px, py, nx, ny); +} + +/* Scroll region up. */ +void +grid_view_scroll_region_up(struct grid_data *gd, u_int rupper, u_int rlower) +{ + GRID_DEBUG(gd, "rupper=%u, rlower=%u", rupper, rlower); + + if (rupper == 0 && rlower == gd->sy - 1) { + grid_scroll_line(gd); + return; + } + + rupper = grid_view_y(gd, rupper); + rlower = grid_view_y(gd, rlower); + + grid_move_lines(gd, rupper, rupper + 1, rlower - rupper); +} + +/* Scroll region down. */ +void +grid_view_scroll_region_down(struct grid_data *gd, u_int rupper, u_int rlower) +{ + GRID_DEBUG(gd, "rupper=%u, rlower=%u", rupper, rlower); + + rupper = grid_view_y(gd, rupper); + rlower = grid_view_y(gd, rlower); + + grid_move_lines(gd, rupper + 1, rupper, rlower - rupper); +} + +/* Insert lines. */ +void +grid_view_insert_lines(struct grid_data *gd, u_int py, u_int ny) +{ + u_int sy; + + GRID_DEBUG(gd, "py=%u, ny=%u", py, ny); + + py = grid_view_y(gd, py); + + sy = grid_view_y(gd, gd->sy); + + grid_move_lines(gd, py + ny, py, sy - py - ny); +} + +/* Insert lines in region. */ +void +grid_view_insert_lines_region( + struct grid_data *gd, u_int rupper, u_int rlower, u_int py, u_int ny) +{ + GRID_DEBUG( + gd, "rupper=%u, rlower=%u, py=%u, ny=%u", rupper, rlower, py, ny); + + rupper = grid_view_y(gd, rupper); + rlower = grid_view_y(gd, rlower); + + py = grid_view_y(gd, py); + + grid_move_lines(gd, py + ny, py, (rlower + 1) - py - ny); +} + +/* Delete lines. */ +void +grid_view_delete_lines(struct grid_data *gd, u_int py, u_int ny) +{ + u_int sy; + + GRID_DEBUG(gd, "py=%u, ny=%u", py, ny); + + py = grid_view_y(gd, py); + + sy = grid_view_y(gd, gd->sy); + + grid_move_lines(gd, py, py + ny, sy - py - ny); +} + +/* Delete lines inside scroll region. */ +void +grid_view_delete_lines_region( + struct grid_data *gd, u_int rupper, u_int rlower, u_int py, u_int ny) +{ + GRID_DEBUG( + gd, "rupper=%u, rlower=%u, py=%u, ny=%u", rupper, rlower, py, ny); + + rupper = grid_view_y(gd, rupper); + rlower = grid_view_y(gd, rlower); + + py = grid_view_y(gd, py); + + grid_move_lines(gd, py, py + ny, (rlower + 1) - py - ny); +} + +/* Insert characters. */ +void +grid_view_insert_cells(struct grid_data *gd, u_int px, u_int py, u_int nx) +{ + u_int sx; + + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); + + px = grid_view_x(gd, px); + + sx = grid_view_x(gd, gd->sx); + + grid_move_cells(gd, px + nx, px, py, (sx - 1) - (px + nx)); +} + +/* Delete characters. */ +void +grid_view_delete_cells(struct grid_data *gd, u_int px, u_int py, u_int nx) +{ + u_int sx; + + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); + + px = grid_view_x(gd, px); + + sx = grid_view_x(gd, gd->sx); + + grid_move_cells(gd, px, px + nx, py, (sx - 1) - (px + nx)); +} diff --git a/grid.c b/grid.c new file mode 100644 index 00000000..29e39a16 --- /dev/null +++ b/grid.c @@ -0,0 +1,353 @@ +/* $Id: grid.c,v 1.1 2008-09-25 20:08:52 nicm Exp $ */ + +/* + * Copyright (c) 2008 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" + +/* + * Grid data. This is the basic data structure that represents what is shown on + * screen. + * + * A grid is a grid of cells (struct grid_cell). It is sparse, in that cells + * are not allocated until they are written to. The grid is logically split + * into history and viewable data with the history starting at row (line) 0 and + * extending to (hsize - 1); from hsize to hsize + (sy - 1) is the viewable + * data. All functions in this file work on absolute coordinates, grid-view.c + * has functions which work on the screen data. + */ + +/* Default grid cell data. */ +const struct grid_cell grid_default_cell = { ' ', 0, 0, 8, 8 }; + +#define grid_check_x(gd, px) do { \ + if ((px) >= (gd)->sx) \ + log_fatalx("x out of range: %u", px); \ +} while (0) + +#define grid_check_y(gd, py) do { \ + if ((py) >= (gd)->hsize + (gd)->sy) \ + log_fatalx("y out of range: %u", py); \ +} while (0) + +#define grid_put_cell(gd, px, py, gc) do { \ + memcpy(&gd->data[py][px], gc, sizeof gd->data[py][px]); \ +} while (0) + +/* Create a new grid. */ +struct grid_data * +grid_create(u_int sx, u_int sy, u_int hlimit) +{ + struct grid_data *gd; + + gd = xmalloc(sizeof *gd); + gd->sx = sx; + gd->sy = sy; + + gd->hsize = 0; + gd->hlimit = hlimit; + + gd->size = xcalloc(gd->sy, sizeof *gd->size); + gd->data = xcalloc(gd->sy, sizeof *gd->data); + + return (gd); +} + +/* Destroy grid. */ +void +grid_destroy(struct grid_data *gd) +{ + u_int yy; + + for (yy = 0; yy < gd->hsize + gd->sy - 1; yy++) { + if (gd->data[yy] != NULL) + xfree(gd->data[yy]); + } + + if (gd->data != NULL) + xfree(gd->data); + if (gd->size != NULL) + xfree(gd->size); + xfree(gd); +} + +/* Scroll a line into the history. */ +void +grid_scroll_line(struct grid_data *gd) +{ + u_int yy; + + GRID_DEBUG(gd, ""); + + if (gd->hsize >= gd->hlimit - 1) { + /* If the limit is hit, free the bottom 10% and shift up. */ + yy = gd->hlimit / 10; + if (yy < 1) + yy = 1; + + grid_move_lines(gd, 0, yy, gd->hsize + gd->sy - yy); + gd->hsize -= yy; + } + + yy = gd->hsize + gd->sy; + gd->size = xrealloc(gd->size, yy + 1, sizeof *gd->size); + gd->data = xrealloc(gd->data, yy + 1, sizeof *gd->data); + + gd->data[yy] = NULL; + gd->size[yy] = 0; + + gd->hsize++; +} + +/* Reduce line to fit to cell. */ +void +grid_reduce_line(struct grid_data *gd, u_int py, u_int sx) +{ + if (sx >= gd->size[py]) + return; + + gd->data[py] = xrealloc(gd->data[py], sx, sizeof **gd->data); + gd->size[py] = sx; +} + +/* Expand line to fit to cell. */ +void +grid_expand_line(struct grid_data *gd, u_int py, u_int sx) +{ + u_int xx; + + if (sx <= gd->size[py]) + return; + + gd->data[py] = xrealloc(gd->data[py], sx, sizeof **gd->data); + for (xx = gd->size[py]; xx < sx; xx++) + grid_put_cell(gd, xx, py, &grid_default_cell); + gd->size[py] = sx; +} + +/* Get cell for reading. */ +const struct grid_cell * +grid_peek_cell(struct grid_data *gd, u_int px, u_int py) +{ + grid_check_x(gd, px); + grid_check_y(gd, py); + + if (px >= gd->size[py]) + return (&grid_default_cell); + return (&gd->data[py][px]); +} + +/* Get cell at relative position (for writing). */ +struct grid_cell * +grid_get_cell(struct grid_data *gd, u_int px, u_int py) +{ + grid_check_x(gd, px); + grid_check_y(gd, py); + + grid_expand_line(gd, py, px + 1); + return (&gd->data[py][px]); +} + +/* Set cell at relative position. */ +void +grid_set_cell( + struct grid_data *gd, u_int px, u_int py, const struct grid_cell *gc) +{ + grid_check_x(gd, px); + grid_check_y(gd, py); + + grid_expand_line(gd, py, px + 1); + grid_put_cell(gd, px, py, gc); +} + +/* + * Clear area. Note this is different from a fill as it just omits unallocated + * cells. + */ +void +grid_clear(struct grid_data *gd, u_int px, u_int py, u_int nx, u_int ny) +{ + u_int xx, yy; + + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u, ny=%u", px, py, nx, ny); + + if (nx == 0 || ny == 0) + return; + + if (px == 0 && nx == gd->sx) { + grid_clear_lines(gd, py, ny); + return; + } + + grid_check_x(gd, px); + grid_check_x(gd, px + nx - 1); + grid_check_y(gd, py); + grid_check_y(gd, py + ny - 1); + + for (yy = py; yy < py + ny; yy++) { + for (xx = px; xx < px + nx; xx++) { + if (xx >= gd->size[yy]) + break; + grid_put_cell(gd, xx, yy, &grid_default_cell); + } + } +} + +/* Fill area. */ +void +grid_fill(struct grid_data *gd, + const struct grid_cell *gc, u_int px, u_int py, u_int nx, u_int ny) +{ + u_int xx, yy; + + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u, ny=%u", px, py, nx, ny); + + if (nx == 0 || ny == 0) + return; + + grid_check_x(gd, px); + grid_check_x(gd, px + nx - 1); + grid_check_y(gd, py); + grid_check_y(gd, py + ny - 1); + + for (yy = py; yy < py + ny; yy++) { + for (xx = px; xx < px + nx; xx++) { + grid_expand_line(gd, yy, xx + 1); + grid_put_cell(gd, xx, py, gc); + } + } +} + +/* Clear lines. This just frees and truncates the lines. */ +void +grid_clear_lines(struct grid_data *gd, u_int py, u_int ny) +{ + u_int yy; + + GRID_DEBUG(gd, "py=%u, ny=%u", py, ny); + + if (ny == 0) + return; + + grid_check_y(gd, py); + grid_check_y(gd, py + ny - 1); + + for (yy = py; yy < py + ny; yy++) { + if (gd->data[yy] != NULL) { + xfree(gd->data[yy]); + gd->data[yy] = NULL; + gd->size[yy] = 0; + } + } +} + +/* Fill a group of lines. */ +void +grid_fill_lines( + struct grid_data *gd, const struct grid_cell *gc, u_int py, u_int ny) +{ + grid_fill(gd, gc, 0, py, gd->sx, ny); +} + +/* Move a group of lines. */ +void +grid_move_lines(struct grid_data *gd, u_int dy, u_int py, u_int ny) +{ + u_int yy; + + GRID_DEBUG(gd, "dy=%u, py=%u, ny=%u", dy, py, ny); + + if (ny == 0 || py == dy) + return; + + grid_check_y(gd, py); + grid_check_y(gd, py + ny - 1); + grid_check_y(gd, dy); + grid_check_y(gd, dy + ny - 1); + + /* Free any lines which are being replaced. */ + for (yy = dy; yy < dy + ny; yy++) { + if (yy >= py && yy < py + ny) + continue; + grid_clear_lines(gd, yy, 1); + } + + memmove(&gd->data[dy], &gd->data[py], ny * (sizeof *gd->data)); + memmove(&gd->size[dy], &gd->size[py], ny * (sizeof *gd->size)); + + /* Wipe any lines that have been moved (without freeing them). */ + for (yy = py; yy < py + ny; yy++) { + if (yy >= dy && yy < dy + ny) + continue; + gd->data[yy] = NULL; + gd->size[yy] = 0; + } +} + +/* Clear a group of cells. */ +void +grid_clear_cells(struct grid_data *gd, u_int px, u_int py, u_int nx) +{ + u_int xx; + + GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); + + if (nx == 0) + return; + + grid_check_x(gd, px); + grid_check_x(gd, px + nx - 1); + grid_check_y(gd, py); + + for (xx = px; xx < px + nx; xx++) { + if (xx >= gd->size[py]) + break; + grid_put_cell(gd, xx, py, &grid_default_cell); + } +} + +/* Move a group of cells. */ +void +grid_move_cells(struct grid_data *gd, u_int dx, u_int px, u_int py, u_int nx) +{ + u_int xx; + + GRID_DEBUG(gd, "dx=%u, px=%u, py=%u, nx=%u", dx, px, py, nx); + + if (nx == 0 || px == dx) + return; + + grid_check_x(gd, px); + grid_check_x(gd, px + nx - 1); + grid_check_y(gd, py); + + grid_expand_line(gd, py ,px + nx); + grid_expand_line(gd, py, dx + nx); + memmove(&gd->data[py][dx], &gd->data[py][px], nx * (sizeof **gd->data)); + + /* Wipe any cells that have been moved. */ + for (xx = px; xx < px + nx; xx++) { + if (xx >= dx && xx < dx + nx) + continue; + memcpy( + &gd->data[py][xx], &grid_default_cell, sizeof **gd->data); + } +} + diff --git a/input.c b/input.c index a15f60cb..ada32df1 100644 --- a/input.c +++ b/input.c @@ -1,4 +1,4 @@ -/* $Id: input.c,v 1.58 2008-09-09 22:16:36 nicm Exp $ */ +/* $Id: input.c,v 1.59 2008-09-25 20:08:52 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -186,12 +186,20 @@ input_state(struct input_ctx *ictx, void *state) void input_init(struct window *w) { - ARRAY_INIT(&w->ictx.args); + struct input_ctx *ictx = &w->ictx; - w->ictx.string_len = 0; - w->ictx.string_buf = NULL; + ARRAY_INIT(&ictx->args); - input_state(&w->ictx, input_state_first); + ictx->string_len = 0; + ictx->string_buf = NULL; + + memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); + + memcpy(&ictx->saved_cell, &grid_default_cell, sizeof ictx->saved_cell); + ictx->saved_cx = 0; + ictx->saved_cy = 0; + + input_state(ictx, input_state_first); } void @@ -341,10 +349,9 @@ void input_state_title_next(u_char ch, struct input_ctx *ictx) { if (ch == '\007') { - if (ictx->string_type == STRING_TITLE) { - screen_write_set_title( - &ictx->ctx, input_get_string(ictx)); - } else + if (ictx->string_type == STRING_TITLE) + screen_set_title(ictx->ctx.s, input_get_string(ictx)); + else input_abort_string(ictx); input_state(ictx, input_state_first); return; @@ -490,59 +497,67 @@ input_state_string_escape(u_char ch, struct input_ctx *ictx) void input_state_utf8(u_char ch, struct input_ctx *ictx) { + u_int value; + log_debug2("-- un %zu: %hhu (%c)", ictx->off, ch, ch); - ictx->utf8_buf.data[ictx->utf8_off++] = ch; + ictx->utf8_buf[ictx->utf8_off++] = ch; if (--ictx->utf8_len != 0) return; input_state(ictx, input_state_first); - screen_write_put_utf8(&ictx->ctx, &ictx->utf8_buf); + value = utf8_combine(ictx->utf8_buf); + if (value > 0xffff) /* non-BMP not supported */ + value = '_'; + + ictx->cell.data = value; + screen_write_cell(&ictx->ctx, &ictx->cell); } void input_handle_character(u_char ch, struct input_ctx *ictx) { - log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch); - if (ch > 0x7f) { /* - * UTF8 sequence. + * UTF-8 sequence. * * 11000010-11011111 C2-DF start of 2-byte sequence * 11100000-11101111 E0-EF start of 3-byte sequence * 11110000-11110100 F0-F4 start of 4-byte sequence */ - memset(&ictx->utf8_buf.data, 0xff, sizeof &ictx->utf8_buf.data); - ictx->utf8_buf.data[0] = ch; + memset(ictx->utf8_buf, 0xff, sizeof ictx->utf8_buf); + ictx->utf8_buf[0] = ch; ictx->utf8_off = 1; if (ch >= 0xc2 && ch <= 0xdf) { - log_debug2(":: u2"); + log_debug2("-- u2 %zu: %hhu (%c)", ictx->off, ch, ch); input_state(ictx, input_state_utf8); ictx->utf8_len = 1; + return; } if (ch >= 0xe0 && ch <= 0xef) { - log_debug2(":: u3"); + log_debug2("-- u3 %zu: %hhu (%c)", ictx->off, ch, ch); input_state(ictx, input_state_utf8); ictx->utf8_len = 2; + return; } if (ch >= 0xf0 && ch <= 0xf4) { - log_debug2(":: u4"); + log_debug2("-- u4 %zu: %hhu (%c)", ictx->off, ch, ch); input_state(ictx, input_state_utf8); ictx->utf8_len = 3; + return; } - return; } + log_debug2("-- ch %zu: %hhu (%c)", ictx->off, ch, ch); - screen_write_put_character(&ictx->ctx, ch); + ictx->cell.data = ch; + screen_write_cell(&ictx->ctx, &ictx->cell); } void input_handle_c0_control(u_char ch, struct input_ctx *ictx) { struct screen *s = ictx->ctx.s; - u_short attr; log_debug2("-- c0 %zu: %hhu", ictx->off, ch); @@ -550,32 +565,31 @@ input_handle_c0_control(u_char ch, struct input_ctx *ictx) case '\0': /* NUL */ break; case '\n': /* LF */ - screen_write_cursor_down_scroll(&ictx->ctx); + screen_write_linefeed(&ictx->ctx); break; case '\r': /* CR */ - screen_write_move_cursor(&ictx->ctx, 0, s->cy); + screen_write_carriagereturn(&ictx->ctx); break; case '\007': /* BELL */ ictx->w->flags |= WINDOW_BELL; break; case '\010': /* BS */ - screen_write_cursor_left(&ictx->ctx, 1); + screen_write_cursorleft(&ictx->ctx, 1); break; case '\011': /* TAB */ + /* XXX right? */ s->cx = ((s->cx / 8) * 8) + 8; - if (s->cx > screen_last_x(s)) { + if (s->cx > screen_size_x(s) - 1) { s->cx = 0; - screen_write_cursor_down(&ictx->ctx, 1); + screen_write_cursordown(&ictx->ctx, 1); } - screen_write_move_cursor(&ictx->ctx, s->cx, s->cy); + screen_write_cursormove(&ictx->ctx, s->cx, s->cy); break; case '\016': /* SO */ - attr = s->attr | ATTR_CHARSET; - screen_write_set_attributes(&ictx->ctx, attr, s->fg, s->bg); + ictx->cell.attr |= GRID_ATTR_CHARSET; break; case '\017': /* SI */ - attr = s->attr & ~ATTR_CHARSET; - screen_write_set_attributes(&ictx->ctx, attr, s->fg, s->bg); + ictx->cell.attr &= ~GRID_ATTR_CHARSET; break; default: log_debug("unknown c0: %hhu", ch); @@ -590,7 +604,7 @@ input_handle_c1_control(u_char ch, struct input_ctx *ictx) switch (ch) { case 'M': /* RI */ - screen_write_cursor_up_scroll(&ictx->ctx); + screen_write_reverseindex(&ictx->ctx); break; default: log_debug("unknown c1: %hhu", ch); @@ -607,27 +621,22 @@ input_handle_private_two(u_char ch, struct input_ctx *ictx) switch (ch) { case '=': /* DECKPAM */ - screen_write_set_mode(&ictx->ctx, MODE_KKEYPAD); + screen_write_kkeypadmode(&ictx->ctx, 1); log_debug("kkeypad on (application mode)"); break; case '>': /* DECKPNM */ - screen_write_clear_mode(&ictx->ctx, MODE_KKEYPAD); + screen_write_kkeypadmode(&ictx->ctx, 0); log_debug("kkeypad off (number mode)"); break; case '7': /* DECSC */ - s->saved_cx = s->cx; - s->saved_cy = s->cy; - s->saved_attr = s->attr; - s->saved_fg = s->fg; - s->saved_bg = s->bg; - s->mode |= MODE_SAVED; + memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell); + ictx->saved_cx = s->cx; + ictx->saved_cy = s->cy; break; case '8': /* DECRC */ - if (!(s->mode & MODE_SAVED)) - break; - screen_write_set_attributes( - &ictx->ctx, s->saved_attr, s->saved_fg, s->saved_bg); - screen_write_move_cursor(&ictx->ctx, s->saved_cx, s->saved_cy); + memcpy(&ictx->cell, &ictx->saved_cell, sizeof ictx->cell); + screen_write_cursormove( + &ictx->ctx, ictx->saved_cx, ictx->saved_cy); break; default: log_debug("unknown p2: %hhu", ch); @@ -641,6 +650,21 @@ input_handle_standard_two(u_char ch, struct input_ctx *ictx) log_debug2("-- s2 %zu: %hhu (%c)", ictx->off, ch, ch); switch (ch) { + case 'c': /* RIS */ + memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell); + + memcpy(&ictx->saved_cell, &ictx->cell, sizeof ictx->saved_cell); + ictx->saved_cx = 0; + ictx->saved_cy = 0; + + screen_write_insertmode(&ictx->ctx, 0); + screen_write_kcursormode(&ictx->ctx, 0); + screen_write_kkeypadmode(&ictx->ctx, 0); + screen_write_mousemode(&ictx->ctx, 0); + + screen_write_clearscreen(&ictx->ctx); + screen_write_cursormove(&ictx->ctx, 0, 0); + break; case 'k': input_start_string(ictx, STRING_NAME); input_state(ictx, input_state_string_next); @@ -718,7 +742,7 @@ input_handle_sequence_cuu(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_cursor_up(&ictx->ctx, n); + screen_write_cursorup(&ictx->ctx, n); } void @@ -736,7 +760,7 @@ input_handle_sequence_cud(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_cursor_down(&ictx->ctx, n); + screen_write_cursordown(&ictx->ctx, n); } void @@ -754,7 +778,7 @@ input_handle_sequence_cuf(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_cursor_right(&ictx->ctx, n); + screen_write_cursorright(&ictx->ctx, n); } void @@ -772,7 +796,7 @@ input_handle_sequence_cub(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_cursor_left(&ictx->ctx, n); + screen_write_cursorleft(&ictx->ctx, n); } void @@ -790,7 +814,7 @@ input_handle_sequence_dch(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_delete_characters(&ictx->ctx, n); + screen_write_deletecharacter(&ictx->ctx, n); } void @@ -808,7 +832,7 @@ input_handle_sequence_dl(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_delete_lines(&ictx->ctx, n); + screen_write_deleteline(&ictx->ctx, n); } void @@ -826,7 +850,7 @@ input_handle_sequence_ich(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_insert_characters(&ictx->ctx, n); + screen_write_insertcharacter(&ictx->ctx, n); } void @@ -844,7 +868,7 @@ input_handle_sequence_il(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_insert_lines(&ictx->ctx, n); + screen_write_insertline(&ictx->ctx, n); } void @@ -863,7 +887,7 @@ input_handle_sequence_vpa(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_move_cursor(&ictx->ctx, s->cx, n - 1); + screen_write_cursormove(&ictx->ctx, s->cx, n - 1); } void @@ -882,7 +906,7 @@ input_handle_sequence_hpa(struct input_ctx *ictx) if (n == 0) n = 1; - screen_write_move_cursor(&ictx->ctx, n - 1, s->cy); + screen_write_cursormove(&ictx->ctx, n - 1, s->cy); } void @@ -904,7 +928,7 @@ input_handle_sequence_cup(struct input_ctx *ictx) if (m == 0) m = 1; - screen_write_move_cursor(&ictx->ctx, m - 1, n - 1); + screen_write_cursormove(&ictx->ctx, m - 1, n - 1); } void @@ -924,10 +948,13 @@ input_handle_sequence_ed(struct input_ctx *ictx) switch (n) { case 0: - screen_write_fill_end_of_screen(&ictx->ctx); + screen_write_clearendofscreen(&ictx->ctx); + break; + case 1: + screen_write_clearstartofscreen(&ictx->ctx); break; case 2: - screen_write_fill_screen(&ictx->ctx); + screen_write_clearscreen(&ictx->ctx); break; } } @@ -949,13 +976,13 @@ input_handle_sequence_el(struct input_ctx *ictx) switch (n) { case 0: - screen_write_fill_end_of_line(&ictx->ctx); + screen_write_clearendofline(&ictx->ctx); break; case 1: - screen_write_fill_start_of_line(&ictx->ctx); + screen_write_clearstartofline(&ictx->ctx); break; case 2: - screen_write_fill_line(&ictx->ctx); + screen_write_clearline(&ictx->ctx); break; } } @@ -973,15 +1000,15 @@ input_handle_sequence_sm(struct input_ctx *ictx) if (ictx->private == '?') { switch (n) { case 1: /* GATM */ - screen_write_set_mode(&ictx->ctx, MODE_KCURSOR); + screen_write_kcursormode(&ictx->ctx, 1); log_debug("kcursor on"); break; case 25: /* TCEM */ - screen_write_set_mode(&ictx->ctx, MODE_CURSOR); + screen_write_cursormode(&ictx->ctx, 1); log_debug("cursor on"); break; case 1000: - screen_write_set_mode(&ictx->ctx, MODE_MOUSE); + screen_write_mousemode(&ictx->ctx, 1); log_debug("mouse on"); break; default: @@ -991,7 +1018,7 @@ input_handle_sequence_sm(struct input_ctx *ictx) } else { switch (n) { case 4: /* IRM */ - screen_write_set_mode(&ictx->ctx, MODE_INSERT); + screen_write_insertmode(&ictx->ctx, 1); log_debug("insert on"); break; case 34: @@ -1017,15 +1044,15 @@ input_handle_sequence_rm(struct input_ctx *ictx) if (ictx->private == '?') { switch (n) { case 1: /* GATM */ - screen_write_clear_mode(&ictx->ctx, MODE_KCURSOR); + screen_write_kcursormode(&ictx->ctx, 0); log_debug("kcursor off"); break; case 25: /* TCEM */ - screen_write_clear_mode(&ictx->ctx, MODE_CURSOR); + screen_write_cursormode(&ictx->ctx, 0); log_debug("cursor off"); break; case 1000: - screen_write_clear_mode(&ictx->ctx, MODE_MOUSE); + screen_write_mousemode(&ictx->ctx, 0); log_debug("mouse off"); break; default: @@ -1035,7 +1062,7 @@ input_handle_sequence_rm(struct input_ctx *ictx) } else if (ictx->private == '\0') { switch (n) { case 4: /* IRM */ - screen_write_clear_mode(&ictx->ctx, MODE_INSERT); + screen_write_insertmode(&ictx->ctx, 0); log_debug("insert off"); break; case 34: @@ -1093,118 +1120,107 @@ input_handle_sequence_decstbm(struct input_ctx *ictx) if (m == 0) m = screen_size_y(s); - screen_write_set_region(&ictx->ctx, n - 1, m - 1); + screen_write_scrollregion(&ictx->ctx, n - 1, m - 1); } void input_handle_sequence_sgr(struct input_ctx *ictx) { - struct screen *s = ictx->ctx.s; - u_int i, n; - uint16_t m, o; - u_short attr; - u_char fg, bg; + struct grid_cell *gc = &ictx->cell; + u_int i; + uint16_t m, o; - attr = s->attr; - fg = s->fg; - bg = s->bg; + if (ARRAY_LENGTH(&ictx->args) == 0) { + memcpy(gc, &grid_default_cell, sizeof *gc); + return; + } - n = ARRAY_LENGTH(&ictx->args); - if (n == 0) { - attr = 0; - fg = 8; - bg = 8; - } else { - for (i = 0; i < n; i++) { - if (input_get_argument(ictx, i, &m, 0) != 0) + for (i = 0; i < ARRAY_LENGTH(&ictx->args); i++) { + if (input_get_argument(ictx, i, &m, 0) != 0) + return; + + if (m == 38 || m == 48) { + i++; + if (input_get_argument(ictx, i, &o, 0) != 0) return; - - if (m == 38 || m == 48) { - i++; - if (input_get_argument(ictx, i, &o, 0) != 0) - return; - if (o != 5) - continue; - - i++; - if (input_get_argument(ictx, i, &o, 0) != 0) - return; - if (m == 38) { - attr |= ATTR_FG256; - fg = o; - } else if (m == 48) { - attr |= ATTR_BG256; - bg = o; - } + if (o != 5) continue; + + i++; + if (input_get_argument(ictx, i, &o, 0) != 0) + return; + if (m == 38) { + gc->flags |= GRID_FLAG_FG256; + gc->fg = o; + } else if (m == 48) { + gc->flags |= GRID_FLAG_BG256; + gc->bg = o; } + continue; + } - switch (m) { - case 0: - case 10: - attr &= ATTR_CHARSET; - fg = 8; - bg = 8; - break; - case 1: - attr |= ATTR_BRIGHT; - break; - case 2: - attr |= ATTR_DIM; - break; - case 3: - attr |= ATTR_ITALICS; - break; - case 4: - attr |= ATTR_UNDERSCORE; - break; - case 5: - attr |= ATTR_BLINK; - break; - case 7: - attr |= ATTR_REVERSE; - break; - case 8: - attr |= ATTR_HIDDEN; - break; - case 23: - attr &= ~ATTR_ITALICS; - break; - case 24: - attr &= ~ATTR_UNDERSCORE; - break; - case 30: - case 31: - case 32: - case 33: - case 34: - case 35: - case 36: - case 37: - attr &= ~ATTR_FG256; - fg = m - 30; - break; - case 39: - attr &= ~ATTR_FG256; - fg = 8; - break; - case 40: - case 41: - case 42: - case 43: - case 44: - case 45: - case 46: - case 47: - attr &= ~ATTR_BG256; - bg = m - 40; - break; - case 49: - attr &= ~ATTR_BG256; - bg = 8; - break; - } + switch (m) { + case 0: + case 10: + memcpy(gc, &grid_default_cell, sizeof *gc); + break; + case 1: + gc->attr |= GRID_ATTR_BRIGHT; + break; + case 2: + gc->attr |= GRID_ATTR_DIM; + break; + case 3: + gc->attr |= GRID_ATTR_ITALICS; + break; + case 4: + gc->attr |= GRID_ATTR_UNDERSCORE; + break; + case 5: + gc->attr |= GRID_ATTR_BLINK; + break; + case 7: + gc->attr |= GRID_ATTR_REVERSE; + break; + case 8: + gc->attr |= GRID_ATTR_HIDDEN; + break; + case 23: + gc->attr &= ~GRID_ATTR_ITALICS; + break; + case 24: + gc->attr &= ~GRID_ATTR_UNDERSCORE; + break; + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + gc->flags &= ~GRID_FLAG_FG256; + gc->fg = m - 30; + break; + case 39: + gc->flags &= ~GRID_FLAG_FG256; + gc->fg = 8; + break; + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + gc->flags &= ~GRID_FLAG_BG256; + gc->bg = m - 40; + break; + case 49: + gc->flags &= ~GRID_FLAG_BG256; + gc->bg = 8; + break; } } - screen_write_set_attributes(&ictx->ctx, attr, fg, bg); } diff --git a/log.c b/log.c index ac23e301..f81c2bb4 100644 --- a/log.c +++ b/log.c @@ -1,4 +1,4 @@ -/* $Id: log.c,v 1.5 2008-08-08 17:35:42 nicm Exp $ */ +/* $Id: log.c,v 1.6 2008-09-25 20:08:52 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -224,6 +224,9 @@ log_vfatal(const char *msg, va_list ap) } free(fmt); +#ifdef DEBUG + abort(); +#endif exit(1); } diff --git a/screen-display.c b/screen-display.c deleted file mode 100644 index 4760d8ee..00000000 --- a/screen-display.c +++ /dev/null @@ -1,477 +0,0 @@ -/* $Id: screen-display.c,v 1.21 2008-09-09 22:16:36 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" - -/* Get a cell. */ -void -screen_display_get_cell(struct screen *s, - u_int px, u_int py, u_char *data, u_short *attr, u_char *fg, u_char *bg) -{ - screen_get_cell( - s, screen_x(s, px), screen_y(s, py), data, attr, fg, bg); -} - -/* Set a cell. */ -void -screen_display_set_cell(struct screen *s, - u_int px, u_int py, u_char data, u_short attr, u_char fg, u_char bg) -{ - screen_set_cell( - s, screen_x(s, px), screen_y(s, py), data, attr, fg, bg); -} - -/* Create a region of lines. */ -void -screen_display_make_lines(struct screen *s, u_int py, u_int ny) -{ - if (ny == 0 || !screen_in_y(s, py) || !screen_in_y(s, py + ny - 1)) { - SCREEN_DEBUG2(s, py, ny); - return; - } - screen_make_lines(s, screen_y(s, py), ny); - if (s->attr != 0 || s->fg != 8 || s->bg != 8) { - screen_display_fill_area( - s, 0, py, screen_size_x(s), ny, ' ', s->attr, s->fg, s->bg); - } -} - -/* Free a region of lines. */ -void -screen_display_free_lines(struct screen *s, u_int py, u_int ny) -{ - if (ny == 0 || !screen_in_y(s, py) || !screen_in_y(s, py + ny - 1)) { - SCREEN_DEBUG2(s, py, ny); - return; - } - screen_free_lines(s, screen_y(s, py), ny); -} - -/* Move a set of lines. */ -void -screen_display_move_lines(struct screen *s, u_int dy, u_int py, u_int ny) -{ - if (ny == 0 || !screen_in_y(s, py) || !screen_in_y(s, py + ny - 1)) { - SCREEN_DEBUG3(s, dy, py, ny); - return; - } - if (!screen_in_y(s, dy) || !screen_in_y(s, dy + ny - 1) || dy == py) { - SCREEN_DEBUG3(s, dy, py, ny); - return; - } - screen_move_lines(s, screen_y(s, dy), screen_y(s, py), ny); -} - -/* Fill a set of cells. */ -void -screen_display_fill_area(struct screen *s, u_int px, u_int py, - u_int nx, u_int ny, u_char data, u_short attr, u_char fg, u_char bg) -{ - if (nx == 0 || ny == 0) { - SCREEN_DEBUG4(s, px, py, nx, ny); - return; - } - if (!screen_in_x(s, px) || !screen_in_y(s, py)) { - SCREEN_DEBUG4(s, px, py, nx, ny); - return; - } - if (!screen_in_x(s, px + nx - 1) || !screen_in_y(s, py + ny - 1)) { - SCREEN_DEBUG4(s, px, py, nx, ny); - return; - } - screen_fill_area( - s, screen_x(s, px), screen_y(s, py), nx, ny, data, attr, fg, bg); -} - -/* Scroll region up. */ -void -screen_display_scroll_region_up(struct screen *s) -{ - u_int ny, sy; - - /* - * If the region is the entire screen, this is easy-peasy. Allocate - * a new line and adjust the history size. - * XXX should this be done somewhere else? - */ - if (s->rupper == 0 && s->rlower == screen_last_y(s)) { - if (s->hsize == s->hlimit) { - /* If the limit is hit, free 10% and shift up. */ - ny = s->hlimit / 10; - if (ny < 1) - ny = 1; - - sy = screen_size_y(s) + s->hsize; - screen_free_lines(s, 0, ny); - screen_move_lines(s, 0, ny, sy - ny); - - s->hsize -= ny; - } - s->hsize++; - - sy = screen_size_y(s) + s->hsize; - s->grid_data = xrealloc(s->grid_data, sy, sizeof *s->grid_data); - s->grid_attr = xrealloc(s->grid_attr, sy, sizeof *s->grid_attr); - s->grid_fg = xrealloc(s->grid_fg, sy, sizeof *s->grid_fg); - s->grid_bg = xrealloc(s->grid_bg, sy, sizeof *s->grid_fg); - s->grid_size = xrealloc(s->grid_size, sy, sizeof *s->grid_size); - screen_display_make_lines(s, screen_last_y(s), 1); - return; - } - - /* - * Scroll scrolling region up: - * - delete rupper - * - move rupper + 1 to rlower to rupper - * - make new line at rlower - * - * Example: region is 12 to 24. - * rlower = 24, rupper = 12 - * screen_free_lines(s, 12, 1); - * screen_move_lines(s, 12, 13, 12); - * screen_make_lines(s, 24, 1); - */ - - screen_display_free_lines(s, s->rupper, 1); - - if (s->rupper != s->rlower) { - screen_display_move_lines(s, - s->rupper, s->rupper + 1, s->rlower - s->rupper); - } - - screen_display_make_lines(s, s->rlower, 1); -} - -/* Scroll region down. */ -void -screen_display_scroll_region_down(struct screen *s) -{ - /* - * Scroll scrolling region down: - * - delete rlower - * - move rupper to rlower - 1 to rupper + 1 - * - make new line at rupper - * - * Example: region is 12 to 24. - * rlower = 24, rupper = 12 - * screen_free_lines(s, 24, 1); - * screen_move_lines(s, 13, 12, 12); - * screen_make_lines(s, 12, 1); - */ - - screen_display_free_lines(s, s->rlower, 1); - - if (s->rupper != s->rlower) { - screen_display_move_lines(s, - s->rupper + 1, s->rupper, s->rlower - s->rupper); - } - - screen_display_make_lines(s, s->rupper, 1); -} - -/* Insert lines. */ -void -screen_display_insert_lines(struct screen *s, u_int py, u_int ny) -{ - if (!screen_in_y(s, py)) { - SCREEN_DEBUG2(s, py, ny); - return; - } - if (ny == 0) { - SCREEN_DEBUG2(s, py, ny); - return; - } - - if (py + ny > screen_last_y(s)) - ny = screen_size_y(s) - py; - if (ny == 0) { - SCREEN_DEBUG2(s, py, ny); - return; - } - - /* - * Insert range of ny lines at py: - * - Free ny lines from end of screen. - * - Move from py to end of screen - ny to py + ny. - * - Create ny lines at py. - * - * Example: insert 2 lines at 4. - * sy = 10, py = 4, ny = 2 - * screen_free_lines(s, 8, 2); - delete lines 8,9 - * screen_move_lines(s, 6, 4, 4); - move 4,5,6,7 to 6,7,8,9 - * screen_make_lines(s, 4, 2); - make lines 4,5 - */ - - screen_display_free_lines(s, screen_size_y(s) - ny, ny); - - if (py + ny != screen_size_y(s)) { - screen_display_move_lines( - s, py + ny, py, screen_size_y(s) - py - ny); - } - - screen_display_make_lines(s, py, ny); -} - -/* Insert lines in region. */ -void -screen_display_insert_lines_region(struct screen *s, u_int py, u_int ny) -{ - if (!screen_in_region(s, py)) { - SCREEN_DEBUG2(s, py, ny); - return; - } - if (ny == 0) { - SCREEN_DEBUG2(s, py, ny); - return; - } - - if (py + ny > s->rlower) - ny = (s->rlower + 1) - py; - if (ny == 0) { - SCREEN_DEBUG2(s, py, ny); - return; - } - - /* - * Insert range of ny lines at py: - * - Free ny lines from end of screen. - * - Move from py to end of screen - ny to py + ny. - * - Create ny lines at py. - * - * Example: insert 2 lines at 4. - * ryu = 11, ryl = 16, py = 13, ny = 2 - * screen_free_lines(s, 15, 2); - delete lines 15,16 - * screen_move_lines(s, 13, 15, 2);- move 13,14 to 15,16 - * screen_make_lines(s, 13, 2); - make lines 13,14 - */ - - screen_display_free_lines(s, (s->rlower + 1) - ny, ny); - - if (py + ny != s->rlower + 1) { - screen_display_move_lines( - s, py + ny, py, (s->rlower + 1) - py - ny); - } - - screen_display_make_lines(s, py, ny); -} - -/* Delete lines. */ -void -screen_display_delete_lines(struct screen *s, u_int py, u_int ny) -{ - if (!screen_in_y(s, py)) { - SCREEN_DEBUG2(s, py, ny); - return; - } - if (ny == 0) { - SCREEN_DEBUG2(s, py, ny); - return; - } - - if (py + ny > screen_last_y(s)) - ny = screen_size_y(s) - py; - if (ny == 0) { - SCREEN_DEBUG2(s, py, ny); - return; - } - - /* - * Delete range of ny lines at py: - * - Free ny lines at py. - * - Move from py + ny to end of screen to py. - * - Free and recreate last ny lines. - * - * Example: delete lines 3,4. - * sy = 10, py = 3, ny = 2 - * screen_free_lines(s, 3, 2); - delete lines 3,4 - * screen_move_lines(s, 3, 5, 5); - move 5,6,7,8,9 to 3 - * screen_make_lines(s, 8, 2); - make lines 8,9 - */ - - screen_display_free_lines(s, py, ny); - - if (py + ny != screen_size_y(s)) { - screen_display_move_lines( - s, py, py + ny, screen_size_y(s) - py - ny); - } - - screen_display_make_lines(s, screen_size_y(s) - ny, ny); -} - -/* Delete lines inside scroll region. */ -void -screen_display_delete_lines_region(struct screen *s, u_int py, u_int ny) -{ - if (!screen_in_region(s, py)) { - SCREEN_DEBUG2(s, py, ny); - return; - } - if (ny == 0) { - SCREEN_DEBUG2(s, py, ny); - return; - } - - if (py + ny > s->rlower) - ny = (s->rlower + 1) - py; - if (ny == 0) - return; - - /* - * Delete range of ny lines at py: - * - Free ny lines at py. - * - Move from py + ny to end of region to py. - * - Free and recreate last ny lines. - * - * Example: delete lines 13,14. - * ryu = 11, ryl = 16, py = 13, ny = 2 - * screen_free_lines(s, 13, 2); - delete lines 13,14 - * screen_move_lines(s, 15, 16, 2);- move 15,16 to 13 - * screen_make_lines(s, 15, 16); - make lines 15,16 - */ - - screen_display_free_lines(s, py, ny); - - if (py + ny != s->rlower + 1) { - screen_display_move_lines( - s, py, py + ny, (s->rlower + 1) - py - ny); - } - - screen_display_make_lines(s, (s->rlower + 1) - ny, ny); -} - -/* Insert characters. */ -void -screen_display_insert_characters(struct screen *s, u_int px, u_int py, u_int nx) -{ - u_int mx; - - if (!screen_in_x(s, px) || !screen_in_y(s, py)) { - SCREEN_DEBUG3(s, px, py, nx); - return; - } - - if (px + nx > screen_last_x(s)) - nx = screen_last_x(s) - px; - - py = screen_y(s, py); - - /* XXX Cheat and make the line a full line. */ - if (s->grid_size[py] < screen_size_x(s)) - screen_expand_line(s, py, screen_size_x(s)); - - /* - * Inserting a range of nx at px. - * - * - Move sx - (px + nx) from px to px + nx. - * - Clear the range at px to px + nx. - */ - - if (px + nx != screen_last_x(s)) { - mx = screen_last_x(s) - (px + nx); - memmove(&s->grid_data[py][px + nx], - &s->grid_data[py][px], mx * sizeof **s->grid_data); - memmove(&s->grid_attr[py][px + nx], - &s->grid_attr[py][px], mx * sizeof **s->grid_attr); - memmove(&s->grid_fg[py][px + nx], - &s->grid_fg[py][px], mx * sizeof **s->grid_fg); - memmove(&s->grid_bg[py][px + nx], - &s->grid_bg[py][px], mx * sizeof **s->grid_bg); - } - - memset(&s->grid_data[py][px], ' ', nx); - memset(&s->grid_attr[py][px], s->attr, nx); - memset(&s->grid_fg[py][px], s->fg, nx); - memset(&s->grid_bg[py][px], s->bg, nx); -} - -/* Delete characters. */ -void -screen_display_delete_characters(struct screen *s, u_int px, u_int py, u_int nx) -{ - u_int mx; - - if (!screen_in_x(s, px) || !screen_in_y(s, py)) { - SCREEN_DEBUG3(s, px, py, nx); - return; - } - - if (px + nx > screen_last_x(s)) - nx = screen_last_x(s) - px; - - py = screen_y(s, py); - - /* XXX Cheat and make the line a full line. */ - if (s->grid_size[py] < screen_size_x(s)) - screen_expand_line(s, py, screen_size_x(s)); - - /* - * Deleting the range from px to px + nx. - * - * - Move sx - (px + nx) from px + nx to px. - * - Clear the range from sx - nx to sx. - */ - - if (px + nx != screen_last_x(s)) { - mx = screen_last_x(s) - (px + nx); - memmove(&s->grid_data[py][px], &s->grid_data[py][px + nx], mx); - memmove(&s->grid_attr[py][px], &s->grid_attr[py][px + nx], mx); - memmove(&s->grid_fg[py][px], &s->grid_fg[py][px + nx], mx); - memmove(&s->grid_bg[py][px], &s->grid_bg[py][px + nx], mx); - } - - memset(&s->grid_data[py][screen_size_x(s) - nx], ' ', nx); - memset(&s->grid_attr[py][screen_size_x(s) - nx], s->attr, nx); - memset(&s->grid_fg[py][screen_size_x(s) - nx], s->fg, nx); - memset(&s->grid_bg[py][screen_size_x(s) - nx], s->bg, nx); -} - -/* Fill cells from another screen, with an offset. */ -void -screen_display_copy_area(struct screen *dst, struct screen *src, - u_int px, u_int py, u_int nx, u_int ny, u_int ox, u_int oy) -{ - u_int i, j; - u_short attr; - u_char data, fg, bg; - - if (nx == 0 || ny == 0) { - SCREEN_DEBUG4(dst, px, py, nx, ny); - return; - } - if (!screen_in_x(dst, px) || !screen_in_y(dst, py)) { - SCREEN_DEBUG4(dst, px, py, nx, ny); - return; - } - if (!screen_in_x(dst, px + nx - 1) || !screen_in_y(dst, py + ny - 1)) { - SCREEN_DEBUG4(dst, px, py, nx, ny); - return; - } - - for (i = py; i < py + ny; i++) { - for (j = px; j < px + nx; j++) { - screen_get_cell(src, - screen_x(src, j) + ox, screen_y(src, i) - oy, - &data, &attr, &fg, &bg); - screen_display_set_cell(dst, j, i, data, attr, fg, bg); - } - } -} diff --git a/screen-redraw.c b/screen-redraw.c index a66aee45..7542d14e 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -1,4 +1,4 @@ -/* $Id: screen-redraw.c,v 1.11 2008-09-08 22:03:54 nicm Exp $ */ +/* $Id: screen-redraw.c,v 1.12 2008-09-25 20:08:54 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -22,9 +22,6 @@ #include "tmux.h" -void screen_redraw_get_cell(struct screen_redraw_ctx *, - u_int, u_int, u_char *, u_short *, u_char *, u_char *); - /* Initialise redrawing with a window. */ void screen_redraw_start_window(struct screen_redraw_ctx *ctx, struct window *w) @@ -66,16 +63,15 @@ screen_redraw_start(struct screen_redraw_ctx *ctx, * Save screen cursor position. Emulation of some TTY_* commands * requires this to be correct in the screen, so rather than having * a local copy and just manipulating it, save the screen's values, - * modify them during redraw, and restore them when finished. + * modify them during redraw, and restore them when finished. XXX. */ ctx->saved_cx = s->cx; ctx->saved_cy = s->cy; - ctx->write(ctx->data, TTY_ATTRIBUTES, s->attr, s->fg, s->bg); - ctx->write(ctx->data, TTY_SCROLLREGION, 0, screen_last_y(s)); - ctx->write(ctx->data, TTY_CURSORMOVE, s->cy, s->cx); - ctx->write(ctx->data, TTY_CURSOROFF); - ctx->write(ctx->data, TTY_MOUSEOFF); + ctx->write(ctx->data, TTY_SCROLLREGION, 0, screen_size_y(s) - 1); + ctx->write(ctx->data, TTY_CURSORMOVE, s->cx, s->cy); + ctx->write(ctx->data, TTY_CURSORMODE, 0); + ctx->write(ctx->data, TTY_MOUSEMODE, 0); } /* Finish redrawing. */ @@ -87,62 +83,38 @@ screen_redraw_stop(struct screen_redraw_ctx *ctx) s->cx = ctx->saved_cx; s->cy = ctx->saved_cy; - ctx->write(ctx->data, TTY_ATTRIBUTES, s->attr, s->fg, s->bg); ctx->write(ctx->data, TTY_SCROLLREGION, s->rupper, s->rlower); - ctx->write(ctx->data, TTY_CURSORMOVE, s->cy, s->cx); + ctx->write(ctx->data, TTY_CURSORMOVE, s->cx, s->cy); if (s->mode & MODE_CURSOR) - ctx->write(ctx->data, TTY_CURSORON); + ctx->write(ctx->data, TTY_CURSORMODE, 1); if (s->mode & MODE_MOUSE) - ctx->write(ctx->data, TTY_MOUSEON); + ctx->write(ctx->data, TTY_MOUSEMODE, 1); } -/* Get cell data. */ +/* Write character. */ void -screen_redraw_get_cell(struct screen_redraw_ctx *ctx, - u_int px, u_int py, u_char *data, u_short *attr, u_char *fg, u_char *bg) +screen_redraw_putc( + struct screen_redraw_ctx *ctx, struct grid_cell *gc, u_char ch) { - struct screen *s = ctx->s; - - screen_get_cell( - s, screen_x(s, px), screen_y(s, py), data, attr, fg, bg); -} - -/* Move cursor. */ -void -screen_redraw_move_cursor(struct screen_redraw_ctx *ctx, u_int px, u_int py) -{ - if (px != ctx->s->cx || py != ctx->s->cy) { - ctx->s->cx = px; - ctx->s->cy = py; - ctx->write(ctx->data, TTY_CURSORMOVE, ctx->s->cy, ctx->s->cx); - } -} - -/* Set attributes. */ -void -screen_redraw_set_attributes( - struct screen_redraw_ctx *ctx, u_short attr, u_char fg, u_char bg) -{ - ctx->write(ctx->data, TTY_ATTRIBUTES, attr, fg, bg); + gc->data = ch; + ctx->write(ctx->data, TTY_CELL, gc); + ctx->s->cx++; } /* Write string. */ -void printflike2 -screen_redraw_write_string(struct screen_redraw_ctx *ctx, const char *fmt, ...) +void printflike3 +screen_redraw_puts( + struct screen_redraw_ctx *ctx, struct grid_cell *gc, const char *fmt, ...) { - va_list ap; - char *msg, *ptr; + va_list ap; + char *msg, *ptr; va_start(ap, fmt); xvasprintf(&msg, fmt, ap); va_end(ap); - for (ptr = msg; *ptr != '\0'; ptr++) { - if (*ptr < 0x20) - continue; - ctx->write(ctx->data, TTY_CHARACTER, *ptr); - ctx->s->cx++; - } + for (ptr = msg; *ptr != '\0'; ptr++) + screen_redraw_putc(ctx, gc, (u_char) *ptr); xfree(msg); } @@ -151,41 +123,45 @@ screen_redraw_write_string(struct screen_redraw_ctx *ctx, const char *fmt, ...) void screen_redraw_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py) { - u_short attr; - u_char data, fg, bg; + const struct grid_cell *gc; + struct grid_cell hc; - screen_redraw_move_cursor(ctx, px, py); - screen_redraw_get_cell(ctx, px, py, &data, &attr, &fg, &bg); - - ctx->write(ctx->data, TTY_ATTRIBUTES, attr, fg, bg); - ctx->write(ctx->data, TTY_CHARACTER, data); - - ctx->s->cx++; -} - -/* Redraw area of cells. */ -void -screen_redraw_area( - struct screen_redraw_ctx *ctx, u_int px, u_int py, u_int nx, u_int ny) -{ - u_int i, j; - - for (i = py; i < py + ny; i++) { - for (j = px; j < px + nx; j++) - screen_redraw_cell(ctx, j, i); + if (px != ctx->s->cx || py != ctx->s->cy) { + ctx->s->cx = px; + ctx->s->cy = py; + ctx->write(ctx->data, TTY_CURSORMOVE, ctx->s->cx, ctx->s->cy); } + + gc = grid_view_peek_cell(ctx->s->grid, px, py); + if (screen_check_selection(ctx->s, px, py)) { + memcpy(&hc, gc, sizeof hc); + hc.attr |= GRID_ATTR_REVERSE; + ctx->write(ctx->data, TTY_CELL, &hc); + } else + ctx->write(ctx->data, TTY_CELL, gc); + ctx->s->cx++; } /* Draw set of lines. */ void screen_redraw_lines(struct screen_redraw_ctx *ctx, u_int py, u_int ny) { - screen_redraw_area(ctx, 0, py, screen_size_x(ctx->s), ny); + u_int i, j; + + for (j = py; j < py + ny; j++) { + for (i = 0; i < screen_size_x(ctx->s); i++) + screen_redraw_cell(ctx, i, j); + } } /* Draw set of columns. */ void screen_redraw_columns(struct screen_redraw_ctx *ctx, u_int px, u_int nx) { - screen_redraw_area(ctx, px, 0, nx, screen_size_y(ctx->s)); + u_int i, j; + + for (j = 0; j < screen_size_y(ctx->s); j++) { + for (i = px; i < px + nx; i++) + screen_redraw_cell(ctx, i, j); + } } diff --git a/screen-write.c b/screen-write.c index 35ac3a59..fa64f2a1 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1,4 +1,4 @@ -/* $Id: screen-write.c,v 1.13 2008-09-09 22:16:36 nicm Exp $ */ +/* $Id: screen-write.c,v 1.14 2008-09-25 20:08:54 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -22,17 +22,6 @@ #include "tmux.h" -#define screen_write_limit(s, v, lower, upper) do { \ - if (v < lower) { \ - v = lower; \ - SCREEN_DEBUG3(s, v, lower, upper); \ - } \ - if (v > upper) { \ - v = upper; \ - SCREEN_DEBUG3(s, v, lower, upper); \ - } \ -} while (0) - /* Initialise writing with a window. */ void screen_write_start_window(struct screen_write_ctx *ctx, struct window *w) @@ -71,520 +60,558 @@ screen_write_start(struct screen_write_ctx *ctx, ctx->s = s; if (ctx->write != NULL) - ctx->write(ctx->data, TTY_CURSOROFF); + ctx->write(ctx->data, TTY_CURSORMODE, 0); } -/* Finalise writing. */ +/* Finish writing. */ void screen_write_stop(struct screen_write_ctx *ctx) { struct screen *s = ctx->s; if (ctx->write != NULL && s->mode & MODE_CURSOR) - ctx->write(ctx->data, TTY_CURSORON); + ctx->write(ctx->data, TTY_CURSORMODE, 1); } -/* Set screen title. */ +/* Write character. */ void -screen_write_set_title(struct screen_write_ctx *ctx, char *title) +screen_write_putc( + struct screen_write_ctx *ctx, struct grid_cell *gc, u_char ch) { - struct screen *s = ctx->s; - - xfree(s->title); - s->title = title; + gc->data = ch; + screen_write_cell(ctx, gc); } -/* Put a character. */ -void -screen_write_put_character(struct screen_write_ctx *ctx, u_char ch) +/* Write string. */ +void printflike3 +screen_write_puts( + struct screen_write_ctx *ctx, struct grid_cell *gc, const char *fmt, ...) { - struct screen *s = ctx->s; - u_short attr; + va_list ap; + char *msg, *ptr; - if (s->cx == screen_size_x(s)) { - s->cx = 0; - if (ctx->write != NULL) - ctx->write(ctx->data, TTY_CHARACTER, '\r'); - screen_write_cursor_down_scroll(ctx); - } else if (!screen_in_x(s, s->cx) || !screen_in_y(s, s->cy)) { - SCREEN_DEBUG(s); - return; + va_start(ap, fmt); + xvasprintf(&msg, fmt, ap); + va_end(ap); + + for (ptr = msg; *ptr != '\0'; ptr++) + screen_write_putc(ctx, gc, (u_char) *ptr); + + xfree(msg); +} + +/* Copy from another screen. */ +void +screen_write_copy(struct screen_write_ctx *ctx, + struct screen *src, u_int px, u_int py, u_int nx, u_int ny) +{ + struct screen *s = ctx->s; + struct grid_data *gd = src->grid; + const struct grid_cell *gc; + u_int xx, yy, cx, cy; + + cx = s->cx; + cy = s->cy; + for (yy = py; yy < py + ny; yy++) { + for (xx = px; xx < px + nx; xx++) { + if (xx >= gd->sx || yy >= gd->hsize + gd->sy) + gc = &grid_default_cell; + else + gc = grid_peek_cell(gd, xx, yy); + screen_write_cell(ctx, gc); + } + cy++; + screen_write_cursormove(ctx, cx, cy); } - attr = s->attr & ~(ATTR_UTF8|ATTR_PAD); +} - screen_display_set_cell(s, s->cx, s->cy, ch, attr, s->fg, s->bg); - s->cx++; +/* Cursor up by ny. */ +void +screen_write_cursorup(struct screen_write_ctx *ctx, u_int ny) +{ + struct screen *s = ctx->s; + + if (ny > s->cy) + ny = s->cy; + if (ny == 0) + ny = 1; + + s->cy -= ny; + + if (ctx != NULL) + ctx->write(ctx->data, TTY_CURSORUP, ny); +} + +/* Cursor down by ny. */ +void +screen_write_cursordown(struct screen_write_ctx *ctx, u_int ny) +{ + struct screen *s = ctx->s; + + if (ny > screen_size_y(s) - 1 - s->cy) + ny = screen_size_y(s) - 1 - s->cy; + if (ny == 0) + ny = 1; + + s->cy += ny; if (ctx->write != NULL) - ctx->write(ctx->data, TTY_CHARACTER, ch); + ctx->write(ctx->data, TTY_CURSORDOWN, ny); } -/* Put a UTF8 character. */ +/* Cursor right by nx. */ void -screen_write_put_utf8(struct screen_write_ctx *ctx, struct utf8_data *udat) +screen_write_cursorright(struct screen_write_ctx *ctx, u_int nx) { struct screen *s = ctx->s; - u_char ch, ch2, fg, bg; - u_short attr, attr2; - int idx, wide; - u_int n; - wide = 0; - if (udat->data[2] == 0xff) - n = ((udat->data[0] & 0x1f)<<6) + (udat->data[1] & 0x3f); - else if (udat->data[3] == 0xff) { - n = ((udat->data[0] & 0x0f)<<12) + - ((udat->data[1] & 0x3f)<<6) + (udat->data[2] & 0x3f); - } else - n = 0; - if ((n >= 0x1100 && n <= 0x115f) || n == 0x2329 || n == 0x232a || - (n >= 0x2e80 && n <= 0xa4cf && n != 0x303f) || - (n >= 0xac00 && n <= 0xd7a3) || (n >= 0xf900 && n <= 0xfaff) || - (n >= 0xfe10 && n <= 0xfe19) || (n >= 0xfe30 && n <= 0xfe6f) || - (n >= 0xff00 && n <= 0xff60) || (n >= 0xffe0 && n <= 0xffe6) || - (n >= 0x20000 && n <= 0x2fffd) || (n >= 0x30000 && n <= 0x3fffd)) - wide = 1; + if (nx > screen_size_x(s) - 1 - s->cx) + nx = screen_size_x(s) - 1 - s->cx; + if (nx == 0) + nx = 1; - if (s->cx >= screen_size_x(s) - wide) { - s->cx = 0; - if (ctx->write != NULL) - ctx->write(ctx->data, TTY_CHARACTER, '\r'); - screen_write_cursor_down_scroll(ctx); - } else if (!screen_in_x(s, s->cx) || !screen_in_y(s, s->cy)) { - SCREEN_DEBUG(s); - return; - } - attr = s->attr & ~(ATTR_UTF8|ATTR_PAD); + s->cx += nx; + + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_CURSORRIGHT, nx); +} - if ((idx = utf8_add(&s->utf8_table, udat)) == -1) - ch = '_'; +/* Cursor left by nx. */ +void +screen_write_cursorleft(struct screen_write_ctx *ctx, u_int nx) +{ + struct screen *s = ctx->s; + + if (nx > s->cx) + nx = s->cx; + if (nx == 0) + nx = 1; + + s->cx -= nx; + + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_CURSORLEFT, nx); +} + +/* Insert nx characters. */ +void +screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx) +{ + struct screen *s = ctx->s; + + if (nx > screen_size_x(s) - 1 - s->cx) + nx = screen_size_x(s) - 1 - s->cx; + if (nx == 0) + nx = 1; + + grid_view_insert_cells(s->grid, s->cx, s->cy, nx); + + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_INSERTCHARACTER, nx); +} + +/* Delete nx characters. */ +void +screen_write_deletecharacter(struct screen_write_ctx *ctx, u_int nx) +{ + struct screen *s = ctx->s; + + if (nx > screen_size_x(s) - 1 - s->cx) + nx = screen_size_x(s) - 1 - s->cx; + if (nx == 0) + nx = 1; + + grid_view_delete_cells(s->grid, s->cx, s->cy, nx); + + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_DELETECHARACTER, nx); +} + +/* Insert ny lines. */ +void +screen_write_insertline(struct screen_write_ctx *ctx, u_int ny) +{ + struct screen *s = ctx->s; + + if (ny > screen_size_y(s) - 1 - s->cy) + ny = screen_size_y(s) - 1 - s->cy; + if (ny == 0) + ny = 1; + + if (s->cy < s->rupper || s->cy > s->rlower) + grid_view_insert_lines(s->grid, s->cy, ny); else { - utf8_pack(idx, &ch, &attr); - attr |= ATTR_UTF8; - } - - /* Remove padding before and after, if any. */ - screen_display_get_cell(s, s->cx, s->cy, &ch2, &attr2, &fg, &bg); - if (s->cx > 0 && (attr2 & ATTR_PAD)) - screen_display_set_cell(s, s->cx - 1, s->cy, ' ', 0, 8, 8); - if (s->cx < screen_last_x(s) && (attr2 & ATTR_UTF8)) { - screen_display_get_cell( - s, s->cx + 1, s->cy, &ch2, &attr2, &fg, &bg); - if (s->cx > 0 && (attr2 & ATTR_PAD)) { - screen_display_set_cell( - s, s->cx + 1, s->cy, ' ', 0, 8, 8); - } - } - - screen_display_set_cell(s, s->cx, s->cy, ch, attr, s->fg, s->bg); - s->cx++; - - if (wide) { - screen_display_set_cell(s, s->cx, s->cy, ' ', ATTR_PAD, 8, 8); - s->cx++; - } - - if (ctx->write != NULL) { - ctx->write(ctx->data, TTY_ATTRIBUTES, attr, s->fg, s->bg); - ctx->write(ctx->data, TTY_CHARACTER, ch); - ctx->write(ctx->data, TTY_ATTRIBUTES, s->attr, s->fg, s->bg); - } -} - -/* Put a string right-justified. */ -size_t printflike2 -screen_write_put_string_rjust( - struct screen_write_ctx *ctx, const char *fmt, ...) -{ - struct screen *s = ctx->s; - va_list ap; - size_t size; - char *msg, *ptr; - - va_start(ap, fmt); - size = vasprintf(&msg, fmt, ap); - va_end(ap); - - ptr = msg; - if (size > screen_size_x(s)) { - ptr += size - screen_size_x(s); - size = screen_size_x(s); - } - screen_write_move_cursor(ctx, screen_size_x(s) - size, s->cy); - for (; *ptr != '\0'; ptr++) { - if (s->cx == screen_size_x(s)) - break; - screen_write_put_character(ctx, *ptr); - } - - xfree(msg); - - return (size); -} - -/* Put a string, truncating at end of line. */ -void printflike2 -screen_write_put_string(struct screen_write_ctx *ctx, const char *fmt, ...) -{ - struct screen *s = ctx->s; - va_list ap; - char *msg, *ptr; - - va_start(ap, fmt); - vasprintf(&msg, fmt, ap); - va_end(ap); - - for (ptr = msg; *ptr != '\0'; ptr++) { - if (s->cx == screen_size_x(s)) - break; - screen_write_put_character(ctx, *ptr); - } - - xfree(msg); -} - -/* Set screen attributes. */ -void -screen_write_set_attributes( - struct screen_write_ctx *ctx, u_short attr, u_char fg, u_char bg) -{ - struct screen *s = ctx->s; - - if (s->attr != attr || s->fg != fg || s->bg != bg) { - s->attr = attr; - s->fg = fg; - s->bg = bg; - - if (ctx->write != NULL) - ctx->write(ctx->data, TTY_ATTRIBUTES, attr, fg, bg); - } -} - -/* Set scroll region. */ -void -screen_write_set_region(struct screen_write_ctx *ctx, u_int upper, u_int lower) -{ - struct screen *s = ctx->s; - - screen_write_limit(s, upper, 0, screen_last_y(s)); - screen_write_limit(s, lower, 0, screen_last_y(s)); - if (upper > lower) { - SCREEN_DEBUG2(s, upper, lower); - return; - } - - /* Cursor moves to top-left. */ - s->cx = 0; - s->cy = upper; - - s->rupper = upper; - s->rlower = lower; - + grid_view_insert_lines_region( + s->grid, s->rupper, s->rlower, s->cy, ny); + } + if (ctx->write != NULL) - ctx->write(ctx->data, TTY_SCROLLREGION, s->rupper, s->rlower); + ctx->write(ctx->data, TTY_INSERTLINE, ny); } -/* Move cursor up and scroll if necessary. */ +/* Delete ny lines. */ void -screen_write_cursor_up_scroll(struct screen_write_ctx *ctx) +screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny) { struct screen *s = ctx->s; - if (s->cy == s->rupper) - screen_display_scroll_region_down(s); - else if (s->cy > 0) - s->cy--; - - if (ctx->write != NULL) - ctx->write(ctx->data, TTY_REVERSEINDEX); -} - -/* Move cursor down and scroll if necessary */ -void -screen_write_cursor_down_scroll(struct screen_write_ctx *ctx) -{ - struct screen *s = ctx->s; - - if (s->cy == s->rlower) - screen_display_scroll_region_up(s); - else if (s->cy < screen_last_y(s)) - s->cy++; - - if (ctx->write != NULL) /* XXX FORWARDINDEX */ - ctx->write(ctx->data, TTY_CHARACTER, '\n'); -} - -/* Move cursor up. */ -void -screen_write_cursor_up(struct screen_write_ctx *ctx, u_int n) -{ - struct screen *s = ctx->s; - - screen_write_limit(s, n, 1, screen_above_y(s, s->cy) - 1); - - s->cy -= n; - - if (ctx->write != NULL) - ctx->write(ctx->data, TTY_CURSORMOVE, s->cy, s->cx); -} - -/* Move cursor down. */ -void -screen_write_cursor_down(struct screen_write_ctx *ctx, u_int n) -{ - struct screen *s = ctx->s; - - screen_write_limit(s, n, 1, screen_below_y(s, s->cy) - 1); - - s->cy += n; - - if (ctx->write != NULL) - ctx->write(ctx->data, TTY_CURSORMOVE, s->cy, s->cx); -} - -/* Move cursor left. */ -void -screen_write_cursor_left(struct screen_write_ctx *ctx, u_int n) -{ - struct screen *s = ctx->s; - - screen_write_limit(s, n, 1, screen_left_x(s, s->cx) - 1); - - s->cx -= n; - - if (ctx->write != NULL) - ctx->write(ctx->data, TTY_CURSORMOVE, s->cy, s->cx); -} - -/* Move cursor right. */ -void -screen_write_cursor_right(struct screen_write_ctx *ctx, u_int n) -{ - struct screen *s = ctx->s; - - screen_write_limit(s, n, 1, screen_right_x(s, s->cx) - 1); - - s->cx += n; - - if (ctx->write != NULL) - ctx->write(ctx->data, TTY_CURSORMOVE, s->cy, s->cx); -} - -/* Delete lines. */ -void -screen_write_delete_lines(struct screen_write_ctx *ctx, u_int n) -{ - struct screen *s = ctx->s; - - screen_write_limit(s, n, 1, screen_below_y(s, s->cy)); + if (ny > screen_size_y(s) - 1 - s->cy) + ny = screen_size_y(s) - 1 - s->cy; + if (ny == 0) + ny = 1; if (s->cy < s->rupper || s->cy > s->rlower) - screen_display_delete_lines(s, s->cy, n); - else - screen_display_delete_lines_region(s, s->cy, n); + grid_view_delete_lines(s->grid, s->cy, ny); + else { + grid_view_delete_lines_region( + s->grid, s->rupper, s->rlower, s->cy, ny); + } if (ctx->write != NULL) - ctx->write(ctx->data, TTY_DELETELINE, n); + ctx->write(ctx->data, TTY_DELETELINE, ny); } -/* Delete characters. */ +/* Clear line at cursor. */ void -screen_write_delete_characters(struct screen_write_ctx *ctx, u_int n) +screen_write_clearline(struct screen_write_ctx *ctx) { struct screen *s = ctx->s; - - screen_write_limit(s, n, 1, screen_right_x(s, s->cx)); - - screen_display_delete_characters(s, s->cx, s->cy, n); - - if (ctx->write != NULL) - ctx->write(ctx->data, TTY_DELETECHARACTER, n); -} - -/* Insert lines. */ -void -screen_write_insert_lines(struct screen_write_ctx *ctx, u_int n) -{ - struct screen *s = ctx->s; - - screen_write_limit(s, n, 1, screen_below_y(s, s->cy)); - - if (s->cy < s->rupper || s->cy > s->rlower) - screen_display_insert_lines(s, s->cy, n); - else - screen_display_insert_lines_region(s, s->cy, n); - - if (ctx->write != NULL) - ctx->write(ctx->data, TTY_INSERTLINE, n); -} - -/* Insert characters. */ -void -screen_write_insert_characters(struct screen_write_ctx *ctx, u_int n) -{ - struct screen *s = ctx->s; - - screen_write_limit(s, n, 1, screen_right_x(s, s->cx)); - - screen_display_insert_characters(s, s->cx, s->cy, n); - - if (ctx->write != NULL) - ctx->write(ctx->data, TTY_INSERTCHARACTER, n); -} - -/* Move the cursor. */ -void -screen_write_move_cursor(struct screen_write_ctx *ctx, u_int n, u_int m) -{ - struct screen *s = ctx->s; - - screen_write_limit(s, n, 0, screen_last_x(s)); - screen_write_limit(s, m, 0, screen_last_y(s)); - - s->cx = n; - s->cy = m; - - if (ctx->write != NULL) - ctx->write(ctx->data, TTY_CURSORMOVE, s->cy, s->cx); -} - -/* Full to end of screen. */ -void -screen_write_fill_end_of_screen(struct screen_write_ctx *ctx) -{ - struct screen *s = ctx->s; - u_int i; - - screen_display_fill_area(s, s->cx, s->cy, - screen_right_x(s, s->cx), 1, ' ', s->attr, s->fg, s->bg); - screen_display_fill_area(s, 0, s->cy + 1, screen_size_x(s), - screen_below_y(s, s->cy + 1), ' ', s->attr, s->fg, s->bg); - - if (ctx->write != NULL) { - ctx->write(ctx->data, TTY_CLEARENDOFLINE); - for (i = s->cy + 1; i < screen_size_y(s); i++) { - ctx->write(ctx->data, TTY_CURSORMOVE, i, 0); - ctx->write(ctx->data, TTY_CLEARENDOFLINE); - } - ctx->write(ctx->data, TTY_CURSORMOVE, s->cy, s->cx); - } -} - -/* Fill entire screen. */ -void -screen_write_fill_screen(struct screen_write_ctx *ctx) -{ - struct screen *s = ctx->s; - u_int i; - - screen_display_fill_area(s, 0, 0, - screen_size_x(s), screen_size_y(s), ' ', s->attr, s->fg, s->bg); - - if (ctx->write != NULL) { - for (i = 0; i < screen_size_y(s); i++) { - ctx->write(ctx->data, TTY_CURSORMOVE, i, 0); - ctx->write(ctx->data, TTY_CLEARENDOFLINE); - } - ctx->write(ctx->data, TTY_CURSORMOVE, s->cy, s->cx); - } -} - -/* Fill to end of line. */ -void -screen_write_fill_end_of_line(struct screen_write_ctx *ctx) -{ - struct screen *s = ctx->s; - - screen_display_fill_area(s, s->cx, s->cy, - screen_right_x(s, s->cx), 1, ' ', s->attr, s->fg, s->bg); - - if (ctx->write != NULL) - ctx->write(ctx->data, TTY_CLEARENDOFLINE); -} - -/* Fill to start of line. */ -void -screen_write_fill_start_of_line(struct screen_write_ctx *ctx) -{ - struct screen *s = ctx->s; - - screen_display_fill_area(s, 0, s->cy, - screen_left_x(s, s->cx), 1, ' ', s->attr, s->fg, s->bg); - - if (ctx->write != NULL) - ctx->write(ctx->data, TTY_CLEARSTARTOFLINE); -} - -/* Fill entire line. */ -void -screen_write_fill_line(struct screen_write_ctx *ctx) -{ - struct screen *s = ctx->s; - - screen_display_fill_area( - s, 0, s->cy, screen_size_x(s), s->cy, ' ', s->attr, s->fg, s->bg); - + + grid_view_clear(s->grid, 0, s->cy, screen_size_x(s), 1); + if (ctx->write != NULL) ctx->write(ctx->data, TTY_CLEARLINE); } -/* Set a screen mode. */ +/* Clear to end of line from cursor. */ void -screen_write_set_mode(struct screen_write_ctx *ctx, int mode) +screen_write_clearendofline(struct screen_write_ctx *ctx) { - struct screen *s = ctx->s; - - s->mode |= mode; - - if (ctx->write == NULL) - return; - - if (mode & MODE_INSERT) - ctx->write(ctx->data, TTY_INSERTON); - if (mode & MODE_MOUSE) - ctx->write(ctx->data, TTY_MOUSEON); + struct screen *s = ctx->s; + + grid_view_clear(s->grid, s->cx, s->cy, screen_size_x(s) - s->cx, 1); + + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_CLEARENDOFLINE); } -/* Clear a screen mode. */ +/* Clear to start of line from cursor. */ void -screen_write_clear_mode(struct screen_write_ctx *ctx, int mode) +screen_write_clearstartofline(struct screen_write_ctx *ctx) { - struct screen *s = ctx->s; - - s->mode &= ~mode; - - if (ctx->write == NULL) - return; - - if (mode & MODE_INSERT) - ctx->write(ctx->data, TTY_INSERTOFF); - if (mode & MODE_MOUSE) - ctx->write(ctx->data, TTY_MOUSEOFF); + struct screen *s = ctx->s; + + grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1); + + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_CLEARSTARTOFLINE); } -/* Copy cells from another screen. */ +/* Move cursor to px,py. */ void -screen_write_copy_area(struct screen_write_ctx *ctx, - struct screen *src, u_int nx, u_int ny, u_int ox, u_int oy) +screen_write_cursormove(struct screen_write_ctx *ctx, u_int px, u_int py) { - struct screen *s = ctx->s; - struct screen_redraw_ctx rctx; - int saved_mode; + struct screen *s = ctx->s; + + if (px > screen_size_x(s) - 1) + px = screen_size_x(s) - 1; + if (py > screen_size_y(s) - 1) + py = screen_size_y(s) - 1; - screen_write_limit(s, nx, 1, screen_right_x(s, s->cx)); - screen_write_limit(s, ny, 1, screen_below_y(s, s->cy)); + s->cx = px; + s->cy = py; + + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_CURSORMOVE, px, py); +} - screen_display_copy_area(ctx->s, src, s->cx, s->cy, nx, ny, ox, oy); +/* Set cursor mode. */ +void +screen_write_cursormode(struct screen_write_ctx *ctx, int state) +{ + struct screen *s = ctx->s; + + if (state) + s->mode |= MODE_CURSOR; + else + s->mode &= ~MODE_CURSOR; + + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_CURSORMODE, state); +} +/* Reverse index (up with scroll). */ +void +screen_write_reverseindex(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + + if (s->cy == s->rupper) + grid_view_scroll_region_down(s->grid, s->rupper, s->rlower); + else if (s->cy > 0) + s->cy--; + + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_REVERSEINDEX); +} + +/* Set scroll region. */ +void +screen_write_scrollregion( + struct screen_write_ctx *ctx, u_int rupper, u_int rlower) +{ + struct screen *s = ctx->s; + + if (rupper > screen_size_y(s) - 1) + rupper = screen_size_y(s) - 1; + if (rlower > screen_size_y(s) - 1) + rlower = screen_size_y(s) - 1; + if (rupper > rlower) + return; + + /* Cursor moves to top-left. */ + s->cx = 0; + s->cy = rupper; + + s->rupper = rupper; + s->rlower = rlower; + + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_SCROLLREGION, rupper, rlower); +} + +/* Set insert mode. */ +void +screen_write_insertmode(struct screen_write_ctx *ctx, int state) +{ + struct screen *s = ctx->s; + + if (state) + s->mode |= MODE_INSERT; + else + s->mode &= ~MODE_INSERT; + + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_INSERTMODE, state); +} + +/* Set mouse mode. */ +void +screen_write_mousemode(struct screen_write_ctx *ctx, int state) +{ + struct screen *s = ctx->s; + + if (state) + s->mode |= MODE_MOUSE; + else + s->mode &= ~MODE_MOUSE; + + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_MOUSEMODE, state); +} + +/* Line feed (down with scroll). */ +void +screen_write_linefeed(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + + if (s->cy == s->rlower) + grid_view_scroll_region_up(s->grid, s->rupper, s->rlower); + else if (s->cy < screen_size_x(s) - 1) + s->cy++; + + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_LINEFEED); +} + +/* Carriage return (cursor to start of line). */ +void +screen_write_carriagereturn(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + + s->cx = 0; + + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_CARRIAGERETURN); +} + +/* Set keypad cursor keys mode. */ +void +screen_write_kcursormode(struct screen_write_ctx *ctx, int state) +{ + struct screen *s = ctx->s; + + if (state) + s->mode |= MODE_KCURSOR; + else + s->mode &= ~MODE_KCURSOR; + + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_KCURSORMODE); +} + +/* Set keypad number keys mode. */ +void +screen_write_kkeypadmode(struct screen_write_ctx *ctx, int state) +{ + struct screen *s = ctx->s; + + if (state) + s->mode |= MODE_KKEYPAD; + else + s->mode &= ~MODE_KKEYPAD; + + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_KKEYPADMODE); +} + +/* Clear to end of screen from cursor. */ +void +screen_write_clearendofscreen(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + u_int sx, sy; + + sx = screen_size_x(s); + sy = screen_size_y(s); + + grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1); + grid_view_clear(s->grid, 0, s->cy + 1, sx, sy - (s->cy + 1)); + + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_CLEARENDOFSCREEN); +} + +/* Clear to start of screen. */ +void +screen_write_clearstartofscreen(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + u_int sx, sy; + + sx = screen_size_x(s); + sy = screen_size_y(s); + + if (s->cy > 0) + grid_view_clear(s->grid, 0, 0, sx, s->cy - 1); + grid_view_clear(s->grid, 0, s->cy, s->cx, 1); + + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_CLEARSTARTOFSCREEN); +} + +/* Clear entire screen. */ +void +screen_write_clearscreen(struct screen_write_ctx *ctx) +{ + struct screen *s = ctx->s; + + grid_view_clear(s->grid, 0, 0, screen_size_x(s), screen_size_y(s)); + + if (ctx->write != NULL) + ctx->write(ctx->data, TTY_CLEARSCREEN); +} + +/* Write cell data. */ +void +screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) +{ + struct screen *s = ctx->s; + struct grid_data *gd = s->grid; + u_int width, xx; + const struct grid_cell *hc; + struct grid_cell *ic, tc; + + width = utf8_width(gc->data); + + /* If the character is wider than the screen, don't print it. */ + if (width > screen_size_x(s)) { + memcpy(&tc, gc, sizeof tc); + tc.data = '_'; + + width = 1; + gc = &tc; + } + + /* Check this will fit on the current line; scroll if not. */ + if (s->cx >= screen_size_x(s) + 1 - width) { + screen_write_carriagereturn(ctx); + screen_write_linefeed(ctx); + } + + /* Sanity checks. */ + if (s->cx > screen_size_x(s) - 1 || s->cy > screen_size_y(s) - 1) + return; + + /* + * UTF-8 wide characters are a bit of an annoyance. They take up more + * than one cell on the screen, so following cells must not be drawn by + * marking them as padding. + * + * So far, so good. The problem is, when overwriting a padding cell, or + * a UTF-8 character, it is necessary to also overwrite any other cells + * which covered by the same character. + */ + hc = grid_view_peek_cell(gd, s->cx, s->cy); + if (hc->flags & GRID_FLAG_PADDING) { + /* + * A padding cell, so clear any following and leading padding + * cells back to the character. Don't overwrite the current + * cell as that happens later anyway. + */ + xx = s->cx; + while (xx-- > 0) { + hc = grid_view_peek_cell(gd, xx, s->cy); + if (!(hc->flags & GRID_FLAG_PADDING)) + break; + grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); + } + + /* Overwrite the character at the start of this padding. */ + grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); + + /* Overwrite following padding cells. */ + xx = s->cx; + while (++xx < screen_size_x(s)) { + hc = grid_view_peek_cell(gd, xx, s->cy); + if (!(hc->flags & GRID_FLAG_PADDING)) + break; + grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); + } + } else if (utf8_width(hc->data) > 1) { + /* + * An UTF-8 wide cell; overwrite following padding cells only. + */ + xx = s->cx; + while (++xx < screen_size_x(s)) { + hc = grid_view_peek_cell(gd, xx, s->cy); + if (!(hc->flags & GRID_FLAG_PADDING)) + break; + grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); + } + } + + /* + * If the new character is UTF-8 wide, fill in padding cells. Have + * already ensured there is enough room. + */ + for (xx = s->cx + 1; xx < s->cx + width; xx++) { + ic = grid_view_get_cell(gd, xx, s->cy); + ic->flags |= GRID_FLAG_PADDING; + } + + /* Write the actual cell. */ + grid_view_set_cell(gd, s->cx, s->cy, gc); + s->cx += width; + if (ctx->write != NULL) { - /* Save mode XXX hack */ - saved_mode = ctx->s->mode; - ctx->s->mode &= ~MODE_CURSOR; - - screen_redraw_start(&rctx, ctx->s, ctx->write, ctx->data); - screen_redraw_area(&rctx, s->cx, s->cy, nx, ny); - screen_redraw_stop(&rctx); - - ctx->s->mode = saved_mode; + if (screen_check_selection(ctx->s, s->cx, s->cy)) { + memcpy(&tc, gc, sizeof tc); + tc.attr |= GRID_ATTR_REVERSE; + ctx->write(ctx->data, TTY_CELL, &tc); + } else + ctx->write(ctx->data, TTY_CELL, gc); } } diff --git a/screen.c b/screen.c index de643ab0..d85eb676 100644 --- a/screen.c +++ b/screen.c @@ -1,4 +1,4 @@ -/* $Id: screen.c,v 1.71 2008-09-10 19:15:04 nicm Exp $ */ +/* $Id: screen.c,v 1.72 2008-09-25 20:08:54 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -22,90 +22,18 @@ #include "tmux.h" -/* - * Virtual screen. - * - * A screen is stored as three arrays of lines of 8-bit values, one for the - * actual characters (data), one for attributes and one for colours. Three - * seperate blocks means memset and friends can be used. Each array is y by x - * in size, row then column order. Sizes are 0-based. There is an additional - * array of u_ints with the size of each line. - * - * Each screen has a history starting at the beginning of the arrays and - * extending for hsize lines. Beyond that is the screen display of size - * dy: - * - * ----------- array base - * | | - * | history | - * ----------- array base + hsize - * | | - * | display | - * | | - * ----------- array base + hsize + dy - * - * The screen_x/screen_y macros are used to convert a cell on the displayed - * area to an absolute position in the arrays. - * - * Screen handling code is split into four files: - * - * screen.c: Creation/deletion, utility functions, and basic functions to - * manipulate the screen based on offsets from the base. - * screen-display.c: Basic functions for manipulating the displayed - * part of the screen. x,y coordinates passed to these - * are relative to the display. These are largely - * utility functions for screen-write.c. - * screen-redraw.c: Functions for redrawing all or part of a screen to - * one or more ttys. A context is filled via one of the - * screen_redraw_start* variants which sets up (removes - * cursor etc) and figures out which tty_write_* function - * to use to write to the terminals, then the other - * screen_redraw_* functions are used to draw the screen, - * and screen_redraw_stop used to reset the cursor and - * clean up. These are used when changing window and a - * few other bits (status line). - * screen-write.c: Functions for modifying (writing into) the screen and - * optionally simultaneously updating one or more ttys. - * These are used in much the same way as the redraw - * functions. These are used to update when parsing - * input from the window (input.c) and for the various - * other modes which maintain private screens. - * - * If you're thinking this all seems too complicated, that's because it is :-/. - */ +void screen_resize_x(struct screen *, u_int); +void screen_resize_y(struct screen *, u_int); /* Create a new screen. */ void -screen_init(struct screen *s, u_int dx, u_int dy, u_int hlimit) +screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit) { - s->dx = dx; - s->dy = dy; - s->cx = 0; - s->cy = 0; + s->grid = grid_create(sx, sy, hlimit); - s->rupper = 0; - s->rlower = s->dy - 1; - - s->hsize = 0; - s->hlimit = hlimit; - - s->attr = 0; - s->fg = 8; - s->bg = 8; - - s->mode = MODE_CURSOR; s->title = xstrdup(""); - s->grid_data = xmalloc(dy * (sizeof *s->grid_data)); - s->grid_attr = xmalloc(dy * (sizeof *s->grid_attr)); - s->grid_fg = xmalloc(dy * (sizeof *s->grid_fg)); - s->grid_bg = xmalloc(dy * (sizeof *s->grid_bg)); - s->grid_size = xmalloc(dy * (sizeof *s->grid_size)); - screen_make_lines(s, 0, dy); - - utf8_init(&s->utf8_table, UTF8_LIMIT); - - screen_clear_selection(s); + screen_reinit(s); } /* Reinitialise screen. */ @@ -116,16 +44,13 @@ screen_reinit(struct screen *s) s->cy = 0; s->rupper = 0; - s->rlower = s->dy - 1; - - s->attr = 0; - s->fg = 8; - s->bg = 8; + s->rlower = screen_size_y(s) - 1; s->mode = MODE_CURSOR; - screen_display_fill_area(s, 0, 0, - screen_size_x(s), screen_size_y(s), ' ', 0, 8, 8); + /* XXX */ + grid_clear_lines( + s->grid, s->grid->hsize, s->grid->hsize + s->grid->sy - 1); screen_clear_selection(s); } @@ -134,245 +59,121 @@ screen_reinit(struct screen *s) void screen_free(struct screen *s) { - utf8_free(&s->utf8_table); xfree(s->title); - screen_free_lines(s, 0, s->dy + s->hsize); - xfree(s->grid_data); - xfree(s->grid_attr); - xfree(s->grid_fg); - xfree(s->grid_bg); - xfree(s->grid_size); + grid_destroy(s->grid); +} + +/* Set screen title. */ +void +screen_set_title(struct screen *s, const char *title) +{ + xfree(s->title); + s->title = xstrdup(title); } /* Resize screen. */ void screen_resize(struct screen *s, u_int sx, u_int sy) { - u_int i, ox, oy, ny, my; - if (sx < 1) sx = 1; if (sy < 1) sy = 1; - ox = s->dx; - oy = s->dy; - if (sx == ox && sy == oy) + if (sx != screen_size_x(s)) + screen_resize_x(s, sx); + if (sy != screen_size_y(s)) + screen_resize_y(s, sy); +} + +void +screen_resize_x(struct screen *s, u_int sx) +{ + struct grid_data *gd = s->grid; + const struct grid_cell *gc; + u_int xx, yy; + + /* If getting larger, not much to do. */ + if (sx > screen_size_x(s)) { + gd->sx = sx; return; - - /* - * X dimension. - */ - if (sx != ox) { - /* - * If getting smaller, nuke any data in lines over the new - * size. - */ - if (sx < ox) { - for (i = s->hsize; i < s->hsize + oy; i++) { - if (s->grid_size[i] > sx) - screen_reduce_line(s, i, sx); - } - } - - if (s->cx >= sx) - s->cx = sx - 1; - s->dx = sx; } - /* - * Y dimension. - */ - if (sy == oy) - return; + /* If getting smaller, nuke any data in lines over the new size. */ + for (yy = gd->hsize; yy < gd->hsize + screen_size_y(s); yy++) { + /* + * If the character after the last is wide or padding, remove + * it and any leading padding. + */ + for (xx = sx; xx > 0; xx--) { + gc = grid_peek_cell(gd, xx - 1, yy); + if (!(gc->flags & GRID_FLAG_PADDING)) + break; + grid_set_cell(gd, xx - 1, yy, &grid_default_cell); + } + if (xx > 0 && xx != sx && utf8_width(gc->data) != 1) + grid_set_cell(gd, xx - 1, yy, &grid_default_cell); + + /* Reduce the line size. */ + grid_reduce_line(gd, yy, sx); + } + + if (s->cx >= sx) + s->cx = sx - 1; + gd->sx = sx; +} + +void +screen_resize_y(struct screen *s, u_int sy) +{ + struct grid_data *gd = s->grid; + u_int oy, yy, ny; /* Size decreasing. */ - if (sy < oy) { - ny = oy - sy; + if (sy < screen_size_y(s)) { + oy = screen_size_y(s); + if (s->cy != 0) { /* * The cursor is not at the start. Try to remove as * many lines as possible from the top. (Up to the * cursor line.) */ - my = s->cy; - if (my > ny) - my = ny; + ny = s->cy; + if (ny > oy - sy) + ny = oy - sy; - screen_free_lines(s, s->hsize, my); - screen_move_lines(s, s->hsize, s->hsize + my, oy - my); + grid_view_delete_lines(gd, 0, ny); - s->cy -= my; - oy -= my; + s->cy -= ny; + oy -= ny; } - ny = oy - sy; - if (ny > 0) { - /* - * Remove any remaining lines from the bottom. - */ - screen_free_lines(s, s->hsize + oy - ny, ny); + if (sy < oy) { + /* Remove any remaining lines from the bottom. */ + grid_view_delete_lines(gd, sy, oy - sy); if (s->cy >= sy) s->cy = sy - 1; } } /* Resize line arrays. */ - ny = s->hsize + sy; - s->grid_data = xrealloc(s->grid_data, ny, sizeof *s->grid_data); - s->grid_attr = xrealloc(s->grid_attr, ny, sizeof *s->grid_attr); - s->grid_fg = xrealloc(s->grid_fg, ny, sizeof *s->grid_fg); - s->grid_bg = xrealloc(s->grid_bg, ny, sizeof *s->grid_bg); - s->grid_size = xrealloc(s->grid_size, ny, sizeof *s->grid_size); - s->dy = sy; + gd->size = xrealloc(gd->size, gd->hsize + sy, sizeof *gd->size); + gd->data = xrealloc(gd->data, gd->hsize + sy, sizeof *gd->data); /* Size increasing. */ - if (sy > oy) - screen_make_lines(s, s->hsize + oy, sy - oy); + if (sy > screen_size_y(s)) { + oy = screen_size_y(s); + for (yy = gd->hsize + oy; yy < gd->hsize + sy; yy++) { + gd->size[yy] = 0; + gd->data[yy] = NULL; + } + } + gd->sy = sy; + s->rupper = 0; - s->rlower = s->dy - 1; -} - -/* Expand line. */ -void -screen_expand_line(struct screen *s, u_int py, u_int nx) -{ - u_int ox; - - ox = s->grid_size[py]; - s->grid_size[py] = nx; - - s->grid_data[py] = xrealloc( - s->grid_data[py], sizeof **s->grid_data, nx); - memset(&s->grid_data[py][ox], ' ', (nx - ox) * sizeof **s->grid_data); - s->grid_attr[py] = xrealloc( - s->grid_attr[py], sizeof **s->grid_attr, nx); - memset(&s->grid_attr[py][ox], 0, (nx - ox) * sizeof **s->grid_attr); - s->grid_fg[py] = xrealloc( - s->grid_fg[py], sizeof **s->grid_fg, nx); - memset(&s->grid_fg[py][ox], 8, (nx - ox) * sizeof **s->grid_fg); - s->grid_bg[py] = xrealloc( - s->grid_bg[py], sizeof **s->grid_bg, nx); - memset(&s->grid_bg[py][ox], 8, (nx - ox) * sizeof **s->grid_bg); -} - -/* Reduce line. */ -void -screen_reduce_line(struct screen *s, u_int py, u_int nx) -{ - s->grid_size[py] = nx; - - s->grid_data[py] = xrealloc( - s->grid_data[py], sizeof **s->grid_data, nx); - s->grid_attr[py] = xrealloc( - s->grid_attr[py], sizeof **s->grid_attr, nx); - s->grid_fg[py] = xrealloc( - s->grid_fg[py], sizeof **s->grid_fg, nx); - s->grid_bg[py] = xrealloc( - s->grid_bg[py], sizeof **s->grid_bg, nx); -} - -/* Get cell. */ -void -screen_get_cell(struct screen *s, - u_int cx, u_int cy, u_char *data, u_short *attr, u_char *fg, u_char *bg) -{ - if (cx >= s->grid_size[cy]) { - *data = ' '; - *attr = 0; - *fg = 8; - *bg = 8; - } else { - *data = s->grid_data[cy][cx]; - *attr = s->grid_attr[cy][cx]; - *fg = s->grid_fg[cy][cx]; - *bg = s->grid_bg[cy][cx]; - } - - if (screen_check_selection(s, cx, cy)) - *attr |= ATTR_REVERSE; -} - -/* Set a cell. */ -void -screen_set_cell(struct screen *s, - u_int cx, u_int cy, u_char data, u_short attr, u_char fg, u_char bg) -{ - if (cx >= s->grid_size[cy]) - screen_expand_line(s, cy, cx + 1); - - s->grid_data[cy][cx] = data; - s->grid_attr[cy][cx] = attr; - s->grid_fg[cy][cx] = fg; - s->grid_bg[cy][cx] = bg; -} - -/* Create a range of lines. */ -void -screen_make_lines(struct screen *s, u_int py, u_int ny) -{ - u_int i; - - for (i = py; i < py + ny; i++) { - s->grid_data[i] = NULL; - s->grid_attr[i] = NULL; - s->grid_fg[i] = NULL; - s->grid_bg[i] = NULL; - s->grid_size[i] = 0; - } -} - -/* Free a range of ny lines at py. */ -void -screen_free_lines(struct screen *s, u_int py, u_int ny) -{ - u_int i; - - for (i = py; i < py + ny; i++) { - if (s->grid_data[i] != NULL) - xfree(s->grid_data[i]); - s->grid_data[i] = NULL; - if (s->grid_attr[i] != NULL) - xfree(s->grid_attr[i]); - s->grid_attr[i] = NULL; - if (s->grid_fg[i] != NULL) - xfree(s->grid_fg[i]); - s->grid_fg[i] = NULL; - if (s->grid_bg[i] != NULL) - xfree(s->grid_bg[i]); - s->grid_bg[i] = NULL; - s->grid_size[i] = 0; - } -} - -/* Move a range of lines. */ -void -screen_move_lines(struct screen *s, u_int dy, u_int py, u_int ny) -{ - memmove( - &s->grid_data[dy], &s->grid_data[py], ny * (sizeof *s->grid_data)); - memmove( - &s->grid_attr[dy], &s->grid_attr[py], ny * (sizeof *s->grid_attr)); - memmove( - &s->grid_fg[dy], &s->grid_fg[py], ny * (sizeof *s->grid_fg)); - memmove( - &s->grid_bg[dy], &s->grid_bg[py], ny * (sizeof *s->grid_bg)); - memmove( - &s->grid_size[dy], &s->grid_size[py], ny * (sizeof *s->grid_size)); -} - -/* Fill an area. */ -void -screen_fill_area(struct screen *s, u_int px, u_int py, - u_int nx, u_int ny, u_char data, u_short attr, u_char fg, u_char bg) -{ - u_int i, j; - - for (i = py; i < py + ny; i++) { - for (j = px; j < px + nx; j++) - screen_set_cell(s, j, i, data, attr, fg, bg); - } + s->rlower = screen_size_y(s) - 1; } /* Set selection. */ diff --git a/server-msg.c b/server-msg.c index f7dfe2bb..65d90f52 100644 --- a/server-msg.c +++ b/server-msg.c @@ -1,4 +1,4 @@ -/* $Id: server-msg.c,v 1.50 2008-09-09 22:16:37 nicm Exp $ */ +/* $Id: server-msg.c,v 1.51 2008-09-25 20:08:54 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -189,6 +189,10 @@ server_msg_fn_identify(struct hdr *hdr, struct client *c) tty_init(&c->tty, data.tty, xstrdup(term)); if (data.flags & IDENTIFY_UTF8) c->tty.flags |= TTY_UTF8; + if (data.flags & IDENTIFY_256COLOURS) + c->tty.term_flags |= TERM_256COLOURS; + if (data.flags & IDENTIFY_HASDEFAULTS) + c->tty.term_flags |= TERM_HASDEFAULTS; xfree(term); c->flags |= CLIENT_TERMINAL; diff --git a/server.c b/server.c index d5bd5bab..4553f6af 100644 --- a/server.c +++ b/server.c @@ -1,4 +1,4 @@ -/* $Id: server.c,v 1.80 2008-09-10 19:15:04 nicm Exp $ */ +/* $Id: server.c,v 1.81 2008-09-25 20:08:54 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -186,14 +186,14 @@ server_main(const char *srv_path, int srv_fd) server_fill_clients(&pfd); /* Do the poll. */ - log_debug("polling %d fds", nfds); + /* log_debug("polling %d fds", nfds); */ if ((nfds = poll(pfds, nfds, 100)) == -1) { if (errno == EAGAIN || errno == EINTR) continue; fatal("poll failed"); } pfd = pfds; - log_debug("poll returned %d", nfds); + /* log_debug("poll returned %d", nfds); */ /* Handle server socket. */ #ifndef BROKEN_POLL @@ -271,7 +271,7 @@ server_fill_windows(struct pollfd **pfd) (*pfd)->events = POLLIN; if (BUFFER_USED(w->out) > 0) (*pfd)->events |= POLLOUT; - log_debug("adding window %d (%d)", (*pfd)->fd, w->fd); + /* log_debug("adding window %d (%d)", (*pfd)->fd, w->fd); */ } (*pfd)++; } @@ -286,7 +286,7 @@ server_handle_windows(struct pollfd **pfd) for (i = 0; i < ARRAY_LENGTH(&windows); i++) { if ((w = ARRAY_ITEM(&windows, i)) != NULL && w->fd != -1) { - log_debug("testing window %d (%d)", (*pfd)->fd, w->fd); + /* log_debug("testing window %d (%d)", (*pfd)->fd, w->fd); */ if (buffer_poll(*pfd, w->in, w->out) != 0) server_lost_window(w); else @@ -303,6 +303,7 @@ server_check_redraw(struct client *c) struct session *s; struct screen_redraw_ctx ctx; struct screen screen; + struct grid_cell gc; u_int xx, yy, sx, sy; char title[BUFSIZ]; int flags; @@ -344,8 +345,9 @@ server_check_redraw(struct client *c) if (sx < xx) screen_redraw_columns(&ctx, sx, xx - sx); if (sy < yy) { - screen_fill_area( - &screen, 0, sy, xx, 1, '-', 0, 8, 8); + memcpy(&gc, &grid_default_cell, sizeof gc); + gc.data = '-'; + grid_view_fill(screen.grid, &gc, 0, sy, xx, 1); screen_redraw_lines(&ctx, sy, yy - sy); } screen_redraw_stop(&ctx); @@ -423,7 +425,7 @@ server_fill_clients(struct pollfd **pfd) (*pfd)->events = POLLIN; if (BUFFER_USED(c->out) > 0) (*pfd)->events |= POLLOUT; - log_debug("adding client %d (%d)", (*pfd)->fd, c->fd); + /* log_debug("adding client %d (%d)", (*pfd)->fd, c->fd); */ } (*pfd)++; @@ -434,7 +436,7 @@ server_fill_clients(struct pollfd **pfd) (*pfd)->events = POLLIN; if (BUFFER_USED(c->tty.out) > 0) (*pfd)->events |= POLLOUT; - log_debug("adding tty %d (%d)", (*pfd)->fd, c->tty.fd); + /* log_debug("adding tty %d (%d)", (*pfd)->fd, c->tty.fd); */ } (*pfd)++; } @@ -451,7 +453,7 @@ server_handle_clients(struct pollfd **pfd) c = ARRAY_ITEM(&clients, i); if (c != NULL) { - log_debug("testing client %d (%d)", (*pfd)->fd, c->fd); + /* log_debug("testing client %d (%d)", (*pfd)->fd, c->fd); */ if (buffer_poll(*pfd, c->in, c->out) != 0) { server_lost_client(c); (*pfd) += 2; @@ -462,7 +464,7 @@ server_handle_clients(struct pollfd **pfd) (*pfd)++; if (c != NULL && c->tty.fd != -1 && c->session != NULL) { - log_debug("testing tty %d (%d)", (*pfd)->fd, c->tty.fd); + /* log_debug("testing tty %d (%d)", (*pfd)->fd, c->tty.fd); */ if (buffer_poll(*pfd, c->tty.in, c->tty.out) != 0) server_lost_client(c); else @@ -594,12 +596,12 @@ server_handle_window(struct window *w) action = options_get_number(&s->options, "bell-action"); switch (action) { case BELL_ANY: - tty_write_session(s, TTY_CHARACTER, '\007'); + tty_write_session(s, TTY_BELL); break; case BELL_CURRENT: if (s->curw->window != w) break; - tty_write_session(s, TTY_CHARACTER, '\007'); + tty_write_session(s, TTY_BELL); break; } update = 1; diff --git a/status.c b/status.c index 6f2a534d..a420b8ae 100644 --- a/status.c +++ b/status.c @@ -1,4 +1,4 @@ -/* $Id: status.c,v 1.45 2008-09-08 22:03:54 nicm Exp $ */ +/* $Id: status.c,v 1.46 2008-09-25 20:08:54 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -25,7 +25,7 @@ #include "tmux.h" size_t status_width(struct winlink *); -char *status_print(struct session *, struct winlink *, u_short *); +char *status_print(struct session *, struct winlink *, struct grid_cell *); /* Draw status for client on the last lines of given context. */ void @@ -38,8 +38,7 @@ status_redraw(struct client *c) char lbuf[BUFSIZ], rbuf[BUFSIZ]; size_t llen, rlen, offset, xx, yy; size_t size, start, width; - u_short attr; - u_char fg, bg; + struct grid_cell gc; struct tm *tm; time_t t; int larrow, rarrow; @@ -50,8 +49,8 @@ status_redraw(struct client *c) if (gettimeofday(&c->status_timer, NULL) != 0) fatal("gettimeofday"); - fg = options_get_number(&s->options, "status-fg"); - bg = options_get_number(&s->options, "status-bg"); + gc.fg = options_get_number(&s->options, "status-fg"); + gc.bg = options_get_number(&s->options, "status-bg"); yy = c->sy - 1; if (yy == 0) @@ -138,24 +137,22 @@ draw: /* Begin drawing and move to the starting position. */ screen_redraw_start_client(&ctx, c); - screen_redraw_set_attributes(&ctx, 0, fg, bg); if (llen != 0) { - screen_redraw_move_cursor(&ctx, 0, yy); - screen_redraw_write_string(&ctx, "%s ", lbuf); + ctx.write(ctx.data, TTY_CURSORMOVE, 0, yy); + screen_redraw_puts(&ctx, &gc, "%s ", lbuf); if (larrow) - ctx.write(ctx.data, TTY_CHARACTER, ' '); + screen_redraw_putc(&ctx, &gc, ' '); } else { if (larrow) - screen_redraw_move_cursor(&ctx, 1, yy); + ctx.write(ctx.data, TTY_CURSORMOVE, 1, yy); else - screen_redraw_move_cursor(&ctx, 0, yy); + ctx.write(ctx.data, TTY_CURSORMOVE, 0, yy); } /* Draw each character in succession. */ offset = 0; RB_FOREACH(wl, winlinks, &s->windows) { - text = status_print(s, wl, &attr); - screen_redraw_set_attributes(&ctx, attr, fg, bg); + text = status_print(s, wl, &gc); if (larrow == 1 && offset < start) { if (session_alert_has(s, wl, WINDOW_ACTIVITY)) @@ -166,7 +163,7 @@ draw: for (ptr = text; *ptr != '\0'; ptr++) { if (offset >= start && offset < start + width) - ctx.write(ctx.data, TTY_CHARACTER, *ptr); + screen_redraw_putc(&ctx, &gc, *ptr); offset++; } @@ -177,10 +174,10 @@ draw: rarrow = -1; } + gc.attr &= ~GRID_ATTR_REVERSE; if (offset < start + width) { if (offset >= start) { - screen_redraw_set_attributes(&ctx, 0, fg, bg); - ctx.write(ctx.data, TTY_CHARACTER, ' '); + screen_redraw_putc(&ctx, &gc, ' '); } offset++; } @@ -189,52 +186,50 @@ draw: } /* Fill the remaining space if any. */ - screen_redraw_set_attributes(&ctx, 0, fg, bg); while (offset++ < xx) - ctx.write(ctx.data, TTY_CHARACTER, ' '); + screen_redraw_putc(&ctx, &gc, ' '); /* Draw the last item. */ if (rlen != 0) { - screen_redraw_move_cursor(&ctx, c->sx - rlen - 1, yy); - screen_redraw_write_string(&ctx, " %s", rbuf); + ctx.write(ctx.data, TTY_CURSORMOVE, c->sx - rlen - 1, yy); + screen_redraw_puts(&ctx, &gc, " %s", rbuf); } /* Draw the arrows. */ if (larrow != 0) { - if (larrow == -1) { - screen_redraw_set_attributes( - &ctx, ATTR_REVERSE, fg, bg); - } else - screen_redraw_set_attributes(&ctx, 0, fg, bg); - if (llen != 0) - screen_redraw_move_cursor(&ctx, llen + 1, yy); + if (larrow == -1) + gc.attr |= GRID_ATTR_REVERSE; else - screen_redraw_move_cursor(&ctx, 0, yy); - ctx.write(ctx.data, TTY_CHARACTER, '<'); + gc.attr &= ~GRID_ATTR_REVERSE; + if (llen != 0) + ctx.write(ctx.data, TTY_CURSORMOVE, llen + 1, yy); + else + ctx.write(ctx.data, TTY_CURSORMOVE, 0, yy); + screen_redraw_putc(&ctx, &gc, '<'); + gc.attr &= ~GRID_ATTR_REVERSE; } if (rarrow != 0) { - if (rarrow == -1) { - screen_redraw_set_attributes( - &ctx, ATTR_REVERSE, fg, bg); - } else - screen_redraw_set_attributes(&ctx, 0, fg, bg); - if (rlen != 0) - screen_redraw_move_cursor(&ctx, c->sx - rlen - 2, yy); + if (rarrow == -1) + gc.attr |= GRID_ATTR_REVERSE; else - screen_redraw_move_cursor(&ctx, c->sx - 1, yy); - ctx.write(ctx.data, TTY_CHARACTER, '>'); + gc.attr &= ~GRID_ATTR_REVERSE; + if (rlen != 0) + ctx.write(ctx.data, TTY_CURSORMOVE, c->sx - rlen - 2, yy); + else + ctx.write(ctx.data, TTY_CURSORMOVE, c->sx - 1, yy); + screen_redraw_putc(&ctx, &gc, '>'); + gc.attr &= ~GRID_ATTR_REVERSE; } - + screen_redraw_stop(&ctx); return; blank: /* Just draw the whole line as blank. */ screen_redraw_start_client(&ctx, c); - screen_redraw_set_attributes(&ctx, 0, fg, bg); - screen_redraw_move_cursor(&ctx, 0, yy); + ctx.write(ctx.data, TTY_CURSORMOVE, 0, yy); for (offset = 0; offset < c->sx; offset++) - ctx.write(ctx.data, TTY_CHARACTER, ' '); + screen_redraw_putc(&ctx, &gc, ' '); screen_redraw_stop(&ctx); return; @@ -247,10 +242,9 @@ off: screen_redraw_start_client(&ctx, c); /* If the screen is too small, use blank. */ if (screen_size_y(c->session->curw->window->screen) < c->sy) { - screen_redraw_move_cursor(&ctx, 0, c->sy - 1); - screen_redraw_set_attributes(&ctx, 0, 8, 8); + ctx.write(ctx.data, TTY_CURSORMOVE, 0, c->sy - 1); for (offset = 0; offset < c->sx; offset++) - ctx.write(ctx.data, TTY_CHARACTER, ' '); + screen_redraw_putc(&ctx, &gc, ' '); } else screen_redraw_lines(&ctx, c->sy - 1, 1); screen_redraw_stop(&ctx); @@ -276,7 +270,7 @@ status_width(struct winlink *wl) } char * -status_print(struct session *s, struct winlink *wl, u_short *attr) +status_print(struct session *s, struct winlink *wl, struct grid_cell *gc) { char *text, flag; @@ -286,14 +280,14 @@ status_print(struct session *s, struct winlink *wl, u_short *attr) if (wl == s->curw) flag = '*'; - *attr = 0; + gc->attr &= ~GRID_ATTR_REVERSE; if (session_alert_has(s, wl, WINDOW_ACTIVITY)) { flag = '#'; - *attr = ATTR_REVERSE; + gc->attr |= GRID_ATTR_REVERSE; } if (session_alert_has(s, wl, WINDOW_BELL)) { flag = '!'; - *attr = ATTR_REVERSE; + gc->attr |= GRID_ATTR_REVERSE; } xasprintf(&text, "%d:%s%c", wl->idx, wl->window->name, flag); @@ -306,6 +300,7 @@ status_message_redraw(struct client *c) { struct screen_redraw_ctx ctx; size_t xx, yy; + struct grid_cell gc; if (c->sx == 0 || c->sy == 0) return; @@ -315,16 +310,19 @@ status_message_redraw(struct client *c) xx = c->sx; yy = c->sy - 1; - screen_redraw_start_client(&ctx, c); - screen_redraw_set_attributes(&ctx, ATTR_REVERSE, 8, 8); + memcpy(&gc, &grid_default_cell, sizeof gc); + gc.attr |= GRID_ATTR_REVERSE; - screen_redraw_move_cursor(&ctx, 0, yy); - screen_redraw_write_string(&ctx, "%.*s", (int) xx, c->message_string); + screen_redraw_start_client(&ctx, c); + + ctx.write(ctx.data, TTY_CURSORMOVE, 0, yy); + screen_redraw_puts(&ctx, &gc, "%.*s", (int) xx, c->message_string); for (; xx < c->sx; xx++) - ctx.write(ctx.data, TTY_CHARACTER, ' '); + screen_redraw_putc(&ctx, &gc, ' '); + screen_redraw_stop(&ctx); - tty_write_client(c, TTY_CURSOROFF); + tty_write_client(c, TTY_CURSORMODE, 0); } /* Draw client prompt on status line of present else on last line. */ @@ -334,6 +332,7 @@ status_prompt_redraw(struct client *c) struct screen_redraw_ctx ctx; size_t i, xx, yy, left, size, offset; char ch; + struct grid_cell gc; if (c->sx == 0 || c->sy == 0) return; @@ -344,11 +343,13 @@ status_prompt_redraw(struct client *c) xx = c->sx; yy = c->sy - 1; - screen_redraw_start_client(&ctx, c); - screen_redraw_set_attributes(&ctx, ATTR_REVERSE, 8, 8); + memcpy(&gc, &grid_default_cell, sizeof gc); + gc.attr |= GRID_ATTR_REVERSE; - screen_redraw_move_cursor(&ctx, 0, yy); - screen_redraw_write_string(&ctx, "%.*s", (int) xx, c->prompt_string); + screen_redraw_start_client(&ctx, c); + + ctx.write(ctx.data, TTY_CURSORMOVE, 0, yy); + screen_redraw_puts(&ctx, &gc, "%.*s", (int) xx, c->prompt_string); left = c->sx - xx; if (left != 0) { @@ -360,29 +361,29 @@ status_prompt_redraw(struct client *c) left--; size = left; } - screen_redraw_write_string( - &ctx, "%.*s", (int) left, c->prompt_buffer + offset); + screen_redraw_puts( + &ctx, &gc, "%.*s", (int) left, c->prompt_buffer + offset); for (i = xx + size; i < c->sx; i++) { - ctx.write(ctx.data, TTY_CHARACTER, ' '); + screen_redraw_putc(&ctx, &gc, ' '); ctx.s->cx++; } } /* Draw a fake cursor. */ - screen_redraw_set_attributes(&ctx, 0, 8, 8); - screen_redraw_move_cursor(&ctx, xx + c->prompt_index - offset, yy); + ctx.write(ctx.data, TTY_CURSORMOVE, xx + c->prompt_index - offset, yy); if (c->prompt_index == strlen(c->prompt_buffer)) ch = ' '; else ch = c->prompt_buffer[c->prompt_index]; if (ch == '\0') ch = ' '; - tty_write_client(c, TTY_CHARACTER, ch); + gc.attr &= ~GRID_ATTR_REVERSE; + screen_redraw_putc(&ctx, &gc, ch); screen_redraw_stop(&ctx); - tty_write_client(c, TTY_CURSOROFF); + tty_write_client(c, TTY_CURSORMODE, 0); } /* Handle keys in prompt. */ diff --git a/tmux.1 b/tmux.1 index a10468dd..799ace09 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1,4 +1,4 @@ -.\" $Id: tmux.1,v 1.48 2008-06-30 18:27:14 nicm Exp $ +.\" $Id: tmux.1,v 1.49 2008-09-25 20:08:56 nicm Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott .\" @@ -668,6 +668,15 @@ maintain this maximum length. Set the maximum number of lines held in window history. This setting applies only to new windows - existing window histories are not resized and retain the limit at the point they were created. +.It Xo Ic mode-keys +.Op Ic vi | Ic emacs +.Xc +Use +.Xr vi 1 - +or +.Xr emacs 1 - +style key bindings in scroll and copy modes. +Key bindings default to emacs. .It Ic prefix Ar key Set the current prefix key. .It Xo Ic remain-by-default diff --git a/tmux.c b/tmux.c index fb7e56f7..bf52e2ea 100644 --- a/tmux.c +++ b/tmux.c @@ -1,4 +1,4 @@ -/* $Id: tmux.c,v 1.75 2008-09-09 22:16:37 nicm Exp $ */ +/* $Id: tmux.c,v 1.76 2008-09-25 20:08:56 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -62,7 +62,7 @@ __dead void usage(void) { fprintf(stderr, - "usage: %s [-qVv] [-f file] [-S socket-path] [command [flags]]\n", + "usage: %s [-2dquVv] [-f file] [-S socket-path] [command [flags]]\n", __progname); exit(1); } @@ -179,8 +179,11 @@ main(int argc, char **argv) flags = 0; path = NULL; - while ((opt = getopt(argc, argv, "f:qS:uVv")) != EOF) { + while ((opt = getopt(argc, argv, "2df:qS:uVv")) != EOF) { switch (opt) { + case '2': + flags |= IDENTIFY_256COLOURS; + break; case 'f': cfg_file = xstrdup(optarg); break; @@ -193,6 +196,9 @@ main(int argc, char **argv) case 'u': flags |= IDENTIFY_UTF8; break; + case 'd': + flags |= IDENTIFY_HASDEFAULTS; + break; case 'v': debug_level++; break; diff --git a/tmux.h b/tmux.h index ccf87657..d74b9e00 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.188 2008-09-10 19:15:04 nicm Exp $ */ +/* $Id: tmux.h,v 1.189 2008-09-25 20:08:56 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -19,7 +19,7 @@ #ifndef TMUX_H #define TMUX_H -#define PROTOCOL_VERSION -2 +#define PROTOCOL_VERSION -3 /* Shut up gcc warnings about empty if bodies. */ #define RB_AUGMENT(x) do {} while (0) @@ -321,28 +321,32 @@ struct buffer { #define KEYC_KP4_2 (KEYC_OFFSET + 0x10f) /* Output codes. */ -#define TTY_CHARACTER 0 -#define TTY_CURSORUP 1 -#define TTY_CURSORDOWN 2 -#define TTY_CURSORRIGHT 3 -#define TTY_CURSORLEFT 4 -#define TTY_INSERTCHARACTER 5 -#define TTY_DELETECHARACTER 6 -#define TTY_INSERTLINE 7 -#define TTY_DELETELINE 8 -#define TTY_CLEARLINE 9 -#define TTY_CLEARENDOFLINE 10 -#define TTY_CLEARSTARTOFLINE 11 -#define TTY_CURSORMOVE 12 -#define TTY_ATTRIBUTES 13 -#define TTY_CURSOROFF 14 -#define TTY_CURSORON 15 -#define TTY_REVERSEINDEX 16 -#define TTY_SCROLLREGION 17 -#define TTY_INSERTON 18 -#define TTY_INSERTOFF 19 -#define TTY_MOUSEON 20 -#define TTY_MOUSEOFF 21 /* XXX merge all on/off into 1 arg? */ +#define TTY_CURSORUP 0 +#define TTY_CURSORDOWN 1 +#define TTY_CURSORRIGHT 2 +#define TTY_CURSORLEFT 3 +#define TTY_INSERTCHARACTER 4 +#define TTY_DELETECHARACTER 5 +#define TTY_INSERTLINE 6 +#define TTY_DELETELINE 7 +#define TTY_CLEARLINE 8 +#define TTY_CLEARENDOFLINE 9 +#define TTY_CLEARSTARTOFLINE 10 +#define TTY_CURSORMOVE 11 +#define TTY_CURSORMODE 12 +#define TTY_REVERSEINDEX 13 +#define TTY_SCROLLREGION 14 +#define TTY_INSERTMODE 15 +#define TTY_MOUSEMODE 16 +#define TTY_LINEFEED 17 +#define TTY_CARRIAGERETURN 18 +#define TTY_BELL 19 +#define TTY_KCURSORMODE 20 +#define TTY_KKEYPADMODE 21 +#define TTY_CLEARENDOFSCREEN 22 +#define TTY_CLEARSTARTOFSCREEN 23 +#define TTY_CLEARSCREEN 24 +#define TTY_CELL 25 /* Message codes. */ enum hdrtype { @@ -376,6 +380,8 @@ struct msg_identify_data { int version; #define IDENTIFY_UTF8 0x1 +#define IDENTIFY_256COLOURS 0x2 +#define IDENTIFY_HASDEFAULTS 0x4 int flags; u_int sx; @@ -389,45 +395,52 @@ struct msg_resize_data { u_int sy; }; -/* UTF8 data. */ -struct utf8_data { - u_char data[4]; -}; - -struct utf8_table { - u_int limit; - ARRAY_DECL(, struct utf8_data) array; -}; -#define UTF8_LIMIT ((1<<11) - 1) - -/* Attributes. */ -#define ATTR_BRIGHT 0x1 -#define ATTR_DIM 0x2 -#define ATTR_UNDERSCORE 0x4 -#define ATTR_BLINK 0x8 -#define ATTR_REVERSE 0x10 -#define ATTR_HIDDEN 0x20 -#define ATTR_ITALICS 0x40 -#define ATTR_CHARSET 0x80 /* alternative character set */ - -#define ATTR_FG256 0x100 -#define ATTR_BG256 0x200 - -#define ATTR_UTF8 0x400 -#define ATTR_PAD 0x800 - -#define ATTR_UTF8b8 0x8000 -#define ATTR_UTF8b9 0x4000 -#define ATTR_UTF8b10 0x2000 -#define ATTR_UTF8b11 0x1000 - /* Modes. */ #define MODE_CURSOR 0x1 #define MODE_INSERT 0x2 #define MODE_KCURSOR 0x4 #define MODE_KKEYPAD 0x8 -#define MODE_SAVED 0x10 -#define MODE_MOUSE 0x20 +#define MODE_MOUSE 0x10 + +/* Grid output. */ +#define GRID_DEBUG(gd, fmt, ...) log_debug3("%s: (sx=%u, sy=%u, hsize=%u) " \ + fmt, __func__, (gd)->sx, (gd)->sy, (gd)->hsize, ## __VA_ARGS__) + +/* Grid attributes. */ +#define GRID_ATTR_BRIGHT 0x1 +#define GRID_ATTR_DIM 0x2 +#define GRID_ATTR_UNDERSCORE 0x4 +#define GRID_ATTR_BLINK 0x8 +#define GRID_ATTR_REVERSE 0x10 +#define GRID_ATTR_HIDDEN 0x20 +#define GRID_ATTR_ITALICS 0x40 +#define GRID_ATTR_CHARSET 0x80 /* alternative character set */ + +/* Grid flags. */ +#define GRID_FLAG_FG256 0x1 +#define GRID_FLAG_BG256 0x2 +#define GRID_FLAG_PADDING 0x4 + +/* Grid cell. */ +struct grid_cell { + u_short data; + u_char attr; + u_char flags; + u_char fg; + u_char bg; +} __packed; + +/* Grid data. */ +struct grid_data { + u_int sx; + u_int sy; + + u_int hsize; + u_int hlimit; + + u_int *size; + struct grid_cell **data; +}; /* Screen selection. */ struct screen_sel { @@ -444,34 +457,13 @@ struct screen_sel { struct screen { char *title; - u_char **grid_data; - u_short **grid_attr; - u_char **grid_fg; - u_char **grid_bg; - u_int *grid_size; - - u_int dx; /* display x size */ - u_int dy; /* display y size */ - - u_int hsize; /* history y size */ - u_int hlimit; /* history y limit */ - - u_int rupper; /* scroll region top */ - u_int rlower; /* scroll region bottom */ + struct grid_data *grid; /* grid data */ u_int cx; /* cursor x */ u_int cy; /* cursor y */ - u_short attr; - u_char fg; - u_char bg; - struct utf8_table utf8_table; - - u_int saved_cx; - u_int saved_cy; - u_short saved_attr; - u_char saved_fg; - u_char saved_bg; + u_int rupper; /* scroll region top */ + u_int rlower; /* scroll region bottom */ int mode; @@ -497,51 +489,11 @@ struct screen_write_ctx { struct screen *s; }; -/* Screen display access macros. */ -#define screen_x(s, x) (x) -#define screen_y(s, y) ((s)->hsize + y) - -#define screen_last_x(s) ((s)->dx - 1) -#define screen_last_y(s) ((s)->dy - 1) - -#define screen_size_x(s) ((s)->dx) -#define screen_size_y(s) ((s)->dy) - -#define screen_in_x(s, x) ((x) < screen_size_x(s)) -#define screen_in_y(s, y) ((y) < screen_size_y(s)) -#define screen_in_region(s, y) ((y) >= (s)->rupper && (y) <= (s)->rlower) - -/* These are inclusive... */ -#define screen_left_x(s, x) ((x) + 1) -#define screen_right_x(s, x) \ - ((x) < screen_size_x(s) ? screen_size_x(s) - (x) : 0) - -#define screen_above_y(s, y) ((y) + 1) -#define screen_below_y(s, y) \ - ((y) < screen_size_y(s) ? screen_size_y(s) - (y) : 0) - -#define SCREEN_DEBUG(s) do { \ - log_warnx("%s: cx=%u,cy=%u sx=%u,sy=%u", __func__, \ - s->cx, s->cy, screen_size_x(s), screen_size_y(s)); \ -} while (0) -#define SCREEN_DEBUG1(s, n) do { \ - log_warnx("%s: cx=%u,cy=%u sx=%u,sy=%u n=%u m=%u", __func__, \ - s->cx, s->cy, screen_size_x(s), screen_size_y(s), n); \ -} while (0) -#define SCREEN_DEBUG2(s, n, m) do { \ - log_warnx("%s: cx=%u,cy=%u sx=%u,sy=%u n=%u m=%u", __func__, \ - s->cx, s->cy, screen_size_x(s), screen_size_y(s), n, m); \ -} while (0) -#define SCREEN_DEBUG3(s, n, m, o) do { \ - log_warnx("%s: cx=%u,cy=%u sx=%u,sy=%u n=%u m=%u o=%u", \ - __func__, s->cx, s->cy, screen_size_x(s), screen_size_y(s), \ - n, m, o); \ -} while (0) -#define SCREEN_DEBUG4(s, n, m, o, p) do { \ - log_warnx("%s: cx=%u,cy=%u sx=%u,sy=%u n=%u m=%u o=%u p=%u", \ - __func__, s->cx, s->cy, screen_size_x(s), screen_size_y(s), \ - n, m, o, p); \ -} while (0) +/* Screen size. */ +#define screen_size_x(s) ((s)->grid->sx) +#define screen_size_y(s) ((s)->grid->sy) +#define screen_hsize(s) ((s)->grid->hsize) +#define screen_hlimit(s) ((s)->grid->hlimit) /* Input parser sequence argument. */ struct input_arg { @@ -558,6 +510,12 @@ struct input_ctx { size_t len; size_t off; + struct grid_cell cell; /* current cell data */ + + struct grid_cell saved_cell; + u_int saved_cx; + u_int saved_cy; + #define MAXSTRINGLEN 1024 u_char *string_buf; size_t string_len; @@ -566,7 +524,7 @@ struct input_ctx { #define STRING_NAME 1 #define STRING_IGNORE 2 - struct utf8_data utf8_buf; + u_char utf8_buf[4]; u_int utf8_len; u_int utf8_off; @@ -725,9 +683,7 @@ struct tty { struct termios tio; - u_short attr; - u_char fg; - u_char bg; + struct grid_cell cell; u_char acs[UCHAR_MAX + 1]; @@ -737,6 +693,8 @@ struct tty { #define TTY_UTF8 0x8 int flags; + int term_flags; + struct timeval key_timer; size_t ksize; /* maximum key size */ @@ -1175,65 +1133,85 @@ void input_key(struct window *, int); const char *colour_tostring(u_char); u_char colour_fromstring(const char *); -/* screen-display.c */ -void screen_display_get_cell(struct screen *, - u_int, u_int, u_char *, u_short *, u_char *, u_char *); -void screen_display_set_cell( - struct screen *, u_int, u_int, u_char, u_short, u_char, u_char); -void screen_display_make_lines(struct screen *, u_int, u_int); -void screen_display_free_lines(struct screen *, u_int, u_int); -void screen_display_move_lines(struct screen *, u_int, u_int, u_int); -void screen_display_fill_area(struct screen *, - u_int, u_int, u_int, u_int, u_char, u_short, u_char, u_char); -void screen_display_scroll_region_up(struct screen *); -void screen_display_scroll_region_down(struct screen *); -void screen_display_insert_lines(struct screen *, u_int, u_int); -void screen_display_insert_lines_region(struct screen *, u_int, u_int); -void screen_display_delete_lines(struct screen *, u_int, u_int); -void screen_display_delete_lines_region(struct screen *, u_int, u_int); -void screen_display_insert_characters(struct screen *, u_int, u_int, u_int); -void screen_display_delete_characters(struct screen *, u_int, u_int, u_int); -void screen_display_copy_area(struct screen *, struct screen *, - u_int, u_int, u_int, u_int, u_int, u_int); +/* grid.c */ +extern const struct grid_cell grid_default_cell; +struct grid_data *grid_create(u_int, u_int, u_int); +void grid_destroy(struct grid_data *); +void grid_reduce_line(struct grid_data *, u_int, u_int); +void grid_expand_line(struct grid_data *, u_int, u_int); +void grid_scroll_line(struct grid_data *); +const struct grid_cell *grid_peek_cell(struct grid_data *, u_int, u_int); +struct grid_cell *grid_get_cell(struct grid_data *, u_int, u_int); +void grid_set_cell( + struct grid_data *, u_int, u_int, const struct grid_cell *); +void grid_clear(struct grid_data *, u_int, u_int, u_int, u_int); +void grid_fill(struct grid_data *, + const struct grid_cell *, u_int, u_int, u_int, u_int); +void grid_fill_lines( + struct grid_data *, const struct grid_cell *, u_int, u_int); +void grid_clear_lines(struct grid_data *, u_int, u_int); +void grid_move_lines(struct grid_data *, u_int, u_int, u_int); +void grid_clear_cells(struct grid_data *, u_int, u_int, u_int); +void grid_move_cells(struct grid_data *, u_int, u_int, u_int, u_int); + +/* grid-view.c */ +const struct grid_cell *grid_view_peek_cell(struct grid_data *, u_int, u_int); +struct grid_cell *grid_view_get_cell(struct grid_data *, u_int, u_int); +void grid_view_set_cell( + struct grid_data *, u_int, u_int, const struct grid_cell *); +void grid_view_clear(struct grid_data *, u_int, u_int, u_int, u_int); +void grid_view_fill(struct grid_data *, + const struct grid_cell *, u_int, u_int, u_int, u_int); +void grid_view_scroll_region_up(struct grid_data *, u_int, u_int); +void grid_view_scroll_region_down(struct grid_data *, u_int, u_int); +void grid_view_insert_lines(struct grid_data *, u_int, u_int); +void grid_view_insert_lines_region( + struct grid_data *, u_int, u_int, u_int, u_int); +void grid_view_delete_lines(struct grid_data *, u_int, u_int); +void grid_view_delete_lines_region( + struct grid_data *, u_int, u_int, u_int, u_int); +void grid_view_insert_cells(struct grid_data *, u_int, u_int, u_int); +void grid_view_delete_cells(struct grid_data *, u_int, u_int, u_int); /* screen-write.c */ void screen_write_start_window(struct screen_write_ctx *, struct window *); void screen_write_start_client(struct screen_write_ctx *, struct client *); void screen_write_start_session( - struct screen_write_ctx *, struct session *); + struct screen_write_ctx *, struct session *); void screen_write_start(struct screen_write_ctx *, - struct screen *, void (*)(void *, int, ...), void *); + struct screen *, void (*)(void *, int, ...), void *); void screen_write_stop(struct screen_write_ctx *); -void screen_write_set_title(struct screen_write_ctx *, char *); -void screen_write_put_character(struct screen_write_ctx *, u_char); -void screen_write_put_utf8(struct screen_write_ctx *, struct utf8_data *); -size_t printflike2 screen_write_put_string_rjust( - struct screen_write_ctx *, const char *, ...); -void printflike2 screen_write_put_string( - struct screen_write_ctx *, const char *, ...); -void screen_write_set_attributes( - struct screen_write_ctx *, u_short, u_char, u_char); -void screen_write_set_region(struct screen_write_ctx *, u_int, u_int); -void screen_write_cursor_up_scroll(struct screen_write_ctx *); -void screen_write_cursor_down_scroll(struct screen_write_ctx *); -void screen_write_cursor_up(struct screen_write_ctx *, u_int); -void screen_write_cursor_down(struct screen_write_ctx *, u_int); -void screen_write_cursor_left(struct screen_write_ctx *, u_int); -void screen_write_cursor_right(struct screen_write_ctx *, u_int); -void screen_write_delete_lines(struct screen_write_ctx *, u_int); -void screen_write_delete_characters(struct screen_write_ctx *, u_int); -void screen_write_insert_lines(struct screen_write_ctx *, u_int); -void screen_write_insert_characters(struct screen_write_ctx *, u_int); -void screen_write_move_cursor(struct screen_write_ctx *, u_int, u_int); -void screen_write_fill_end_of_screen(struct screen_write_ctx *); -void screen_write_fill_screen(struct screen_write_ctx *); -void screen_write_fill_end_of_line(struct screen_write_ctx *); -void screen_write_fill_start_of_line(struct screen_write_ctx *); -void screen_write_fill_line(struct screen_write_ctx *); -void screen_write_set_mode(struct screen_write_ctx *, int); -void screen_write_clear_mode(struct screen_write_ctx *, int); -void screen_write_copy_area(struct screen_write_ctx *, - struct screen *, u_int, u_int, u_int, u_int); +void printflike3 screen_write_puts( + struct screen_write_ctx *, struct grid_cell *, const char *, ...); +void screen_write_putc( + struct screen_write_ctx *, struct grid_cell *, u_char); +void screen_write_copy(struct screen_write_ctx *, + struct screen *, u_int, u_int, u_int, u_int); +void screen_write_cursorup(struct screen_write_ctx *, u_int); +void screen_write_cursordown(struct screen_write_ctx *, u_int); +void screen_write_cursorright(struct screen_write_ctx *, u_int); +void screen_write_cursorleft(struct screen_write_ctx *, u_int); +void screen_write_insertcharacter(struct screen_write_ctx *, u_int); +void screen_write_deletecharacter(struct screen_write_ctx *, u_int); +void screen_write_insertline(struct screen_write_ctx *, u_int); +void screen_write_deleteline(struct screen_write_ctx *, u_int); +void screen_write_clearline(struct screen_write_ctx *); +void screen_write_clearendofline(struct screen_write_ctx *); +void screen_write_clearstartofline(struct screen_write_ctx *); +void screen_write_cursormove(struct screen_write_ctx *, u_int, u_int); +void screen_write_cursormode(struct screen_write_ctx *, int); +void screen_write_reverseindex(struct screen_write_ctx *); +void screen_write_scrollregion(struct screen_write_ctx *, u_int, u_int); +void screen_write_insertmode(struct screen_write_ctx *, int); +void screen_write_mousemode(struct screen_write_ctx *, int); +void screen_write_linefeed(struct screen_write_ctx *); +void screen_write_carriagereturn(struct screen_write_ctx *); +void screen_write_kcursormode(struct screen_write_ctx *, int); +void screen_write_kkeypadmode(struct screen_write_ctx *, int); +void screen_write_clearendofscreen(struct screen_write_ctx *); +void screen_write_clearstartofscreen(struct screen_write_ctx *); +void screen_write_clearscreen(struct screen_write_ctx *); +void screen_write_cell(struct screen_write_ctx *, const struct grid_cell *); /* screen-redraw.c */ void screen_redraw_start_window(struct screen_redraw_ctx *, struct window *); @@ -1243,14 +1221,11 @@ void screen_redraw_start_session( void screen_redraw_start(struct screen_redraw_ctx *, struct screen *, void (*)(void *, int, ...), void *); void screen_redraw_stop(struct screen_redraw_ctx *); -void screen_redraw_move_cursor(struct screen_redraw_ctx *, u_int, u_int); -void screen_redraw_set_attributes( - struct screen_redraw_ctx *, u_short, u_char, u_char); -void printflike2 screen_redraw_write_string( - struct screen_redraw_ctx *, const char *, ...); +void printflike3 screen_redraw_puts( + struct screen_redraw_ctx *, struct grid_cell *, const char *, ...); +void screen_redraw_putc( + struct screen_redraw_ctx *, struct grid_cell *, u_char); void screen_redraw_cell(struct screen_redraw_ctx *, u_int, u_int); -void screen_redraw_area( - struct screen_redraw_ctx *, u_int, u_int, u_int, u_int); void screen_redraw_lines(struct screen_redraw_ctx *, u_int, u_int); void screen_redraw_columns(struct screen_redraw_ctx *, u_int, u_int); @@ -1258,21 +1233,13 @@ void screen_redraw_columns(struct screen_redraw_ctx *, u_int, u_int); void screen_init(struct screen *, u_int, u_int, u_int); void screen_reinit(struct screen *); void screen_free(struct screen *); +void screen_set_title(struct screen *, const char *); void screen_resize(struct screen *, u_int, u_int); -void screen_expand_line(struct screen *, u_int, u_int); -void screen_reduce_line(struct screen *, u_int, u_int); -void screen_get_cell(struct screen *, - u_int, u_int, u_char *, u_short *, u_char *, u_char *); -void screen_set_cell( - struct screen *, u_int, u_int, u_char, u_short, u_char, u_char); -void screen_make_lines(struct screen *, u_int, u_int); -void screen_free_lines(struct screen *, u_int, u_int); -void screen_move_lines(struct screen *, u_int, u_int, u_int); -void screen_fill_area(struct screen *, - u_int, u_int, u_int, u_int, u_char, u_short, u_char, u_char); void screen_set_selection(struct screen *, u_int, u_int, u_int, u_int); void screen_clear_selection(struct screen *); int screen_check_selection(struct screen *, u_int, u_int); +void screen_display_copy_area(struct screen *, struct screen *, + u_int, u_int, u_int, u_int, u_int, u_int); /* window.c */ extern struct windows windows; @@ -1328,13 +1295,9 @@ int session_select(struct session *, int); int session_last(struct session *); /* utf8.c */ -void utf8_pack(int, u_char *, u_short *); -int utf8_unpack(u_char, u_short); -void utf8_init(struct utf8_table *, int); -void utf8_free(struct utf8_table *); -struct utf8_data *utf8_lookup(struct utf8_table *, int); -int utf8_search(struct utf8_table *, struct utf8_data *); -int utf8_add(struct utf8_table *, struct utf8_data *); +u_int utf8_combine(const u_char [4]); +void utf8_split(u_int, u_char [4]); +int utf8_width(u_int); /* buffer.c */ struct buffer *buffer_create(size_t); diff --git a/tty.c b/tty.c index 39c58087..74b75c20 100644 --- a/tty.c +++ b/tty.c @@ -1,4 +1,4 @@ -/* $Id: tty.c,v 1.42 2008-09-23 17:54:35 nicm Exp $ */ +/* $Id: tty.c,v 1.43 2008-09-25 20:08:56 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -39,10 +39,64 @@ void tty_raw(struct tty *, const char *); void tty_puts(struct tty *, const char *); void tty_putc(struct tty *, char); -void tty_attributes(struct tty *, u_short, u_char, u_char); -u_char tty_attributes_fg(struct tty *, u_char); -u_char tty_attributes_bg(struct tty *, u_char); -char tty_translate(char); +void tty_reset(struct tty *); +void tty_attributes(struct tty *, const struct grid_cell *); +void tty_attributes_fg(struct tty *, const struct grid_cell *); +void tty_attributes_bg(struct tty *, const struct grid_cell *); + +void tty_cmd_cursorup(struct tty *, struct screen *, va_list); +void tty_cmd_cursordown(struct tty *, struct screen *, va_list); +void tty_cmd_cursorright(struct tty *, struct screen *, va_list); +void tty_cmd_cursorleft(struct tty *, struct screen *, va_list); +void tty_cmd_insertcharacter(struct tty *, struct screen *, va_list); +void tty_cmd_deletecharacter(struct tty *, struct screen *, va_list); +void tty_cmd_insertline(struct tty *, struct screen *, va_list); +void tty_cmd_deleteline(struct tty *, struct screen *, va_list); +void tty_cmd_clearline(struct tty *, struct screen *, va_list); +void tty_cmd_clearendofline(struct tty *, struct screen *, va_list); +void tty_cmd_clearstartofline(struct tty *, struct screen *, va_list); +void tty_cmd_cursormove(struct tty *, struct screen *, va_list); +void tty_cmd_cursormode(struct tty *, struct screen *, va_list); +void tty_cmd_reverseindex(struct tty *, struct screen *, va_list); +void tty_cmd_scrollregion(struct tty *, struct screen *, va_list); +void tty_cmd_insertmode(struct tty *, struct screen *, va_list); +void tty_cmd_mousemode(struct tty *, struct screen *, va_list); +void tty_cmd_linefeed(struct tty *, struct screen *, va_list); +void tty_cmd_carriagereturn(struct tty *, struct screen *, va_list); +void tty_cmd_bell(struct tty *, struct screen *, va_list); +void tty_cmd_clearendofscreen(struct tty *, struct screen *, va_list); +void tty_cmd_clearstartofscreen(struct tty *, struct screen *, va_list); +void tty_cmd_clearscreen(struct tty *, struct screen *, va_list); +void tty_cmd_cell(struct tty *, struct screen *, va_list); + +void (*tty_cmds[])(struct tty *, struct screen *, va_list) = { + tty_cmd_cursorup, + tty_cmd_cursordown, + tty_cmd_cursorright, + tty_cmd_cursorleft, + tty_cmd_insertcharacter, + tty_cmd_deletecharacter, + tty_cmd_insertline, + tty_cmd_deleteline, + tty_cmd_clearline, + tty_cmd_clearendofline, + tty_cmd_clearstartofline, + tty_cmd_cursormove, + tty_cmd_cursormode, + tty_cmd_reverseindex, + tty_cmd_scrollregion, + tty_cmd_insertmode, + tty_cmd_mousemode, + tty_cmd_linefeed, + tty_cmd_carriagereturn, + tty_cmd_bell, + NULL, + NULL, + tty_cmd_clearendofscreen, + tty_cmd_clearstartofscreen, + tty_cmd_clearscreen, + tty_cmd_cell, +}; TAILQ_HEAD(, tty_term) tty_terms = TAILQ_HEAD_INITIALIZER(tty_terms); @@ -55,6 +109,7 @@ tty_init(struct tty *tty, char *path, char *term) else tty->termname = xstrdup(term); tty->flags = 0; + tty->term_flags = 0; } int @@ -74,9 +129,9 @@ tty_open(struct tty *tty, char **cause) if (fcntl(tty->fd, F_SETFL, mode|O_NONBLOCK) == -1) fatal("fcntl"); - if (debug_level > 3) { + if (debug_level > 3) tty->log_fd = open("tmux.out", O_WRONLY|O_CREAT|O_TRUNC, 0644); - } else + else tty->log_fd = -1; if ((tty->term = tty_find_term(tty->termname, tty->fd, cause)) == NULL) @@ -86,10 +141,7 @@ tty_open(struct tty *tty, char **cause) tty->out = buffer_create(BUFSIZ); tty->flags &= TTY_UTF8; - - tty->attr = 0; - tty->fg = 8; - tty->bg = 8; + memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell); if (tcgetattr(tty->fd, &tty->tio) != 0) fatal("tcgetattr failed"); @@ -163,15 +215,17 @@ tty_close(struct tty *tty) fatal("tcsetattr failed"); tty_raw(tty, tparm(change_scroll_region, 0, ws.ws_row - 1)); + if (exit_alt_charset_mode != NULL) + tty_puts(tty, exit_alt_charset_mode); + if (exit_attribute_mode != NULL) + tty_raw(tty, exit_attribute_mode); + tty_raw(tty, clear_screen); if (keypad_local != NULL) tty_raw(tty, keypad_local); if (exit_ca_mode != NULL) tty_raw(tty, exit_ca_mode); - tty_raw(tty, clear_screen); if (cursor_normal != NULL) tty_raw(tty, cursor_normal); - if (exit_attribute_mode != NULL) - tty_raw(tty, exit_attribute_mode); } tty_free_term(tty->term); @@ -405,7 +459,7 @@ tty_puts(struct tty *tty, const char *s) void tty_putc(struct tty *tty, char ch) { - if (tty->attr & ATTR_CHARSET) + if (tty->cell.attr & GRID_ATTR_CHARSET) ch = tty_get_acs(tty, ch); buffer_write8(tty->out, ch); @@ -429,10 +483,6 @@ tty_set_title(struct tty *tty, const char *title) void tty_vwrite(struct tty *tty, struct screen *s, int cmd, va_list ap) { - struct utf8_data *udat; - char ch; - u_int i, ua, ub, uc; - if (tty->flags & TTY_FREEZE) return; @@ -440,273 +490,493 @@ tty_vwrite(struct tty *tty, struct screen *s, int cmd, va_list ap) return; set_curterm(tty->term->term); - switch (cmd) { - case TTY_CHARACTER: - ch = va_arg(ap, int); - - if (tty->attr & ATTR_PAD) - break; + if (tty_cmds[cmd] != NULL) + tty_cmds[cmd](tty, s, ap); +} - if ((tty->attr & ATTR_UTF8) && (tty->flags & TTY_UTF8)) { - udat = utf8_lookup( - &s->utf8_table, utf8_unpack(ch, tty->attr)); - if (udat == NULL) - ch = '_'; - else { - if (udat->data[0] == 0xff) - break; - tty_putc(tty, udat->data[0]); - if (udat->data[1] == 0xff) - break; - tty_putc(tty, udat->data[1]); - if (udat->data[2] == 0xff) - break; - tty_putc(tty, udat->data[2]); - if (udat->data[3] == 0xff) - break; - tty_putc(tty, udat->data[3]); - break; - } - } else if (tty->attr & ATTR_UTF8) - ch = '_'; +void +tty_cmd_cursorup(struct tty *tty, unused struct screen *s, va_list ap) +{ + u_int ua; - switch (ch) { - case '\n': /* LF */ - tty_putc(tty, '\n'); - break; - case '\r': /* CR */ - tty_puts(tty, carriage_return); - break; - case '\007': /* BEL */ - if (bell != NULL) - tty_puts(tty, bell); - break; - case '\010': /* BS */ - tty_puts(tty, cursor_left); - break; - default: - tty_putc(tty, ch); - break; - } - break; - case TTY_CURSORUP: - ua = va_arg(ap, u_int); - if (parm_up_cursor != NULL) - tty_puts(tty, tparm(parm_up_cursor, ua)); - else { - while (ua-- > 0) - tty_puts(tty, cursor_up); - } - break; - case TTY_CURSORDOWN: - ua = va_arg(ap, u_int); - if (parm_down_cursor != NULL) - tty_puts(tty, tparm(parm_down_cursor, ua)); - else { - while (ua-- > 0) - tty_puts(tty, cursor_down); - } - break; - case TTY_CURSORRIGHT: - ua = va_arg(ap, u_int); - if (parm_right_cursor != NULL) - tty_puts(tty, tparm(parm_right_cursor, ua)); - else { - while (ua-- > 0) - tty_puts(tty, cursor_right); - } - break; - case TTY_CURSORLEFT: - ua = va_arg(ap, u_int); - if (parm_left_cursor != NULL) - tty_puts(tty, tparm(parm_left_cursor, ua)); - else { - while (ua-- > 0) - tty_puts(tty, cursor_left); - } - break; - case TTY_CURSORMOVE: - ua = va_arg(ap, u_int); - ub = va_arg(ap, u_int); - tty_puts(tty, tparm(cursor_address, ua, ub)); - break; - case TTY_CLEARENDOFLINE: - if (clr_eol != NULL) - tty_puts(tty, clr_eol); - else { - tty_puts(tty, tparm(cursor_address, s->cy, s->cx)); - for (i = s->cx; i < screen_size_x(s); i++) - tty_putc(tty, ' '); - tty_puts(tty, tparm(cursor_address, s->cy, s->cx)); - } - break; - case TTY_CLEARSTARTOFLINE: - if (clr_bol != NULL) - tty_puts(tty, clr_bol); - else { - tty_puts(tty, tparm(cursor_address, s->cy, 0)); - for (i = 0; i < s->cx + 1; i++) - tty_putc(tty, ' '); - tty_puts(tty, tparm(cursor_address, s->cy, s->cx)); - } - break; - case TTY_CLEARLINE: - if (clr_eol != NULL) { - tty_puts(tty, tparm(cursor_address, s->cy, 0)); - tty_puts(tty, clr_eol); - tty_puts(tty, tparm(cursor_address, s->cy, s->cx)); - } else { - tty_puts(tty, tparm(cursor_address, s->cy, 0)); - for (i = 0; i < screen_size_x(s); i++) - tty_putc(tty, ' '); - tty_puts(tty, tparm(cursor_address, s->cy, s->cx)); - } - break; - case TTY_INSERTLINE: - ua = va_arg(ap, u_int); - if (parm_insert_line != NULL) - tty_puts(tty, tparm(parm_insert_line, ua)); - else { - while (ua-- > 0) - tty_puts(tty, insert_line); - } - break; - case TTY_DELETELINE: - ua = va_arg(ap, u_int); - if (parm_delete_line != NULL) - tty_puts(tty, tparm(parm_delete_line, ua)); - else { - while (ua-- > 0) - tty_puts(tty, delete_line); - } - break; - case TTY_INSERTCHARACTER: - ua = va_arg(ap, u_int); - if (parm_ich != NULL) - tty_puts(tty, tparm(parm_ich, ua)); - else if (insert_character != NULL) { - while (ua-- > 0) - tty_puts(tty, insert_character); - } else if (enter_insert_mode != NULL) { - tty_puts(tty, enter_insert_mode); - while (ua-- > 0) - tty_putc(tty, ' '); - tty_puts(tty, exit_insert_mode); - tty_puts(tty, tparm(cursor_address, s->cy, s->cx)); - } - break; - case TTY_DELETECHARACTER: - ua = va_arg(ap, u_int); - if (parm_dch != NULL) - tty_puts(tty, tparm(parm_dch, ua)); - else if (delete_character != NULL) { - while (ua-- > 0) - tty_puts(tty, delete_character); - } else { - while (ua-- > 0) - tty_putc(tty, '\010'); - } - break; - case TTY_CURSORON: - if (!(tty->flags & TTY_NOCURSOR) && cursor_normal != NULL) - tty_puts(tty, cursor_normal); - break; - case TTY_CURSOROFF: - if (cursor_invisible != NULL) - tty_puts(tty, cursor_invisible); - break; - case TTY_REVERSEINDEX: - tty_puts(tty, scroll_reverse); - break; - case TTY_SCROLLREGION: - ua = va_arg(ap, u_int); - ub = va_arg(ap, u_int); - tty_puts(tty, tparm(change_scroll_region, ua, ub)); - break; -#if 0 - case TTY_INSERTON: - if (enter_insert_mode != NULL) - tty_puts(tty, enter_insert_mode); - break; - case TTY_INSERTOFF: - if (exit_insert_mode != NULL) - tty_puts(tty, exit_insert_mode); - break; -#endif - case TTY_MOUSEOFF: - if (key_mouse != NULL) - tty_puts(tty, "\033[?1000l"); - break; - case TTY_MOUSEON: - if (key_mouse != NULL) - tty_puts(tty, "\033[?1000h"); - break; - case TTY_ATTRIBUTES: - ua = va_arg(ap, u_int); - ub = va_arg(ap, u_int); - uc = va_arg(ap, u_int); - tty_attributes(tty, ua, ub, uc); - break; + ua = va_arg(ap, u_int); + + if (parm_up_cursor != NULL) + tty_puts(tty, tparm(parm_up_cursor, ua)); + else { + while (ua-- > 0) + tty_puts(tty, cursor_up); } } void -tty_attributes(struct tty *tty, u_short attr, u_char fg, u_char bg) +tty_cmd_cursordown(struct tty *tty, unused struct screen *s, va_list ap) { - if (attr == tty->attr && fg == tty->fg && bg == tty->bg) + u_int ua; + + ua = va_arg(ap, u_int); + + if (parm_down_cursor != NULL) + tty_puts(tty, tparm(parm_down_cursor, ua)); + else { + while (ua-- > 0) + tty_puts(tty, cursor_down); + } +} + +void +tty_cmd_cursorright(struct tty *tty, unused struct screen *s, va_list ap) +{ + u_int ua; + + ua = va_arg(ap, u_int); + + if (parm_right_cursor != NULL) + tty_puts(tty, tparm(parm_right_cursor, ua)); + else { + while (ua-- > 0) + tty_puts(tty, cursor_right); + } +} + +void +tty_cmd_cursorleft(struct tty *tty, unused struct screen *s, va_list ap) +{ + u_int ua; + + ua = va_arg(ap, u_int); + + if (parm_left_cursor != NULL) + tty_puts(tty, tparm(parm_left_cursor, ua)); + else { + while (ua-- > 0) + tty_puts(tty, cursor_left); + } +} + +void +tty_cmd_insertcharacter(struct tty *tty, struct screen *s, va_list ap) +{ + u_int ua; + + ua = va_arg(ap, u_int); + + tty_reset(tty); + + if (parm_ich != NULL) + tty_puts(tty, tparm(parm_ich, ua)); + else if (insert_character != NULL) { + while (ua-- > 0) + tty_puts(tty, insert_character); + } else if (enter_insert_mode != NULL) { + tty_puts(tty, enter_insert_mode); + while (ua-- > 0) + tty_putc(tty, ' '); + tty_puts(tty, exit_insert_mode); + tty_puts(tty, tparm(cursor_address, s->cy, s->cx)); + } +} + +void +tty_cmd_deletecharacter(struct tty *tty, unused struct screen *s, va_list ap) +{ + u_int ua; + + ua = va_arg(ap, u_int); + + tty_reset(tty); + + if (parm_dch != NULL) + tty_puts(tty, tparm(parm_dch, ua)); + else if (delete_character != NULL) { + while (ua-- > 0) + tty_puts(tty, delete_character); + } else { + while (ua-- > 0) + tty_putc(tty, '\010'); + } +} + +void +tty_cmd_insertline(struct tty *tty, unused struct screen *s, va_list ap) +{ + u_int ua; + + ua = va_arg(ap, u_int); + + tty_reset(tty); + + if (parm_insert_line != NULL) + tty_puts(tty, tparm(parm_insert_line, ua)); + else { + while (ua-- > 0) + tty_puts(tty, insert_line); + } +} + +void +tty_cmd_deleteline(struct tty *tty, unused struct screen *s, va_list ap) +{ + u_int ua; + + ua = va_arg(ap, u_int); + + tty_reset(tty); + + if (parm_delete_line != NULL) + tty_puts(tty, tparm(parm_delete_line, ua)); + else { + while (ua-- > 0) + tty_puts(tty, delete_line); + } +} + +void +tty_cmd_clearline(struct tty *tty, struct screen *s, unused va_list ap) +{ + u_int i; + + tty_reset(tty); + + if (clr_eol != NULL) { + tty_puts(tty, tparm(cursor_address, s->cy, 0)); + tty_puts(tty, clr_eol); + tty_puts(tty, tparm(cursor_address, s->cy, s->cx)); + } else { + tty_puts(tty, tparm(cursor_address, s->cy, 0)); + for (i = 0; i < screen_size_x(s); i++) + tty_putc(tty, ' '); + tty_puts(tty, tparm(cursor_address, s->cy, s->cx)); + } +} + +void +tty_cmd_clearendofline(struct tty *tty, struct screen *s, unused va_list ap) +{ + u_int i; + + tty_reset(tty); + + if (clr_eol != NULL) + tty_puts(tty, clr_eol); + else { + tty_puts(tty, tparm(cursor_address, s->cy, s->cx)); + for (i = s->cx; i < screen_size_x(s); i++) + tty_putc(tty, ' '); + tty_puts(tty, tparm(cursor_address, s->cy, s->cx)); + } +} + +void +tty_cmd_clearstartofline(struct tty *tty, struct screen *s, unused va_list ap) +{ + u_int i; + + tty_reset(tty); + + if (clr_bol != NULL) + tty_puts(tty, clr_bol); + else { + tty_puts(tty, tparm(cursor_address, s->cy, 0)); + for (i = 0; i < s->cx + 1; i++) + tty_putc(tty, ' '); + tty_puts(tty, tparm(cursor_address, s->cy, s->cx)); + } +} + +void +tty_cmd_cursormove(struct tty *tty, unused struct screen *s, va_list ap) +{ + u_int ua, ub; + + ua = va_arg(ap, u_int); + ub = va_arg(ap, u_int); + + tty_puts(tty, tparm(cursor_address, ub, ua)); +} + +void +tty_cmd_cursormode(struct tty *tty, unused struct screen *s, va_list ap) +{ + u_int ua; + + if (cursor_normal == NULL || cursor_invisible == NULL) return; - /* If any bits are being cleared, reset everything. */ - if (tty->attr & ~attr) { - if ((tty->attr & ATTR_CHARSET) && exit_alt_charset_mode != NULL) - tty_puts(tty, exit_alt_charset_mode); - tty_puts(tty, exit_attribute_mode); - tty->fg = 8; - tty->bg = 8; - tty->attr = 0; - } + ua = va_arg(ap, int); + + if (ua && !(tty->flags & TTY_NOCURSOR)) + tty_puts(tty, cursor_normal); + else + tty_puts(tty, cursor_invisible); +} - /* Filter out attribute bits already set. */ - attr &= ~tty->attr; - tty->attr |= attr; +void +tty_cmd_reverseindex( + struct tty *tty, unused struct screen *s, unused va_list ap) +{ + tty_reset(tty); + tty_puts(tty, scroll_reverse); +} + +void +tty_cmd_scrollregion(struct tty *tty, unused struct screen *s, va_list ap) +{ + u_int ua, ub; + + ua = va_arg(ap, u_int); + ub = va_arg(ap, u_int); + + tty_puts(tty, tparm(change_scroll_region, ua, ub)); +} + +void +tty_cmd_insertmode(unused struct tty *tty, unused struct screen *s, va_list ap) +{ + u_int ua; + + if (enter_insert_mode == NULL || exit_insert_mode == NULL) + return; + + ua = va_arg(ap, int); + +#if 0 + if (ua) + tty_puts(tty, enter_insert_mode); + else + tty_puts(tty, exit_insert_mode); +#endif +} + +void +tty_cmd_mousemode(struct tty *tty, unused struct screen *s, va_list ap) +{ + u_int ua; + + if (key_mouse == NULL) + return; + + ua = va_arg(ap, int); + + if (ua) + tty_puts(tty, "\033[?1000h"); + else + tty_puts(tty, "\033[?1000l"); +} + +void +tty_cmd_linefeed(struct tty *tty, unused struct screen *s, unused va_list ap) +{ + tty_reset(tty); + + tty_putc(tty, '\n'); +} + +void +tty_cmd_carriagereturn( + struct tty *tty, unused struct screen *s, unused va_list ap) +{ + tty_reset(tty); + + if (carriage_return) + tty_puts(tty, carriage_return); + else + tty_putc(tty, '\r'); +} + +void +tty_cmd_bell(struct tty *tty, unused struct screen *s, unused va_list ap) +{ + if (bell) + tty_puts(tty, bell); +} + +void +tty_cmd_clearendofscreen(struct tty *tty, struct screen *s, unused va_list ap) +{ + u_int i, j; + + tty_reset(tty); + + if (clr_eol != NULL) { + for (i = s->cy; i < screen_size_y(s); i++) { + tty_puts(tty, clr_eol); + tty_puts(tty, cursor_down); + } + } else { + for (i = s->cx; i < screen_size_y(s); i++) + tty_putc(tty, ' '); + for (j = s->cy; j < screen_size_y(s); j++) { + for (i = 0; i < screen_size_x(s); i++) + tty_putc(tty, ' '); + } + } + tty_puts(tty, tparm(cursor_address, s->cy, s->cx)); +} + +void +tty_cmd_clearstartofscreen(struct tty *tty, struct screen *s, unused va_list ap) +{ + u_int i, j; + + tty_reset(tty); + + tty_puts(tty, tparm(cursor_address, 0, 0)); + if (clr_eol) { + for (i = 0; i < s->cy; i++) + tty_puts(tty, clr_eol); + tty_puts(tty, tparm(cursor_address, s->cy, 0)); + } else { + for (j = 0; j < s->cy; j++) { + for (i = 0; i < screen_size_x(s); i++) + tty_putc(tty, ' '); + } + } + for (i = 0; i < s->cx; i++) + tty_putc(tty, ' '); + tty_puts(tty, tparm(cursor_address, s->cy, s->cx)); +} + +void +tty_cmd_clearscreen(struct tty *tty, struct screen *s, unused va_list ap) +{ + u_int i, j; + + tty_reset(tty); + + if (clr_eol) { + tty_puts(tty, tparm(cursor_address, 0, 0)); + for (i = 0; i < screen_size_y(s); i++) { + tty_puts(tty, clr_eol); + tty_puts(tty, cursor_down); + } + } else { + tty_puts(tty, tparm(cursor_address, 0, 0)); + for (j = 0; j < screen_size_y(s); j++) { + for (i = 0; i < screen_size_x(s); i++) + tty_putc(tty, ' '); + } + } + tty_puts(tty, tparm(cursor_address, s->cy, s->cx)); +} + +void +tty_cmd_cell(struct tty *tty, unused struct screen *s, va_list ap) +{ + struct grid_cell *gc; + u_int i, width; + u_char out[4]; + + gc = va_arg(ap, struct grid_cell *); + + /* If this is a padding character, do nothing. */ + if (gc->flags & GRID_FLAG_PADDING) + return; + + /* Handle special characters. Should never come into this function.*/ + if (gc->data < 0x20 || gc->data == 0x7f) + return; /* Set the attributes. */ - if ((attr & ATTR_BRIGHT) && enter_bold_mode != NULL) + tty_attributes(tty, gc); + + /* If not UTF8 multibyte, write directly. */ + if (gc->data < 0xff) { + tty_putc(tty, gc->data); + return; + } + + /* If the terminal doesn't support UTF8, write _s. */ + if (!(tty->flags & TTY_UTF8)) { + width = utf8_width(gc->data); + while (width-- > 0) + tty_putc(tty, '_'); + return; + } + + /* Unpack UTF-8 and write it. */ + utf8_split(gc->data, out); + for (i = 0; i < 4; i++) { + if (out[i] == 0xff) + break; + tty_putc(tty, out[i]); + } +} + +void +tty_reset(struct tty *tty) +{ + struct grid_cell *tc = &tty->cell; + + tc->data = grid_default_cell.data; + if (memcmp(tc, &grid_default_cell, sizeof *tc) == 0) + return; + + if (exit_alt_charset_mode != NULL && tc->attr & GRID_ATTR_CHARSET) + tty_puts(tty, exit_alt_charset_mode); + tty_puts(tty, exit_attribute_mode); + memcpy(tc, &grid_default_cell, sizeof *tc); +} + +void +tty_attributes(struct tty *tty, const struct grid_cell *gc) +{ + struct grid_cell *tc = &tty->cell; + u_char changed; + + /* If any bits are being cleared, reset everything. */ + if (tc->attr & ~gc->attr) + tty_reset(tty); + + /* Filter out attribute bits already set. */ + changed = gc->attr & ~tc->attr; + tc->attr = gc->attr; + + /* Set the attributes. */ + if ((changed & GRID_ATTR_BRIGHT) && enter_bold_mode != NULL) tty_puts(tty, enter_bold_mode); - if ((attr & ATTR_DIM) && enter_dim_mode != NULL) + if ((changed & GRID_ATTR_DIM) && enter_dim_mode != NULL) tty_puts(tty, enter_dim_mode); - if ((attr & ATTR_ITALICS) && enter_standout_mode != NULL) + if ((changed & GRID_ATTR_ITALICS) && enter_standout_mode != NULL) tty_puts(tty, enter_standout_mode); - if ((attr & ATTR_UNDERSCORE) && enter_underline_mode != NULL) + if ((changed & GRID_ATTR_UNDERSCORE) && enter_underline_mode != NULL) tty_puts(tty, enter_underline_mode); - if ((attr & ATTR_BLINK) && enter_blink_mode != NULL) + if ((changed & GRID_ATTR_BLINK) && enter_blink_mode != NULL) tty_puts(tty, enter_blink_mode); - if ((attr & ATTR_REVERSE) && enter_reverse_mode != NULL) + if ((changed & GRID_ATTR_REVERSE) && enter_reverse_mode != NULL) tty_puts(tty, enter_reverse_mode); - if ((attr & ATTR_HIDDEN) && enter_secure_mode != NULL) + if ((changed & GRID_ATTR_HIDDEN) && enter_secure_mode != NULL) tty_puts(tty, enter_secure_mode); - if ((attr & ATTR_CHARSET) && enter_alt_charset_mode != NULL) + if ((changed & GRID_ATTR_CHARSET) && enter_alt_charset_mode != NULL) tty_puts(tty, enter_alt_charset_mode); /* Set foreground colour. */ - if (fg != tty->fg || attr & ATTR_FG256) - tty->fg = tty_attributes_fg(tty, fg); - + if (gc->fg != tc->fg || + (gc->flags & GRID_FLAG_FG256) != (tc->flags & GRID_FLAG_FG256)) { + tty_attributes_fg(tty, gc); + tc->fg = gc->fg; + } + /* Set background colour. */ - if (bg != tty->bg || attr & ATTR_BG256) - tty->bg = tty_attributes_bg(tty, bg); + if (gc->bg != tc->bg || + (gc->flags & GRID_FLAG_BG256) != (tc->flags & GRID_FLAG_BG256)) { + tty_attributes_bg(tty, gc); + tc->bg = gc->bg; + } } -u_char -tty_attributes_fg(struct tty *tty, u_char fg) +void +tty_attributes_fg(struct tty *tty, const struct grid_cell *gc) { char s[32]; + u_char fg = gc->fg; - if (tty->attr & ATTR_FG256) { - if (tty->term->flags & TERM_256COLOURS) { + if (gc->flags & GRID_FLAG_FG256) { + if ((tty->term->flags & TERM_256COLOURS) || + (tty->term_flags & TERM_256COLOURS)) { xsnprintf(s, sizeof s, "\033[38;5;%hhum", fg); tty_puts(tty, s); - return (fg); + return; } if (fg > 15) @@ -715,25 +985,28 @@ tty_attributes_fg(struct tty *tty, u_char fg) fg -= 8; } - if (fg == 8 && !(tty->term->flags & TERM_HASDEFAULTS)) + if (fg == 8 && + !(tty->term->flags & TERM_HASDEFAULTS) && + !(tty->term_flags & TERM_HASDEFAULTS)) fg = 7; if (fg == 8) tty_puts(tty, "\033[39m"); else if (set_a_foreground != NULL) tty_puts(tty, tparm(set_a_foreground, fg)); - return (fg); } -u_char -tty_attributes_bg(struct tty *tty, u_char bg) +void +tty_attributes_bg(struct tty *tty, const struct grid_cell *gc) { char s[32]; + u_char bg = gc->bg; - if (tty->attr & ATTR_BG256) { - if (tty->term->flags & TERM_256COLOURS) { + if (gc->flags & GRID_FLAG_BG256) { + if ((tty->term->flags & TERM_256COLOURS) || + (tty->term_flags & TERM_256COLOURS)) { xsnprintf(s, sizeof s, "\033[48;5;%hhum", bg); tty_puts(tty, s); - return (bg); + return; } if (bg > 15) @@ -742,11 +1015,12 @@ tty_attributes_bg(struct tty *tty, u_char bg) bg -= 8; } - if (bg == 8 && !(tty->term->flags & TERM_HASDEFAULTS)) + if (bg == 8 && + !(tty->term->flags & TERM_HASDEFAULTS) && + !(tty->term_flags & TERM_HASDEFAULTS)) bg = 0; if (bg == 8) tty_puts(tty, "\033[49m"); else if (set_a_background != NULL) tty_puts(tty, tparm(set_a_background, bg)); - return (bg); } diff --git a/utf8.c b/utf8.c index 77179e77..5e1c6b94 100644 --- a/utf8.c +++ b/utf8.c @@ -1,4 +1,4 @@ -/* $Id: utf8.c,v 1.1 2008-09-09 22:16:37 nicm Exp $ */ +/* $Id: utf8.c,v 1.2 2008-09-25 20:08:56 nicm Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -22,93 +22,66 @@ #include "tmux.h" -/* - * UTF8 data structures. Just crappy array + linear search for now. - */ - -/* Pack UTF8 index into attr, data. */ -void -utf8_pack(int idx, u_char *data, u_short *attr) +u_int +utf8_combine(const u_char data[4]) { - *data = idx & 0xff; + u_int uv; - *attr &= ~(ATTR_UTF8b8|ATTR_UTF8b9); - if (idx & 0x100) - *attr |= ATTR_UTF8b8; - if (idx & 0x200) - *attr |= ATTR_UTF8b9; - if (idx & 0x400) - *attr |= ATTR_UTF8b10; - if (idx & 0x800) - *attr |= ATTR_UTF8b11; -} - -/* Unpack UTF8 index from attr, data. */ -int -utf8_unpack(u_char data, u_short attr) -{ - int idx; - - idx = data; - if (attr & ATTR_UTF8b8) - idx |= 0x100; - if (attr & ATTR_UTF8b9) - idx |= 0x200; - if (attr & ATTR_UTF8b10) - idx |= 0x400; - if (attr & ATTR_UTF8b11) - idx |= 0x800; - - return (idx); -} - -void -utf8_init(struct utf8_table *utab, int limit) -{ - utab->limit = limit; - ARRAY_INIT(&utab->array); -} - -void -utf8_free(struct utf8_table *utab) -{ - ARRAY_FREE(&utab->array); -} - -struct utf8_data * -utf8_lookup(struct utf8_table *utab, int idx) -{ - if (idx < 0 || idx >= (int) ARRAY_LENGTH(&utab->array)) - return (NULL); - return (&ARRAY_ITEM(&utab->array, idx)); -} - -int -utf8_search(struct utf8_table *utab, struct utf8_data *udat) -{ - u_int idx; - - for (idx = 0; idx < ARRAY_LENGTH(&utab->array); idx++) { - if (memcmp(udat->data, - ARRAY_ITEM(&utab->array, idx).data, sizeof udat->data) == 0) - return (idx); + if (data[1] == 0xff) + uv = data[0]; + else if (data[2] == 0xff) { + uv = data[1] & 0x3f; + uv |= (data[0] & 0x1f) << 6; + } else if (data[3] == 0xff) { + uv = data[2] & 0x3f; + uv |= (data[1] & 0x3f) << 6; + uv |= (data[0] & 0x0f) << 12; + } else { + uv = data[3] & 0x3f; + uv |= (data[2] & 0x3f) << 6; + uv |= (data[1] & 0x3f) << 12; + uv |= (data[0] & 0x3f) << 18; + } + return (uv); +} + +void +utf8_split(u_int uv, u_char data[4]) +{ + memset(data, 0xff, sizeof data); + + if (uv <= 0x7f) + data[0] = uv; + else if (uv > 0x7f && uv <= 0x7ff) { + data[0] = (uv >> 6) | 0xc0; + data[1] = (uv & 0x3f) | 0x80; + } else if (uv > 0x7ff && uv <= 0xffff) { + data[0] = (uv >> 12) | 0xe0; + data[1] = ((uv >> 6) & 0x3f) | 0x80; + data[2] = (uv & 0x3f) | 0x80; + } else if (uv > 0xffff && uv <= 0x10ffff) { + data[0] = (uv >> 18) | 0xf0; + data[1] = ((uv >> 12) & 0x3f) | 0x80; + data[2] = ((uv >> 6) & 0x3f) | 0x80; + data[3] = (uv & 0x3f) | 0x80; } - return (-1); } int -utf8_add(struct utf8_table *utab, struct utf8_data *udat) +utf8_width(u_int uv) { - int idx; - - if (ARRAY_LENGTH(&utab->array) == utab->limit) - return (-1); - - if ((idx = utf8_search(utab, udat)) != -1) - return (idx); - - ARRAY_EXPAND(&utab->array, 1); - memcpy( - &ARRAY_LAST(&utab->array), udat, sizeof ARRAY_LAST(&utab->array)); - return (ARRAY_LENGTH(&utab->array) - 1); + if ((uv >= 0x1100 && uv <= 0x115f) || + uv == 0x2329 || + uv == 0x232a || + (uv >= 0x2e80 && uv <= 0xa4cf && uv != 0x303f) || + (uv >= 0xac00 && uv <= 0xd7a3) || + (uv >= 0xf900 && uv <= 0xfaff) || + (uv >= 0xfe10 && uv <= 0xfe19) || + (uv >= 0xfe30 && uv <= 0xfe6f) || + (uv >= 0xff00 && uv <= 0xff60) || + (uv >= 0xffe0 && uv <= 0xffe6) || + (uv >= 0x20000 && uv <= 0x2fffd) || + (uv >= 0x30000 && uv <= 0x3fffd)) + return (2); + return (1); } diff --git a/window-copy.c b/window-copy.c index 51d53e4a..27486ce9 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1,4 +1,4 @@ -/* $Id: window-copy.c,v 1.30 2008-09-10 19:15:04 nicm Exp $ */ +/* $Id: window-copy.c,v 1.31 2008-09-25 20:08:57 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -44,6 +44,7 @@ int window_copy_update_selection(struct window *); void window_copy_copy_selection(struct window *, struct client *); void window_copy_copy_line( struct window *, char **, size_t *, u_int, u_int, u_int); +int window_copy_is_space(struct window *, u_int, u_int); u_int window_copy_find_length(struct window *, u_int); void window_copy_cursor_start_of_line(struct window *); void window_copy_cursor_end_of_line(struct window *); @@ -58,10 +59,6 @@ void window_copy_scroll_right(struct window *, u_int); void window_copy_scroll_up(struct window *, u_int); void window_copy_scroll_down(struct window *, u_int); -const char *space_characters = " -_@"; -#define window_copy_is_space(w, x, y) \ - (strchr(space_characters, (w)->base.grid_data[y][x]) != NULL) - const struct window_mode window_copy_mode = { window_copy_init, window_copy_free, @@ -104,7 +101,7 @@ window_copy_init(struct window *w) screen_write_start(&ctx, s, NULL, NULL); for (i = 0; i < screen_size_y(s); i++) window_copy_write_line(w, &ctx, i); - screen_write_move_cursor(&ctx, data->cx, data->cy); + screen_write_cursormove(&ctx, data->cx, data->cy); screen_write_stop(&ctx); return (s); @@ -124,10 +121,12 @@ window_copy_resize(struct window *w, u_int sx, u_int sy) { struct window_copy_mode_data *data = w->modedata; struct screen *s = &data->screen; + struct screen_write_ctx ctx; screen_resize(s, sx, sy); - screen_display_copy_area(&data->screen, &w->base, - 0, 0, screen_size_x(s), screen_size_y(s), data->ox, data->oy); + screen_write_start(&ctx, s, NULL, NULL); + window_copy_write_lines(w, &ctx, 0, screen_size_y(s) - 1); + screen_write_stop(&ctx); window_copy_update_selection(w); } @@ -156,8 +155,8 @@ window_copy_key(struct window *w, struct client *c, int key) window_copy_cursor_down(w); return; case MODEKEY_PPAGE: - if (data->oy + screen_size_y(s) > w->base.hsize) - data->oy = w->base.hsize; + if (data->oy + screen_size_y(s) > screen_hsize(&w->base)) + data->oy = screen_hsize(&w->base); else data->oy += screen_size_y(s); window_copy_update_selection(w); @@ -202,44 +201,38 @@ window_copy_key(struct window *w, struct client *c, int key) } void -window_copy_write_line( - struct window *w, struct screen_write_ctx *ctx, u_int py) +window_copy_write_line(struct window *w, struct screen_write_ctx *ctx, u_int py) { struct window_copy_mode_data *data = w->modedata; struct screen *s = &data->screen; + struct grid_cell gc; + char hdr[32]; size_t size; if (py == 0) { - screen_write_set_attributes( - ctx, ATTR_BRIGHT|ATTR_REVERSE, 8, 8); - screen_write_move_cursor(ctx, 0, 0); - size = screen_write_put_string_rjust( - ctx, "[%u,%u/%u]", data->ox, data->oy, w->base.hsize); - screen_write_set_attributes(ctx, 0, 8, 8); + memcpy(&gc, &grid_default_cell, sizeof gc); + size = xsnprintf(hdr, sizeof hdr, + "[%u,%u/%u]", data->ox, data->oy, screen_hsize(&w->base)); + gc.attr |= GRID_ATTR_BRIGHT|GRID_ATTR_REVERSE; + screen_write_cursormove(ctx, screen_size_x(s) - size, 0); + screen_write_puts(ctx, &gc, "%s", hdr); + gc.attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_REVERSE); } else size = 0; - screen_write_move_cursor(ctx, 0, py); - screen_write_copy_area( - ctx, &w->base, screen_size_x(s) - size, 1, data->ox, data->oy); + + screen_write_cursormove(ctx, 0, py); + screen_write_copy(ctx, &w->base, data->ox, (screen_hsize(&w->base) - + data->oy) + py, screen_size_x(s) - size, 1); } void window_copy_write_lines( struct window *w, struct screen_write_ctx *ctx, u_int py, u_int ny) { - struct window_copy_mode_data *data = w->modedata; - struct screen *s = &data->screen; + u_int yy; - if (py == 0) { - window_copy_write_line(w, ctx, 0); - if (ny == 1) - return; - py++; - ny--; - } - screen_write_move_cursor(ctx, 0, py); - screen_write_copy_area( - ctx, &w->base, screen_size_x(s), ny, data->ox, data->oy); + for (yy = py; yy < py + ny; yy++) + window_copy_write_line(w, ctx, py); } void @@ -249,21 +242,19 @@ window_copy_write_column( struct window_copy_mode_data *data = w->modedata; struct screen *s = &data->screen; - screen_write_move_cursor(ctx, px, 0); - screen_write_copy_area( - ctx, &w->base, 1, screen_size_y(s), data->ox, data->oy); + screen_write_cursormove(ctx, px, 0); + screen_write_copy(ctx, &w->base, + data->ox, screen_hsize(&w->base) - data->oy, 1, screen_size_y(s)); } void window_copy_write_columns( struct window *w, struct screen_write_ctx *ctx, u_int px, u_int nx) { - struct window_copy_mode_data *data = w->modedata; - struct screen *s = &data->screen; + u_int xx; - screen_write_move_cursor(ctx, px, 0); - screen_write_copy_area( - ctx, &w->base, nx, screen_size_y(s), data->ox, data->oy); + for (xx = px; xx < px + nx; xx++) + window_copy_write_column(w, ctx, px); } void @@ -276,7 +267,7 @@ window_copy_redraw_lines(struct window *w, u_int py, u_int ny) screen_write_start_window(&ctx, w); for (i = py; i < py + ny; i++) window_copy_write_line(w, &ctx, i); - screen_write_move_cursor(&ctx, data->cx, data->cy); + screen_write_cursormove(&ctx, data->cx, data->cy); screen_write_stop(&ctx); } @@ -295,7 +286,7 @@ window_copy_update_cursor(struct window *w) struct screen_write_ctx ctx; screen_write_start_window(&ctx, w); - screen_write_move_cursor(&ctx, data->cx, data->cy); + screen_write_cursormove(&ctx, data->cx, data->cy); screen_write_stop(&ctx); } @@ -305,8 +296,8 @@ window_copy_start_selection(struct window *w) struct window_copy_mode_data *data = w->modedata; struct screen *s = &data->screen; - data->selx = screen_x(&w->base, data->cx) + data->ox; - data->sely = screen_y(&w->base, data->cy) - data->oy; + data->selx = data->cx + data->ox; + data->sely = screen_hsize(&w->base) + data->cy - data->oy; s->sel.flag = 1; window_copy_update_selection(w); @@ -323,8 +314,8 @@ window_copy_update_selection(struct window *w) return (0); /* Find top-left of screen. */ - tx = screen_x(&w->base, 0) + data->ox; - ty = screen_y(&w->base, 0) - data->oy; + tx = data->ox; + ty = screen_hsize(&w->base) - data->oy; /* Adjust the selection. */ sx = data->selx; @@ -333,28 +324,26 @@ window_copy_update_selection(struct window *w) /* Above it. */ sx = 0; sy = 0; - } else if (sy > ty + screen_last_y(s)) { + } else if (sy > ty + screen_size_y(s) - 1) { /* Below it. */ - sx = screen_last_x(s); - sy = screen_last_y(s); + sx = screen_size_x(s) - 1; + sy = screen_size_y(s) - 1; } else if (sx < tx) { /* To the left. */ sx = 0; - } else if (sx > tx + screen_last_x(s)) { + } else if (sx > tx + screen_size_x(s) - 1) { /* To the right. */ sx = 0; sy++; - if (sy > screen_last_y(s)) - sy = screen_last_y(s); + if (sy > screen_size_y(s) - 1) + sy = screen_size_y(s) - 1; } else { sx -= tx; sy -= ty; } - sx = screen_x(s, sx); - sy = screen_x(s, sy); + sy = screen_hsize(s) + sy; - screen_set_selection( - s, sx, sy, screen_x(s, data->cx), screen_y(s, data->cy)); + screen_set_selection(s, sx, sy, data->cx, screen_hsize(s) + data->cy); return (1); } @@ -381,8 +370,8 @@ window_copy_copy_selection(struct window *w, struct client *c) */ /* Find start and end. */ - xx = screen_x(&w->base, data->cx) + data->ox; - yy = screen_y(&w->base, data->cy) - data->oy; + xx = data->cx + data->ox; + yy = screen_hsize(&w->base) + data->cy - data->oy; if (xx < data->selx || (yy == data->sely && xx < data->selx)) { sx = xx; sy = yy; ex = data->selx; ey = data->sely; @@ -425,7 +414,8 @@ void window_copy_copy_line( struct window *w, char **buf, size_t *off, u_int sy, u_int sx, u_int ex) { - u_char i, xx; + const struct grid_cell *gc; + u_char i, j, xx, data[4]; if (sx > ex) return; @@ -438,9 +428,15 @@ window_copy_copy_line( if (sx < ex) { for (i = sx; i < ex; i++) { - *buf = xrealloc(*buf, 1, (*off) + 1); - (*buf)[*off] = w->base.grid_data[sy][i]; - (*off)++; + gc = grid_peek_cell(w->base.grid, i, sy); + utf8_split(gc->data, data); + + *buf = xrealloc(*buf, 1, (*off) + 4); + for (j = 0; j < sizeof data; j++) { + if (data[j] == 0xff) + break; + (*buf)[(*off)++] = data[j]; + } } } @@ -449,14 +445,33 @@ window_copy_copy_line( (*off)++; } +int +window_copy_is_space(struct window *w, u_int px, u_int py) +{ + const struct grid_cell *gc; + const char *spaces = " -_@"; + + gc = grid_peek_cell(w->base.grid, px, py); + if (gc->flags & GRID_FLAG_PADDING) + return (0); + if (gc->data == 0x00 || gc->data > 0xff) + return (0); + return (strchr(spaces, gc->data) != NULL); +} + u_int window_copy_find_length(struct window *w, u_int py) { - u_int px; + const struct grid_cell *gc; + u_int px; - px = w->base.grid_size[py]; - while (px > 0 && w->base.grid_data[py][px - 1] == ' ') + px = w->base.grid->size[py]; + while (px > 0) { + gc = grid_peek_cell(w->base.grid, px - 1, py); + if (gc->data != 0x20) + break; px--; + } return (px); } @@ -482,32 +497,32 @@ window_copy_cursor_end_of_line(struct window *w) struct screen *s = &data->screen; u_int px, py; - py = screen_y(&w->base, data->cy) - data->oy; + py = screen_hsize(&w->base) + data->cy - data->oy; px = window_copy_find_length(w, py); /* On screen. */ - if (px > data->ox && px <= data->ox + screen_last_x(s)) + if (px > data->ox && px <= data->ox + screen_size_x(s) - 1) data->cx = px - data->ox; /* Off right of screen. */ - if (px > data->ox + screen_last_x(s)) { + if (px > data->ox + screen_size_x(s) - 1) { /* Move cursor to last and scroll screen. */ - window_copy_scroll_left(w, - px - data->ox - screen_last_x(s)); - data->cx = screen_last_x(s); + window_copy_scroll_left( + w, px - data->ox - (screen_size_x(s) - 1)); + data->cx = screen_size_x(s) - 1; } /* Off left of screen. */ if (px <= data->ox) { - if (px < screen_last_x(s)) { + if (px < screen_size_x(s) - 1) { /* Short enough to fit on screen. */ window_copy_scroll_right(w, data->ox); data->cx = px; } else { /* Too long to fit on screen. */ window_copy_scroll_right( - w, data->ox - (px - screen_last_x(s))); - data->cx = screen_last_x(s); + w, data->ox - (px - (screen_size_x(s) - 1))); + data->cx = screen_size_x(s) - 1; } } @@ -544,7 +559,7 @@ window_copy_cursor_right(struct window *w) struct window_copy_mode_data *data = w->modedata; u_int px, py; - py = screen_y(&w->base, data->cy) - data->oy; + py = screen_hsize(&w->base) + data->cy - data->oy; px = window_copy_find_length(w, py); if (data->cx >= px) { @@ -565,7 +580,7 @@ window_copy_cursor_up(struct window *w) struct window_copy_mode_data *data = w->modedata; u_int ox, oy, px, py; - oy = screen_y(&w->base, data->cy) - data->oy; + oy = screen_hsize(&w->base) + data->cy - data->oy; ox = window_copy_find_length(w, oy); if (data->cy == 0) @@ -578,7 +593,7 @@ window_copy_cursor_up(struct window *w) window_copy_update_cursor(w); } - py = screen_y(&w->base, data->cy) - data->oy; + py = screen_hsize(&w->base) + data->cy - data->oy; px = window_copy_find_length(w, py); if (data->cx + data->ox >= px || data->cx + data->ox >= ox) @@ -592,10 +607,10 @@ window_copy_cursor_down(struct window *w) struct screen *s = &data->screen; u_int ox, oy, px, py; - oy = screen_y(&w->base, data->cy) - data->oy; + oy = screen_hsize(&w->base) + data->cy - data->oy; ox = window_copy_find_length(w, oy); - if (data->cy == screen_last_y(s)) + if (data->cy == screen_size_y(s) - 1) window_copy_scroll_up(w, 1); else { data->cy++; @@ -605,7 +620,7 @@ window_copy_cursor_down(struct window *w) window_copy_update_cursor(w); } - py = screen_y(&w->base, data->cy) - data->oy; + py = screen_hsize(&w->base) + data->cy - data->oy; px = window_copy_find_length(w, py); if (data->cx + data->ox >= px || data->cx + data->ox >= ox) @@ -620,7 +635,7 @@ window_copy_cursor_next_word(struct window *w) u_int px, py, xx, skip; px = data->ox + data->cx; - py = screen_y(&w->base, data->cy) - data->oy; + py = screen_hsize(&w->base) + data->cy - data->oy; xx = window_copy_find_length(w, py); skip = 1; @@ -638,7 +653,7 @@ window_copy_cursor_next_word(struct window *w) } while (px >= xx) { - if (data->cy == screen_last_y(s)) { + if (data->cy == screen_size_y(s) - 1) { if (data->oy == 0) goto out; } @@ -646,7 +661,8 @@ window_copy_cursor_next_word(struct window *w) px = 0; window_copy_cursor_down(w); - py = screen_y(&w->base, data->cy) - data->oy; + py =screen_hsize( + &w->base) + data->cy - data->oy; xx = window_copy_find_length(w, py); } } @@ -666,28 +682,28 @@ window_copy_cursor_next_word(struct window *w) out: /* On screen. */ - if (px > data->ox && px <= data->ox + screen_last_x(s)) + if (px > data->ox && px <= data->ox + screen_size_x(s) - 1) data->cx = px - data->ox; /* Off right of screen. */ - if (px > data->ox + screen_last_x(s)) { + if (px > data->ox + screen_size_x(s) - 1) { /* Move cursor to last and scroll screen. */ - window_copy_scroll_left(w, - px - data->ox - screen_last_x(s)); - data->cx = screen_last_x(s); + window_copy_scroll_left( + w, px - data->ox - (screen_size_x(s) - 1)); + data->cx = screen_size_x(s) - 1; } /* Off left of screen. */ if (px <= data->ox) { - if (px < screen_last_x(s)) { + if (px < screen_size_x(s) - 1) { /* Short enough to fit on screen. */ window_copy_scroll_right(w, data->ox); data->cx = px; } else { /* Too long to fit on screen. */ window_copy_scroll_right( - w, data->ox - (px - screen_last_x(s))); - data->cx = screen_last_x(s); + w, data->ox - (px - (screen_size_x(s) - 1))); + data->cx = screen_size_x(s) - 1; } } @@ -705,7 +721,7 @@ window_copy_cursor_previous_word(struct window *w) u_int ox, px, py, skip; ox = px = data->ox + data->cx; - py = screen_y(&w->base, data->cy) - data->oy; + py = screen_hsize(&w->base) + data->cy - data->oy; skip = 1; if (px != 0) { @@ -719,13 +735,15 @@ window_copy_cursor_previous_word(struct window *w) break; while (px == 0) { - if (data->cy == 0 && (w->base.hsize == 0 || - data->oy >= w->base.hsize - 1)) + if (data->cy == 0 && + (screen_hsize(&w->base) == 0 || + data->oy >= screen_hsize(&w->base) - 1)) goto out; window_copy_cursor_up(w); - py = screen_y(&w->base, data->cy) - data->oy; + py = screen_hsize( + &w->base) + data->cy - data->oy; px = window_copy_find_length(w, py); } goto out; @@ -746,28 +764,28 @@ window_copy_cursor_previous_word(struct window *w) out: /* On screen. */ - if (px > data->ox && px <= data->ox + screen_last_x(s)) + if (px > data->ox && px <= data->ox + screen_size_x(s) - 1) data->cx = px - data->ox; /* Off right of screen. */ - if (px > data->ox + screen_last_x(s)) { + if (px > data->ox + screen_size_x(s) - 1) { /* Move cursor to last and scroll screen. */ - window_copy_scroll_left(w, - px - data->ox - screen_last_x(s)); - data->cx = screen_last_x(s); + window_copy_scroll_left( + w, px - data->ox - (screen_size_x(s) - 1)); + data->cx = screen_size_x(s) - 1; } /* Off left of screen. */ if (px <= data->ox) { - if (px < screen_last_x(s)) { + if (px < screen_size_x(s) - 1) { /* Short enough to fit on screen. */ window_copy_scroll_right(w, data->ox); data->cx = px; } else { /* Too long to fit on screen. */ window_copy_scroll_right( - w, data->ox - (px - screen_last_x(s))); - data->cx = screen_last_x(s); + w, data->ox - (px - (screen_size_x(s) - 1))); + data->cx = screen_size_x(s) - 1; } } @@ -794,8 +812,8 @@ window_copy_scroll_left(struct window *w, u_int nx) screen_write_start_window(&ctx, w); for (i = 1; i < screen_size_y(s); i++) { - screen_write_move_cursor(&ctx, 0, i); - screen_write_delete_characters(&ctx, nx); + screen_write_cursormove(&ctx, 0, i); + screen_write_deletecharacter(&ctx, nx); } window_copy_write_columns(w, &ctx, screen_size_x(s) - nx, nx); window_copy_write_line(w, &ctx, 0); @@ -803,7 +821,7 @@ window_copy_scroll_left(struct window *w, u_int nx) window_copy_update_selection(w); window_copy_write_lines(w, &ctx, data->cy, 1); } - screen_write_move_cursor(&ctx, data->cx, data->cy); + screen_write_cursormove(&ctx, data->cx, data->cy); screen_write_stop(&ctx); } @@ -824,14 +842,14 @@ window_copy_scroll_right(struct window *w, u_int nx) screen_write_start_window(&ctx, w); for (i = 1; i < screen_size_y(s); i++) { - screen_write_move_cursor(&ctx, 0, i); - screen_write_insert_characters(&ctx, nx); + screen_write_cursormove(&ctx, 0, i); + screen_write_insertcharacter(&ctx, nx); } window_copy_write_columns(w, &ctx, 0, nx); window_copy_write_line(w, &ctx, 0); if (s->sel.flag) - window_copy_write_lines(w, &ctx, data->cy, 1); - screen_write_move_cursor(&ctx, data->cx, data->cy); + window_copy_write_line(w, &ctx, data->cy); + screen_write_cursormove(&ctx, data->cx, data->cy); screen_write_stop(&ctx); } @@ -850,13 +868,13 @@ window_copy_scroll_up(struct window *w, u_int ny) window_copy_update_selection(w); screen_write_start_window(&ctx, w); - screen_write_move_cursor(&ctx, 0, 0); - screen_write_delete_lines(&ctx, ny); + screen_write_cursormove(&ctx, 0, 0); + screen_write_deleteline(&ctx, ny); window_copy_write_lines(w, &ctx, screen_size_y(s) - ny, ny); window_copy_write_line(w, &ctx, 0); if (s->sel.flag && screen_size_y(s) > ny) - window_copy_write_lines(w, &ctx, screen_size_y(s) - ny - 1, 1); - screen_write_move_cursor(&ctx, data->cx, data->cy); + window_copy_write_line(w, &ctx, screen_size_y(s) - ny - 1); + screen_write_cursormove(&ctx, data->cx, data->cy); screen_write_stop(&ctx); } @@ -867,24 +885,24 @@ window_copy_scroll_down(struct window *w, u_int ny) struct screen *s = &data->screen; struct screen_write_ctx ctx; - if (ny > w->base.hsize) + if (ny > screen_hsize(&w->base)) return; - if (data->oy > w->base.hsize - ny) - ny = w->base.hsize - data->oy; + if (data->oy > screen_hsize(&w->base) - ny) + ny = screen_hsize(&w->base) - data->oy; if (ny == 0) return; data->oy += ny; window_copy_update_selection(w); screen_write_start_window(&ctx, w); - screen_write_move_cursor(&ctx, 0, 0); - screen_write_insert_lines(&ctx, ny); + screen_write_cursormove(&ctx, 0, 0); + screen_write_insertline(&ctx, ny); window_copy_write_lines(w, &ctx, 0, ny); if (s->sel.flag && screen_size_y(s) > ny) - window_copy_write_lines(w, &ctx, ny, 1); + window_copy_write_line(w, &ctx, ny); else if (ny == 1) /* nuke position */ window_copy_write_line(w, &ctx, 1); - screen_write_move_cursor(&ctx, data->cx, data->cy); + screen_write_cursormove(&ctx, data->cx, data->cy); screen_write_stop(&ctx); } diff --git a/window-more.c b/window-more.c index 65a926ed..1bda266c 100644 --- a/window-more.c +++ b/window-more.c @@ -1,4 +1,4 @@ -/* $Id: window-more.c,v 1.18 2008-09-10 19:15:04 nicm Exp $ */ +/* $Id: window-more.c,v 1.19 2008-09-25 20:08:57 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -62,7 +62,7 @@ window_more_vadd(struct window *w, const char *fmt, va_list ap) screen_write_start_window(&ctx, w); size = ARRAY_LENGTH(&data->list) - 1; - if (size >= data->top && size <= data->top + screen_last_y(s)) { + if (size >= data->top && size <= data->top + screen_size_y(s) - 1) { window_more_write_line(w, &ctx, size - data->top); if (size != data->top) window_more_write_line(w, &ctx, 0); @@ -164,27 +164,30 @@ window_more_write_line(struct window *w, struct screen_write_ctx *ctx, u_int py) { struct window_more_mode_data *data = w->modedata; struct screen *s = &data->screen; - char *msg; + struct grid_cell gc; + char *msg, hdr[32]; size_t size; + memcpy(&gc, &grid_default_cell, sizeof gc); + if (py == 0) { - screen_write_set_attributes( - ctx, ATTR_BRIGHT|ATTR_REVERSE, 8, 8); - screen_write_move_cursor(ctx, 0, 0); - size = screen_write_put_string_rjust( - ctx, "[%u/%u]", data->top, ARRAY_LENGTH(&data->list)); + size = xsnprintf(hdr, sizeof hdr, + "[%u/%u]", data->top, ARRAY_LENGTH(&data->list)); + screen_write_cursormove(ctx, screen_size_x(s) - size, 0); + gc.attr |= GRID_ATTR_BRIGHT|GRID_ATTR_REVERSE; + screen_write_puts(ctx, &gc, "%s", hdr); + gc.attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_REVERSE); } else size = 0; - screen_write_set_attributes(ctx, 0, 8, 8); - screen_write_move_cursor(ctx, 0, py); + screen_write_cursormove(ctx, 0, py); if (data->top + py < ARRAY_LENGTH(&data->list)) { msg = ARRAY_ITEM(&data->list, data->top + py); - screen_write_put_string( - ctx, "%.*s", (int) (screen_size_x(s) - size), msg); + screen_write_puts( + ctx, &gc, "%.*s", (int) (screen_size_x(s) - size), msg); } while (s->cx < screen_size_x(s) - size) - screen_write_put_character(ctx, ' '); + screen_write_putc(ctx, &gc, ' '); } void @@ -212,8 +215,8 @@ window_more_scroll_up(struct window *w) data->top--; screen_write_start_window(&ctx, w); - screen_write_move_cursor(&ctx, 0, 0); - screen_write_insert_lines(&ctx, 1); + screen_write_cursormove(&ctx, 0, 0); + screen_write_insertline(&ctx, 1); window_more_write_line(w, &ctx, 0); window_more_write_line(w, &ctx, 1); screen_write_stop(&ctx); @@ -231,9 +234,9 @@ window_more_scroll_down(struct window *w) data->top++; screen_write_start_window(&ctx, w); - screen_write_move_cursor(&ctx, 0, 0); - screen_write_delete_lines(&ctx, 1); - window_more_write_line(w, &ctx, screen_last_y(s)); + screen_write_cursormove(&ctx, 0, 0); + screen_write_deleteline(&ctx, 1); + window_more_write_line(w, &ctx, screen_size_y(s) - 1); window_more_write_line(w, &ctx, 0); screen_write_stop(&ctx); } diff --git a/window-scroll.c b/window-scroll.c index 09f5b1e7..210f66f2 100644 --- a/window-scroll.c +++ b/window-scroll.c @@ -1,4 +1,4 @@ -/* $Id: window-scroll.c,v 1.23 2008-09-10 19:15:05 nicm Exp $ */ +/* $Id: window-scroll.c,v 1.24 2008-09-25 20:08:57 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -90,10 +90,14 @@ window_scroll_resize(struct window *w, u_int sx, u_int sy) { struct window_scroll_mode_data *data = w->modedata; struct screen *s = &data->screen; + struct screen_write_ctx ctx; + u_int i; screen_resize(s, sx, sy); - screen_display_copy_area(&data->screen, &w->base, - 0, 0, screen_size_x(s), screen_size_y(s), data->ox, data->oy); + screen_write_start(&ctx, s, NULL, NULL); + for (i = 0; i < screen_size_y(s); i++) + window_scroll_write_line(w, &ctx, i); + screen_write_stop(&ctx); } void @@ -121,8 +125,8 @@ window_scroll_key(struct window *w, struct client *c, int key) window_scroll_scroll_down(w); break; case MODEKEY_PPAGE: - if (data->oy + screen_size_y(s) > w->base.hsize) - data->oy = w->base.hsize; + if (data->oy + screen_size_y(s) > screen_hsize(&w->base)) + data->oy = screen_hsize(&w->base); else data->oy += screen_size_y(s); window_scroll_redraw_screen(w); @@ -145,19 +149,24 @@ window_scroll_write_line( { struct window_scroll_mode_data *data = w->modedata; struct screen *s = &data->screen; + struct grid_cell gc; + char hdr[32]; size_t size; if (py == 0) { - screen_write_set_attributes( - ctx, ATTR_BRIGHT|ATTR_REVERSE, 8, 8); - screen_write_move_cursor(ctx, 0, 0); - size = screen_write_put_string_rjust( - ctx, "[%u,%u/%u]", data->ox, data->oy, w->base.hsize); + memcpy(&gc, &grid_default_cell, sizeof gc); + size = xsnprintf(hdr, sizeof hdr, + "[%u,%u/%u]", data->ox, data->oy, screen_hsize(&w->base)); + gc.attr |= GRID_ATTR_BRIGHT|GRID_ATTR_REVERSE; + screen_write_cursormove(ctx, screen_size_x(s) - size, 0); + screen_write_puts(ctx, &gc, "%s", hdr); + gc.attr &= ~(GRID_ATTR_BRIGHT|GRID_ATTR_REVERSE); } else size = 0; - screen_write_move_cursor(ctx, 0, py); - screen_write_copy_area( - ctx, &w->base, screen_size_x(s) - size, 1, data->ox, data->oy); + + screen_write_cursormove(ctx, 0, py); + screen_write_copy(ctx, &w->base, data->ox, (screen_hsize(&w->base) - + data->oy) + py, screen_size_x(s) - size, 1); } void @@ -167,9 +176,9 @@ window_scroll_write_column( struct window_scroll_mode_data *data = w->modedata; struct screen *s = &data->screen; - screen_write_move_cursor(ctx, px, 0); - screen_write_copy_area( - ctx, &w->base, 1, screen_size_y(s), data->ox, data->oy); + screen_write_cursormove(ctx, px, 0); + screen_write_copy(ctx, &w->base, data->ox + px, + screen_hsize(&w->base) - data->oy, 1, screen_size_y(s)); } void @@ -192,13 +201,13 @@ window_scroll_scroll_up(struct window *w) struct window_scroll_mode_data *data = w->modedata; struct screen_write_ctx ctx; - if (data->oy >= w->base.hsize) + if (data->oy >= screen_hsize(&w->base)) return; data->oy++; screen_write_start_window(&ctx, w); - screen_write_move_cursor(&ctx, 0, 0); - screen_write_insert_lines(&ctx, 1); + screen_write_cursormove(&ctx, 0, 0); + screen_write_insertline(&ctx, 1); window_scroll_write_line(w, &ctx, 0); window_scroll_write_line(w, &ctx, 1); screen_write_stop(&ctx); @@ -216,9 +225,9 @@ window_scroll_scroll_down(struct window *w) data->oy--; screen_write_start_window(&ctx, w); - screen_write_move_cursor(&ctx, 0, 0); - screen_write_delete_lines(&ctx, 1); - window_scroll_write_line(w, &ctx, screen_last_y(s)); + screen_write_cursormove(&ctx, 0, 0); + screen_write_deleteline(&ctx, 1); + window_scroll_write_line(w, &ctx, screen_size_y(s) - 1); window_scroll_write_line(w, &ctx, 0); screen_write_stop(&ctx); } @@ -237,10 +246,10 @@ window_scroll_scroll_right(struct window *w) screen_write_start_window(&ctx, w); for (i = 1; i < screen_size_y(s); i++) { - screen_write_move_cursor(&ctx, 0, i); - screen_write_delete_characters(&ctx, 1); + screen_write_cursormove(&ctx, 0, i); + screen_write_deletecharacter(&ctx, 1); } - window_scroll_write_column(w, &ctx, screen_last_x(s)); + window_scroll_write_column(w, &ctx, screen_size_x(s) - 1); window_scroll_write_line(w, &ctx, 0); screen_write_stop(&ctx); } @@ -259,8 +268,8 @@ window_scroll_scroll_left(struct window *w) screen_write_start_window(&ctx, w); for (i = 1; i < screen_size_y(s); i++) { - screen_write_move_cursor(&ctx, 0, i); - screen_write_insert_characters(&ctx, 1); + screen_write_cursormove(&ctx, 0, i); + screen_write_insertcharacter(&ctx, 1); } window_scroll_write_column(w, &ctx, 0); window_scroll_write_line(w, &ctx, 0);