Text, Bidi und IME
Von Bytes über Graphem-Cluster und bidirektionale Absätze bis zur IME-Komposition: zenit behandelt Text als Systemfähigkeit, nicht als Reihe von Glyphen, die pro Codepoint ausgelegt werden.
Eine Zeile, vier Schichten
Speicherung, Bearbeitungsgrenzen, Richtungsauflösung und Plattform-Shaping haben jeweils genau eine Autorität und ergeben zusammen visuelle Zeilen, die sich per Hit-Test treffen und auswählen lassen. Keine Schicht entscheidet für eine andere.
src/text_coresrc/text_core/grapheme.zigsrc/i18n/bidi.zigsrc/render/text_renderer.zigGrapheme statt Codepoints
Ein Familien-Emoji besteht aus sieben Unicode-Scalars (vier Personen und drei ZWJs), é kann e plus ein kombinierender Akut sein, und eine Flagge besteht aus zwei regionalen Indikatoren. Für Nutzer ist jedes davon ein einziges Zeichen. zenit verwendet erweiterte Graphem-Cluster als Atom für Cursorbewegung, Löschen, Auswahl und Kürzen an der Kapazitätsgrenze.
Bidirektionaler Text
Text wird in logischer Reihenfolge gespeichert und in visueller Reihenfolge angezeigt. UAX #9 löst zunächst für jedes Zeichen eine Einbettungsebene auf, dann kehrt Regel L2 die Runs von der höchsten Ebene abwärts um. Unten steht abc אבג 123 in einem LTR-Absatz: Das Hebräische wird zu Ebene 1 aufgelöst, die folgenden Ziffern zu Ebene 2.
Der UAX-#9-Resolver ist zenits eigene portable Implementierung in src/i18n/bidi.zig, mit Eigenschaftstabellen, die aus fest gepinnten Unicode-17.0.0-Daten generiert werden. Unter macOS werden das finale Glyph-Shaping und die RTL-Verbindung weiterhin run-weise an CoreText übergeben – der Text-Renderer zerlegt einen RTL-Run nie pro Codepoint.
Unicode-17-Konformität
Die Laufzeit-Eigenschaftstabellen werden aus im Repo gepinnten Unicode-17.0.0-Daten generiert; die offiziellen Testdateien liegen unverändert unter vendor/unicode/17.0.0 und sind per SHA-256 in SHA256SUMS fixiert. „Unterstützt“ heißt hier nicht eine Handvoll Emoji-Unit-Tests – es heißt, die vollständigen offiziellen Suites auszuführen.
python3 tools/generate_grapheme_data.py --check
python3 tools/generate_bidi_data.py --check
(cd vendor/unicode/17.0.0 && shasum -a 256 -c SHA256SUMS)
zig build test-text-core
zig build test-bidi-conformance--check bestätigt, dass die generierten Zig-Tabellen zu den Daten passen; test-text-core führt jeden GraphemeBreakTest-Fall aus; test-bidi-conformance führt beide vollständigen offiziellen Bidi-Dateien aus (bis UAX #9 Regel L2) und ist auch Teil von zig build test-headless.
IME als Bürger erster Klasse
IME ist nicht das fertige Zeichen, getarnt als Tastendruck. Plattform-Events behalten die Phasen: ime_preedit trägt den Kompositionstext plus einen Cursor-Offset darin, ime_commit trägt den finalen Text. Während der Komposition rendern Input und Textarea unterstrichenen Marked Text, doch der kanonische Buffer ändert sich erst beim Commit. Es gibt kein separates „Verwerfen“-Event – ein leeres Preedit bricht die Komposition ab.
ime_preedit / ime_commit behalten die Phase; ein leeres Preedit bricht abime_phase, ime_preedit_len, buffer, cursor_pos, anchor zurückscripts/verify_ime.sh durchläuft den vollständigen NSTextInputClient-Pfad mit den System-Eingabequellen Pinyin / JapanischIME testen
Der E2E-Client stellt beide Phasen als getrennte RPCs bereit, und inputState liest den echten Zustand eines Eingabefelds per Test-ID zurück.
import { imeCommit, imePreedit, inputState } from "./client";
// The input must already have focus (e.g. click it first).
await imePreedit("nihongo");
let s = await inputState("story.input.name");
// s.ime_phase === "composing", s.ime_preedit_len === 7, s.buffer === ""
await imeCommit("日本語");
s = await inputState("story.input.name");
// s.buffer === "日本語", s.ime_preedit_len === 0
await imePreedit(""); // empty preedit cancels an active compositionDen vollständigen Harness-Workflow finden Sie unter E2E-Harness.


