mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-04 04:06:06 -05:00
performance improvements
* action() returns void - this gets rid of checks in vt_from_slave() * split up ACTION_PRINT into ACTION_PRINT (ASCII) and ACTION_UTF8_PRINT ACTION_PRINT is on the hot path, and we want it streamlined. * Remove run-time checkout for unimplemented state transitions, as we shouldn't have any of those left. * Don't re-load current VT state on each iteration in vt_from_slave()
This commit is contained in:
parent
050f7ea6ea
commit
d63629b370
5 changed files with 164 additions and 132 deletions
50
csi.c
50
csi.c
|
|
@ -91,12 +91,12 @@ sgr_reset(struct terminal *term)
|
|||
term->vt.attrs.background = term->background;
|
||||
}
|
||||
|
||||
static bool
|
||||
static void
|
||||
csi_sgr(struct terminal *term)
|
||||
{
|
||||
if (term->vt.params.idx == 0) {
|
||||
sgr_reset(term);
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < term->vt.params.idx; i++) {
|
||||
|
|
@ -162,7 +162,8 @@ csi_sgr(struct terminal *term)
|
|||
i += 4;
|
||||
} else {
|
||||
LOG_ERR("invalid CSI SGR sequence");
|
||||
return false;
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -208,7 +209,8 @@ csi_sgr(struct terminal *term)
|
|||
i += 4;
|
||||
} else {
|
||||
LOG_ERR("invalid CSI SGR sequence");
|
||||
return false;
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -245,11 +247,10 @@ csi_sgr(struct terminal *term)
|
|||
|
||||
default:
|
||||
LOG_ERR("unimplemented: CSI: SGR: %u", term->vt.params.v[i].value);
|
||||
return false;
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char *
|
||||
|
|
@ -279,7 +280,7 @@ csi_as_string(struct terminal *term, uint8_t final)
|
|||
return msg;
|
||||
}
|
||||
|
||||
bool
|
||||
void
|
||||
csi_dispatch(struct terminal *term, uint8_t final)
|
||||
{
|
||||
LOG_DBG("CSI: %s", csi_as_string(term, final));
|
||||
|
|
@ -287,7 +288,8 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
if (term->vt.intermediates.idx == 0) {
|
||||
switch (final) {
|
||||
case 'c':
|
||||
return write(term->ptmx, "\033[?6c", 5) == 5;
|
||||
write(term->ptmx, "\033[?6c", 5);
|
||||
break;
|
||||
|
||||
case 'd': {
|
||||
/* VPA - vertical line position absolute */
|
||||
|
|
@ -297,7 +299,8 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
}
|
||||
|
||||
case 'm':
|
||||
return csi_sgr(term);
|
||||
csi_sgr(term);
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
term_cursor_up(term, param_get(term, 0, 1));
|
||||
|
|
@ -359,7 +362,8 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
default:
|
||||
LOG_ERR("CSI: %s: invalid argument: %d",
|
||||
csi_as_string(term, final), param);
|
||||
return false;
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
term_erase(term, start, end);
|
||||
|
|
@ -394,7 +398,8 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
default:
|
||||
LOG_ERR("CSI: %s: invalid argument: %d",
|
||||
csi_as_string(term, final), param);
|
||||
return false;
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
term_erase(term, start, end);
|
||||
|
|
@ -513,7 +518,7 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
* should provide our own terminfo with *only* \e[?1049h
|
||||
* (and \e[?1049l for rmcup)
|
||||
*/
|
||||
LOG_WARN("ignoring CSI with final 't'");
|
||||
LOG_WARN("ignoring CSI: %s", csi_as_string(term, final));
|
||||
break;
|
||||
|
||||
case 'n': {
|
||||
|
|
@ -536,13 +541,12 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
default:
|
||||
LOG_ERR("unimplemented: CSI: %s, parameter = %d",
|
||||
csi_as_string(term, final), param);
|
||||
return false;
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
LOG_ERR("CSI: %s: missing parameter", csi_as_string(term, final));
|
||||
return false;
|
||||
abort();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -561,8 +565,6 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
LOG_ERR("unimplemented: CSI: %s", csi_as_string(term, final));
|
||||
abort();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (term->vt.intermediates.idx == 1 &&
|
||||
|
|
@ -746,8 +748,6 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
LOG_ERR("unimplemented: CSI: %s", csi_as_string(term, final));
|
||||
abort();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (term->vt.intermediates.idx == 1 &&
|
||||
|
|
@ -759,10 +759,12 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
LOG_ERR(
|
||||
"unimplemented: send device attributes with param = %d",
|
||||
param);
|
||||
return false;
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
return write(term->ptmx, "\033[?6c", 5) == 5;
|
||||
write(term->ptmx, "\033[?6c", 5);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
|
|
@ -775,6 +777,4 @@ csi_dispatch(struct terminal *term, uint8_t final)
|
|||
LOG_ERR("unimplemented: CSI: %s", csi_as_string(term, final));
|
||||
abort();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
2
csi.h
2
csi.h
|
|
@ -3,4 +3,4 @@
|
|||
#include <stdbool.h>
|
||||
#include "terminal.h"
|
||||
|
||||
bool csi_dispatch(struct terminal *term, uint8_t final);
|
||||
void csi_dispatch(struct terminal *term, uint8_t final);
|
||||
|
|
|
|||
9
osc.c
9
osc.c
|
|
@ -7,7 +7,7 @@
|
|||
#include "log.h"
|
||||
#include "render.h"
|
||||
|
||||
bool
|
||||
void
|
||||
osc_dispatch(struct terminal *term)
|
||||
{
|
||||
int param = 0;
|
||||
|
|
@ -24,7 +24,7 @@ osc_dispatch(struct terminal *term)
|
|||
if (!isdigit(c)) {
|
||||
LOG_ERR("OSC: invalid parameter: %.*s",
|
||||
(int)term->vt.osc.idx, term->vt.osc.data);
|
||||
return false;
|
||||
abort();
|
||||
}
|
||||
|
||||
param *= 10;
|
||||
|
|
@ -47,8 +47,7 @@ osc_dispatch(struct terminal *term)
|
|||
default:
|
||||
LOG_ERR("unimplemented: OSC: %.*s",
|
||||
(int)term->vt.osc.idx, term->vt.osc.data);
|
||||
return false;
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
2
osc.h
2
osc.h
|
|
@ -3,4 +3,4 @@
|
|||
#include <stdbool.h>
|
||||
#include "terminal.h"
|
||||
|
||||
bool osc_dispatch(struct terminal *term);
|
||||
void osc_dispatch(struct terminal *term);
|
||||
|
|
|
|||
231
vt.c
231
vt.c
|
|
@ -63,8 +63,10 @@ enum action {
|
|||
ACTION_UTF8_3_ENTRY,
|
||||
ACTION_UTF8_4_ENTRY,
|
||||
ACTION_UTF8_COLLECT,
|
||||
ACTION_UTF8_PRINT,
|
||||
};
|
||||
|
||||
#if 0
|
||||
static const char *const state_names[] = {
|
||||
[STATE_SAME] = "no change",
|
||||
[STATE_GROUND] = "ground",
|
||||
|
|
@ -89,7 +91,7 @@ static const char *const state_names[] = {
|
|||
|
||||
[STATE_UTF8_COLLECT] = "UTF-8",
|
||||
};
|
||||
|
||||
#endif
|
||||
static const char *const action_names[] __attribute__((unused)) = {
|
||||
[ACTION_NONE] = "no action",
|
||||
[ACTION_IGNORE] = "ignore",
|
||||
|
|
@ -111,6 +113,7 @@ static const char *const action_names[] __attribute__((unused)) = {
|
|||
[ACTION_UTF8_3_ENTRY] = "UTF-8 (3 chars) begin",
|
||||
[ACTION_UTF8_4_ENTRY] = "UTF-8 (4 chars) begin",
|
||||
[ACTION_UTF8_COLLECT] = "UTF-8 collect",
|
||||
[ACTION_UTF8_PRINT] = "UTF-8 print",
|
||||
};
|
||||
|
||||
struct state_transition {
|
||||
|
|
@ -566,7 +569,7 @@ esc_as_string(struct terminal *term, uint8_t final)
|
|||
|
||||
}
|
||||
|
||||
static bool
|
||||
static void
|
||||
esc_dispatch(struct terminal *term, uint8_t final)
|
||||
{
|
||||
LOG_DBG("ESC: %s", esc_as_string(term, final));
|
||||
|
|
@ -594,7 +597,8 @@ esc_dispatch(struct terminal *term, uint8_t final)
|
|||
|
||||
default:
|
||||
LOG_ERR("%s: invalid charset identifier", esc_as_string(term, final));
|
||||
return false;
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -611,7 +615,8 @@ esc_dispatch(struct terminal *term, uint8_t final)
|
|||
|
||||
default:
|
||||
LOG_ERR("%s: invalid charset identifier", esc_as_string(term, final));
|
||||
return false;
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -633,16 +638,104 @@ esc_dispatch(struct terminal *term, uint8_t final)
|
|||
|
||||
default:
|
||||
LOG_ERR("unimplemented: ESC: %s", esc_as_string(term, final));
|
||||
return false;
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
action(struct terminal *term, enum action action, uint8_t c)
|
||||
static inline void
|
||||
pre_print(struct terminal *term)
|
||||
{
|
||||
switch (action) {
|
||||
if (unlikely(term->print_needs_wrap) && term->auto_margin) {
|
||||
if (term->cursor.row == term->scroll_region.end - 1) {
|
||||
term_scroll(term, 1);
|
||||
term_cursor_to(term, term->cursor.row, 0);
|
||||
} else
|
||||
term_cursor_to(term, term->cursor.row + 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
post_print(struct terminal *term)
|
||||
{
|
||||
if (term->cursor.col < term->cols - 1)
|
||||
term_cursor_right(term, 1);
|
||||
else
|
||||
term->print_needs_wrap = true;
|
||||
}
|
||||
|
||||
static inline void
|
||||
print_insert(struct terminal *term)
|
||||
{
|
||||
if (unlikely(term->insert_mode)) {
|
||||
assert(false && "untested");
|
||||
grid_memmove(
|
||||
term->grid, term->cursor.linear + 1, term->cursor.linear,
|
||||
term->cols - term->cursor.col - 1);
|
||||
term_damage_update(
|
||||
term, term->cursor.linear + 1, term->cols - term->cursor.col - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
action_print_utf8(struct terminal *term)
|
||||
{
|
||||
pre_print(term);
|
||||
|
||||
struct cell *cell = &term->grid->cur_line[term->cursor.col];
|
||||
term_damage_update(term, term->cursor.linear, 1);
|
||||
|
||||
print_insert(term);
|
||||
|
||||
//LOG_DBG("print: UTF8: %.*s", (int)term->vt.utf8.idx, term->vt.utf8.data);
|
||||
memcpy(cell->c, term->vt.utf8.data, term->vt.utf8.idx);
|
||||
cell->c[term->vt.utf8.idx] = '\0';
|
||||
term->vt.utf8.idx = 0;
|
||||
|
||||
cell->attrs = term->vt.attrs;
|
||||
post_print(term);
|
||||
}
|
||||
|
||||
static void
|
||||
action_print(struct terminal *term, uint8_t c)
|
||||
{
|
||||
pre_print(term);
|
||||
|
||||
struct cell *cell = &term->grid->cur_line[term->cursor.col];
|
||||
term_damage_update(term, term->cursor.linear, 1);
|
||||
|
||||
print_insert(term);
|
||||
|
||||
static const char *const vt100_0[62] = { /* 0x41 - 0x7e */
|
||||
"↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* H - O */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* P - W */
|
||||
0, 0, 0, 0, 0, 0, 0, " ", /* X - _ */
|
||||
"◆", "▒", "␉", "␌", "␍", "␊", "°", "±", /* ` - g */
|
||||
"", "␋", "┘", "┐", "┌", "└", "┼", "⎺", /* h - o */
|
||||
"⎻", "─", "⎼", "⎽", "├", "┤", "┴", "┬", /* p - w */
|
||||
"│", "≤", "≥", "π", "≠", "£", "·", /* x - ~ */
|
||||
};
|
||||
|
||||
if (unlikely(term->charset[term->selected_charset] == CHARSET_GRAPHIC) &&
|
||||
c >= 0x41 && c <= 0x7e)
|
||||
{
|
||||
strcpy(cell->c, vt100_0[c - 0x41]);
|
||||
} else {
|
||||
//LOG_DBG("print: ASCII: %c", c);
|
||||
cell->c[0] = c;
|
||||
cell->c[1] = '\0';
|
||||
}
|
||||
|
||||
cell->attrs = term->vt.attrs;
|
||||
|
||||
post_print(term);
|
||||
}
|
||||
|
||||
static void
|
||||
action(struct terminal *term, enum action _action, uint8_t c)
|
||||
{
|
||||
switch (_action) {
|
||||
case ACTION_NONE:
|
||||
break;
|
||||
|
||||
|
|
@ -685,10 +778,11 @@ action(struct terminal *term, enum action action, uint8_t c)
|
|||
|
||||
default:
|
||||
LOG_ERR("execute: unimplemented: %c (0x%02x)", c, c);
|
||||
return false;
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
break;
|
||||
|
||||
case ACTION_CLEAR:
|
||||
memset(&term->vt.params, 0, sizeof(term->vt.params));
|
||||
|
|
@ -697,64 +791,13 @@ action(struct terminal *term, enum action action, uint8_t c)
|
|||
term->vt.utf8.idx = 0;
|
||||
break;
|
||||
|
||||
case ACTION_PRINT: {
|
||||
if (unlikely(term->print_needs_wrap) && term->auto_margin) {
|
||||
if (term->cursor.row == term->scroll_region.end - 1) {
|
||||
term_scroll(term, 1);
|
||||
term_cursor_to(term, term->cursor.row, 0);
|
||||
} else
|
||||
term_cursor_to(term, term->cursor.row + 1, 0);
|
||||
}
|
||||
|
||||
struct cell *cell = &term->grid->cur_line[term->cursor.col];
|
||||
term_damage_update(term, term->cursor.linear, 1);
|
||||
|
||||
if (unlikely(term->insert_mode)) {
|
||||
assert(false && "untested");
|
||||
grid_memmove(
|
||||
term->grid, term->cursor.linear + 1, term->cursor.linear,
|
||||
term->cols - term->cursor.col - 1);
|
||||
term_damage_update(
|
||||
term, term->cursor.linear + 1, term->cols - term->cursor.col - 1);
|
||||
}
|
||||
|
||||
if (term->vt.utf8.idx > 0) {
|
||||
//LOG_DBG("print: UTF8: %.*s", (int)term->vt.utf8.idx, term->vt.utf8.data);
|
||||
memcpy(cell->c, term->vt.utf8.data, term->vt.utf8.idx);
|
||||
cell->c[term->vt.utf8.idx] = '\0';
|
||||
term->vt.utf8.idx = 0;
|
||||
} else {
|
||||
static const char *const vt100_0[62] = { /* 0x41 - 0x7e */
|
||||
"↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* H - O */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /* P - W */
|
||||
0, 0, 0, 0, 0, 0, 0, " ", /* X - _ */
|
||||
"◆", "▒", "␉", "␌", "␍", "␊", "°", "±", /* ` - g */
|
||||
"", "␋", "┘", "┐", "┌", "└", "┼", "⎺", /* h - o */
|
||||
"⎻", "─", "⎼", "⎽", "├", "┤", "┴", "┬", /* p - w */
|
||||
"│", "≤", "≥", "π", "≠", "£", "·", /* x - ~ */
|
||||
};
|
||||
|
||||
if (unlikely(term->charset[term->selected_charset] == CHARSET_GRAPHIC) &&
|
||||
c >= 0x41 && c <= 0x7e)
|
||||
{
|
||||
strcpy(cell->c, vt100_0[c - 0x41]);
|
||||
} else {
|
||||
//LOG_DBG("print: ASCII: %c", c);
|
||||
cell->c[0] = c;
|
||||
cell->c[1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
cell->attrs = term->vt.attrs;
|
||||
|
||||
if (term->cursor.col < term->cols - 1)
|
||||
term_cursor_right(term, 1);
|
||||
else
|
||||
term->print_needs_wrap = true;
|
||||
|
||||
case ACTION_PRINT:
|
||||
action_print(term, c);
|
||||
break;
|
||||
|
||||
case ACTION_UTF8_PRINT:
|
||||
action_print_utf8(term);
|
||||
break;
|
||||
}
|
||||
|
||||
case ACTION_PARAM:{
|
||||
if (term->vt.params.idx == 0)
|
||||
|
|
@ -785,14 +828,16 @@ action(struct terminal *term, enum action action, uint8_t c)
|
|||
break;
|
||||
|
||||
LOG_ERR("unimplemented: action ESC dispatch");
|
||||
return false;
|
||||
abort();
|
||||
break;
|
||||
|
||||
case ACTION_ESC_DISPATCH:
|
||||
return esc_dispatch(term, c);
|
||||
esc_dispatch(term, c);
|
||||
break;
|
||||
|
||||
case ACTION_CSI_DISPATCH:
|
||||
return csi_dispatch(term, c);
|
||||
csi_dispatch(term, c);
|
||||
break;
|
||||
|
||||
case ACTION_OSC_START:
|
||||
term->vt.osc.idx = 0;
|
||||
|
|
@ -806,13 +851,14 @@ action(struct terminal *term, enum action action, uint8_t c)
|
|||
case ACTION_OSC_END:
|
||||
assert(term->vt.osc.idx < sizeof(term->vt.osc.data));
|
||||
term->vt.osc.data[term->vt.osc.idx] = '\0';
|
||||
return osc_dispatch(term);
|
||||
osc_dispatch(term);
|
||||
break;
|
||||
|
||||
case ACTION_HOOK:
|
||||
case ACTION_UNHOOK:
|
||||
case ACTION_PUT:
|
||||
LOG_ERR("unimplemented: action %s", action_names[action]);
|
||||
return false;
|
||||
LOG_ERR("unimplemented: action %s", action_names[_action]);
|
||||
abort();
|
||||
|
||||
case ACTION_UTF8_2_ENTRY:
|
||||
term->vt.utf8.idx = 0;
|
||||
|
|
@ -837,51 +883,38 @@ action(struct terminal *term, enum action action, uint8_t c)
|
|||
|
||||
case ACTION_UTF8_COLLECT:
|
||||
term->vt.utf8.data[term->vt.utf8.idx++] = c;
|
||||
if (--term->vt.utf8.left == 0)
|
||||
if (--term->vt.utf8.left == 0) {
|
||||
term->vt.state = STATE_GROUND;
|
||||
action_print_utf8(term);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
vt_from_slave(struct terminal *term, const uint8_t *data, size_t len)
|
||||
{
|
||||
//int cursor = term->grid.cursor;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
//LOG_DBG("input: 0x%02x", data[i]);
|
||||
enum state current_state = term->vt.state;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
|
||||
if (current_state == STATE_UTF8_COLLECT) {
|
||||
if (!action(term, ACTION_UTF8_COLLECT, data[i]))
|
||||
abort();
|
||||
action(term, ACTION_UTF8_COLLECT, data[i]);
|
||||
|
||||
current_state = term->vt.state;
|
||||
if (current_state == STATE_UTF8_COLLECT)
|
||||
continue;
|
||||
|
||||
if (!action(term, ACTION_PRINT, 0))
|
||||
abort();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const struct state_transition *transition = &states[current_state][data[i]];
|
||||
if (transition->action == ACTION_NONE && transition->state == STATE_SAME) {
|
||||
LOG_ERR("unimplemented transition from %s: 0x%02x",
|
||||
state_names[current_state], data[i]);
|
||||
abort();
|
||||
}
|
||||
assert(transition->action != ACTION_NONE || transition->state != STATE_SAME);
|
||||
|
||||
if (transition->state != STATE_SAME) {
|
||||
enum action exit_action = exit_actions[current_state];
|
||||
if (exit_action != ACTION_NONE && !action(term, exit_action, data[i]))
|
||||
abort();
|
||||
action(term, exit_action, data[i]);
|
||||
}
|
||||
|
||||
if (!action(term, transition->action, data[i]))
|
||||
abort();
|
||||
action(term, transition->action, data[i]);
|
||||
|
||||
if (transition->state != STATE_SAME) {
|
||||
/*
|
||||
|
|
@ -889,10 +922,10 @@ vt_from_slave(struct terminal *term, const uint8_t *data, size_t len)
|
|||
* state_names[transition->state]);
|
||||
*/
|
||||
term->vt.state = transition->state;
|
||||
current_state = transition->state;
|
||||
|
||||
enum action entry_action = entry_actions[transition->state];
|
||||
if (entry_action != ACTION_NONE && !action(term, entry_action, data[i]))
|
||||
abort();
|
||||
action(term, entry_action, data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue