mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-15 22:05:24 -05:00
cell: pack more efficiently and store glyph as a wchar
The 'attributes' struct is now 8 bytes and naturally packed (used to be 9 bytes, artificially packed). 'cell' struct is now 12 bytes, naturally packed (used to be 13 bytes, artificially packed). Furthermore, the glyph is stored as a wchar instead of a char*. This makes it easier (faster) to do glyph lookup when rendering.
This commit is contained in:
parent
ab92abbd21
commit
4d7993b36f
9 changed files with 146 additions and 129 deletions
38
csi.c
38
csi.c
|
|
@ -50,8 +50,8 @@ static void
|
|||
sgr_reset(struct terminal *term)
|
||||
{
|
||||
memset(&term->vt.attrs, 0, sizeof(term->vt.attrs));
|
||||
term->vt.attrs.foreground = term->colors.fg;
|
||||
term->vt.attrs.background = term->colors.bg;
|
||||
term->vt.attrs.fg = term->colors.fg;
|
||||
term->vt.attrs.bg = term->colors.bg;
|
||||
}
|
||||
|
||||
static const char *
|
||||
|
|
@ -129,7 +129,8 @@ csi_sgr(struct terminal *term)
|
|||
case 35:
|
||||
case 36:
|
||||
case 37:
|
||||
term->vt.attrs.foreground = 1 << 30 | term->colors.regular[param - 30];
|
||||
term->vt.attrs.have_fg = 1;
|
||||
term->vt.attrs.fg = term->colors.regular[param - 30];
|
||||
break;
|
||||
|
||||
case 38: {
|
||||
|
|
@ -144,7 +145,8 @@ csi_sgr(struct terminal *term)
|
|||
color = term->colors.bright[idx - 8];
|
||||
else
|
||||
color = colors256[idx];
|
||||
term->vt.attrs.foreground = 1 << 30 | color;
|
||||
term->vt.attrs.have_fg = 1;
|
||||
term->vt.attrs.fg = color;
|
||||
i += 2;
|
||||
|
||||
}
|
||||
|
|
@ -155,7 +157,8 @@ csi_sgr(struct terminal *term)
|
|||
uint8_t r = term->vt.params.v[i + 2].value;
|
||||
uint8_t g = term->vt.params.v[i + 3].value;
|
||||
uint8_t b = term->vt.params.v[i + 4].value;
|
||||
term->vt.attrs.foreground = 1 << 30 | r << 16 | g << 8 | b;
|
||||
term->vt.attrs.have_fg = 1;
|
||||
term->vt.attrs.fg = r << 16 | g << 8 | b;
|
||||
i += 4;
|
||||
}
|
||||
|
||||
|
|
@ -171,7 +174,8 @@ csi_sgr(struct terminal *term)
|
|||
/* 6 - CS tolerance */
|
||||
/* 7 - color space associated with tolerance */
|
||||
|
||||
term->vt.attrs.foreground = 1 << 30 | r << 16 | g << 8 | b;
|
||||
term->vt.attrs.have_fg = 1;
|
||||
term->vt.attrs.fg = r << 16 | g << 8 | b;
|
||||
} else
|
||||
UNHANDLED_SGR();
|
||||
}
|
||||
|
|
@ -183,7 +187,7 @@ csi_sgr(struct terminal *term)
|
|||
}
|
||||
|
||||
case 39:
|
||||
term->vt.attrs.foreground = 0;
|
||||
term->vt.attrs.have_fg = 0;
|
||||
break;
|
||||
|
||||
/* Regular background colors */
|
||||
|
|
@ -195,7 +199,8 @@ csi_sgr(struct terminal *term)
|
|||
case 45:
|
||||
case 46:
|
||||
case 47:
|
||||
term->vt.attrs.background = 1 << 30 | term->colors.regular[param - 40];
|
||||
term->vt.attrs.have_bg = 1;
|
||||
term->vt.attrs.bg = term->colors.regular[param - 40];
|
||||
break;
|
||||
|
||||
case 48: {
|
||||
|
|
@ -211,7 +216,8 @@ csi_sgr(struct terminal *term)
|
|||
color = term->colors.bright[idx - 8];
|
||||
else
|
||||
color = colors256[idx];
|
||||
term->vt.attrs.background = 1 << 30 | color;
|
||||
term->vt.attrs.have_bg = 1;
|
||||
term->vt.attrs.bg = color;
|
||||
i += 2;
|
||||
}
|
||||
|
||||
|
|
@ -221,7 +227,8 @@ csi_sgr(struct terminal *term)
|
|||
uint8_t r = term->vt.params.v[i + 2].value;
|
||||
uint8_t g = term->vt.params.v[i + 3].value;
|
||||
uint8_t b = term->vt.params.v[i + 4].value;
|
||||
term->vt.attrs.background = 1 << 30 | r << 16 | g << 8 | b;
|
||||
term->vt.attrs.have_bg = 1;
|
||||
term->vt.attrs.bg = r << 16 | g << 8 | b;
|
||||
i += 4;
|
||||
|
||||
}
|
||||
|
|
@ -238,7 +245,8 @@ csi_sgr(struct terminal *term)
|
|||
/* 6 - CS tolerance */
|
||||
/* 7 - color space associated with tolerance */
|
||||
|
||||
term->vt.attrs.background = 1 << 30 | r << 16 | g << 8 | b;
|
||||
term->vt.attrs.have_bg = 1;
|
||||
term->vt.attrs.bg = r << 16 | g << 8 | b;
|
||||
} else
|
||||
UNHANDLED_SGR();
|
||||
}
|
||||
|
|
@ -249,7 +257,7 @@ csi_sgr(struct terminal *term)
|
|||
break;
|
||||
}
|
||||
case 49:
|
||||
term->vt.attrs.background = 0;
|
||||
term->vt.attrs.have_bg = 0;
|
||||
break;
|
||||
|
||||
/* Bright foreground colors */
|
||||
|
|
@ -261,7 +269,8 @@ csi_sgr(struct terminal *term)
|
|||
case 95:
|
||||
case 96:
|
||||
case 97:
|
||||
term->vt.attrs.foreground = 1 << 30 | term->colors.bright[param - 90];
|
||||
term->vt.attrs.have_fg = 1;
|
||||
term->vt.attrs.fg = term->colors.bright[param - 90];
|
||||
break;
|
||||
|
||||
/* Regular background colors */
|
||||
|
|
@ -273,7 +282,8 @@ csi_sgr(struct terminal *term)
|
|||
case 105:
|
||||
case 106:
|
||||
case 107:
|
||||
term->vt.attrs.background = 1 << 30 | term->colors.bright[param - 100];
|
||||
term->vt.attrs.have_bg = 1;
|
||||
term->vt.attrs.bg = term->colors.bright[param - 100];
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
|||
23
font.c
23
font.c
|
|
@ -381,29 +381,23 @@ glyph_for_wchar(struct font *font, wchar_t wc, struct glyph *glyph)
|
|||
.left = font->face->glyph->bitmap_left,
|
||||
.top = font->face->glyph->bitmap_top,
|
||||
.pixel_size_fixup = font->pixel_size_fixup,
|
||||
.valid = true,
|
||||
};
|
||||
|
||||
return true;
|
||||
|
||||
err:
|
||||
*glyph = (struct glyph){
|
||||
.valid = false,
|
||||
};
|
||||
return false;
|
||||
}
|
||||
|
||||
const struct glyph *
|
||||
font_glyph_for_utf8(struct font *font, const char *utf8)
|
||||
font_glyph_for_wc(struct font *font, wchar_t wc)
|
||||
{
|
||||
mtx_lock(&font->lock);
|
||||
|
||||
mbstate_t ps = {0};
|
||||
wchar_t wc;
|
||||
if (mbrtowc(&wc, utf8, 4, &ps) < 0) {
|
||||
LOG_DBG("failed to convert utf-8 sequence %02x %02x %02x %02x to unicode",
|
||||
(unsigned char)utf8[0], (unsigned char)utf8[1],
|
||||
(unsigned char)utf8[2], (unsigned char)utf8[3]);
|
||||
mtx_unlock(&font->lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(font->cache != NULL);
|
||||
size_t hash_idx = hash_index(wc);
|
||||
hash_entry_t *hash_entry = font->cache[hash_idx];
|
||||
|
|
@ -418,10 +412,7 @@ font_glyph_for_utf8(struct font *font, const char *utf8)
|
|||
}
|
||||
|
||||
struct glyph glyph;
|
||||
if (!glyph_for_wchar(font, wc, &glyph)) {
|
||||
mtx_unlock(&font->lock);
|
||||
return NULL;
|
||||
}
|
||||
bool got_glyph = glyph_for_wchar(font, wc, &glyph);
|
||||
|
||||
if (hash_entry == NULL) {
|
||||
hash_entry = calloc(1, sizeof(*hash_entry));
|
||||
|
|
@ -434,7 +425,7 @@ font_glyph_for_utf8(struct font *font, const char *utf8)
|
|||
tll_push_back(*hash_entry, glyph);
|
||||
|
||||
mtx_unlock(&font->lock);
|
||||
return &tll_back(*hash_entry);
|
||||
return got_glyph ? &tll_back(*hash_entry) : NULL;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
3
font.h
3
font.h
|
|
@ -22,6 +22,7 @@ struct glyph {
|
|||
int top;
|
||||
|
||||
double pixel_size_fixup;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
typedef tll(struct glyph) hash_entry_t;
|
||||
|
|
@ -51,5 +52,5 @@ struct font {
|
|||
};
|
||||
|
||||
bool font_from_name(font_list_t names, const char *attributes, struct font *result);
|
||||
const struct glyph *font_glyph_for_utf8(struct font *font, const char *utf8);
|
||||
const struct glyph *font_glyph_for_wc(struct font *font, wchar_t wc);
|
||||
void font_destroy(struct font *font);
|
||||
|
|
|
|||
55
input.c
55
input.c
|
|
@ -60,12 +60,6 @@ static void
|
|||
keyboard_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
||||
struct wl_surface *surface, struct wl_array *keys)
|
||||
{
|
||||
LOG_DBG("enter");
|
||||
#if 0
|
||||
uint32_t *key;
|
||||
wl_array_for_each(key, keys)
|
||||
xkb_state_update_key(xkb_state, *key, 1);
|
||||
#endif
|
||||
struct terminal *term = data;
|
||||
term->input_serial = serial;
|
||||
term_focus_in(term);
|
||||
|
|
@ -76,7 +70,6 @@ keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|||
struct wl_surface *surface)
|
||||
{
|
||||
struct terminal *term = data;
|
||||
term_focus_out(term);
|
||||
|
||||
mtx_lock(&term->kbd.repeat.mutex);
|
||||
if (term->kbd.repeat.cmd != REPEAT_EXIT) {
|
||||
|
|
@ -84,6 +77,35 @@ keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|||
cnd_signal(&term->kbd.repeat.cond);
|
||||
}
|
||||
mtx_unlock(&term->kbd.repeat.mutex);
|
||||
|
||||
term_focus_out(term);
|
||||
}
|
||||
|
||||
static void
|
||||
start_repeater(struct terminal *term, uint32_t key)
|
||||
{
|
||||
mtx_lock(&term->kbd.repeat.mutex);
|
||||
if (!term->kbd.repeat.dont_re_repeat) {
|
||||
if (term->kbd.repeat.cmd != REPEAT_EXIT) {
|
||||
term->kbd.repeat.cmd = REPEAT_START;
|
||||
term->kbd.repeat.key = key;
|
||||
cnd_signal(&term->kbd.repeat.cond);
|
||||
}
|
||||
}
|
||||
mtx_unlock(&term->kbd.repeat.mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
stop_repeater(struct terminal *term, uint32_t key)
|
||||
{
|
||||
mtx_lock(&term->kbd.repeat.mutex);
|
||||
if (term->kbd.repeat.key == key) {
|
||||
if (term->kbd.repeat.cmd != REPEAT_EXIT) {
|
||||
term->kbd.repeat.cmd = REPEAT_STOP;
|
||||
cnd_signal(&term->kbd.repeat.cond);
|
||||
}
|
||||
}
|
||||
mtx_unlock(&term->kbd.repeat.mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -97,14 +119,7 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|||
const xkb_mod_mask_t shift = 1 << term->kbd.mod_shift;
|
||||
|
||||
if (state == XKB_KEY_UP) {
|
||||
mtx_lock(&term->kbd.repeat.mutex);
|
||||
if (term->kbd.repeat.key == key) {
|
||||
if (term->kbd.repeat.cmd != REPEAT_EXIT) {
|
||||
term->kbd.repeat.cmd = REPEAT_STOP;
|
||||
cnd_signal(&term->kbd.repeat.cond);
|
||||
}
|
||||
}
|
||||
mtx_unlock(&term->kbd.repeat.mutex);
|
||||
stop_repeater(term, key);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -261,15 +276,7 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|||
}
|
||||
}
|
||||
|
||||
mtx_lock(&term->kbd.repeat.mutex);
|
||||
if (!term->kbd.repeat.dont_re_repeat) {
|
||||
if (term->kbd.repeat.cmd != REPEAT_EXIT) {
|
||||
term->kbd.repeat.cmd = REPEAT_START;
|
||||
term->kbd.repeat.key = key - 8;
|
||||
cnd_signal(&term->kbd.repeat.cond);
|
||||
}
|
||||
}
|
||||
mtx_unlock(&term->kbd.repeat.mutex);
|
||||
start_repeater(term, key - 8);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
12
render.c
12
render.c
|
|
@ -154,11 +154,11 @@ render_cell(struct terminal *term, cairo_t *cr,
|
|||
bool block_cursor = has_cursor && term->cursor_style == CURSOR_BLOCK;
|
||||
bool is_selected = coord_is_selected(term, col, row);
|
||||
|
||||
uint32_t _fg = cell->attrs.foreground >> 30
|
||||
? cell->attrs.foreground
|
||||
uint32_t _fg = cell->attrs.have_fg
|
||||
? cell->attrs.fg
|
||||
: !term->reverse ? term->colors.fg : term->colors.bg;
|
||||
uint32_t _bg = cell->attrs.background >> 30
|
||||
? cell->attrs.background
|
||||
uint32_t _bg = cell->attrs.have_bg
|
||||
? cell->attrs.bg
|
||||
: !term->reverse ? term->colors.bg : term->colors.fg;
|
||||
|
||||
/* If *one* is set, we reverse */
|
||||
|
|
@ -185,7 +185,7 @@ render_cell(struct terminal *term, cairo_t *cr,
|
|||
}
|
||||
|
||||
struct font *font = attrs_to_font(term, &cell->attrs);
|
||||
const struct glyph *glyph = font_glyph_for_utf8(font, cell->c);
|
||||
const struct glyph *glyph = font_glyph_for_wc(font, cell->wc);
|
||||
|
||||
int cell_cols = glyph != NULL ? max(1, glyph->width) : 1;
|
||||
|
||||
|
|
@ -210,7 +210,7 @@ render_cell(struct terminal *term, cairo_t *cr,
|
|||
arm_blink_timer(term);
|
||||
}
|
||||
|
||||
if (cell->c[0] == '\0' || cell->attrs.conceal)
|
||||
if (cell->wc == 0 || cell->attrs.conceal)
|
||||
return cell_cols;
|
||||
|
||||
if (glyph != NULL) {
|
||||
|
|
|
|||
49
selection.c
49
selection.c
|
|
@ -5,6 +5,7 @@
|
|||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <wctype.h>
|
||||
|
||||
#define LOG_MODULE "selection"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
|
|
@ -58,11 +59,12 @@ extract_selection(const struct terminal *term)
|
|||
/* TODO: replace '\0' with spaces, then trim lines */
|
||||
for (int col = start_col; col < term->cols; col++) {
|
||||
const struct cell *cell = &row->cells[col];
|
||||
if (cell->c[0] == '\0')
|
||||
if (cell->wc == 0)
|
||||
continue;
|
||||
|
||||
size_t len = strnlen(cell->c, 4);
|
||||
memcpy(&buf[idx], cell->c, len);
|
||||
mbstate_t ps = {0};
|
||||
size_t len = wcrtomb(&buf[idx], cell->wc, &ps);
|
||||
assert(len >= 0); /* All wchars were valid multibyte strings to begin with */
|
||||
idx += len;
|
||||
}
|
||||
|
||||
|
|
@ -76,11 +78,12 @@ extract_selection(const struct terminal *term)
|
|||
const struct row *row = grid_row_in_view(term->grid, end->row - term->grid->view);
|
||||
for (int col = start_col; row != NULL && col <= end->col; col++) {
|
||||
const struct cell *cell = &row->cells[col];
|
||||
if (cell->c[0] == '\0')
|
||||
if (cell->wc == 0)
|
||||
continue;
|
||||
|
||||
size_t len = strnlen(cell->c, 4);
|
||||
memcpy(&buf[idx], cell->c, len);
|
||||
mbstate_t ps = {0};
|
||||
size_t len = wcrtomb(&buf[idx], cell->wc, &ps);
|
||||
assert(len >= 0); /* All wchars were valid multibyte strings to begin with */
|
||||
idx += len;
|
||||
}
|
||||
}
|
||||
|
|
@ -214,19 +217,19 @@ selection_cancel(struct terminal *term)
|
|||
}
|
||||
|
||||
static bool
|
||||
isword(int c)
|
||||
isword(wint_t c)
|
||||
{
|
||||
switch (c) {
|
||||
default: return !isspace(c);
|
||||
default: return !iswspace(c);
|
||||
|
||||
case '{': case '}':
|
||||
case '[': case ']':
|
||||
case '(': case ')':
|
||||
case '`':
|
||||
case '\'':
|
||||
case '"':
|
||||
case ',': case '.':
|
||||
case ':': case ';':
|
||||
case L'{': case L'}':
|
||||
case L'[': case L']':
|
||||
case L'(': case L')':
|
||||
case L'`':
|
||||
case L'\'':
|
||||
case L'"':
|
||||
case L',': case L'.':
|
||||
case L':': case L';':
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -243,9 +246,9 @@ selection_mark_word(struct terminal *term, int col, int row, uint32_t serial)
|
|||
struct coord end = {col, row};
|
||||
|
||||
const struct row *r = grid_row_in_view(term->grid, start.row);
|
||||
unsigned char c = r->cells[start.col].c[0];
|
||||
wchar_t c = r->cells[start.col].wc;
|
||||
|
||||
if (!(c == '\0' || !isword(c))) {
|
||||
if (!(c == 0 || !isword(c))) {
|
||||
while (true) {
|
||||
int next_col = start.col - 1;
|
||||
int next_row = start.row;
|
||||
|
|
@ -259,8 +262,8 @@ selection_mark_word(struct terminal *term, int col, int row, uint32_t serial)
|
|||
|
||||
const struct row *row = grid_row_in_view(term->grid, next_row);
|
||||
|
||||
unsigned char c = row->cells[next_col].c[0];
|
||||
if (c == '\0' || !isword(c))
|
||||
c = row->cells[next_col].wc;
|
||||
if (c == 0 || !isword(c))
|
||||
break;
|
||||
|
||||
start.col = next_col;
|
||||
|
|
@ -269,9 +272,9 @@ selection_mark_word(struct terminal *term, int col, int row, uint32_t serial)
|
|||
}
|
||||
|
||||
r = grid_row_in_view(term->grid, end.row);
|
||||
c = r->cells[end.col].c[0];
|
||||
c = r->cells[end.col].wc;
|
||||
|
||||
if (!(c == '\0' || !isword(c))) {
|
||||
if (!(c == 0 || !isword(c))) {
|
||||
while (true) {
|
||||
int next_col = end.col + 1;
|
||||
int next_row = end.row;
|
||||
|
|
@ -285,7 +288,7 @@ selection_mark_word(struct terminal *term, int col, int row, uint32_t serial)
|
|||
|
||||
const struct row *row = grid_row_in_view(term->grid, next_row);
|
||||
|
||||
unsigned char c = row->cells[next_col].c[0];
|
||||
c = row->cells[next_col].wc;
|
||||
if (c == '\0' || !isword(c))
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -163,11 +163,12 @@ erase_cell_range(struct terminal *term, struct row *row, int start, int end)
|
|||
assert(start < term->cols);
|
||||
assert(end < term->cols);
|
||||
|
||||
if (unlikely(term->vt.attrs.background >> 30)) {
|
||||
if (unlikely(term->vt.attrs.have_bg)) {
|
||||
for (int col = start; col <= end; col++) {
|
||||
row->cells[col].c[0] = '\0';
|
||||
row->cells[col].wc = 0;
|
||||
row->cells[col].attrs.clean = 0;
|
||||
row->cells[col].attrs.background = term->vt.attrs.background;
|
||||
row->cells[col].attrs.have_bg = 1;
|
||||
row->cells[col].attrs.bg = term->vt.attrs.bg;
|
||||
}
|
||||
} else {
|
||||
memset(&row->cells[start], 0, (end - start + 1) * sizeof(row->cells[0]));
|
||||
|
|
|
|||
39
terminal.h
39
terminal.h
|
|
@ -3,6 +3,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include <threads.h>
|
||||
#include <semaphore.h>
|
||||
|
|
@ -50,28 +51,34 @@ struct rgb { float r, g, b; };
|
|||
/*
|
||||
* Note: we want the cells to be as small as possible. Larger cells
|
||||
* means fewer scrollback lines (or performance drops due to cache
|
||||
* misses) */
|
||||
* misses)
|
||||
*
|
||||
* Note that the members are laid out optimized for x86
|
||||
*/
|
||||
struct attributes {
|
||||
uint8_t bold:1;
|
||||
uint8_t dim:1;
|
||||
uint8_t italic:1;
|
||||
uint8_t underline:1;
|
||||
uint8_t strikethrough:1;
|
||||
uint8_t blink:1;
|
||||
uint8_t conceal:1;
|
||||
uint8_t reverse:1;
|
||||
uint32_t bold:1;
|
||||
uint32_t dim:1;
|
||||
uint32_t italic:1;
|
||||
uint32_t underline:1;
|
||||
uint32_t strikethrough:1;
|
||||
uint32_t blink:1;
|
||||
uint32_t conceal:1;
|
||||
uint32_t reverse:1;
|
||||
uint32_t fg:24;
|
||||
|
||||
uint32_t clean:1;
|
||||
uint32_t foreground:31;
|
||||
|
||||
uint32_t reserved:1;
|
||||
uint32_t background:31;
|
||||
} __attribute__((packed));
|
||||
uint32_t have_fg:1;
|
||||
uint32_t have_bg:1;
|
||||
uint32_t reserved:5;
|
||||
uint32_t bg:24;
|
||||
};
|
||||
static_assert(sizeof(struct attributes) == 8, "bad size");
|
||||
|
||||
struct cell {
|
||||
wchar_t wc;
|
||||
struct attributes attrs;
|
||||
char c[4];
|
||||
} __attribute__((packed));
|
||||
};
|
||||
static_assert(sizeof(struct cell) == 12, "bad size");
|
||||
|
||||
struct scroll_region {
|
||||
int start;
|
||||
|
|
|
|||
49
vt.c
49
vt.c
|
|
@ -728,33 +728,29 @@ action_print_utf8(struct terminal *term)
|
|||
|
||||
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';
|
||||
mbstate_t ps = {0};
|
||||
if (mbrtowc(&cell->wc, (const char *)term->vt.utf8.data, term->vt.utf8.idx, &ps) < 0)
|
||||
cell->wc = 0;
|
||||
|
||||
term->vt.utf8.idx = 0;
|
||||
|
||||
cell->attrs = term->vt.attrs;
|
||||
|
||||
/* Hack: zero- and double-width characters */
|
||||
mbstate_t ps = {0};
|
||||
wchar_t wc;
|
||||
if (mbrtowc(&wc, cell->c, 4, &ps) >= 0) {
|
||||
int width = wcwidth(wc);
|
||||
if (width <= 0) {
|
||||
/* Skip post_print() below - i.e. don't advance cursor */
|
||||
return;
|
||||
}
|
||||
int width = wcwidth(cell->wc);
|
||||
if (width <= 0) {
|
||||
/* Skip post_print() below - i.e. don't advance cursor */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Advance cursor the 'additional' columns (last step is done
|
||||
* by post_print()) */
|
||||
for (int i = 1; i < width && term->cursor.col < term->cols - 1; i++) {
|
||||
term_cursor_right(term, 1);
|
||||
/* Advance cursor the 'additional' columns (last step is done
|
||||
* by post_print()) */
|
||||
for (int i = 1; i < width && term->cursor.col < term->cols - 1; i++) {
|
||||
term_cursor_right(term, 1);
|
||||
|
||||
assert(term->cursor.col < term->cols);
|
||||
struct cell *cell = &row->cells[term->cursor.col];
|
||||
cell->c[0] = '\0';
|
||||
cell->attrs.clean = 0;
|
||||
}
|
||||
assert(term->cursor.col < term->cols);
|
||||
struct cell *cell = &row->cells[term->cursor.col];
|
||||
cell->wc = 0;
|
||||
cell->attrs.clean = 0;
|
||||
}
|
||||
|
||||
post_print(term);
|
||||
|
|
@ -788,16 +784,17 @@ action_print(struct terminal *term, uint8_t c)
|
|||
c >= 0x41 && c <= 0x7e)
|
||||
{
|
||||
const char *glyph = vt100_0[c - 0x41];
|
||||
if (glyph != NULL)
|
||||
strncpy(cell->c, glyph, sizeof(cell->c));
|
||||
if (glyph != NULL) {
|
||||
mbstate_t ps = {0};
|
||||
if (mbrtowc(&cell->wc, glyph, strlen(glyph), &ps) < 0)
|
||||
cell->wc = 0;
|
||||
}
|
||||
} else {
|
||||
//LOG_DBG("print: ASCII: %c", c);
|
||||
cell->c[0] = c;
|
||||
cell->c[1] = '\0';
|
||||
cell->wc = c;
|
||||
}
|
||||
|
||||
cell->attrs = term->vt.attrs;
|
||||
|
||||
post_print(term);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue