docs: README/ARCHITECTURE 同步階段一/二——設置速查表+三分類分層+avoid 七源+修正過時

goal 2 文檔重整(main 部分)。反映階段一/二之行為與契約變更,並修審計發現之過時內容。

README:
・新增「全部選項速查」表——突出被埋沒之強力設置(lang.style/styleInlines/blockTags/
  skipTags 之標籤名陣列、skipAttribute/isSkipped 函數鉤子)+ HTML 屬性一覽;標明「標籤名
  陣列」與「CSS 選擇器」兩機制之別。
・選項示例補 lang.style;三分類「共用同一判定」改分層表述(邏輯流共用 isTransparent、未知
  行內=嚴格白名單邊界、canSplit/lineedge 為獨立層);avoid 要點改七源+isAvoided 組合入口+
  skipTags 不含 CODE/KBD 之三分類互斥說明。

ARCHITECTURE:
・§3.1 scope.avoid 過時示例修正(無默認、與內建 skipTags 並存,非「追加於內建 avoid」)。
・§4.1 avoid 內建名單去 code/kbd、改七源表述;「共用同一判定」改分層(isTransparent 為邏輯流
  單一真相源+嚴格白名單;canSplit/lineedge 兩層正當不同、不硬併,含 lineedge 須跨 isolate 之
  物理測量理由);transparentInline→isTransparent、avoidsSelf/isAvoided 組合入口。
・§4.2 標點六子類修正(bd-stop/pause/open/close/middle/liga——舊列 bd-cop/bd-sep/quote
  與實作不符)。
This commit is contained in:
2026-07-07 21:16:05 +08:00
parent e3296104a6
commit 3e57c2c2cf
2 changed files with 116 additions and 36 deletions
+41 -30
View File
@@ -86,7 +86,7 @@ jz.revert(root?); // 還原
root: document.body, // 預設處理根;render(root) 可逐次覆寫
include: null, // 啟用選擇器;設則僅處理命中子樹(opt-in)
// 如 ".juzhen, [data-juzhen]"
avoid: "code, kbd, pre, samp, textarea, [contenteditable]", // 追加於內建 avoid
avoid: null, // 追加排除子樹之選擇器(預設 null,與內建 skipTags 名單並存;見 §4.1
},
// 全域逐功能開關(true/false 或細部物件),預設見各 pass
@@ -219,8 +219,10 @@ Nvim peekClaude 模板等 v1 消費端之過渡期。**最後一批 v1 消費
職責(所有 pass 的共同地基):
- **遍歷**`TreeWalker(SHOW_TEXT)``root` 下文本節點。
- **avoid**跳過 avoid 名單之子樹(內建:`code/kbd/pre/samp/textarea/script/
style/SVG/[contenteditable]/[data-jz-skip]`,可由 `scope.avoid` 追加)。
- **avoid**avoid 之**七源**`isSkipped``skipTags` 名單/SVG`contentEditable`
`data-jz-skip``skipAttribute``scope.avoid`)任一命中即跳過其子樹。內建 `skipTags`
`pre/samp/tt/var/script/style/textarea/input`**不含 code/kbd**——二者由 `pillSelector`
以 pill 涵蓋,三分類互斥)。自身判定用 `avoidsSelf`、自身或祖先之組合用 `isAvoided`
- **scope.include**:若設啟用選擇器,僅走訪命中之子樹(opt-in,§3.6)。
- **featureEnabledFor(node, name)**:解析該節點之有效功能集(§3.6),供各 pass 之
`collect` per-node 閘用;結果以元素為鍵快取。
@@ -234,9 +236,11 @@ Nvim peekClaude 模板等 v1 消費端之過渡期。**最後一批 v1 消費
設計要點:finder 不知道任何具體排版規則;它只提供「在何處、跨何種邊界、對哪些
字元」的遍歷與安全變更原語。規則由各 pass 以 unicode 表 + 回呼注入。
**行內元素三分類(下游問題六後確立)**:行內元素對排版有且僅有三種口徑,所有遍歷
原語(`collectRuns``adjacentLogicalChar``eachTextNode`、`jiyaAdjacency` 之相鄰
掃描、`core/split` 之可切判定、orphan 之實義字收集)共用同一判定:
**行內元素三分類(下游問題六後確立)**:行內元素對排版有且僅有三種口徑。**邏輯文本流**之
遍歷原語(`collectRuns``adjacentLogicalChar``jiyaAdjacency` 之相鄰掃描、orphan 之實義字
收集)共用單一判定 `isTransparent`。**未在 `styleInlines` 之未知行內標籤採嚴格白名單、一律
當隔離式邊界**(斷 run/相鄰、內部自成脈絡),透明須顯式登記 `styleInlines`(另兩層見下)。
三口徑:
- **透明**`styleInlines` wrap 類 `jz-*`)——穿越、run 延續、禁則可克隆切分。
- **隔離**`isolateSelector`,預設 `mark`)——邊界斷 run/斷相鄰/不可切分、兩端
@@ -246,25 +250,33 @@ Nvim peekClaude 模板等 v1 消費端之過渡期。**最後一批 v1 消費
過濾 `insidePill`,不 charify/不插間隙/不切分/不下潛),禁則時作為原子鄰字
單位**整體綁入** `jz-jinze`。典型:`code``kbd`、行內公式 `.katex`
判定**以元素為準、非標籤名**`transparentInline(el)`,先排除 pillisolate
avoid 再查標籤集):KaTeX 全樹皆 `<span>`,舊版按標籤名判透明曾令 `canSplit`
`descend` 整棵下潛——禁則把公式內側末字連同完整殼層逐層克隆切出(`splitoff`),
上標漂移錯位(下游問題六);`pillSelector``skipAttribute``scope.avoid` 三層
防護全被刺穿。同根修復:**avoid 自身判定**`avoidsSelf(el)`——`isAvoided` 僅查
祖先鏈,元素自身命中 avoid 時曾被穿越);`adjacentLogicalChar` 之 `descend` 改三態
判定**以元素為準、非標籤名**`isTransparent(el)`,先排除 pillisolateavoid
再查標籤集):KaTeX 全樹皆 `<span>`,舊版按標籤名判透明曾令 `canSplit``descend`
整棵下潛——禁則把公式內側末字連同完整殼層逐層克隆切出(`splitoff`),上標漂移錯位
(下游問題六);`pillSelector``skipAttribute``scope.avoid` 三層防護全被刺穿。
同根修復:**avoid 自身判定** `avoidsSelf(el)` 供遍歷原語逐元素下探自判;一次性「是否
avoid」用組合入口 `isAvoided`(=自身或祖先,階段二歸一,免「avoidsSelf ‖ isAvoided」
漏一半致自身命中 avoid 時仍被穿越)。`adjacentLogicalChar``descend` 改三態
(邊界字/無內容續找兄弟/**blocked** 終止——遇 pillisolateavoid 不可跳過續找
更遠之字,否則重蹈「越過 `jz-char` 取更前字 → 誤隙」之同型錯誤);`core/split`
`canSplit` 諮詢 finderpillisolateavoid 一律不可切、退化整綁)。
**「行內透明」原則之一致性(下游 Bug 修復)**:「邏輯文本應透明穿越之行內元素」一語
須在所有遍歷原語中**口徑一致**,否則同一段文本在不同原語下被切成不同邏輯串、生成相
互矛盾之結果。`transparentInline` 為單一真相源,列入:樣式行內標籤、`jz-hws`
`jz-jinze`wrap 群組、**`jz-char``jz-inner`(標點原子)**。後者必須透明,否則
`adjacentLogicalChar` 之 `descend` 遇標點原子既不進入亦不終止、而是**跳過**它續找更前
之兄弟——`漢字。<code>` 經禁則綁定後pill 左鄰字應為「。」(標點,非 pill 鄰字、不
補間隙),舊邏輯卻越過 `jz-char` 取到「字」誤補 `jz-hws`。修復後與 `collectRuns` 之既
有透明遞迴對齊。同理 `lineedge` 之 `edgeRect` 攀爬集由 `options.finder.styleInlines`
**派生**(非硬編碼子集),免遺漏 `ins``del``sub` 等致行端誤判(T4)。
**「行內透明」判定之分層(階段二確立)**:「透明穿越」曾有兩套口徑散落——`collectRuns`
默認透明、`isTransparent``adjacentLogicalChar` 默認邊界——同一未登記行內標籤(如 `<button>`
在不同原語被判為兩種身份、切出相互矛盾之邏輯串。**階段二歸一**:邏輯文本流共用單一判定
`isTransparent`(列入樣式行內標籤、`jz-hws``jz-jinze` wrap 群組、**`jz-char``jz-inner`
標點原子**——後者必須透明,否則 `adjacentLogicalChar``descend` 遇標點原子既不進入亦不
終止而**跳過**它續找更前之字:`漢字。<code>` 綁定後 pill 左鄰字應為「。」卻誤取「字」補
`jz-hws`);未登記之未知行內標籤採嚴格白名單、一律當邊界。
**另兩層各有正當之不同邊界、刻意不併入 `isTransparent`**(承 lineedge#4 之教訓:正當差異不硬併):
- **結構克隆切分安全**`core/split``canSplit`)——更窄白名單(`STRONG/EM/…`,排除
`<a>``ABBR``RUBY`/帶 `id` 等——切分會重複語義/結構),故「可透明穿越」⊋「可克隆切分」。
- **物理版面**`lineedge``edgeRect`)——依 `getClientRects` 之物理相鄰判行首/行尾,攀爬集
`styleInlines` 派生(免遺漏 `ins``del``sub` 致行端誤判 T4),且**須跨 isolate**`<mark>`
找真實相鄰內容:isolate 斷的是**邏輯** run/相鄰,非**物理**位置(`文字<mark>「引」</mark>`
`「` 物理上接在「文字」後、非行首,若停在 mark 邊界會誤判行首而錯收左半)。
### 4.2 `unicode.ts`——字元分類與規則表
@@ -272,14 +284,13 @@ avoid 再查標籤集):KaTeX 全樹皆 `<span>`,舊版按標籤名判透
- **CJK**:表意文字、假名、注音符號等範圍(沿用並擴充 v1 之 `PANGU_CJK`)。
- **西文**:拉丁字母、數字、常見符號(v1 之 `AN_CHARS` 等)。
- **標點(biaodian)子類**(對應 CSS class):
- `bd-open` 開始括號/引號:`「『(《〈【〖〔[{` 等
- `bd-close` 結束括號/引號:`」』)》〉】〗〕]}` 等
- `bd-cop` 句逗號(comma/period,字面偏移因簡繁而異):`,。.`
- `bd-stop` 句末其餘:`!?;:⁇‼` 等
- `bd-sep` 分隔/間隔號:`·・‧`
- `bd-liga` 連續省略/破折:`…—` 等
- `quote` 彎引號:`“”‘’`
- **標點(biaodian子類**(對應 `jz-char``bd-*` class):
- `bd-stop` 句末點號:`。.!?`(開明式與全角式保持全形,banjiao 擠半)
- `bd-pause` 句內點號:`,、;:`(開明式擠半形)
- `bd-open` 開始括號/引號:`「『(《〈【〖〔[{“‘`
- `bd-close` 結束括號/引號:`」』)》〉】〗〕]}”’`
- `bd-middle` 間隔號:`·・‧`
- `bd-liga` 省略/破折:`…—`
- **規則正則**:中西間隙邊界、擠壓相鄰組合、禁則對象等,皆以此表組裝。
**規則集抽象(`Ruleset``charClass`,可配置)**:字符分類不再各 pass 硬編碼,而統一為
@@ -374,7 +385,7 @@ class 約定:`bd`(標點)、`bd-open/close/cop/stop/sep/liga`、`cjk`、`j
- **邊界正規化一致性(下游回饋 1a/1b 修)**:
- **1a pill 穿越 jz-jinze**jinzeorder 40)先於 spacingorder 50),會把尾隨
標點之 pill 納入 `jz-jinze``adjacentLogicalChar` 須**透明穿越 `jz-jinze`**
(與 `jz-hws`、樣式行內同列,見 `finder.transparentInline`),否則 pill 左鄰字
(與 `jz-hws`、樣式行內同列,見 `finder.isTransparent`),否則 pill 左鄰字
不可達、左緣間隙與作者空格剝除雙失。
- **1b CJK↔CJK 贅餘空格**:中文不用詞間空格,故 CJK 表意字之間的單一 ASCII 作者
空格(含跨樣式行內標籤,`collectRuns` 已透明合併)一律**剝除、不留隙**(以