@8btc/mditor 0.0.13 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/css/content-theme/dark.css +7 -2
- package/dist/index.css +67 -17
- package/dist/index.js +438 -124
- package/dist/index.min.js +1 -1
- package/dist/js/highlight.js/styles/a11y-dark.min.css +82 -2
- package/dist/js/highlight.js/styles/a11y-light.min.css +80 -2
- package/dist/js/highlight.js/styles/agate.min.css +101 -2
- package/dist/js/highlight.js/styles/an-old-hope.min.css +60 -2
- package/dist/js/highlight.js/styles/androidstudio.min.css +57 -1
- package/dist/js/highlight.js/styles/arduino-light.min.css +74 -1
- package/dist/js/highlight.js/styles/arta.min.css +63 -1
- package/dist/js/highlight.js/styles/ascetic.min.css +41 -1
- package/dist/js/highlight.js/styles/atom-one-dark-reasonable.min.css +95 -1
- package/dist/js/highlight.js/styles/atom-one-dark.min.css +72 -1
- package/dist/js/highlight.js/styles/atom-one-light.min.css +72 -1
- package/dist/js/highlight.js/styles/base16/3024.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/apathy.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/apprentice.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/ashes.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-cave-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-cave.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-dune-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-dune.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-estuary-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-estuary.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-forest-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-forest.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-heath-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-heath.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-lakeside-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-lakeside.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-plateau-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-plateau.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-savanna-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-savanna.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-seaside-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-seaside.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-sulphurpool-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atelier-sulphurpool.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/atlas.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/bespin.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/black-metal-bathory.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/black-metal-burzum.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/black-metal-dark-funeral.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/black-metal-gorgoroth.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/black-metal-immortal.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/black-metal-khold.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/black-metal-marduk.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/black-metal-mayhem.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/black-metal-nile.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/black-metal-venom.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/black-metal.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/brewer.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/bright.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/brogrammer.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/brush-trees-dark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/brush-trees.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/chalk.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/circus.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/classic-dark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/classic-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/codeschool.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/colors.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/cupcake.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/cupertino.min.css +95 -1
- package/dist/js/highlight.js/styles/base16/danqing.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/darcula.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/dark-violet.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/darkmoss.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/darktooth.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/decaf.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/default-dark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/default-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/dirtysea.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/dracula.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/edge-dark.min.css +95 -1
- package/dist/js/highlight.js/styles/base16/edge-light.min.css +95 -1
- package/dist/js/highlight.js/styles/base16/eighties.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/embers.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/equilibrium-dark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/equilibrium-gray-dark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/equilibrium-gray-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/equilibrium-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/espresso.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/eva-dim.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/eva.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/flat.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/framer.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/fruit-soda.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/gigavolt.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/github.min.css +95 -1
- package/dist/js/highlight.js/styles/base16/google-dark.min.css +95 -1
- package/dist/js/highlight.js/styles/base16/google-light.min.css +95 -1
- package/dist/js/highlight.js/styles/base16/grayscale-dark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/grayscale-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/green-screen.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/gruvbox-dark-hard.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/gruvbox-dark-medium.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/gruvbox-dark-pale.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/gruvbox-dark-soft.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/gruvbox-light-hard.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/gruvbox-light-medium.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/gruvbox-light-soft.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/hardcore.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/harmonic16-dark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/harmonic16-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/heetch-dark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/heetch-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/helios.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/hopscotch.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/horizon-dark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/horizon-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/humanoid-dark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/humanoid-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/ia-dark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/ia-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/icy-dark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/ir-black.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/isotope.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/kimber.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/london-tube.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/macintosh.min.css +95 -1
- package/dist/js/highlight.js/styles/base16/marrakesh.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/materia.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/material-darker.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/material-lighter.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/material-palenight.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/material-vivid.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/material.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/mellow-purple.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/mexico-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/mocha.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/monokai.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/nebula.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/nord.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/nova.min.css +95 -1
- package/dist/js/highlight.js/styles/base16/ocean.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/oceanicnext.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/one-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/onedark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/outrun-dark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/papercolor-dark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/papercolor-light.min.css +95 -1
- package/dist/js/highlight.js/styles/base16/paraiso.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/pasque.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/phd.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/pico.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/pop.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/porple.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/qualia.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/railscasts.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/rebecca.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/ros-pine-dawn.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/ros-pine-moon.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/ros-pine.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/sagelight.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/sandcastle.min.css +93 -1
- package/dist/js/highlight.js/styles/base16/seti-ui.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/shapeshifter.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/silk-dark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/silk-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/snazzy.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/solar-flare-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/solar-flare.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/solarized-dark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/solarized-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/spacemacs.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/summercamp.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/summerfruit-dark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/summerfruit-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/synth-midnight-terminal-dark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/synth-midnight-terminal-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/tango.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/tender.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/tomorrow-night.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/tomorrow.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/twilight.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/unikitty-dark.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/unikitty-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/vulcan.min.css +93 -1
- package/dist/js/highlight.js/styles/base16/windows-10-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/windows-10.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/windows-95-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/windows-95.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/windows-high-contrast-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/windows-high-contrast.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/windows-nt-light.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/windows-nt.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/woodland.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/xcode-dusk.min.css +97 -1
- package/dist/js/highlight.js/styles/base16/zenburn.min.css +97 -1
- package/dist/js/highlight.js/styles/brown-paper.min.css +54 -1
- package/dist/js/highlight.js/styles/codepen-embed.min.css +53 -1
- package/dist/js/highlight.js/styles/color-brewer.min.css +56 -1
- package/dist/js/highlight.js/styles/dark.min.css +54 -1
- package/dist/js/highlight.js/styles/default.min.css +79 -1
- package/dist/js/highlight.js/styles/devibeans.min.css +80 -2
- package/dist/js/highlight.js/styles/docco.min.css +81 -1
- package/dist/js/highlight.js/styles/far.min.css +59 -1
- package/dist/js/highlight.js/styles/felipec.min.css +89 -2
- package/dist/js/highlight.js/styles/foundation.min.css +74 -1
- package/dist/js/highlight.js/styles/github-dark-dimmed.min.css +87 -2
- package/dist/js/highlight.js/styles/github-dark.min.css +87 -2
- package/dist/js/highlight.js/styles/github.min.css +87 -2
- package/dist/js/highlight.js/styles/gml.min.css +68 -1
- package/dist/js/highlight.js/styles/googlecode.min.css +75 -1
- package/dist/js/highlight.js/styles/gradient-dark.min.css +92 -1
- package/dist/js/highlight.js/styles/gradient-light.min.css +94 -1
- package/dist/js/highlight.js/styles/grayscale.min.css +85 -1
- package/dist/js/highlight.js/styles/hybrid.min.css +75 -1
- package/dist/js/highlight.js/styles/idea.min.css +82 -1
- package/dist/js/highlight.js/styles/intellij-light.min.css +91 -1
- package/dist/js/highlight.js/styles/ir-black.min.css +64 -1
- package/dist/js/highlight.js/styles/isbl-editor-dark.min.css +84 -1
- package/dist/js/highlight.js/styles/isbl-editor-light.min.css +84 -1
- package/dist/js/highlight.js/styles/kimbie-dark.min.css +58 -1
- package/dist/js/highlight.js/styles/kimbie-light.min.css +58 -1
- package/dist/js/highlight.js/styles/lightfair.min.css +73 -1
- package/dist/js/highlight.js/styles/lioshi.min.css +65 -1
- package/dist/js/highlight.js/styles/magula.min.css +59 -1
- package/dist/js/highlight.js/styles/mono-blue.min.css +54 -1
- package/dist/js/highlight.js/styles/monokai-sublime.min.css +72 -1
- package/dist/js/highlight.js/styles/monokai.min.css +66 -1
- package/dist/js/highlight.js/styles/night-owl.min.css +136 -1
- package/dist/js/highlight.js/styles/nnfx-dark.min.css +96 -2
- package/dist/js/highlight.js/styles/nnfx-light.min.css +96 -2
- package/dist/js/highlight.js/styles/nord.min.css +205 -1
- package/dist/js/highlight.js/styles/obsidian.min.css +76 -1
- package/dist/js/highlight.js/styles/panda-syntax-dark.min.css +88 -1
- package/dist/js/highlight.js/styles/panda-syntax-light.min.css +85 -1
- package/dist/js/highlight.js/styles/paraiso-dark.min.css +57 -1
- package/dist/js/highlight.js/styles/paraiso-light.min.css +57 -1
- package/dist/js/highlight.js/styles/pojoaque.min.css +70 -1
- package/dist/js/highlight.js/styles/purebasic.min.css +66 -1
- package/dist/js/highlight.js/styles/qtcreator-dark.min.css +71 -1
- package/dist/js/highlight.js/styles/qtcreator-light.min.css +69 -1
- package/dist/js/highlight.js/styles/rainbow.min.css +73 -1
- package/dist/js/highlight.js/styles/routeros.min.css +77 -1
- package/dist/js/highlight.js/styles/school-book.min.css +57 -1
- package/dist/js/highlight.js/styles/shades-of-purple.min.css +76 -1
- package/dist/js/highlight.js/styles/srcery.min.css +70 -1
- package/dist/js/highlight.js/styles/stackoverflow-dark.min.css +79 -2
- package/dist/js/highlight.js/styles/stackoverflow-light.min.css +79 -2
- package/dist/js/highlight.js/styles/sunburst.min.css +85 -1
- package/dist/js/highlight.js/styles/tokyo-night-dark.min.css +83 -2
- package/dist/js/highlight.js/styles/tokyo-night-light.min.css +83 -2
- package/dist/js/highlight.js/styles/tomorrow-night-blue.min.css +59 -1
- package/dist/js/highlight.js/styles/tomorrow-night-bright.min.css +59 -1
- package/dist/js/highlight.js/styles/vs.min.css +59 -1
- package/dist/js/highlight.js/styles/vs2015.min.css +94 -1
- package/dist/js/highlight.js/styles/xcode.min.css +85 -1
- package/dist/js/highlight.js/styles/xt256.min.css +74 -1
- package/dist/js/icons/material.js +8 -4
- package/dist/method.d.ts +4 -1
- package/dist/method.js +430 -121
- package/dist/method.min.js +1 -1
- package/dist/ts/markdown/codeRender.d.ts +9 -1
- package/dist/ts/util/attachLineNumbers.d.ts +6 -5
- package/dist/types/index.d.ts +8 -1
- package/package.json +2 -2
- package/src/assets/less/_line-number.less +24 -13
- package/src/assets/less/_reset.less +13 -7
- package/src/ts/markdown/codeRender.ts +152 -58
- package/src/ts/markdown/previewRender.ts +69 -25
- package/src/ts/util/attachLineNumbers.ts +382 -98
- package/src/ts/util/editorCommonEvent.ts +15 -8
- package/src/ts/wysiwyg/index.ts +6 -3
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* -
|
|
4
|
-
* -
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
* 功能:为编辑区域批量添加行号与列表/表格标记(O(n))
|
|
3
|
+
* - 块级:为所有 `data-block` 写入 `data-linenumber`
|
|
4
|
+
* - 列表:为 `ul/ol > li` 写入 `data-linenumber`、`data-list-level`、`data-list-number`
|
|
5
|
+
* - 表格:为 `table` 的 `tr` 写入 `data-linenumber`(不为 `th` 设置)
|
|
6
|
+
* - 性能:一次解析 Markdown 建索引,批量收集并一次性更新属性,缓存避免重复计算
|
|
7
|
+
* - 精度:支持嵌套列表、换行列表项、多级序号;表格跨页连续行号,容忍合并单元格
|
|
7
8
|
*/
|
|
8
9
|
export const attachLineNumbersToBlocks = (
|
|
9
10
|
root: HTMLElement,
|
|
@@ -12,6 +13,39 @@ export const attachLineNumbersToBlocks = (
|
|
|
12
13
|
if (!root || !sourceMarkdown) {
|
|
13
14
|
return;
|
|
14
15
|
}
|
|
16
|
+
const t0 = performance.now();
|
|
17
|
+
|
|
18
|
+
const computeHash = (s: string): string => {
|
|
19
|
+
let h = 0;
|
|
20
|
+
for (let i = 0; i < s.length; i++) {
|
|
21
|
+
h = (h * 31 + s.charCodeAt(i)) | 0;
|
|
22
|
+
}
|
|
23
|
+
return `${s.length}:${h}`;
|
|
24
|
+
};
|
|
25
|
+
type ParseCache = {
|
|
26
|
+
srcNorm: string;
|
|
27
|
+
srcLines: string[];
|
|
28
|
+
strippedLines: string[];
|
|
29
|
+
lineLookup: Map<string, number[]>;
|
|
30
|
+
unorderedListEntries: Array<{ ln: number; content: string }>;
|
|
31
|
+
unorderedLookup: Map<string, number[]>;
|
|
32
|
+
orderedListEntries: Array<{ ln: number; content: string }>;
|
|
33
|
+
orderedLookup: Map<string, number[]>;
|
|
34
|
+
orderedGroups: Array<number[]>;
|
|
35
|
+
tableRowLookup: Map<string, number[]>;
|
|
36
|
+
tableGroups: Array<{ rows: number[]; rowTexts: string[] }>;
|
|
37
|
+
};
|
|
38
|
+
const GLOBAL_CACHE: Map<string, ParseCache> =
|
|
39
|
+
(
|
|
40
|
+
globalThis as unknown as {
|
|
41
|
+
__VDITOR_LINE_CACHE__?: Map<string, ParseCache>;
|
|
42
|
+
}
|
|
43
|
+
).__VDITOR_LINE_CACHE__ || new Map<string, ParseCache>();
|
|
44
|
+
(
|
|
45
|
+
globalThis as unknown as {
|
|
46
|
+
__VDITOR_LINE_CACHE__?: Map<string, ParseCache>;
|
|
47
|
+
}
|
|
48
|
+
).__VDITOR_LINE_CACHE__ = GLOBAL_CACHE;
|
|
15
49
|
|
|
16
50
|
const ZWSP = "\u200b";
|
|
17
51
|
|
|
@@ -25,7 +59,10 @@ export const attachLineNumbersToBlocks = (
|
|
|
25
59
|
};
|
|
26
60
|
|
|
27
61
|
const srcNorm = normalize(sourceMarkdown);
|
|
28
|
-
const
|
|
62
|
+
const tNorm = performance.now();
|
|
63
|
+
const hash = computeHash(srcNorm);
|
|
64
|
+
const cached = GLOBAL_CACHE.get(hash);
|
|
65
|
+
const srcLines = cached?.srcLines ?? srcNorm.split("\n");
|
|
29
66
|
const stripInlineMD = (text: string): string => {
|
|
30
67
|
return (
|
|
31
68
|
text
|
|
@@ -58,14 +95,17 @@ export const attachLineNumbersToBlocks = (
|
|
|
58
95
|
.trim()
|
|
59
96
|
);
|
|
60
97
|
};
|
|
61
|
-
const strippedLines =
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
98
|
+
const strippedLines =
|
|
99
|
+
cached?.strippedLines ?? srcLines.map((l) => stripInlineMD(l));
|
|
100
|
+
const lineLookup = cached?.lineLookup ?? new Map<string, number[]>();
|
|
101
|
+
if (!cached) {
|
|
102
|
+
for (let i = 0; i < strippedLines.length; i++) {
|
|
103
|
+
const key = strippedLines[i];
|
|
104
|
+
if (!lineLookup.has(key)) {
|
|
105
|
+
lineLookup.set(key, [i + 1]);
|
|
106
|
+
} else {
|
|
107
|
+
lineLookup.get(key)!.push(i + 1);
|
|
108
|
+
}
|
|
69
109
|
}
|
|
70
110
|
}
|
|
71
111
|
const usedLines = new Set<number>();
|
|
@@ -96,19 +136,26 @@ export const attachLineNumbersToBlocks = (
|
|
|
96
136
|
* 预处理:收集 Markdown 中所有无序列表(ul)行及其去除行内标记后的内容,构建快速查找结构。
|
|
97
137
|
* 仅匹配以 `*`、`-`、`+` 开头的条目,支持任务列表如 `- [ ]`、`* [x]`。
|
|
98
138
|
*/
|
|
99
|
-
const unorderedListEntries: Array<{ ln: number; content: string }> =
|
|
100
|
-
|
|
139
|
+
const unorderedListEntries: Array<{ ln: number; content: string }> =
|
|
140
|
+
cached?.unorderedListEntries ?? [];
|
|
141
|
+
const unorderedLookup =
|
|
142
|
+
cached?.unorderedLookup ?? new Map<string, number[]>();
|
|
101
143
|
const usedUnorderedLines = new Set<number>();
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
144
|
+
if (!cached) {
|
|
145
|
+
for (let i = 0; i < srcLines.length; i++) {
|
|
146
|
+
const raw = srcLines[i];
|
|
147
|
+
const m = raw.match(/^\s*[*+-]\s+(?:\[(?: |x|X)\]\s+)?(.*)$/);
|
|
148
|
+
if (m && typeof m[1] === "string") {
|
|
149
|
+
const contentStripped = stripInlineForList(m[1]);
|
|
150
|
+
unorderedListEntries.push({
|
|
151
|
+
ln: i + 1,
|
|
152
|
+
content: contentStripped,
|
|
153
|
+
});
|
|
154
|
+
if (!unorderedLookup.has(contentStripped)) {
|
|
155
|
+
unorderedLookup.set(contentStripped, [i + 1]);
|
|
156
|
+
} else {
|
|
157
|
+
unorderedLookup.get(contentStripped)!.push(i + 1);
|
|
158
|
+
}
|
|
112
159
|
}
|
|
113
160
|
}
|
|
114
161
|
}
|
|
@@ -147,43 +194,48 @@ export const attachLineNumbersToBlocks = (
|
|
|
147
194
|
/**
|
|
148
195
|
* 预处理:收集 Markdown 中所有有序列表(ol)行及其内容,支持 `1.` 或 `1)` 以及任务列表前缀。
|
|
149
196
|
*/
|
|
150
|
-
const orderedListEntries: Array<{ ln: number; content: string }> =
|
|
151
|
-
|
|
197
|
+
const orderedListEntries: Array<{ ln: number; content: string }> =
|
|
198
|
+
cached?.orderedListEntries ?? [];
|
|
199
|
+
const orderedLookup = cached?.orderedLookup ?? new Map<string, number[]>();
|
|
152
200
|
const usedOrderedLines = new Set<number>();
|
|
153
201
|
const ORDERED_RE =
|
|
154
202
|
/\s*\d+(?:[.)、.。]|[\uFF0E\uFF09\u3001])\s+(?:\[(?: |x|X)\]\s+)?(.*)/;
|
|
155
203
|
const ORDERED_FULL = new RegExp(`^${ORDERED_RE.source}$`);
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
204
|
+
if (!cached) {
|
|
205
|
+
for (let i = 0; i < srcLines.length; i++) {
|
|
206
|
+
const raw = srcLines[i];
|
|
207
|
+
const m = raw.match(ORDERED_FULL);
|
|
208
|
+
if (m && typeof m[1] === "string") {
|
|
209
|
+
const contentStripped = stripInlineForList(m[1]);
|
|
210
|
+
orderedListEntries.push({
|
|
211
|
+
ln: i + 1,
|
|
212
|
+
content: contentStripped,
|
|
213
|
+
});
|
|
214
|
+
if (!orderedLookup.has(contentStripped)) {
|
|
215
|
+
orderedLookup.set(contentStripped, [i + 1]);
|
|
216
|
+
} else {
|
|
217
|
+
orderedLookup.get(contentStripped)!.push(i + 1);
|
|
218
|
+
}
|
|
166
219
|
}
|
|
167
220
|
}
|
|
168
221
|
}
|
|
169
|
-
console.debug("[LineNumber][ol:index]", {
|
|
170
|
-
total: orderedListEntries.length,
|
|
171
|
-
});
|
|
172
222
|
|
|
173
|
-
const orderedGroups: Array<number[]> = [];
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
223
|
+
const orderedGroups: Array<number[]> = cached?.orderedGroups ?? [];
|
|
224
|
+
if (!cached) {
|
|
225
|
+
for (let i = 0; i < srcLines.length; ) {
|
|
226
|
+
const raw = srcLines[i];
|
|
227
|
+
if (ORDERED_FULL.test(raw)) {
|
|
228
|
+
const group: number[] = [];
|
|
229
|
+
while (i < srcLines.length && ORDERED_FULL.test(srcLines[i])) {
|
|
230
|
+
group.push(i + 1);
|
|
231
|
+
i++;
|
|
232
|
+
}
|
|
233
|
+
if (group.length > 0) {
|
|
234
|
+
orderedGroups.push(group);
|
|
235
|
+
}
|
|
236
|
+
} else {
|
|
180
237
|
i++;
|
|
181
238
|
}
|
|
182
|
-
if (group.length > 0) {
|
|
183
|
-
orderedGroups.push(group);
|
|
184
|
-
}
|
|
185
|
-
} else {
|
|
186
|
-
i++;
|
|
187
239
|
}
|
|
188
240
|
}
|
|
189
241
|
|
|
@@ -235,6 +287,8 @@ export const attachLineNumbersToBlocks = (
|
|
|
235
287
|
return buf;
|
|
236
288
|
};
|
|
237
289
|
|
|
290
|
+
const attrUpdates: Array<[HTMLElement, string, string]> = [];
|
|
291
|
+
|
|
238
292
|
const blocks = root.querySelectorAll("[data-block]");
|
|
239
293
|
blocks.forEach((el) => {
|
|
240
294
|
try {
|
|
@@ -244,23 +298,27 @@ export const attachLineNumbersToBlocks = (
|
|
|
244
298
|
return;
|
|
245
299
|
}
|
|
246
300
|
|
|
247
|
-
// 仅 li 需要行号:跳过并清理 ul/ol 自身及其内部嵌套的 p/div 等块
|
|
248
301
|
const tagName = container.tagName;
|
|
249
302
|
if (tagName === "UL" || tagName === "OL") {
|
|
250
|
-
container.
|
|
303
|
+
if (container.getAttribute("data-linenumber")) {
|
|
304
|
+
attrUpdates.push([container, "data-linenumber", ""]);
|
|
305
|
+
}
|
|
251
306
|
return;
|
|
252
307
|
}
|
|
253
308
|
const liAncestor = container.closest("li");
|
|
254
309
|
if (liAncestor) {
|
|
255
|
-
container.
|
|
310
|
+
if (container.getAttribute("data-linenumber")) {
|
|
311
|
+
attrUpdates.push([container, "data-linenumber", ""]);
|
|
312
|
+
}
|
|
256
313
|
return;
|
|
257
314
|
}
|
|
258
315
|
|
|
259
316
|
const text = container.textContent || "";
|
|
260
317
|
const normText = normalize(text);
|
|
261
|
-
// 跳过纯空白块
|
|
262
318
|
if (!normText.trim()) {
|
|
263
|
-
container.
|
|
319
|
+
if (container.getAttribute("data-linenumber")) {
|
|
320
|
+
attrUpdates.push([container, "data-linenumber", ""]);
|
|
321
|
+
}
|
|
264
322
|
return;
|
|
265
323
|
}
|
|
266
324
|
|
|
@@ -292,12 +350,17 @@ export const attachLineNumbersToBlocks = (
|
|
|
292
350
|
|
|
293
351
|
if (lineNumber !== -1) {
|
|
294
352
|
usedLines.add(lineNumber);
|
|
295
|
-
container.
|
|
353
|
+
const cur = container.getAttribute("data-linenumber");
|
|
354
|
+
const val = String(lineNumber);
|
|
355
|
+
if (cur !== val) {
|
|
356
|
+
attrUpdates.push([container, "data-linenumber", val]);
|
|
357
|
+
}
|
|
296
358
|
}
|
|
297
359
|
} catch {
|
|
298
360
|
void 0;
|
|
299
361
|
}
|
|
300
362
|
});
|
|
363
|
+
const tBlockDone = performance.now();
|
|
301
364
|
|
|
302
365
|
/**
|
|
303
366
|
* 为所有 `ul` 下的每个直接 `li` 子元素追加 `data-linenumber`,不修改 `ul` 本身。
|
|
@@ -316,27 +379,59 @@ export const attachLineNumbersToBlocks = (
|
|
|
316
379
|
norm.split("\n").find((l) => l.trim().length > 0) || norm;
|
|
317
380
|
|
|
318
381
|
const ln = findUnorderedListLineNumber(firstLine);
|
|
382
|
+
const level = (() => {
|
|
383
|
+
let depth = 0;
|
|
384
|
+
let p: HTMLElement | null = li;
|
|
385
|
+
while (p) {
|
|
386
|
+
p = p.parentElement as HTMLElement | null;
|
|
387
|
+
if (!p) break;
|
|
388
|
+
const tag = p.tagName;
|
|
389
|
+
if (tag === "UL" || tag === "OL") depth++;
|
|
390
|
+
}
|
|
391
|
+
return depth;
|
|
392
|
+
})();
|
|
393
|
+
const levelStr = String(level);
|
|
394
|
+
const curLevel = li.getAttribute("data-list-level");
|
|
395
|
+
if (curLevel !== levelStr) {
|
|
396
|
+
attrUpdates.push([li, "data-list-level", levelStr]);
|
|
397
|
+
}
|
|
319
398
|
if (ln !== -1) {
|
|
320
399
|
usedUnorderedLines.add(ln);
|
|
321
|
-
li.
|
|
400
|
+
const curLn = li.getAttribute("data-linenumber");
|
|
401
|
+
const val = String(ln);
|
|
402
|
+
if (curLn !== val) {
|
|
403
|
+
attrUpdates.push([li, "data-linenumber", val]);
|
|
404
|
+
}
|
|
322
405
|
} else {
|
|
323
|
-
li.
|
|
406
|
+
if (li.getAttribute("data-linenumber")) {
|
|
407
|
+
attrUpdates.push([li, "data-linenumber", ""]);
|
|
408
|
+
}
|
|
324
409
|
}
|
|
325
410
|
}
|
|
326
411
|
} catch {
|
|
327
412
|
void 0;
|
|
328
413
|
}
|
|
329
414
|
});
|
|
415
|
+
const tUlDone = performance.now();
|
|
330
416
|
|
|
331
417
|
/**
|
|
332
418
|
* 为所有 `ol` 下的每个直接 `li` 子元素追加 `data-linenumber`,不修改 `ol` 本身。
|
|
333
419
|
*/
|
|
334
420
|
const olElements = root.querySelectorAll("ol");
|
|
421
|
+
const orderedIndexMap = new WeakMap<HTMLElement, number>();
|
|
335
422
|
olElements.forEach((ol) => {
|
|
336
423
|
try {
|
|
337
424
|
let currentGroupIdx = -1;
|
|
338
425
|
let lastAssigned = -1;
|
|
426
|
+
const startAttr = Number((ol as HTMLElement).getAttribute("start"));
|
|
427
|
+
const start =
|
|
428
|
+
Number.isFinite(startAttr) && startAttr > 0 ? startAttr : 1;
|
|
339
429
|
const children = Array.from(ol.children);
|
|
430
|
+
let seq = start;
|
|
431
|
+
for (const child of children) {
|
|
432
|
+
if (child.tagName !== "LI") continue;
|
|
433
|
+
orderedIndexMap.set(child as HTMLElement, seq++);
|
|
434
|
+
}
|
|
340
435
|
for (const child of children) {
|
|
341
436
|
if (child.tagName !== "LI") continue;
|
|
342
437
|
const li = child as HTMLElement;
|
|
@@ -347,21 +442,15 @@ export const attachLineNumbersToBlocks = (
|
|
|
347
442
|
|
|
348
443
|
const stripped0 = stripInlineForList(firstLine);
|
|
349
444
|
const stripped = stripped0 || stripInlineMD(firstLine);
|
|
350
|
-
|
|
351
|
-
const available = candidates.filter(
|
|
352
|
-
(n) => !usedOrderedLines.has(n)
|
|
353
|
-
);
|
|
445
|
+
orderedLookup.get(stripped);
|
|
354
446
|
const ln = findOrderedListLineNumber(firstLine);
|
|
355
447
|
if (ln !== -1) {
|
|
356
448
|
usedOrderedLines.add(ln);
|
|
357
|
-
li.
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
line: ln,
|
|
363
|
-
});
|
|
364
|
-
// 记录当前组
|
|
449
|
+
const cur = li.getAttribute("data-linenumber");
|
|
450
|
+
const val = String(ln);
|
|
451
|
+
if (cur !== val) {
|
|
452
|
+
attrUpdates.push([li, "data-linenumber", val]);
|
|
453
|
+
}
|
|
365
454
|
for (let gi = 0; gi < orderedGroups.length; gi++) {
|
|
366
455
|
if (orderedGroups[gi].includes(ln)) {
|
|
367
456
|
currentGroupIdx = gi;
|
|
@@ -370,12 +459,10 @@ export const attachLineNumbersToBlocks = (
|
|
|
370
459
|
}
|
|
371
460
|
lastAssigned = ln;
|
|
372
461
|
} else {
|
|
373
|
-
// 顺序回退:基于当前组或猜测组,按序分配下一未使用行
|
|
374
462
|
let assigned = -1;
|
|
375
463
|
const pickNextFromGroup = (gi: number): number | -1 => {
|
|
376
464
|
if (gi < 0 || gi >= orderedGroups.length) return -1;
|
|
377
465
|
const lines = orderedGroups[gi];
|
|
378
|
-
// 优先从上次分配后续查找
|
|
379
466
|
let startIdx = 0;
|
|
380
467
|
if (lastAssigned !== -1) {
|
|
381
468
|
const idx = lines.indexOf(lastAssigned);
|
|
@@ -396,7 +483,6 @@ export const attachLineNumbersToBlocks = (
|
|
|
396
483
|
assigned = pickNextFromGroup(currentGroupIdx);
|
|
397
484
|
}
|
|
398
485
|
if (assigned === -1) {
|
|
399
|
-
// 猜测组:选择拥有可用行的首个组
|
|
400
486
|
for (
|
|
401
487
|
let gi = 0;
|
|
402
488
|
gi < orderedGroups.length && assigned === -1;
|
|
@@ -412,37 +498,235 @@ export const attachLineNumbersToBlocks = (
|
|
|
412
498
|
|
|
413
499
|
if (assigned !== -1) {
|
|
414
500
|
usedOrderedLines.add(assigned);
|
|
415
|
-
li.
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
group: currentGroupIdx,
|
|
421
|
-
});
|
|
501
|
+
const cur = li.getAttribute("data-linenumber");
|
|
502
|
+
const val = String(assigned);
|
|
503
|
+
if (cur !== val) {
|
|
504
|
+
attrUpdates.push([li, "data-linenumber", val]);
|
|
505
|
+
}
|
|
422
506
|
lastAssigned = assigned;
|
|
423
507
|
} else {
|
|
424
|
-
li.
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
text: firstLine,
|
|
428
|
-
stripped,
|
|
429
|
-
candidates,
|
|
430
|
-
available,
|
|
431
|
-
reason: !stripped0
|
|
432
|
-
? "empty-after-strip"
|
|
433
|
-
: candidates.length === 0
|
|
434
|
-
? "no-index-candidates"
|
|
435
|
-
: available.length === 0
|
|
436
|
-
? "all-candidates-consumed"
|
|
437
|
-
: "fallback-no-match",
|
|
438
|
-
});
|
|
508
|
+
if (li.getAttribute("data-linenumber")) {
|
|
509
|
+
attrUpdates.push([li, "data-linenumber", ""]);
|
|
510
|
+
}
|
|
439
511
|
}
|
|
440
512
|
}
|
|
513
|
+
|
|
514
|
+
const level = (() => {
|
|
515
|
+
let depth = 0;
|
|
516
|
+
let p: HTMLElement | null = li;
|
|
517
|
+
while (p) {
|
|
518
|
+
p = p.parentElement as HTMLElement | null;
|
|
519
|
+
if (!p) break;
|
|
520
|
+
const tag = p.tagName;
|
|
521
|
+
if (tag === "UL" || tag === "OL") depth++;
|
|
522
|
+
}
|
|
523
|
+
return depth;
|
|
524
|
+
})();
|
|
525
|
+
const levelStr = String(level);
|
|
526
|
+
const curLevel = li.getAttribute("data-list-level");
|
|
527
|
+
if (curLevel !== levelStr) {
|
|
528
|
+
attrUpdates.push([li, "data-list-level", levelStr]);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
const numbering = (() => {
|
|
532
|
+
const parts: number[] = [];
|
|
533
|
+
let node: HTMLElement | null = li;
|
|
534
|
+
while (node) {
|
|
535
|
+
const parentOl = node.closest("ol");
|
|
536
|
+
if (!parentOl) break;
|
|
537
|
+
const parentLi =
|
|
538
|
+
parentOl.parentElement?.closest("li") ||
|
|
539
|
+
(parentOl.parentElement as HTMLElement | null);
|
|
540
|
+
const idx = orderedIndexMap.get(node);
|
|
541
|
+
if (typeof idx === "number") {
|
|
542
|
+
parts.push(idx);
|
|
543
|
+
}
|
|
544
|
+
node = parentLi as HTMLElement | null;
|
|
545
|
+
}
|
|
546
|
+
return parts.reverse().join(".");
|
|
547
|
+
})();
|
|
548
|
+
const curNum = li.getAttribute("data-list-number") || "";
|
|
549
|
+
if (numbering && curNum !== numbering) {
|
|
550
|
+
attrUpdates.push([li, "data-list-number", numbering]);
|
|
551
|
+
}
|
|
441
552
|
}
|
|
442
553
|
} catch {
|
|
443
554
|
void 0;
|
|
444
555
|
}
|
|
445
556
|
});
|
|
557
|
+
const tOlDone = performance.now();
|
|
558
|
+
|
|
559
|
+
const tableRowLookup: Map<string, number[]> =
|
|
560
|
+
cached?.tableRowLookup ?? new Map<string, number[]>();
|
|
561
|
+
const tableGroups: Array<{ rows: number[]; rowTexts: string[] }> =
|
|
562
|
+
cached?.tableGroups ?? [];
|
|
563
|
+
if (!cached) {
|
|
564
|
+
const isTableRowLine = (line: string): boolean => {
|
|
565
|
+
return /^\s*\|.*\|\s*$/.test(line);
|
|
566
|
+
};
|
|
567
|
+
const isAlignLine = (line: string): boolean => {
|
|
568
|
+
return /^\s*\|?(?:\s*:?-{2,}:?\s*\|)+\s*:?-{2,}:?\s*\|?\s*$/.test(
|
|
569
|
+
line
|
|
570
|
+
);
|
|
571
|
+
};
|
|
572
|
+
for (let i = 0; i < srcLines.length; ) {
|
|
573
|
+
const header = srcLines[i];
|
|
574
|
+
const align = srcLines[i + 1];
|
|
575
|
+
if (isTableRowLine(header) && isAlignLine(align || "")) {
|
|
576
|
+
const groupRows: number[] = [i + 1];
|
|
577
|
+
const groupRowTexts: string[] = [
|
|
578
|
+
stripInlineMD(header.replace(/^\s*\|?|\|?\s*$/g, "")),
|
|
579
|
+
];
|
|
580
|
+
i += 2;
|
|
581
|
+
while (i < srcLines.length && isTableRowLine(srcLines[i])) {
|
|
582
|
+
groupRows.push(i + 1);
|
|
583
|
+
groupRowTexts.push(
|
|
584
|
+
stripInlineMD(
|
|
585
|
+
srcLines[i].replace(/^\s*\|?|\|?\s*$/g, "")
|
|
586
|
+
)
|
|
587
|
+
);
|
|
588
|
+
i++;
|
|
589
|
+
}
|
|
590
|
+
tableGroups.push({
|
|
591
|
+
rows: groupRows,
|
|
592
|
+
rowTexts: groupRowTexts,
|
|
593
|
+
});
|
|
594
|
+
for (let t = 0; t < groupRowTexts.length; t++) {
|
|
595
|
+
const key = groupRowTexts[t];
|
|
596
|
+
const ln = groupRows[t];
|
|
597
|
+
const arr = tableRowLookup.get(key);
|
|
598
|
+
if (arr) arr.push(ln);
|
|
599
|
+
else tableRowLookup.set(key, [ln]);
|
|
600
|
+
}
|
|
601
|
+
} else {
|
|
602
|
+
i++;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
const usedTableLines = new Set<number>();
|
|
607
|
+
const tIndexDone = performance.now();
|
|
608
|
+
|
|
609
|
+
const tables = root.querySelectorAll("table");
|
|
610
|
+
let groupPtr = 0;
|
|
611
|
+
tables.forEach((table) => {
|
|
612
|
+
try {
|
|
613
|
+
const trs = table.querySelectorAll("tr");
|
|
614
|
+
trs.forEach((tr) => {
|
|
615
|
+
const cells = Array.from(tr.cells);
|
|
616
|
+
const rowText = cells.map((c) => c.textContent || "").join("|");
|
|
617
|
+
const normRow = stripInlineMD(normalize(rowText));
|
|
618
|
+
let ln = pickFirstUnused(tableRowLookup.get(normRow));
|
|
619
|
+
if (ln === -1) {
|
|
620
|
+
while (
|
|
621
|
+
groupPtr < tableGroups.length &&
|
|
622
|
+
tableGroups[groupPtr].rows.every((r) =>
|
|
623
|
+
usedTableLines.has(r)
|
|
624
|
+
)
|
|
625
|
+
) {
|
|
626
|
+
groupPtr++;
|
|
627
|
+
}
|
|
628
|
+
if (groupPtr < tableGroups.length) {
|
|
629
|
+
const g = tableGroups[groupPtr];
|
|
630
|
+
let chosen = -1;
|
|
631
|
+
for (let k = 0; k < g.rows.length; k++) {
|
|
632
|
+
const cand = g.rows[k];
|
|
633
|
+
if (!usedTableLines.has(cand)) {
|
|
634
|
+
chosen = cand;
|
|
635
|
+
break;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
ln = chosen;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
if (ln !== -1) {
|
|
642
|
+
usedTableLines.add(ln);
|
|
643
|
+
const cur = (tr as HTMLElement).getAttribute(
|
|
644
|
+
"data-linenumber"
|
|
645
|
+
);
|
|
646
|
+
const val = String(ln);
|
|
647
|
+
if (cur !== val) {
|
|
648
|
+
attrUpdates.push([
|
|
649
|
+
tr as HTMLElement,
|
|
650
|
+
"data-linenumber",
|
|
651
|
+
val,
|
|
652
|
+
]);
|
|
653
|
+
}
|
|
654
|
+
} else {
|
|
655
|
+
const cur = (tr as HTMLElement).getAttribute(
|
|
656
|
+
"data-linenumber"
|
|
657
|
+
);
|
|
658
|
+
if (cur) {
|
|
659
|
+
attrUpdates.push([
|
|
660
|
+
tr as HTMLElement,
|
|
661
|
+
"data-linenumber",
|
|
662
|
+
"",
|
|
663
|
+
]);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
const ths = tr.querySelectorAll("th");
|
|
667
|
+
ths.forEach((th) => {
|
|
668
|
+
const curTh = (th as HTMLElement).getAttribute(
|
|
669
|
+
"data-linenumber"
|
|
670
|
+
);
|
|
671
|
+
if (curTh) {
|
|
672
|
+
attrUpdates.push([
|
|
673
|
+
th as HTMLElement,
|
|
674
|
+
"data-linenumber",
|
|
675
|
+
"",
|
|
676
|
+
]);
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
});
|
|
680
|
+
} catch {
|
|
681
|
+
void 0;
|
|
682
|
+
}
|
|
683
|
+
});
|
|
684
|
+
const tTableDone = performance.now();
|
|
685
|
+
|
|
686
|
+
for (const [el, attr, val] of attrUpdates) {
|
|
687
|
+
if (val === "") {
|
|
688
|
+
el.removeAttribute(attr);
|
|
689
|
+
} else {
|
|
690
|
+
el.setAttribute(attr, val);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
const tApplyDone = performance.now();
|
|
694
|
+
|
|
695
|
+
if (!cached) {
|
|
696
|
+
GLOBAL_CACHE.set(hash, {
|
|
697
|
+
srcNorm,
|
|
698
|
+
srcLines,
|
|
699
|
+
strippedLines,
|
|
700
|
+
lineLookup,
|
|
701
|
+
unorderedListEntries,
|
|
702
|
+
unorderedLookup,
|
|
703
|
+
orderedListEntries,
|
|
704
|
+
orderedLookup,
|
|
705
|
+
orderedGroups,
|
|
706
|
+
tableRowLookup,
|
|
707
|
+
tableGroups,
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
console.log("[LineNumber][perf]", {
|
|
711
|
+
cached: !!cached,
|
|
712
|
+
times: {
|
|
713
|
+
normalize: Math.round((tNorm - t0) * 100) / 100,
|
|
714
|
+
index: Math.round((tIndexDone - tNorm) * 100) / 100,
|
|
715
|
+
blocks: Math.round((tBlockDone - tIndexDone) * 100) / 100,
|
|
716
|
+
ul: Math.round((tUlDone - tBlockDone) * 100) / 100,
|
|
717
|
+
ol: Math.round((tOlDone - tUlDone) * 100) / 100,
|
|
718
|
+
table: Math.round((tTableDone - tIndexDone) * 100) / 100,
|
|
719
|
+
apply: Math.round((tApplyDone - tTableDone) * 100) / 100,
|
|
720
|
+
total: Math.round((tApplyDone - t0) * 100) / 100,
|
|
721
|
+
},
|
|
722
|
+
counts: {
|
|
723
|
+
blocks: blocks.length,
|
|
724
|
+
ul: ulElements.length,
|
|
725
|
+
ol: olElements.length,
|
|
726
|
+
tables: tables.length,
|
|
727
|
+
updates: attrUpdates.length,
|
|
728
|
+
},
|
|
729
|
+
});
|
|
446
730
|
};
|
|
447
731
|
|
|
448
732
|
/**
|
|
@@ -146,10 +146,10 @@ export const scrollCenter = (vditor: IVditor) => {
|
|
|
146
146
|
window.scrollTo(
|
|
147
147
|
window.scrollX,
|
|
148
148
|
cursorTop +
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
149
|
+
vditor.element.offsetTop +
|
|
150
|
+
vditor.toolbar.element.offsetHeight -
|
|
151
|
+
window.innerHeight / 2 +
|
|
152
|
+
10
|
|
153
153
|
);
|
|
154
154
|
}
|
|
155
155
|
if (
|
|
@@ -337,8 +337,7 @@ export const selectEvent = (vditor: IVditor, editorElement: HTMLElement) => {
|
|
|
337
337
|
let debounceTimer = 0;
|
|
338
338
|
const handleSelection = () => {
|
|
339
339
|
window.clearTimeout(debounceTimer);
|
|
340
|
-
const delay =
|
|
341
|
-
vditor.options.selectionPopover?.debounceDelay ?? 150;
|
|
340
|
+
const delay = vditor.options.selectionPopover?.debounceDelay ?? 150;
|
|
342
341
|
debounceTimer = window.setTimeout(() => {
|
|
343
342
|
const selectText = getSelectText(
|
|
344
343
|
vditor[vditor.currentMode].element
|
|
@@ -372,9 +371,17 @@ export const selectEvent = (vditor: IVditor, editorElement: HTMLElement) => {
|
|
|
372
371
|
);
|
|
373
372
|
|
|
374
373
|
editorElement.addEventListener("keyup", (event: KeyboardEvent) => {
|
|
375
|
-
if (
|
|
374
|
+
if (
|
|
375
|
+
event.shiftKey &&
|
|
376
|
+
(event.key.startsWith("Arrow") ||
|
|
377
|
+
event.key === "Home" ||
|
|
378
|
+
event.key === "End")
|
|
379
|
+
) {
|
|
376
380
|
handleSelection();
|
|
377
|
-
} else if (
|
|
381
|
+
} else if (
|
|
382
|
+
!event.shiftKey &&
|
|
383
|
+
(event.key.startsWith("Arrow") || event.key === "Escape")
|
|
384
|
+
) {
|
|
378
385
|
// Cancel selection or move cursor without selection
|
|
379
386
|
handleSelection();
|
|
380
387
|
}
|