Implement a bunch of escape codes.

Bash command line editing and gdb is pretty much there.  Emacs, vi and even less
need more work.
Kristian Høgsberg 16 years ago
parent 73f4e760a2
commit dbd54640f4
  1. 168
      terminal.c

@ -55,7 +55,7 @@ struct terminal {
struct wl_display *display;
int redraw_scheduled, redraw_pending;
char *data;
int width, height, tail, row, column, total_rows;
int width, height, start, row, column;
int fd, master;
struct buffer *buffer;
GIOChannel *channel;
@ -66,12 +66,22 @@ struct terminal {
int margin;
};
static char *
terminal_get_row(struct terminal *terminal, int row)
{
int index;
index = (row + terminal->start) % terminal->height;
return &terminal->data[index * (terminal->width + 1)];
}
static void
terminal_resize(struct terminal *terminal, int width, int height)
{
size_t size;
char *data;
int i, l, total_rows, row, tail;
int i, l, total_rows, start;
if (terminal->width == width && terminal->height == height)
return;
@ -85,34 +95,30 @@ terminal_resize(struct terminal *terminal, int width, int height)
else
l = width;
if (terminal->total_rows > height) {
if (terminal->height > height) {
total_rows = height;
tail = terminal->tail + terminal->total_rows - height;
start = terminal->height - height;
} else {
total_rows = terminal->total_rows;
tail = terminal->tail;
total_rows = terminal->height;
start = 0;
}
for (i = 0; i < total_rows; i++) {
row = (tail + i) % terminal->height;
for (i = 0; i < total_rows; i++)
memcpy(data + (width + 1) * i,
&terminal->data[row * (terminal->width + 1)], l);
}
terminal_get_row(terminal, i), l);
free(terminal->data);
} else {
total_rows = 1;
}
terminal->width = width;
terminal->height = height;
terminal->data = data;
terminal->total_rows = total_rows;
terminal->row = total_rows - 1;
if (terminal->row >= terminal->height)
terminal->row = terminal->height - 1;
if (terminal->column >= terminal->width)
terminal->column = terminal->width - 1;
terminal->tail = 0;
terminal->start = 0;
}
static void
@ -122,7 +128,7 @@ terminal_draw_contents(struct terminal *terminal)
cairo_surface_t *surface;
cairo_t *cr;
cairo_font_extents_t extents;
int i, row;
int i;
window_get_child_rectangle(terminal->window, &rectangle);
@ -141,11 +147,10 @@ terminal_draw_contents(struct terminal *terminal)
cairo_set_font_size(cr, 14);
cairo_font_extents(cr, &extents);
for (i = 0; i < terminal->total_rows; i++) {
row = (terminal->tail + i) % terminal->height;
for (i = 0; i < terminal->height; i++) {
cairo_move_to(cr, terminal->margin,
terminal->margin + extents.ascent + extents.height * i);
cairo_show_text(cr, &terminal->data[row * (terminal->width + 1)]);
cairo_show_text(cr, terminal_get_row(terminal, i));
}
cairo_destroy(cr);
@ -219,30 +224,93 @@ terminal_schedule_redraw(struct terminal *terminal)
}
}
static void
terminal_data(struct terminal *terminal, const char *data, size_t length);
static void
handle_escape(struct terminal *terminal)
{
char *row;
int i, j;
char *row, *p;
int i, count;
int args[10], set[10] = { 0, };
terminal->escape[terminal->escape_length++] = '\0';
if (strcmp(terminal->escape, "\e[J") == 0) {
row = &terminal->data[terminal->row * (terminal->width + 1)];
memset(&row[terminal->column], 0, terminal->width - terminal->column);
for (i = terminal->total_rows; i < terminal->height; i++) {
j = terminal->row + i;
if (j >= terminal->height)
j -= terminal->height;
row = &terminal->data[j * (terminal->width + 1)];
memset(row, 0, terminal->width);
i = 0;
p = &terminal->escape[2];
while ((isdigit(*p) || *p == ';') && i < 10) {
if (*p == ';') {
p++;
i++;
} else {
args[i] = strtol(p, &p, 10);
set[i] = 1;
}
} else if (strcmp(terminal->escape, "\e[H") == 0) {
terminal->row = terminal->tail;
terminal->total_rows = 1;
terminal->column = 0;
}
switch (*p) {
case 'A':
count = set[0] ? args[0] : 1;
if (terminal->row - count >= 0)
terminal->row -= count;
else
terminal->row = 0;
break;
case 'B':
count = set[0] ? args[0] : 1;
if (terminal->row + count < terminal->height)
terminal->row += count;
else
terminal->row = terminal->height;
break;
case 'C':
count = set[0] ? args[0] : 1;
if (terminal->column + count < terminal->width)
terminal->column += count;
else
terminal->column = terminal->width;
break;
case 'D':
count = set[0] ? args[0] : 1;
if (terminal->column - count >= 0)
terminal->column -= count;
else
terminal->column = 0;
break;
case 'J':
row = terminal_get_row(terminal, terminal->row);
memset(&row[terminal->column], 0, terminal->width - terminal->column);
for (i = terminal->row + 1; i < terminal->height; i++)
memset(terminal_get_row(terminal, i), 0, terminal->width);
break;
case 'G':
if (set[0])
terminal->column = args[0] - 1;
break;
case 'H':
case 'f':
terminal->row = set[0] ? args[0] - 1 : 0;
terminal->column = set[1] ? args[1] - 1 : 0;
break;
case 'K':
row = terminal_get_row(terminal, terminal->row);
memset(&row[terminal->column], 0, terminal->width - terminal->column);
break;
case 'm':
/* color, blink, bold etc*/
break;
case '?':
if (strcmp(p, "?25l") == 0) {
/* hide cursor */
} else if (strcmp(p, "?25h") == 0) {
/* show cursor */
}
break;
default:
terminal_data(terminal,
terminal->escape + 1,
terminal->escape_length - 2);
break;
}
}
static void
@ -252,7 +320,7 @@ terminal_data(struct terminal *terminal, const char *data, size_t length)
char *row;
for (i = 0; i < length; i++) {
row = &terminal->data[terminal->row * (terminal->width + 1)];
row = terminal_get_row(terminal, terminal->row);
if (terminal->state == STATE_ESCAPE) {
terminal->escape[terminal->escape_length++] = data[i];
@ -276,19 +344,16 @@ terminal_data(struct terminal *terminal, const char *data, size_t length)
break;
case '\n':
terminal->column = 0;
terminal->row++;
if (terminal->row == terminal->height)
terminal->row = 0;
if (terminal->total_rows == terminal->height) {
memset(&terminal->data[terminal->row * (terminal->width + 1)],
0, terminal->width);
terminal->tail++;
if (terminal->row + 1 < terminal->height) {
terminal->row++;
} else {
terminal->total_rows++;
terminal->start++;
if (terminal->start == terminal->height)
terminal->start = 0;
memset(terminal_get_row(terminal, terminal->row),
0, terminal->width);
}
if (terminal->tail == terminal->height)
terminal->tail = 0;
break;
case '\t':
memset(&row[terminal->column], ' ', -terminal->column & 7);
@ -299,9 +364,16 @@ terminal_data(struct terminal *terminal, const char *data, size_t length)
terminal->escape[0] = '\e';
terminal->escape_length = 1;
break;
case '\b':
if (terminal->column > 0)
terminal->column--;
break;
case '\a':
/* Bell */
break;
default:
if (terminal->column < terminal->width)
row[terminal->column++] = data[i];
row[terminal->column++] = data[i] < 32 ? data[i] + 64 : data[i];
break;
}
}

Loading…
Cancel
Save