mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-04-02 07:15:31 -04: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)
|
sgr_reset(struct terminal *term)
|
||||||
{
|
{
|
||||||
memset(&term->vt.attrs, 0, sizeof(term->vt.attrs));
|
memset(&term->vt.attrs, 0, sizeof(term->vt.attrs));
|
||||||
term->vt.attrs.foreground = term->colors.fg;
|
term->vt.attrs.fg = term->colors.fg;
|
||||||
term->vt.attrs.background = term->colors.bg;
|
term->vt.attrs.bg = term->colors.bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
|
|
@ -129,7 +129,8 @@ csi_sgr(struct terminal *term)
|
||||||
case 35:
|
case 35:
|
||||||
case 36:
|
case 36:
|
||||||
case 37:
|
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;
|
break;
|
||||||
|
|
||||||
case 38: {
|
case 38: {
|
||||||
|
|
@ -144,7 +145,8 @@ csi_sgr(struct terminal *term)
|
||||||
color = term->colors.bright[idx - 8];
|
color = term->colors.bright[idx - 8];
|
||||||
else
|
else
|
||||||
color = colors256[idx];
|
color = colors256[idx];
|
||||||
term->vt.attrs.foreground = 1 << 30 | color;
|
term->vt.attrs.have_fg = 1;
|
||||||
|
term->vt.attrs.fg = color;
|
||||||
i += 2;
|
i += 2;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -155,7 +157,8 @@ csi_sgr(struct terminal *term)
|
||||||
uint8_t r = term->vt.params.v[i + 2].value;
|
uint8_t r = term->vt.params.v[i + 2].value;
|
||||||
uint8_t g = term->vt.params.v[i + 3].value;
|
uint8_t g = term->vt.params.v[i + 3].value;
|
||||||
uint8_t b = term->vt.params.v[i + 4].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;
|
i += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,7 +174,8 @@ csi_sgr(struct terminal *term)
|
||||||
/* 6 - CS tolerance */
|
/* 6 - CS tolerance */
|
||||||
/* 7 - color space associated with 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
|
} else
|
||||||
UNHANDLED_SGR();
|
UNHANDLED_SGR();
|
||||||
}
|
}
|
||||||
|
|
@ -183,7 +187,7 @@ csi_sgr(struct terminal *term)
|
||||||
}
|
}
|
||||||
|
|
||||||
case 39:
|
case 39:
|
||||||
term->vt.attrs.foreground = 0;
|
term->vt.attrs.have_fg = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Regular background colors */
|
/* Regular background colors */
|
||||||
|
|
@ -195,7 +199,8 @@ csi_sgr(struct terminal *term)
|
||||||
case 45:
|
case 45:
|
||||||
case 46:
|
case 46:
|
||||||
case 47:
|
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;
|
break;
|
||||||
|
|
||||||
case 48: {
|
case 48: {
|
||||||
|
|
@ -211,7 +216,8 @@ csi_sgr(struct terminal *term)
|
||||||
color = term->colors.bright[idx - 8];
|
color = term->colors.bright[idx - 8];
|
||||||
else
|
else
|
||||||
color = colors256[idx];
|
color = colors256[idx];
|
||||||
term->vt.attrs.background = 1 << 30 | color;
|
term->vt.attrs.have_bg = 1;
|
||||||
|
term->vt.attrs.bg = color;
|
||||||
i += 2;
|
i += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -221,7 +227,8 @@ csi_sgr(struct terminal *term)
|
||||||
uint8_t r = term->vt.params.v[i + 2].value;
|
uint8_t r = term->vt.params.v[i + 2].value;
|
||||||
uint8_t g = term->vt.params.v[i + 3].value;
|
uint8_t g = term->vt.params.v[i + 3].value;
|
||||||
uint8_t b = term->vt.params.v[i + 4].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;
|
i += 4;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -238,7 +245,8 @@ csi_sgr(struct terminal *term)
|
||||||
/* 6 - CS tolerance */
|
/* 6 - CS tolerance */
|
||||||
/* 7 - color space associated with 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
|
} else
|
||||||
UNHANDLED_SGR();
|
UNHANDLED_SGR();
|
||||||
}
|
}
|
||||||
|
|
@ -249,7 +257,7 @@ csi_sgr(struct terminal *term)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 49:
|
case 49:
|
||||||
term->vt.attrs.background = 0;
|
term->vt.attrs.have_bg = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Bright foreground colors */
|
/* Bright foreground colors */
|
||||||
|
|
@ -261,7 +269,8 @@ csi_sgr(struct terminal *term)
|
||||||
case 95:
|
case 95:
|
||||||
case 96:
|
case 96:
|
||||||
case 97:
|
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;
|
break;
|
||||||
|
|
||||||
/* Regular background colors */
|
/* Regular background colors */
|
||||||
|
|
@ -273,7 +282,8 @@ csi_sgr(struct terminal *term)
|
||||||
case 105:
|
case 105:
|
||||||
case 106:
|
case 106:
|
||||||
case 107:
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
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,
|
.left = font->face->glyph->bitmap_left,
|
||||||
.top = font->face->glyph->bitmap_top,
|
.top = font->face->glyph->bitmap_top,
|
||||||
.pixel_size_fixup = font->pixel_size_fixup,
|
.pixel_size_fixup = font->pixel_size_fixup,
|
||||||
|
.valid = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
|
*glyph = (struct glyph){
|
||||||
|
.valid = false,
|
||||||
|
};
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct glyph *
|
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);
|
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);
|
assert(font->cache != NULL);
|
||||||
size_t hash_idx = hash_index(wc);
|
size_t hash_idx = hash_index(wc);
|
||||||
hash_entry_t *hash_entry = font->cache[hash_idx];
|
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;
|
struct glyph glyph;
|
||||||
if (!glyph_for_wchar(font, wc, &glyph)) {
|
bool got_glyph = glyph_for_wchar(font, wc, &glyph);
|
||||||
mtx_unlock(&font->lock);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hash_entry == NULL) {
|
if (hash_entry == NULL) {
|
||||||
hash_entry = calloc(1, sizeof(*hash_entry));
|
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);
|
tll_push_back(*hash_entry, glyph);
|
||||||
|
|
||||||
mtx_unlock(&font->lock);
|
mtx_unlock(&font->lock);
|
||||||
return &tll_back(*hash_entry);
|
return got_glyph ? &tll_back(*hash_entry) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
3
font.h
3
font.h
|
|
@ -22,6 +22,7 @@ struct glyph {
|
||||||
int top;
|
int top;
|
||||||
|
|
||||||
double pixel_size_fixup;
|
double pixel_size_fixup;
|
||||||
|
bool valid;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef tll(struct glyph) hash_entry_t;
|
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);
|
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);
|
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,
|
keyboard_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
||||||
struct wl_surface *surface, struct wl_array *keys)
|
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;
|
struct terminal *term = data;
|
||||||
term->input_serial = serial;
|
term->input_serial = serial;
|
||||||
term_focus_in(term);
|
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 wl_surface *surface)
|
||||||
{
|
{
|
||||||
struct terminal *term = data;
|
struct terminal *term = data;
|
||||||
term_focus_out(term);
|
|
||||||
|
|
||||||
mtx_lock(&term->kbd.repeat.mutex);
|
mtx_lock(&term->kbd.repeat.mutex);
|
||||||
if (term->kbd.repeat.cmd != REPEAT_EXIT) {
|
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);
|
cnd_signal(&term->kbd.repeat.cond);
|
||||||
}
|
}
|
||||||
mtx_unlock(&term->kbd.repeat.mutex);
|
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
|
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;
|
const xkb_mod_mask_t shift = 1 << term->kbd.mod_shift;
|
||||||
|
|
||||||
if (state == XKB_KEY_UP) {
|
if (state == XKB_KEY_UP) {
|
||||||
mtx_lock(&term->kbd.repeat.mutex);
|
stop_repeater(term, key);
|
||||||
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);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -261,15 +276,7 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mtx_lock(&term->kbd.repeat.mutex);
|
start_repeater(term, key - 8);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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 block_cursor = has_cursor && term->cursor_style == CURSOR_BLOCK;
|
||||||
bool is_selected = coord_is_selected(term, col, row);
|
bool is_selected = coord_is_selected(term, col, row);
|
||||||
|
|
||||||
uint32_t _fg = cell->attrs.foreground >> 30
|
uint32_t _fg = cell->attrs.have_fg
|
||||||
? cell->attrs.foreground
|
? cell->attrs.fg
|
||||||
: !term->reverse ? term->colors.fg : term->colors.bg;
|
: !term->reverse ? term->colors.fg : term->colors.bg;
|
||||||
uint32_t _bg = cell->attrs.background >> 30
|
uint32_t _bg = cell->attrs.have_bg
|
||||||
? cell->attrs.background
|
? cell->attrs.bg
|
||||||
: !term->reverse ? term->colors.bg : term->colors.fg;
|
: !term->reverse ? term->colors.bg : term->colors.fg;
|
||||||
|
|
||||||
/* If *one* is set, we reverse */
|
/* 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);
|
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;
|
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);
|
arm_blink_timer(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cell->c[0] == '\0' || cell->attrs.conceal)
|
if (cell->wc == 0 || cell->attrs.conceal)
|
||||||
return cell_cols;
|
return cell_cols;
|
||||||
|
|
||||||
if (glyph != NULL) {
|
if (glyph != NULL) {
|
||||||
|
|
|
||||||
49
selection.c
49
selection.c
|
|
@ -5,6 +5,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <wctype.h>
|
||||||
|
|
||||||
#define LOG_MODULE "selection"
|
#define LOG_MODULE "selection"
|
||||||
#define LOG_ENABLE_DBG 0
|
#define LOG_ENABLE_DBG 0
|
||||||
|
|
@ -58,11 +59,12 @@ extract_selection(const struct terminal *term)
|
||||||
/* TODO: replace '\0' with spaces, then trim lines */
|
/* TODO: replace '\0' with spaces, then trim lines */
|
||||||
for (int col = start_col; col < term->cols; col++) {
|
for (int col = start_col; col < term->cols; col++) {
|
||||||
const struct cell *cell = &row->cells[col];
|
const struct cell *cell = &row->cells[col];
|
||||||
if (cell->c[0] == '\0')
|
if (cell->wc == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
size_t len = strnlen(cell->c, 4);
|
mbstate_t ps = {0};
|
||||||
memcpy(&buf[idx], cell->c, len);
|
size_t len = wcrtomb(&buf[idx], cell->wc, &ps);
|
||||||
|
assert(len >= 0); /* All wchars were valid multibyte strings to begin with */
|
||||||
idx += len;
|
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);
|
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++) {
|
for (int col = start_col; row != NULL && col <= end->col; col++) {
|
||||||
const struct cell *cell = &row->cells[col];
|
const struct cell *cell = &row->cells[col];
|
||||||
if (cell->c[0] == '\0')
|
if (cell->wc == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
size_t len = strnlen(cell->c, 4);
|
mbstate_t ps = {0};
|
||||||
memcpy(&buf[idx], cell->c, len);
|
size_t len = wcrtomb(&buf[idx], cell->wc, &ps);
|
||||||
|
assert(len >= 0); /* All wchars were valid multibyte strings to begin with */
|
||||||
idx += len;
|
idx += len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -214,19 +217,19 @@ selection_cancel(struct terminal *term)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
isword(int c)
|
isword(wint_t c)
|
||||||
{
|
{
|
||||||
switch (c) {
|
switch (c) {
|
||||||
default: return !isspace(c);
|
default: return !iswspace(c);
|
||||||
|
|
||||||
case '{': case '}':
|
case L'{': case L'}':
|
||||||
case '[': case ']':
|
case L'[': case L']':
|
||||||
case '(': case ')':
|
case L'(': case L')':
|
||||||
case '`':
|
case L'`':
|
||||||
case '\'':
|
case L'\'':
|
||||||
case '"':
|
case L'"':
|
||||||
case ',': case '.':
|
case L',': case L'.':
|
||||||
case ':': case ';':
|
case L':': case L';':
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -243,9 +246,9 @@ selection_mark_word(struct terminal *term, int col, int row, uint32_t serial)
|
||||||
struct coord end = {col, row};
|
struct coord end = {col, row};
|
||||||
|
|
||||||
const struct row *r = grid_row_in_view(term->grid, start.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) {
|
while (true) {
|
||||||
int next_col = start.col - 1;
|
int next_col = start.col - 1;
|
||||||
int next_row = start.row;
|
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);
|
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))
|
if (c == 0 || !isword(c))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
start.col = next_col;
|
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);
|
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) {
|
while (true) {
|
||||||
int next_col = end.col + 1;
|
int next_col = end.col + 1;
|
||||||
int next_row = end.row;
|
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);
|
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))
|
if (c == '\0' || !isword(c))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -163,11 +163,12 @@ erase_cell_range(struct terminal *term, struct row *row, int start, int end)
|
||||||
assert(start < term->cols);
|
assert(start < term->cols);
|
||||||
assert(end < 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++) {
|
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.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 {
|
} else {
|
||||||
memset(&row->cells[start], 0, (end - start + 1) * sizeof(row->cells[0]));
|
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 <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
#include <threads.h>
|
#include <threads.h>
|
||||||
#include <semaphore.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
|
* Note: we want the cells to be as small as possible. Larger cells
|
||||||
* means fewer scrollback lines (or performance drops due to cache
|
* means fewer scrollback lines (or performance drops due to cache
|
||||||
* misses) */
|
* misses)
|
||||||
|
*
|
||||||
|
* Note that the members are laid out optimized for x86
|
||||||
|
*/
|
||||||
struct attributes {
|
struct attributes {
|
||||||
uint8_t bold:1;
|
uint32_t bold:1;
|
||||||
uint8_t dim:1;
|
uint32_t dim:1;
|
||||||
uint8_t italic:1;
|
uint32_t italic:1;
|
||||||
uint8_t underline:1;
|
uint32_t underline:1;
|
||||||
uint8_t strikethrough:1;
|
uint32_t strikethrough:1;
|
||||||
uint8_t blink:1;
|
uint32_t blink:1;
|
||||||
uint8_t conceal:1;
|
uint32_t conceal:1;
|
||||||
uint8_t reverse:1;
|
uint32_t reverse:1;
|
||||||
|
uint32_t fg:24;
|
||||||
|
|
||||||
uint32_t clean:1;
|
uint32_t clean:1;
|
||||||
uint32_t foreground:31;
|
uint32_t have_fg:1;
|
||||||
|
uint32_t have_bg:1;
|
||||||
uint32_t reserved:1;
|
uint32_t reserved:5;
|
||||||
uint32_t background:31;
|
uint32_t bg:24;
|
||||||
} __attribute__((packed));
|
};
|
||||||
|
static_assert(sizeof(struct attributes) == 8, "bad size");
|
||||||
|
|
||||||
struct cell {
|
struct cell {
|
||||||
|
wchar_t wc;
|
||||||
struct attributes attrs;
|
struct attributes attrs;
|
||||||
char c[4];
|
};
|
||||||
} __attribute__((packed));
|
static_assert(sizeof(struct cell) == 12, "bad size");
|
||||||
|
|
||||||
struct scroll_region {
|
struct scroll_region {
|
||||||
int start;
|
int start;
|
||||||
|
|
|
||||||
49
vt.c
49
vt.c
|
|
@ -728,33 +728,29 @@ action_print_utf8(struct terminal *term)
|
||||||
|
|
||||||
print_insert(term);
|
print_insert(term);
|
||||||
|
|
||||||
//LOG_DBG("print: UTF8: %.*s", (int)term->vt.utf8.idx, term->vt.utf8.data);
|
mbstate_t ps = {0};
|
||||||
memcpy(cell->c, term->vt.utf8.data, term->vt.utf8.idx);
|
if (mbrtowc(&cell->wc, (const char *)term->vt.utf8.data, term->vt.utf8.idx, &ps) < 0)
|
||||||
cell->c[term->vt.utf8.idx] = '\0';
|
cell->wc = 0;
|
||||||
|
|
||||||
term->vt.utf8.idx = 0;
|
term->vt.utf8.idx = 0;
|
||||||
|
|
||||||
cell->attrs = term->vt.attrs;
|
cell->attrs = term->vt.attrs;
|
||||||
|
|
||||||
/* Hack: zero- and double-width characters */
|
int width = wcwidth(cell->wc);
|
||||||
mbstate_t ps = {0};
|
if (width <= 0) {
|
||||||
wchar_t wc;
|
/* Skip post_print() below - i.e. don't advance cursor */
|
||||||
if (mbrtowc(&wc, cell->c, 4, &ps) >= 0) {
|
return;
|
||||||
int width = wcwidth(wc);
|
}
|
||||||
if (width <= 0) {
|
|
||||||
/* Skip post_print() below - i.e. don't advance cursor */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Advance cursor the 'additional' columns (last step is done
|
/* Advance cursor the 'additional' columns (last step is done
|
||||||
* by post_print()) */
|
* by post_print()) */
|
||||||
for (int i = 1; i < width && term->cursor.col < term->cols - 1; i++) {
|
for (int i = 1; i < width && term->cursor.col < term->cols - 1; i++) {
|
||||||
term_cursor_right(term, 1);
|
term_cursor_right(term, 1);
|
||||||
|
|
||||||
assert(term->cursor.col < term->cols);
|
assert(term->cursor.col < term->cols);
|
||||||
struct cell *cell = &row->cells[term->cursor.col];
|
struct cell *cell = &row->cells[term->cursor.col];
|
||||||
cell->c[0] = '\0';
|
cell->wc = 0;
|
||||||
cell->attrs.clean = 0;
|
cell->attrs.clean = 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
post_print(term);
|
post_print(term);
|
||||||
|
|
@ -788,16 +784,17 @@ action_print(struct terminal *term, uint8_t c)
|
||||||
c >= 0x41 && c <= 0x7e)
|
c >= 0x41 && c <= 0x7e)
|
||||||
{
|
{
|
||||||
const char *glyph = vt100_0[c - 0x41];
|
const char *glyph = vt100_0[c - 0x41];
|
||||||
if (glyph != NULL)
|
if (glyph != NULL) {
|
||||||
strncpy(cell->c, glyph, sizeof(cell->c));
|
mbstate_t ps = {0};
|
||||||
|
if (mbrtowc(&cell->wc, glyph, strlen(glyph), &ps) < 0)
|
||||||
|
cell->wc = 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
//LOG_DBG("print: ASCII: %c", c);
|
//LOG_DBG("print: ASCII: %c", c);
|
||||||
cell->c[0] = c;
|
cell->wc = c;
|
||||||
cell->c[1] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cell->attrs = term->vt.attrs;
|
cell->attrs = term->vt.attrs;
|
||||||
|
|
||||||
post_print(term);
|
post_print(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue