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:
+41
-30
@@ -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 peek/Claude 模板等 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 peek/Claude 模板等 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 peek/Claude 模板等 v1 消費端之過渡期。**最後一批 v1 消費
|
||||
過濾 `insidePill`,不 charify/不插間隙/不切分/不下潛),禁則時作為原子鄰字
|
||||
單位**整體綁入** `jz-jinze`。典型:`code`/`kbd`、行內公式 `.katex`。
|
||||
|
||||
判定**以元素為準、非標籤名**(`transparentInline(el)`,先排除 pill/isolate/
|
||||
avoid 再查標籤集):KaTeX 全樹皆 `<span>`,舊版按標籤名判透明曾令 `canSplit`/
|
||||
`descend` 整棵下潛——禁則把公式內側末字連同完整殼層逐層克隆切出(`splitoff`),
|
||||
上標漂移錯位(下游問題六);`pillSelector`/`skipAttribute`/`scope.avoid` 三層
|
||||
防護全被刺穿。同根修復:**avoid 以自身判定**(`avoidsSelf(el)`——`isAvoided` 僅查
|
||||
祖先鏈,元素自身命中 avoid 時曾被穿越);`adjacentLogicalChar` 之 `descend` 改三態
|
||||
判定**以元素為準、非標籤名**(`isTransparent(el)`,先排除 pill/isolate/avoid
|
||||
再查標籤集):KaTeX 全樹皆 `<span>`,舊版按標籤名判透明曾令 `canSplit`/`descend`
|
||||
整棵下潛——禁則把公式內側末字連同完整殼層逐層克隆切出(`splitoff`),上標漂移錯位
|
||||
(下游問題六);`pillSelector`/`skipAttribute`/`scope.avoid` 三層防護全被刺穿。
|
||||
同根修復:**avoid 自身判定** `avoidsSelf(el)` 供遍歷原語逐元素下探自判;一次性「是否
|
||||
avoid」用組合入口 `isAvoided`(=自身或祖先,階段二歸一,免「avoidsSelf ‖ isAvoided」
|
||||
漏一半致自身命中 avoid 時仍被穿越)。`adjacentLogicalChar` 之 `descend` 改三態
|
||||
(邊界字/無內容續找兄弟/**blocked** 終止——遇 pill/isolate/avoid 不可跳過續找
|
||||
更遠之字,否則重蹈「越過 `jz-char` 取更前字 → 誤隙」之同型錯誤);`core/split` 之
|
||||
`canSplit` 諮詢 finder(pill/isolate/avoid 一律不可切、退化整綁)。
|
||||
|
||||
**「行內透明」原則之一致性(下游 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**:jinze(order 40)先於 spacing(order 50),會把尾隨
|
||||
標點之 pill 納入 `jz-jinze`。`adjacentLogicalChar` 須**透明穿越 `jz-jinze`**
|
||||
(與 `jz-hws`、樣式行內同列,見 `finder.transparentInline`),否則 pill 左鄰字
|
||||
(與 `jz-hws`、樣式行內同列,見 `finder.isTransparent`),否則 pill 左鄰字
|
||||
不可達、左緣間隙與作者空格剝除雙失。
|
||||
- **1b CJK↔CJK 贅餘空格**:中文不用詞間空格,故 CJK 表意字之間的單一 ASCII 作者
|
||||
空格(含跨樣式行內標籤,`collectRuns` 已透明合併)一律**剝除、不留隙**(以
|
||||
|
||||
@@ -84,7 +84,8 @@ jz.render(document.querySelector("main"));
|
||||
createJuzhen({
|
||||
lang: {
|
||||
default: "zh-Hant", // 無 lang 祖先時之預設
|
||||
policy: { "zh-Hant": "quanjiao", "zh-Hans": "kaiming" }, // 全角/開明/半角
|
||||
style: "kaiming", // 全域政策一鍵覆寫(quanjiao|kaiming|banjiao)
|
||||
policy: { "zh-Hant": "quanjiao", "zh-Hans": "kaiming" }, // 逐 lang(最高優先)
|
||||
},
|
||||
scope: {
|
||||
root: document.body, // 處理根;render(root) 可逐次覆寫
|
||||
@@ -108,14 +109,78 @@ createJuzhen({
|
||||
});
|
||||
```
|
||||
|
||||
### 全部選項速查(含少見但強力者)
|
||||
|
||||
完整選項一覽。**「標籤名」型別只吃大寫標籤名陣列**(精確比對 `nodeName`),與
|
||||
`pillSelector`/`isolateSelector`/`scope.*`(**CSS 選擇器**,可用 class/屬性)**不同機制**,
|
||||
勿混。斜體「詳見」指向本文檔展開該項之小節。
|
||||
|
||||
**語言與擠壓政策**(優先序:`policy` > `style` > 逐語言內建)
|
||||
|
||||
| 選項 | 型別 | 預設 | 作用 |
|
||||
|---|---|---|---|
|
||||
| `lang.default` | string | `"zh-Hant"` | 無 `lang` 祖先時之預設語言標籤 |
|
||||
| `lang.style` | `quanjiao|kaiming|banjiao` | 逐語言內建(繁→全角、簡→開明) | **全域政策一鍵覆寫** |
|
||||
| `lang.policy` | `Record<lang, style>` | `{}` | 逐 lang 政策(最高優先) |
|
||||
|
||||
**作用域**
|
||||
|
||||
| 選項 | 型別 | 預設 | 作用 |
|
||||
|---|---|---|---|
|
||||
| `scope.root` | Element|選擇器 | `document.body` | 處理根(`render(root)` 可逐次覆寫) |
|
||||
| `scope.include` | 選擇器 | `null` | opt-in:僅處理命中此選擇器之子樹 |
|
||||
| `scope.avoid` | 選擇器 | `null` | 追加排除子樹 |
|
||||
|
||||
**功能開關 / 對齊 / 分級 / 分塊**(詳見「已實作功能」表及各節)
|
||||
|
||||
| 選項 | 型別 | 預設 | 作用 |
|
||||
|---|---|---|---|
|
||||
| `spacing` | bool | `true` | 中西間隙 |
|
||||
| `longWord` | bool|`{minLength,lang}` | `true`(`{6,"en"}`) | 長英文詞斷字 |
|
||||
| `jiya` | bool|`{halfWidth,bias}` | `true` | 標點擠壓(*詳見「標點半形」*) |
|
||||
| `jinze` | bool | `true` | 禁則避頭尾 |
|
||||
| `orphan` | bool|`{chars}` | `true`(`{chars:2}`) | 垂懸字避免 |
|
||||
| `justifyAtoms` | bool | `true` | inline-block 對齊原子(分頁器設 `false`) |
|
||||
| `level.text` | 選擇器 | `null` | 命中子樹僅跑文本級(*詳見「功能分級」*) |
|
||||
| `blocks` | `{selector,features}[]` | `[]` | 分塊功能選擇 |
|
||||
| `charClass` | `{cjk,western,biaodian}` | — | 追加字符分類(*詳見「自定義字符分類」*) |
|
||||
|
||||
**行內三分類與排除**(*詳見「行內元素三分類」*)
|
||||
|
||||
| 選項 | 型別 | 預設 | 作用 |
|
||||
|---|---|---|---|
|
||||
| `pillSelector` | CSS 選擇器 | `"code, kbd"` | 整體元素(內部不可見、兩端補隙) |
|
||||
| `isolateSelector` | CSS 選擇器 | `"mark"`(`""` 停用) | 隔離元素(內部照常、兩端補隙) |
|
||||
| `styleInlines` | 標籤名[] | 27 個標準行內標籤 | **透明穿越白名單**(未列之行內標籤=邊界) |
|
||||
| `blockTags` | 標籤名[] | 36 個塊標籤 | 塊級邊界集 |
|
||||
| `skipTags` | 標籤名[] | `PRE,SAMP,TT,VAR,SCRIPT,STYLE,TEXTAREA,INPUT` | avoid 標籤集(**不含 CODE/KBD**,由 pill 涵蓋) |
|
||||
| `skipAttribute` | string | `null` | 自訂「跳過」屬性名(命中即 avoid) |
|
||||
| `isSkipped` | `(node)=>bool` | `null` | 自訂跳過謂詞(函數級排除鉤子) |
|
||||
|
||||
**HTML 屬性**(就近繼承,最近祖先勝)
|
||||
|
||||
| 屬性 | 值 | 作用 |
|
||||
|---|---|---|
|
||||
| `data-jz-level` | `text|paragraph` | 逐子樹功能分級 |
|
||||
| `data-juzhen` | 功能名(空格分隔) | 白名單:僅列出之功能生效 |
|
||||
| `data-juzhen-off` | 功能名 | 黑名單:停用列出之功能 |
|
||||
| `data-jz-skip` | (存在即可) | 標記元素為 avoid(內外皆不處理) |
|
||||
| `data-jz-halfwidth` | `halt|margin` | 逐子樹半形渲染模式 |
|
||||
|
||||
**預留、當前無效果**:`hanging`(已移除,見下);`biaodian`/`emphasis`/`ruby`(架構預留切片
|
||||
#7/#8)。注意頂層 `biaodian`(功能開關)與 `charClass.biaodian`(標點子類擴充表)**同名異義**。
|
||||
|
||||
### 行內元素三分類:透明/隔離/整體
|
||||
|
||||
行內元素對排版有且僅有三種口徑,**所有遍歷原語共用同一判定**(中西間隙、擠壓相鄰、
|
||||
禁則綁定、垂懸字、克隆切分皆一致):
|
||||
行內元素對排版有且僅有三種口徑。**邏輯文本流之遍歷原語**(中西間隙、擠壓相鄰、禁則綁定、
|
||||
垂懸字)**共用同一判定** `isTransparent`;未在 `styleInlines` 之**未知行內標籤**(自訂元素/
|
||||
web component 等)採**嚴格白名單**、一律當**邊界**(語義同隔離、內部自成脈絡),透明須顯式
|
||||
登記 `styleInlines`。(另兩層各有其正當之邊界、刻意不併入:結構克隆切分之安全白名單
|
||||
`canSplit`、行端物理版面測量 `lineedge`,詳見 `ARCHITECTURE.md`。)
|
||||
|
||||
| 分類 | 選擇器 | 邊界 | 內部 | 典型 |
|
||||
|---|---|---|---|---|
|
||||
| **透明** | `styleInlines`(預設常見樣式標籤) | 穿越——間隙/相鄰/run 皆延續 | 照常處理;禁則可**克隆切分**(最小綁定) | `strong`/`em`/`b`/`i`/`a`/`span` |
|
||||
| **透明** | `styleInlines`(預設 27 個常見樣式標籤;**未列之行內標籤=邊界**) | 穿越——間隙/相鄰/run 皆延續 | 照常處理;禁則可**克隆切分**(最小綁定) | `strong`/`em`/`b`/`i`/`a`/`span`(自訂元素須自行登記) |
|
||||
| **隔離** | `isolateSelector`(預設 `"mark"`) | 斷 run/斷相鄰/不可切分;**兩端**與 CJK/西文相鄰時補 `jz-hws` 間隙 | **照常處理**(自成脈絡:內部標點照擠、內部中西照補隙) | 帶背景色之 `<mark>`、badge 類盒樣式行內 |
|
||||
| **整體** | `pillSelector`(預設 `"code, kbd"`) | 同隔離(邊界斷、兩端補隙) | **完全不可見**——不 charify、不插間隙、不切分、不下潛 | `code`/`kbd`、行內公式 `.katex`、引用標 `.cite-ref` |
|
||||
|
||||
@@ -127,8 +192,12 @@ createJuzhen({
|
||||
同一段邊界處理代碼),差異僅在內部;同一元素同時命中兩選擇器時 **pill 勝出**(內部不可見)。
|
||||
- **禁則之整體綁定**:pill 緊鄰禁則標點時(`…$公式$,`),整個 pill 作為原子鄰字單位
|
||||
綁入 `jz-jinze`(公式本不可斷,無額外代價);隔離元素同樣整綁(切分背景盒有可見接縫)。
|
||||
- **`scope.avoid`/`skipAttribute`/`data-jz-skip` 以自身判定**:命中元素自身即邊界、
|
||||
內外皆不處理(舊版僅查祖先,元素自身命中時仍被穿越)。
|
||||
- **avoid(排除)之七種來源**,任一命中即邊界、內外皆不處理:`isSkipped` 謂詞/`skipTags`
|
||||
標籤集/SVG/`contentEditable`/`data-jz-skip` 屬性/`skipAttribute`(自訂屬性名)/
|
||||
`scope.avoid` 選擇器。**以自身判定**(元素自身命中即是,非僅查祖先);一次性檢查用
|
||||
`isAvoided`(自身或祖先之組合判定)。**`skipTags` 預設不含 `CODE`/`KBD`**——二者已由
|
||||
`pillSelector` 以 pill 涵蓋(三分類互斥;若把 `code` 移出 `pillSelector`,須自行加入
|
||||
`skipTags`/`scope.avoid`,否則其內部將被當普通文本處理)。
|
||||
- **行內公式/夾注引用宜列為 pill**:`pillSelector: "code, kbd, .katex, .cite-ref"`——
|
||||
獨立行內單位以 pill 邊界邏輯統一處理(兩側補隙、吸收作者空格、整體綁定)。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user