summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES12
-rw-r--r--GNUmakefile8
-rw-r--r--Makefile5
-rw-r--r--TODO125
-rw-r--r--cmd-list-windows.c23
-rw-r--r--grid-view.c199
-rw-r--r--grid.c353
-rw-r--r--input.c362
-rw-r--r--log.c5
-rw-r--r--screen-display.c477
-rw-r--r--screen-redraw.c118
-rw-r--r--screen-write.c737
-rw-r--r--screen.c365
-rw-r--r--server-msg.c6
-rw-r--r--server.c28
-rw-r--r--status.c127
-rw-r--r--tmux.111
-rw-r--r--tmux.c12
-rw-r--r--tmux.h379
-rw-r--r--tty.c780
-rw-r--r--utf8.c133
-rw-r--r--window-copy.c264
-rw-r--r--window-more.c39
-rw-r--r--window-scroll.c63
24 files changed, 2342 insertions, 2289 deletions
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 <nicm@users.sourceforge.net>
@@ -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 <nicm@users.sourceforge.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <string.h>
+
+#include "tmux.h"
+
+/*
+ * 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 <nicm@users.sourceforge.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <string.h>
+
+#include "tmux.h"
+
+/*
+ * 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 <nicm@users.sourceforge.net>
@@ -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;
+
+ ARRAY_INIT(&ictx->args);
- w->ictx.string_len = 0;
- w->ictx.string_buf = NULL;
+ ictx->string_len = 0;
+ ictx->string_buf = NULL;
- input_state(&w->ictx, input_state_first);
+ 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);