summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core.h33
-rw-r--r--src/text.c158
2 files changed, 128 insertions, 63 deletions
diff --git a/src/core.h b/src/core.h
index 79e6eb9..aab2cde 100644
--- a/src/core.h
+++ b/src/core.h
@@ -30,6 +30,39 @@ static inline void sc_print_ascii(struct term *t, const char *s, int n);
/* Print one glyph (single codepoint or cluster handle). */
void term_sc_print_glyph(struct term *t, uint32_t cp, int width, uint16_t flags);
+static inline void sc_print_cell(struct term *t, uint32_t cp, int width, uint16_t flags)
+{
+ if (TERM_EXPECT(width == 1 && !t->pending_wrap && !t->insert_mode &&
+ !t->lr_margin_mode && t->cursor_x < t->cols, 1)) {
+ struct srow *srow = term_row(t, t->cursor_y);
+ int cx = t->cursor_x;
+ int len = srow->len;
+ if (TERM_EXPECT(srow->kind == ROW_CELLS && cx <= len, 1)) {
+ struct cell *row = srow->cells;
+ if (TERM_EXPECT(!((cx < len && (row[cx].flags & CELL_TRAIL)) ||
+ (cx + 1 < len && (row[cx + 1].flags & CELL_TRAIL))), 1)) {
+ row[cx] = (struct cell){cp,
+ t->inverse ? t->cur_bg : t->cur_fg,
+ t->inverse ? t->cur_fg : t->cur_bg,
+ flags, t->cur_link};
+ t->last_char = cp;
+ cx++;
+ if (cx > len) srow->len = (uint16_t)cx;
+ srow->version++;
+ if (cx < t->cols) {
+ t->cursor_x = cx;
+ t->pending_wrap = false;
+ } else {
+ t->cursor_x = t->cols - 1;
+ t->pending_wrap = t->autowrap;
+ }
+ return;
+ }
+ }
+ }
+ term_sc_print_glyph(t, cp, width, flags);
+}
+
/* Extend the last printed glyph into a grapheme cluster. */
bool term_sc_extend_cluster(struct term *t, uint32_t cp, int klass);
diff --git a/src/text.c b/src/text.c
index 80c4914..88b23a5 100644
--- a/src/text.c
+++ b/src/text.c
@@ -23,7 +23,7 @@ static void dispatch_c1_control(struct term *t, uint32_t cp)
term_escape_byte(t, (unsigned char)ch);
}
-static inline void emit_codepoint(struct term *t, uint32_t cp, int klass)
+static inline void emit_codepoint(struct term *t, uint32_t cp, int klass, uint16_t flags)
{
static const uint32_t dec_graphics[] = {
0x00a0,
@@ -39,14 +39,14 @@ static inline void emit_codepoint(struct term *t, uint32_t cp, int klass)
cp = dec_graphics[cp - '_'];
klass = -1;
}
- term_sc_print_glyph(t, cp, klass, term_current_flags(t));
+ sc_print_cell(t, cp, klass, flags);
}
-static inline void emit_decoded(struct term *t, uint32_t cp)
+static inline void emit_decoded(struct term *t, uint32_t cp, uint16_t flags)
{
int klass = term_text_class(cp);
if (!term_sc_extend_cluster(t, cp, klass))
- emit_codepoint(t, cp, klass);
+ emit_codepoint(t, cp, klass, flags);
}
/* A byte that cannot continue a UTF-8 sequence ends it: the unfinished
@@ -56,13 +56,13 @@ void term_text_utf8_interrupt(struct term *t)
if (TERM_EXPECT(t->utf8_state == UTF8_ACCEPT, 1))
return;
t->utf8_state = UTF8_ACCEPT;
- emit_decoded(t, 0xFFFD);
+ emit_decoded(t, 0xFFFD, term_current_flags(t));
}
void term_text_ground(struct term *t, unsigned char ch)
{
if (ch >= 0x20 && ch < 0x7f && t->utf8_state == UTF8_ACCEPT) {
- emit_codepoint(t, ch, 1);
+ emit_codepoint(t, ch, 1, term_current_flags(t));
return;
}
@@ -94,10 +94,10 @@ void term_text_ground(struct term *t, unsigned char ch)
uint32_t before = t->utf8_state;
uint32_t st = utf8_decode(&t->utf8_state, &t->utf8_codep, ch);
if (st == UTF8_ACCEPT) {
- emit_decoded(t, t->utf8_codep);
+ emit_decoded(t, t->utf8_codep, term_current_flags(t));
} else if (st == UTF8_REJECT) {
t->utf8_state = UTF8_ACCEPT;
- emit_decoded(t, 0xFFFD);
+ emit_decoded(t, 0xFFFD, term_current_flags(t));
/* The byte that ended an unfinished sequence starts anew. */
if (before != UTF8_ACCEPT)
term_text_ground(t, ch);
@@ -131,15 +131,15 @@ static inline bool try_text_run(struct term *t, const char *buf, size_t len,
((unsigned char)buf[i] < 0xc2 || (unsigned char)buf[i] > 0xf4)) ||
t->last_char == 0x200D || grapheme_is_handle(t->last_char))
return false;
+ if (t->cursor_x != 0 &&
+ t->cursor_x != term_row(t, t->cursor_y)->len)
+ return false;
if ((unsigned char)buf[i] >= 0x80) {
uint32_t cp;
int bytes = utf8_decode_one(buf + i, len - i, &cp);
if (!bytes || term_text_class(cp) <= 0)
return false;
}
- if (t->cursor_x != 0 &&
- t->cursor_x != term_row(t, t->cursor_y)->len)
- return false;
struct text_pen pen = term_text_pen(t);
bool wrote = false;
do {
@@ -201,6 +201,7 @@ static void term_feed_inner(struct term *t, const char *buf, size_t len, unsigne
if (!t || !buf || len == 0)
return;
t->transport_newline = (flags & TERM_FEED_ONLCR) != 0;
+ uint16_t cur_flags = term_current_flags(t);
for (size_t i = 0; i < len; i++) {
while (t->state != ST_GROUND) {
@@ -210,6 +211,7 @@ static void term_feed_inner(struct term *t, const char *buf, size_t len, unsigne
i += term_escape_str(t, buf + i, len - i);
else
term_escape_byte(t, (unsigned char)buf[i++]);
+ cur_flags = term_current_flags(t);
if (i == len) return;
}
@@ -220,7 +222,10 @@ static void term_feed_inner(struct term *t, const char *buf, size_t len, unsigne
int avail = t->pending_wrap ? t->cols : t->cols - t->cursor_x;
int rem = (int)(len - i);
if (rem > avail) rem = avail;
- int run = scan_ascii_run(buf + i, rem);
+ int run = 1;
+ if (rem > 1 && (unsigned char)buf[i + 1] >= 0x20 &&
+ (unsigned char)buf[i + 1] < 0x7f)
+ run += scan_ascii_run(buf + i + 1, rem - 1);
if (TERM_EXPECT(can_stream_bottom(t), 1) &&
(run == t->cols ||
(i + (size_t)run < len &&
@@ -260,70 +265,97 @@ static void term_feed_inner(struct term *t, const char *buf, size_t len, unsigne
continue;
}
- if ((ch < 0x20 || ch == 0x7f) && t->state == ST_GROUND)
- term_text_utf8_interrupt(t);
-
- if (TERM_EXPECT(ch < 0x20 && t->state == ST_GROUND &&
- ch != 0x1b && ch != '\n' && ch != '\r' && ch != '\b' && ch != '\t' &&
- ch != 0x0e && ch != 0x0f && ch != 0x07 && ch != 0x0b &&
- ch != 0x0c, 0)) {
- continue;
- }
-
- if (TERM_EXPECT(ch == 0x1b && t->state == ST_GROUND &&
- t->utf8_state == UTF8_ACCEPT && i + 1 < len &&
- buf[i + 1] == '[' && !t->insert_mode &&
- !t->lr_margin_mode && !t->graphics, 0)) {
- int fast = term_try_fast_csi(t, buf + i + 2, len - i - 2);
- if (fast > 0) {
- i += 1 + (size_t)fast;
+ if (TERM_EXPECT(ch >= 0x80, 1)) {
+ if (TERM_EXPECT(t->state == ST_GROUND &&
+ t->utf8_state == UTF8_ACCEPT && !t->graphics, 1)) {
+ if (ch >= 0xc2 && ch <= 0xf4 &&
+ (i + 1 == len || ((unsigned char)buf[i + 1] & 0xc0) == 0x80)) {
+ if (!t->insert_mode && !t->lr_margin_mode &&
+ try_text_run(t, buf, len, &i))
+ continue;
+ } else {
+ if (TERM_EXPECT(t->last_char != 0x200D && !grapheme_is_handle(t->last_char), 1))
+ sc_print_cell(t, 0xFFFD, 1, cur_flags);
+ else
+ emit_decoded(t, 0xFFFD, cur_flags);
+ continue;
+ }
+ uint32_t cp;
+ int cp_len = decode_ground_utf8(t, buf + i, len - i, &cp);
+ if (cp)
+ emit_decoded(t, cp, cur_flags);
+ i += (size_t)(cp_len - 1);
continue;
}
- t->state = ST_CSI;
- csi_parser_reset(&t->csi_parser);
- i += 1 + term_escape_csi(t, buf + i + 2, len - i - 2);
- continue;
- }
-
- if (TERM_EXPECT(t->state == ST_GROUND && ch == '\n', 0)) {
- size_t end = i + 1 + scan_byte_run(buf + i + 1, len - i - 1, '\n');
- if (term_lnm(t)) sc_cr(t);
- sc_linefeed(t, end - i);
- i = end - 1;
- continue;
- }
-
- if (TERM_EXPECT(t->state == ST_GROUND && ch == '\r' &&
- i + 1 < len && buf[i + 1] == '\n', 0)) {
- size_t end = i + 2 + scan_crlf_pairs(buf + i + 2, len - i - 2);
- sc_cr(t);
- sc_linefeed(t, (end - i) / 2);
- i = end - 1;
+ if (TERM_EXPECT(t->state == ST_GROUND, 1))
+ term_text_ground(t, ch);
+ else
+ term_escape_byte(t, ch);
continue;
}
- if (TERM_EXPECT(ch == '\r' && t->state == ST_GROUND, 0)) {
- sc_cr(t);
- continue;
- }
+ if (TERM_EXPECT(ch < 0x20 || ch == 0x7f, 0)) {
+ if (t->state == ST_GROUND) {
+ term_text_utf8_interrupt(t);
+ if (ch == 0x7f || ((1u << ch) & 0x0800FF80u) == 0)
+ continue;
- if (TERM_EXPECT(ch >= 0x80 && t->state == ST_GROUND &&
- t->utf8_state == UTF8_ACCEPT && !t->graphics, 1)) {
- if (!t->insert_mode && !t->lr_margin_mode &&
- try_text_run(t, buf, len, &i))
+ switch (ch) {
+ case '\n':
+ case 0x0b:
+ case 0x0c: {
+ size_t end = i + 1 + scan_byte_run(buf + i + 1, len - i - 1, '\n');
+ if (term_lnm(t)) sc_cr(t);
+ sc_linefeed(t, end - i);
+ i = end - 1;
+ continue;
+ }
+ case '\r':
+ if (i + 1 < len && buf[i + 1] == '\n') {
+ size_t end = i + 2 + scan_crlf_pairs(buf + i + 2, len - i - 2);
+ sc_cr(t);
+ sc_linefeed(t, (end - i) / 2);
+ i = end - 1;
+ } else {
+ sc_cr(t);
+ }
+ continue;
+ case 0x1b:
+ if (t->utf8_state == UTF8_ACCEPT && i + 1 < len &&
+ buf[i + 1] == '[' && !t->insert_mode &&
+ !t->lr_margin_mode && !t->graphics) {
+ int fast = term_try_fast_csi(t, buf + i + 2, len - i - 2);
+ if (fast > 0) {
+ cur_flags = term_current_flags(t);
+ i += 1 + (size_t)fast;
+ continue;
+ }
+ t->state = ST_CSI;
+ csi_parser_reset(&t->csi_parser);
+ i += 1 + term_escape_csi(t, buf + i + 2, len - i - 2);
+ cur_flags = term_current_flags(t);
+ continue;
+ }
+ term_text_ground(t, ch);
+ cur_flags = term_current_flags(t);
+ continue;
+ default:
+ term_text_ground(t, ch);
+ cur_flags = term_current_flags(t);
+ continue;
+ }
+ } else {
+ term_escape_byte(t, ch);
+ cur_flags = term_current_flags(t);
continue;
- uint32_t cp;
- int cp_len = decode_ground_utf8(t, buf + i, len - i, &cp);
- if (cp)
- emit_decoded(t, cp);
- i += (size_t)(cp_len - 1);
- continue;
+ }
}
if (TERM_EXPECT(t->state == ST_GROUND, 1))
term_text_ground(t, ch);
else
term_escape_byte(t, ch);
+ cur_flags = term_current_flags(t);
}
}