summaryrefslogtreecommitdiff
path: root/src/pardes.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/pardes.zig')
-rw-r--r--src/pardes.zig24
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;