summaryrefslogtreecommitdiffstats
path: root/screen-write.c
diff options
context:
space:
mode:
authornicm <nicm>2023-09-01 14:29:11 +0000
committernicm <nicm>2023-09-01 14:29:11 +0000
commit9456258ccc03a1a959cfb7d020011d751b39bb1b (patch)
tree6f2331046cfde77a7125d3cc54082161f2fc9303 /screen-write.c
parentc41d59f232a7243bfff34ec3f02adc76fddc91b2 (diff)
Rewrite combined character handling to be more consistent and to support
newer Unicode combined characters (which we have to "know" are combined since they are not width zero). GitHub issue 3600.
Diffstat (limited to 'screen-write.c')
-rw-r--r--screen-write.c64
1 files changed, 37 insertions, 27 deletions
diff --git a/screen-write.c b/screen-write.c
index ee3a31a1..88ca77ae 100644
--- a/screen-write.c
+++ b/screen-write.c
@@ -1840,46 +1840,37 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
{
struct screen *s = ctx->s;
struct grid *gd = s->grid;
- const struct utf8_data *ud = &gc->data;
- const struct utf8_data zwj = { "\342\200\215", 0, 3, 0 };
+ struct grid_cell copy;
+ const struct utf8_data *ud = &gc->data, *previous = NULL, *combine;
struct grid_line *gl;
struct grid_cell_entry *gce;
struct grid_cell tmp_gc, now_gc;
struct tty_ctx ttyctx;
u_int sx = screen_size_x(s), sy = screen_size_y(s);
- u_int width = gc->data.width, xx, last, cx, cy;
+ u_int width = ud->width, xx, last, cx, cy;
int selected, skip = 1;
/* Ignore padding cells. */
if (gc->flags & GRID_FLAG_PADDING)
return;
- /*
- * If this is a zero width joiner, set the flag so the next character
- * will be treated as zero width and appended. Note that we assume a
- * ZWJ will not change the width - the width of the first character is
- * used.
- */
- if (ud->size == 3 && memcmp(ud->data, "\342\200\215", 3) == 0) {
- log_debug("zero width joiner at %u,%u", s->cx, s->cy);
- ctx->flags |= SCREEN_WRITE_ZWJ;
+ /* Check if this cell needs to be combined with the previous cell. */
+ if (ctx->flags & SCREEN_WRITE_COMBINE)
+ previous = &ctx->previous;
+ switch (utf8_try_combined(ud, previous, &combine, &width)) {
+ case UTF8_DISCARD_NOW:
+ log_debug("%s: UTF8_DISCARD_NOW (width %u)", __func__, width);
+ ctx->flags &= ~SCREEN_WRITE_COMBINE;
return;
- }
-
- /*
- * If the width is zero, combine onto the previous character. We always
- * combine with the cell to the left of the cursor position. In theory,
- * the application could have moved the cursor somewhere else, but if
- * they are silly enough to do that, who cares?
- */
- if (ctx->flags & SCREEN_WRITE_ZWJ) {
- screen_write_collect_flush(ctx, 0, __func__);
- screen_write_combine(ctx, &zwj, &xx, &cx);
- }
- if (width == 0 || (ctx->flags & SCREEN_WRITE_ZWJ)) {
- ctx->flags &= ~SCREEN_WRITE_ZWJ;
+ case UTF8_WRITE_NOW:
+ log_debug("%s: UTF8_WRITE_NOW (width %u)", __func__, width);
+ ctx->flags &= ~SCREEN_WRITE_COMBINE;
+ break;
+ case UTF8_COMBINE_NOW:
+ log_debug("%s: UTF8_COMBINE_NOW (width %u)", __func__, width);
screen_write_collect_flush(ctx, 0, __func__);
- if ((gc = screen_write_combine(ctx, ud, &xx, &cx)) != NULL) {
+ gc = screen_write_combine(ctx, combine, &xx, &cx);
+ if (gc != NULL) {
cy = s->cy;
screen_write_set_cursor(ctx, xx, s->cy);
screen_write_initctx(ctx, &ttyctx, 0);
@@ -1887,8 +1878,27 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
tty_write(tty_cmd_cell, &ttyctx);
s->cx = cx; s->cy = cy;
}
+ ctx->flags &= ~SCREEN_WRITE_COMBINE;
return;
+ case UTF8_WRITE_MAYBE_COMBINE:
+ log_debug("%s: UTF8_WRITE_MAYBE_COMBINE (width %u)", __func__,
+ width);
+ utf8_copy(&ctx->previous, ud);
+ ctx->flags |= SCREEN_WRITE_COMBINE;
+ break;
+ case UTF8_DISCARD_MAYBE_COMBINE:
+ log_debug("%s: UTF8_DISCARD_MAYBE_COMBINE (width %u)", __func__,
+ width);
+ utf8_copy(&ctx->previous, ud);
+ ctx->flags |= SCREEN_WRITE_COMBINE;
+ return;
+ }
+ if (width != ud->width) {
+ memcpy(&copy, gc, sizeof copy);
+ copy.data.width = width;
+ gc = &copy;
}
+ ud = NULL;
/* Flush any existing scrolling. */
screen_write_collect_flush(ctx, 1, __func__);