diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index a61fd33..c6bb1e6 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -57,8 +57,8 @@ CSS box、observer、瀏覽器量測,以及 TeX node/glue/penalty/macro `inline-block`/`user-select` 等普遍原語。`text-spacing-trim`/ `hanging-punctuation`/`text-emphasis` 等僅作漸進增強,絕不作為唯一機制。**且當 某原生原語在各引擎支援不一致、會與我們託管之版面衝突或重複作用時,須在 - `.juzhen` 範圍內以 `@supports` 顯式禁用之**(如關閉 Blink 的 `text-spacing-trim`/ - `text-autospace`),使三引擎行為收斂於同一路徑(見 §9.1)。 + `.juzhen` 範圍內以 `@supports` 顯式禁用之**(現行關閉 `text-autospace`; + `text-spacing-trim` 不設定),使三引擎行為收斂於同一路徑(見 §9.1)。 - **I5 justify 單份間距**:間隙與擠壓的結構設計,須保證每個標點在 `text-align: justify` 下只貢獻**一份**對齊伸縮量(見 §8)。 - **I6 冪等與可還原**:每個 pass 對其產物打標記,重跑跳過;提供 `revert` **乾淨移除聚珍注入之 @@ -101,6 +101,10 @@ jz.disconnect(); // 停止觀察 變化 → 自動 `revert`+`render` 最近塊、新增之塊直接 `render`(免全容器重掃);render/revert 期間 **暫停觀察**,故 juzhen 自身之 jz-* 注入絕不自觸發。實測編輯 400 段中之一段,局部恢復較全樹快數 百倍。**元素變化正確性**見 §4.1 末「快取生命週期與失效」。 +變更目標與待新增塊皆以交付時的觀察根包含關係檢查;整根未掛入 document 仍可更新, +同批移出根的節點與已離根的舊記錄則跳過,不以 `isConnected` 代替作用域判斷。 +搬入既有塊時,以同批移除來源、私有產物或已知 render 根辨識;先 revert 再 render +撤回舊祖先的語言/級別/功能效果。純新增塊直接 render,但插入子樹的快取先失效。 **增量粒度契約(下游說明八)**:增量更新須以**塊**為粒度——換塊內容(`textContent`/ `innerHTML`)、增刪塊、改分類屬性,皆與全量重繪一致(差分複驗逐位元相同)。**不支持**對聚珍 @@ -208,19 +212,23 @@ ownerToken, setOwnedClass }`。各 pass 共用同一 `finder` 與 resolved optio 執行器先篩出已啟用的 pass,再按 `kind` 分組。所有 `CharifyPass` 共用一次 `finder.eachTextNode(root)`:對每個文本節點依 `order` 呼叫各 pass 的 `collect`, 先把節點與 `WrapRequest` 累積為 work,遍歷結束後才由管線執行器統一套用,避免走訪途中改 DOM。 +走訪前可執行 `prepare(ctx)`;jiya 用此步驟先建立跨透明 Text 的完整標點原子, +一般同節點標點與長詞仍共用上述 collect/apply 流程。 之後 `StandalonePass` 依 `order` 各自呼叫 `render(ctx)`: ``` charify = enabled.filter(kind == "charify").sort(order) standalone = enabled.filter(kind == "standalone").sort(order) +for pass in charify: pass.prepare?.(ctx) walk(root) 一次:對每個 Text,依序把 charify 的 WrapRequest 收入 work for item in work: applyRequests(item.node, item.requests, ownedElements) for pass in standalone: pass.render(ctx) ``` 聚合僅是**執行優化**:邏輯上仍「一功能一 pass」、可獨立開關與 `revert`(I6)。 -需要自訂掃描、跨節點 run 或 layout 的功能採 standalone,不假裝參與 charify 聚合。 +需要完整獨立掃描或 layout 的功能採 standalone;跨節點標點的 prepare 是明列的 +前置掃描,並不算入共享文本走訪的成本。 ### 3.5 v1 向下相容層 — 已移除(I8 退役) @@ -279,6 +287,12 @@ Nvim peek/Claude 模板等 v1 消費端之過渡期。**最後一批 v1 消費 做正則 find,回呼決定如何包裝/插入標記。樣式行內元素(`strong/em/a/span/…`) 透明穿越;block/pill/avoid 中斷邏輯串。此即 v1 Pass A「剝離樣式收集邏輯文本 再反映射」之一般化,提升為可重用引擎。 +- **完整 Unicode 原子**:`collectRuns` 將跨透明 Text 的 surrogate pair 先合成完整碼點, + 再將 base 與至多一個 variation selector 合為原子;`map.parts` 保留所有來源跨度。 + 間隙、禁則與避孤字共用此映射,不在原子中間建間隙/斷點、不把 selector 另算實義字。 + 排除文本(含空 Text)、作用域及元素分類邊界中斷 run,不跨邊界拼接。 + `collectRuns` 與鄰字查詢可傳入功能名;禁用 Text/空透明元素中斷該功能脈絡, + 最近子白名單仍可重新啟用。spacing 與 jiya 的跨節點預處理共用此口徑。 設計要點:finder 不知道任何具體排版規則;它只提供「在何處、跨何種邊界、對哪些 字元」的遍歷與安全變更原語。規則由各 pass 以 unicode 表 + 回呼注入。 @@ -330,7 +344,8 @@ avoid」用組合入口 `isAvoided`(=自身或祖先,階段二歸一,免 漏一半致自身命中 avoid 時仍被穿越)。`adjacentLogicalChar` 之 `descend` 改三態 (邊界字/無內容續找兄弟/**blocked** 終止——遇 pill/isolate/avoid 不可跳過續找 更遠之字,否則重蹈「越過 `jz-char` 取更前字 → 誤隙」之同型錯誤);`core/split` 之 -`canSplit` 諮詢 finder(pill/isolate/avoid 一律不可切、退化整綁)。 +`canSplit` 諮詢 finder(pill/isolate/avoid 一律不可切);整綁仍須通過禁則/避孤字的 +參與範圍檢查,avoid 不參與整綁。 **「行內透明」判定之分層(階段二確立)**:「透明穿越」曾有兩套口徑散落——`collectRuns` 默認透明、`isTransparent`/`adjacentLogicalChar` 默認邊界——同一未登記行內標籤(如 `