diff options
Diffstat (limited to 'src/pardes.zig')
| -rw-r--r-- | src/pardes.zig | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/src/pardes.zig b/src/pardes.zig index 91811cc9..dcc99aea 100644 --- a/src/pardes.zig +++ b/src/pardes.zig @@ -2848,6 +2848,30 @@ pub const Surface = struct { var i: usize = 0; while (i < text.len) { if (col >= end) break; + // ASCII FAST PATH. Printable ASCII is one byte, one cell, one column, and the general + // path below reaches that answer through a UTF-8 length, a decode, a freshly + // constructed grapheme iterator, a slice validation and a width lookup - per character. + // That made this function 26% of a keystroke when profiled in the ESP32-P4's + // configuration (40x12, no tree-sitter), which is the largest single item there. + // + // The guard on the NEXT byte is what makes it correct rather than merely fast: an ASCII + // base joins a following combining mark, ZWJ or spacing mark into ONE cluster, and every + // scalar that can do that is non-ASCII. So an ASCII byte followed by another ASCII byte + // (or by nothing) is a complete grapheme cluster on its own. Same condition + // `modal.nextGrapheme` uses, for the same reason. + // + // `\t`, `\r` and the C0 controls are excluded by the range test and keep their existing + // handling below; DEL is excluded too. + { + const b = text[i]; + if (b >= 0x20 and b < 0x7f and (i + 1 == text.len or text[i + 1] < 0x80)) { + s.set(col, y, text[i .. i + 1], style); + i += 1; + col += 1; + continue; + } + } + if (col >= end) break; // n == 0: not a start byte at all. A short tail or a bad // continuation decodes to null the same way — one U+FFFD, one byte. const n = std.unicode.utf8ByteSequenceLength(text[i]) catch 0; |
