@inhuman.tools/quickdraw 0.0.0-stage → 0.3.0
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/LICENSE.md +7 -0
- package/README.md +101 -2
- package/aurora.vert +168 -0
- package/dist/bench/host.d.ts +62 -0
- package/dist/bench/host.d.ts.map +1 -0
- package/dist/bench/host.js +77 -0
- package/dist/bench/host.js.map +1 -0
- package/dist/bench/main.d.ts +6 -0
- package/dist/bench/main.d.ts.map +1 -0
- package/dist/bench/main.js +118 -0
- package/dist/bench/main.js.map +1 -0
- package/dist/bench/model.d.ts +36 -0
- package/dist/bench/model.d.ts.map +1 -0
- package/dist/bench/model.js +112 -0
- package/dist/bench/model.js.map +1 -0
- package/dist/bench/tea.d.ts +14 -0
- package/dist/bench/tea.d.ts.map +1 -0
- package/dist/bench/tea.js +6 -0
- package/dist/bench/tea.js.map +1 -0
- package/dist/bench/view.d.ts +9 -0
- package/dist/bench/view.d.ts.map +1 -0
- package/dist/bench/view.js +88 -0
- package/dist/bench/view.js.map +1 -0
- package/dist/bench/worker.d.ts +6 -0
- package/dist/bench/worker.d.ts.map +1 -0
- package/dist/bench/worker.js +46 -0
- package/dist/bench/worker.js.map +1 -0
- package/dist/buffer/bgfx-mark.d.ts +32 -0
- package/dist/buffer/bgfx-mark.d.ts.map +1 -0
- package/dist/buffer/bgfx-mark.js +43 -0
- package/dist/buffer/bgfx-mark.js.map +1 -0
- package/dist/buffer/index.d.ts +191 -0
- package/dist/buffer/index.d.ts.map +1 -0
- package/dist/buffer/index.js +353 -0
- package/dist/buffer/index.js.map +1 -0
- package/dist/capabilities/env.d.ts +23 -0
- package/dist/capabilities/env.d.ts.map +1 -0
- package/dist/capabilities/env.js +35 -0
- package/dist/capabilities/env.js.map +1 -0
- package/dist/capabilities/index.d.ts +13 -0
- package/dist/capabilities/index.d.ts.map +1 -0
- package/dist/capabilities/index.js +13 -0
- package/dist/capabilities/index.js.map +1 -0
- package/dist/capabilities/parse.d.ts +41 -0
- package/dist/capabilities/parse.d.ts.map +1 -0
- package/dist/capabilities/parse.js +86 -0
- package/dist/capabilities/parse.js.map +1 -0
- package/dist/capabilities/probe.d.ts +37 -0
- package/dist/capabilities/probe.d.ts.map +1 -0
- package/dist/capabilities/probe.js +75 -0
- package/dist/capabilities/probe.js.map +1 -0
- package/dist/capabilities/sequences.d.ts +33 -0
- package/dist/capabilities/sequences.d.ts.map +1 -0
- package/dist/capabilities/sequences.js +36 -0
- package/dist/capabilities/sequences.js.map +1 -0
- package/dist/capabilities/types.d.ts +25 -0
- package/dist/capabilities/types.d.ts.map +1 -0
- package/dist/capabilities/types.js +5 -0
- package/dist/capabilities/types.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/input/decode.d.ts +167 -0
- package/dist/input/decode.d.ts.map +1 -0
- package/dist/input/decode.js +825 -0
- package/dist/input/decode.js.map +1 -0
- package/dist/input/draft.d.ts +85 -0
- package/dist/input/draft.d.ts.map +1 -0
- package/dist/input/draft.js +276 -0
- package/dist/input/draft.js.map +1 -0
- package/dist/input/index.d.ts +3 -0
- package/dist/input/index.d.ts.map +1 -0
- package/dist/input/index.js +3 -0
- package/dist/input/index.js.map +1 -0
- package/dist/input/prompt-blocks.d.ts +58 -0
- package/dist/input/prompt-blocks.d.ts.map +1 -0
- package/dist/input/prompt-blocks.js +48 -0
- package/dist/input/prompt-blocks.js.map +1 -0
- package/dist/input/rich-draft.d.ts +46 -0
- package/dist/input/rich-draft.d.ts.map +1 -0
- package/dist/input/rich-draft.js +391 -0
- package/dist/input/rich-draft.js.map +1 -0
- package/dist/input/rich-hit.d.ts +17 -0
- package/dist/input/rich-hit.d.ts.map +1 -0
- package/dist/input/rich-hit.js +89 -0
- package/dist/input/rich-hit.js.map +1 -0
- package/dist/input/rich-intake.d.ts +16 -0
- package/dist/input/rich-intake.d.ts.map +1 -0
- package/dist/input/rich-intake.js +22 -0
- package/dist/input/rich-intake.js.map +1 -0
- package/dist/input/rich-paint.d.ts +13 -0
- package/dist/input/rich-paint.d.ts.map +1 -0
- package/dist/input/rich-paint.js +18 -0
- package/dist/input/rich-paint.js.map +1 -0
- package/dist/internals/bgfx/index.d.ts +17 -0
- package/dist/internals/bgfx/index.d.ts.map +1 -0
- package/dist/internals/bgfx/index.js +17 -0
- package/dist/internals/bgfx/index.js.map +1 -0
- package/dist/internals/bgfx/materialize.d.ts +31 -0
- package/dist/internals/bgfx/materialize.d.ts.map +1 -0
- package/dist/internals/bgfx/materialize.js +117 -0
- package/dist/internals/bgfx/materialize.js.map +1 -0
- package/dist/internals/bgfx/opacity.d.ts +37 -0
- package/dist/internals/bgfx/opacity.d.ts.map +1 -0
- package/dist/internals/bgfx/opacity.js +76 -0
- package/dist/internals/bgfx/opacity.js.map +1 -0
- package/dist/internals/bgfx/registry.d.ts +13 -0
- package/dist/internals/bgfx/registry.d.ts.map +1 -0
- package/dist/internals/bgfx/registry.js +24 -0
- package/dist/internals/bgfx/registry.js.map +1 -0
- package/dist/internals/bgfx/sab-layout.d.ts +61 -0
- package/dist/internals/bgfx/sab-layout.d.ts.map +1 -0
- package/dist/internals/bgfx/sab-layout.js +107 -0
- package/dist/internals/bgfx/sab-layout.js.map +1 -0
- package/dist/internals/bgfx/shader-frame-host.d.ts +22 -0
- package/dist/internals/bgfx/shader-frame-host.d.ts.map +1 -0
- package/dist/internals/bgfx/shader-frame-host.js +165 -0
- package/dist/internals/bgfx/shader-frame-host.js.map +1 -0
- package/dist/internals/bgfx/shadertoy-catalog.d.ts +41 -0
- package/dist/internals/bgfx/shadertoy-catalog.d.ts.map +1 -0
- package/dist/internals/bgfx/shadertoy-catalog.js +200 -0
- package/dist/internals/bgfx/shadertoy-catalog.js.map +1 -0
- package/dist/internals/bgfx/shadertoy-gl.d.ts +38 -0
- package/dist/internals/bgfx/shadertoy-gl.d.ts.map +1 -0
- package/dist/internals/bgfx/shadertoy-gl.js +283 -0
- package/dist/internals/bgfx/shadertoy-gl.js.map +1 -0
- package/dist/internals/bgfx/types.d.ts +51 -0
- package/dist/internals/bgfx/types.d.ts.map +1 -0
- package/dist/internals/bgfx/types.js +14 -0
- package/dist/internals/bgfx/types.js.map +1 -0
- package/dist/internals/bgfx-worker.d.ts +6 -0
- package/dist/internals/bgfx-worker.d.ts.map +1 -0
- package/dist/internals/bgfx-worker.js +131 -0
- package/dist/internals/bgfx-worker.js.map +1 -0
- package/dist/layout/birth.d.ts +77 -0
- package/dist/layout/birth.d.ts.map +1 -0
- package/dist/layout/birth.js +148 -0
- package/dist/layout/birth.js.map +1 -0
- package/dist/layout/children.d.ts +5 -0
- package/dist/layout/children.d.ts.map +1 -0
- package/dist/layout/children.js +19 -0
- package/dist/layout/children.js.map +1 -0
- package/dist/layout/chrome_frame.d.ts +254 -0
- package/dist/layout/chrome_frame.d.ts.map +1 -0
- package/dist/layout/chrome_frame.js +1080 -0
- package/dist/layout/chrome_frame.js.map +1 -0
- package/dist/layout/chrome_mask.d.ts +40 -0
- package/dist/layout/chrome_mask.d.ts.map +1 -0
- package/dist/layout/chrome_mask.js +150 -0
- package/dist/layout/chrome_mask.js.map +1 -0
- package/dist/layout/engine.d.ts +49 -0
- package/dist/layout/engine.d.ts.map +1 -0
- package/dist/layout/engine.js +1269 -0
- package/dist/layout/engine.js.map +1 -0
- package/dist/layout/flex.d.ts +36 -0
- package/dist/layout/flex.d.ts.map +1 -0
- package/dist/layout/flex.js +111 -0
- package/dist/layout/flex.js.map +1 -0
- package/dist/layout/grid.d.ts +36 -0
- package/dist/layout/grid.d.ts.map +1 -0
- package/dist/layout/grid.js +126 -0
- package/dist/layout/grid.js.map +1 -0
- package/dist/layout/index.d.ts +30 -0
- package/dist/layout/index.d.ts.map +1 -0
- package/dist/layout/index.js +30 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/layout/indication.d.ts +34 -0
- package/dist/layout/indication.d.ts.map +1 -0
- package/dist/layout/indication.js +68 -0
- package/dist/layout/indication.js.map +1 -0
- package/dist/layout/length.d.ts +18 -0
- package/dist/layout/length.d.ts.map +1 -0
- package/dist/layout/length.js +24 -0
- package/dist/layout/length.js.map +1 -0
- package/dist/layout/live_paint.d.ts +145 -0
- package/dist/layout/live_paint.d.ts.map +1 -0
- package/dist/layout/live_paint.js +255 -0
- package/dist/layout/live_paint.js.map +1 -0
- package/dist/layout/markdown.d.ts +22 -0
- package/dist/layout/markdown.d.ts.map +1 -0
- package/dist/layout/markdown.js +167 -0
- package/dist/layout/markdown.js.map +1 -0
- package/dist/layout/measure.d.ts +46 -0
- package/dist/layout/measure.d.ts.map +1 -0
- package/dist/layout/measure.js +307 -0
- package/dist/layout/measure.js.map +1 -0
- package/dist/layout/paint-hotkey.d.ts +45 -0
- package/dist/layout/paint-hotkey.d.ts.map +1 -0
- package/dist/layout/paint-hotkey.js +152 -0
- package/dist/layout/paint-hotkey.js.map +1 -0
- package/dist/layout/paint.d.ts +25 -0
- package/dist/layout/paint.d.ts.map +1 -0
- package/dist/layout/paint.js +189 -0
- package/dist/layout/paint.js.map +1 -0
- package/dist/layout/paint_theme.d.ts +85 -0
- package/dist/layout/paint_theme.d.ts.map +1 -0
- package/dist/layout/paint_theme.js +76 -0
- package/dist/layout/paint_theme.js.map +1 -0
- package/dist/layout/progress.d.ts +31 -0
- package/dist/layout/progress.d.ts.map +1 -0
- package/dist/layout/progress.js +83 -0
- package/dist/layout/progress.js.map +1 -0
- package/dist/layout/selection.d.ts +136 -0
- package/dist/layout/selection.d.ts.map +1 -0
- package/dist/layout/selection.js +312 -0
- package/dist/layout/selection.js.map +1 -0
- package/dist/layout/selection_gesture.d.ts +88 -0
- package/dist/layout/selection_gesture.d.ts.map +1 -0
- package/dist/layout/selection_gesture.js +239 -0
- package/dist/layout/selection_gesture.js.map +1 -0
- package/dist/layout/selection_paint.d.ts +47 -0
- package/dist/layout/selection_paint.d.ts.map +1 -0
- package/dist/layout/selection_paint.js +320 -0
- package/dist/layout/selection_paint.js.map +1 -0
- package/dist/layout/serialize.d.ts +49 -0
- package/dist/layout/serialize.d.ts.map +1 -0
- package/dist/layout/serialize.js +437 -0
- package/dist/layout/serialize.js.map +1 -0
- package/dist/layout/squeeze.d.ts +58 -0
- package/dist/layout/squeeze.d.ts.map +1 -0
- package/dist/layout/squeeze.js +239 -0
- package/dist/layout/squeeze.js.map +1 -0
- package/dist/layout/text.d.ts +44 -0
- package/dist/layout/text.d.ts.map +1 -0
- package/dist/layout/text.js +230 -0
- package/dist/layout/text.js.map +1 -0
- package/dist/layout/theme_store.d.ts +21 -0
- package/dist/layout/theme_store.d.ts.map +1 -0
- package/dist/layout/theme_store.js +133 -0
- package/dist/layout/theme_store.js.map +1 -0
- package/dist/layout/types.d.ts +564 -0
- package/dist/layout/types.d.ts.map +1 -0
- package/dist/layout/types.js +2 -0
- package/dist/layout/types.js.map +1 -0
- package/dist/layout/visual_draft.d.ts +60 -0
- package/dist/layout/visual_draft.d.ts.map +1 -0
- package/dist/layout/visual_draft.js +199 -0
- package/dist/layout/visual_draft.js.map +1 -0
- package/dist/lexicon/color.d.ts +22 -0
- package/dist/lexicon/color.d.ts.map +1 -0
- package/dist/lexicon/color.js +6 -0
- package/dist/lexicon/color.js.map +1 -0
- package/dist/lexicon/index.d.ts +15 -0
- package/dist/lexicon/index.d.ts.map +1 -0
- package/dist/lexicon/index.js +15 -0
- package/dist/lexicon/index.js.map +1 -0
- package/dist/lexicon/prominence.d.ts +46 -0
- package/dist/lexicon/prominence.d.ts.map +1 -0
- package/dist/lexicon/prominence.js +73 -0
- package/dist/lexicon/prominence.js.map +1 -0
- package/dist/lexicon/quarantine.d.ts +21 -0
- package/dist/lexicon/quarantine.d.ts.map +1 -0
- package/dist/lexicon/quarantine.js +15 -0
- package/dist/lexicon/quarantine.js.map +1 -0
- package/dist/lexicon/roles.d.ts +37 -0
- package/dist/lexicon/roles.d.ts.map +1 -0
- package/dist/lexicon/roles.js +52 -0
- package/dist/lexicon/roles.js.map +1 -0
- package/dist/lexicon/tiers.d.ts +18 -0
- package/dist/lexicon/tiers.d.ts.map +1 -0
- package/dist/lexicon/tiers.js +17 -0
- package/dist/lexicon/tiers.js.map +1 -0
- package/dist/measure/index.d.ts +43 -0
- package/dist/measure/index.d.ts.map +1 -0
- package/dist/measure/index.js +120 -0
- package/dist/measure/index.js.map +1 -0
- package/dist/render.d.ts +72 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +164 -0
- package/dist/render.js.map +1 -0
- package/dist/runtime/agents_keys.d.ts +8 -0
- package/dist/runtime/agents_keys.d.ts.map +1 -0
- package/dist/runtime/agents_keys.js +24 -0
- package/dist/runtime/agents_keys.js.map +1 -0
- package/dist/runtime/agents_peek.d.ts +44 -0
- package/dist/runtime/agents_peek.d.ts.map +1 -0
- package/dist/runtime/agents_peek.js +96 -0
- package/dist/runtime/agents_peek.js.map +1 -0
- package/dist/runtime/agents_preview.d.ts +25 -0
- package/dist/runtime/agents_preview.d.ts.map +1 -0
- package/dist/runtime/agents_preview.js +118 -0
- package/dist/runtime/agents_preview.js.map +1 -0
- package/dist/runtime/box_bus.d.ts +144 -0
- package/dist/runtime/box_bus.d.ts.map +1 -0
- package/dist/runtime/box_bus.js +74 -0
- package/dist/runtime/box_bus.js.map +1 -0
- package/dist/runtime/clipboard-image.d.ts +20 -0
- package/dist/runtime/clipboard-image.d.ts.map +1 -0
- package/dist/runtime/clipboard-image.js +62 -0
- package/dist/runtime/clipboard-image.js.map +1 -0
- package/dist/runtime/copy_toast.d.ts +46 -0
- package/dist/runtime/copy_toast.d.ts.map +1 -0
- package/dist/runtime/copy_toast.js +117 -0
- package/dist/runtime/copy_toast.js.map +1 -0
- package/dist/runtime/echo.d.ts +41 -0
- package/dist/runtime/echo.d.ts.map +1 -0
- package/dist/runtime/echo.js +112 -0
- package/dist/runtime/echo.js.map +1 -0
- package/dist/runtime/frame.d.ts +79 -0
- package/dist/runtime/frame.d.ts.map +1 -0
- package/dist/runtime/frame.js +258 -0
- package/dist/runtime/frame.js.map +1 -0
- package/dist/runtime/index.d.ts +16 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +16 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/key_buffer.d.ts +19 -0
- package/dist/runtime/key_buffer.d.ts.map +1 -0
- package/dist/runtime/key_buffer.js +24 -0
- package/dist/runtime/key_buffer.js.map +1 -0
- package/dist/runtime/keys.d.ts +66 -0
- package/dist/runtime/keys.d.ts.map +1 -0
- package/dist/runtime/keys.js +220 -0
- package/dist/runtime/keys.js.map +1 -0
- package/dist/runtime/paint_snapshot.d.ts +9 -0
- package/dist/runtime/paint_snapshot.d.ts.map +1 -0
- package/dist/runtime/paint_snapshot.js +8 -0
- package/dist/runtime/paint_snapshot.js.map +1 -0
- package/dist/runtime/paint_source.d.ts +266 -0
- package/dist/runtime/paint_source.d.ts.map +1 -0
- package/dist/runtime/paint_source.js +532 -0
- package/dist/runtime/paint_source.js.map +1 -0
- package/dist/runtime/present_loop.d.ts +11 -0
- package/dist/runtime/present_loop.d.ts.map +1 -0
- package/dist/runtime/present_loop.js +46 -0
- package/dist/runtime/present_loop.js.map +1 -0
- package/dist/runtime/present_profile.d.ts +58 -0
- package/dist/runtime/present_profile.d.ts.map +1 -0
- package/dist/runtime/present_profile.js +130 -0
- package/dist/runtime/present_profile.js.map +1 -0
- package/dist/runtime/raster.d.ts +24 -0
- package/dist/runtime/raster.d.ts.map +1 -0
- package/dist/runtime/raster.js +43 -0
- package/dist/runtime/raster.js.map +1 -0
- package/dist/runtime/renderer.d.ts +151 -0
- package/dist/runtime/renderer.d.ts.map +1 -0
- package/dist/runtime/renderer.js +1607 -0
- package/dist/runtime/renderer.js.map +1 -0
- package/dist/runtime/screenshot.d.ts +9 -0
- package/dist/runtime/screenshot.d.ts.map +1 -0
- package/dist/runtime/screenshot.js +111 -0
- package/dist/runtime/screenshot.js.map +1 -0
- package/dist/runtime/selection_host.d.ts +41 -0
- package/dist/runtime/selection_host.d.ts.map +1 -0
- package/dist/runtime/selection_host.js +190 -0
- package/dist/runtime/selection_host.js.map +1 -0
- package/dist/runtime/stderr_hold.d.ts +16 -0
- package/dist/runtime/stderr_hold.d.ts.map +1 -0
- package/dist/runtime/stderr_hold.js +23 -0
- package/dist/runtime/stderr_hold.js.map +1 -0
- package/dist/runtime/thought_birth.d.ts +25 -0
- package/dist/runtime/thought_birth.d.ts.map +1 -0
- package/dist/runtime/thought_birth.js +122 -0
- package/dist/runtime/thought_birth.js.map +1 -0
- package/dist/runtime/thought_collapsed.d.ts +35 -0
- package/dist/runtime/thought_collapsed.d.ts.map +1 -0
- package/dist/runtime/thought_collapsed.js +94 -0
- package/dist/runtime/thought_collapsed.js.map +1 -0
- package/dist/runtime/tty.d.ts +58 -0
- package/dist/runtime/tty.d.ts.map +1 -0
- package/dist/runtime/tty.js +130 -0
- package/dist/runtime/tty.js.map +1 -0
- package/dist/theme/ansi16.d.ts +34 -0
- package/dist/theme/ansi16.d.ts.map +1 -0
- package/dist/theme/ansi16.js +181 -0
- package/dist/theme/ansi16.js.map +1 -0
- package/dist/theme/ansi256.d.ts +15 -0
- package/dist/theme/ansi256.d.ts.map +1 -0
- package/dist/theme/ansi256.js +94 -0
- package/dist/theme/ansi256.js.map +1 -0
- package/dist/theme/ground.d.ts +8 -0
- package/dist/theme/ground.d.ts.map +1 -0
- package/dist/theme/ground.js +11 -0
- package/dist/theme/ground.js.map +1 -0
- package/dist/theme/index.d.ts +10 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/theme/index.js +10 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/theme/region.d.ts +42 -0
- package/dist/theme/region.d.ts.map +1 -0
- package/dist/theme/region.js +105 -0
- package/dist/theme/region.js.map +1 -0
- package/dist/theme/resolver.d.ts +126 -0
- package/dist/theme/resolver.d.ts.map +1 -0
- package/dist/theme/resolver.js +366 -0
- package/dist/theme/resolver.js.map +1 -0
- package/dist/theme/salience.d.ts +90 -0
- package/dist/theme/salience.d.ts.map +1 -0
- package/dist/theme/salience.js +208 -0
- package/dist/theme/salience.js.map +1 -0
- package/dist/theme/seeds.d.ts +113 -0
- package/dist/theme/seeds.d.ts.map +1 -0
- package/dist/theme/seeds.js +52 -0
- package/dist/theme/seeds.js.map +1 -0
- package/dist/theme/selection.d.ts +94 -0
- package/dist/theme/selection.d.ts.map +1 -0
- package/dist/theme/selection.js +135 -0
- package/dist/theme/selection.js.map +1 -0
- package/dist/theme/theme.d.ts +41 -0
- package/dist/theme/theme.d.ts.map +1 -0
- package/dist/theme/theme.js +34 -0
- package/dist/theme/theme.js.map +1 -0
- package/dist/widgets/composer-caret.d.ts +47 -0
- package/dist/widgets/composer-caret.d.ts.map +1 -0
- package/dist/widgets/composer-caret.js +90 -0
- package/dist/widgets/composer-caret.js.map +1 -0
- package/dist/widgets/composer-click.d.ts +30 -0
- package/dist/widgets/composer-click.d.ts.map +1 -0
- package/dist/widgets/composer-click.js +89 -0
- package/dist/widgets/composer-click.js.map +1 -0
- package/dist/widgets/composer-command.d.ts +64 -0
- package/dist/widgets/composer-command.d.ts.map +1 -0
- package/dist/widgets/composer-command.js +127 -0
- package/dist/widgets/composer-command.js.map +1 -0
- package/dist/widgets/composer-frame.d.ts +74 -0
- package/dist/widgets/composer-frame.d.ts.map +1 -0
- package/dist/widgets/composer-frame.js +284 -0
- package/dist/widgets/composer-frame.js.map +1 -0
- package/dist/widgets/composer-picker.d.ts +89 -0
- package/dist/widgets/composer-picker.d.ts.map +1 -0
- package/dist/widgets/composer-picker.js +240 -0
- package/dist/widgets/composer-picker.js.map +1 -0
- package/dist/widgets/diff.d.ts +11 -0
- package/dist/widgets/diff.d.ts.map +1 -0
- package/dist/widgets/diff.js +19 -0
- package/dist/widgets/diff.js.map +1 -0
- package/dist/widgets/expand.d.ts +28 -0
- package/dist/widgets/expand.d.ts.map +1 -0
- package/dist/widgets/expand.js +94 -0
- package/dist/widgets/expand.js.map +1 -0
- package/dist/widgets/index.d.ts +126 -0
- package/dist/widgets/index.d.ts.map +1 -0
- package/dist/widgets/index.js +455 -0
- package/dist/widgets/index.js.map +1 -0
- package/dist/widgets/internals/arrival-lang.d.ts +88 -0
- package/dist/widgets/internals/arrival-lang.d.ts.map +1 -0
- package/dist/widgets/internals/arrival-lang.js +211 -0
- package/dist/widgets/internals/arrival-lang.js.map +1 -0
- package/dist/widgets/internals/diff-expand.d.ts +93 -0
- package/dist/widgets/internals/diff-expand.d.ts.map +1 -0
- package/dist/widgets/internals/diff-expand.js +1106 -0
- package/dist/widgets/internals/diff-expand.js.map +1 -0
- package/dist/widgets/internals/embedded-syntax.d.ts +62 -0
- package/dist/widgets/internals/embedded-syntax.d.ts.map +1 -0
- package/dist/widgets/internals/embedded-syntax.js +465 -0
- package/dist/widgets/internals/embedded-syntax.js.map +1 -0
- package/dist/widgets/internals/markdown-expand.d.ts +57 -0
- package/dist/widgets/internals/markdown-expand.d.ts.map +1 -0
- package/dist/widgets/internals/markdown-expand.js +980 -0
- package/dist/widgets/internals/markdown-expand.js.map +1 -0
- package/dist/widgets/internals/overlay-syntax.d.ts +24 -0
- package/dist/widgets/internals/overlay-syntax.d.ts.map +1 -0
- package/dist/widgets/internals/overlay-syntax.js +90 -0
- package/dist/widgets/internals/overlay-syntax.js.map +1 -0
- package/dist/widgets/internals/pierre-parse/cleanLastNewline.d.ts +6 -0
- package/dist/widgets/internals/pierre-parse/cleanLastNewline.d.ts.map +1 -0
- package/dist/widgets/internals/pierre-parse/cleanLastNewline.js +8 -0
- package/dist/widgets/internals/pierre-parse/cleanLastNewline.js.map +1 -0
- package/dist/widgets/internals/pierre-parse/constants.d.ts +13 -0
- package/dist/widgets/internals/pierre-parse/constants.d.ts.map +1 -0
- package/dist/widgets/internals/pierre-parse/constants.js +13 -0
- package/dist/widgets/internals/pierre-parse/constants.js.map +1 -0
- package/dist/widgets/internals/pierre-parse/detachString.d.ts +3 -0
- package/dist/widgets/internals/pierre-parse/detachString.d.ts.map +1 -0
- package/dist/widgets/internals/pierre-parse/detachString.js +24 -0
- package/dist/widgets/internals/pierre-parse/detachString.js.map +1 -0
- package/dist/widgets/internals/pierre-parse/index.d.ts +8 -0
- package/dist/widgets/internals/pierre-parse/index.d.ts.map +1 -0
- package/dist/widgets/internals/pierre-parse/index.js +8 -0
- package/dist/widgets/internals/pierre-parse/index.js.map +1 -0
- package/dist/widgets/internals/pierre-parse/parseDiffFromFile.d.ts +15 -0
- package/dist/widgets/internals/pierre-parse/parseDiffFromFile.d.ts.map +1 -0
- package/dist/widgets/internals/pierre-parse/parseDiffFromFile.js +39 -0
- package/dist/widgets/internals/pierre-parse/parseDiffFromFile.js.map +1 -0
- package/dist/widgets/internals/pierre-parse/parsePatchFiles.d.ts +11 -0
- package/dist/widgets/internals/pierre-parse/parsePatchFiles.d.ts.map +1 -0
- package/dist/widgets/internals/pierre-parse/parsePatchFiles.js +621 -0
- package/dist/widgets/internals/pierre-parse/parsePatchFiles.js.map +1 -0
- package/dist/widgets/internals/pierre-parse/types.d.ts +73 -0
- package/dist/widgets/internals/pierre-parse/types.d.ts.map +1 -0
- package/dist/widgets/internals/pierre-parse/types.js +7 -0
- package/dist/widgets/internals/pierre-parse/types.js.map +1 -0
- package/dist/widgets/internals/syntax.d.ts +55 -0
- package/dist/widgets/internals/syntax.d.ts.map +1 -0
- package/dist/widgets/internals/syntax.js +261 -0
- package/dist/widgets/internals/syntax.js.map +1 -0
- package/dist/widgets/markdown.d.ts +14 -0
- package/dist/widgets/markdown.d.ts.map +1 -0
- package/dist/widgets/markdown.js +9 -0
- package/dist/widgets/markdown.js.map +1 -0
- package/dist/widgets/shadow-stream.d.ts +88 -0
- package/dist/widgets/shadow-stream.d.ts.map +1 -0
- package/dist/widgets/shadow-stream.js +359 -0
- package/dist/widgets/shadow-stream.js.map +1 -0
- package/dist/widgets/speech.d.ts +36 -0
- package/dist/widgets/speech.d.ts.map +1 -0
- package/dist/widgets/speech.js +238 -0
- package/dist/widgets/speech.js.map +1 -0
- package/dist/widgets/stream-birth.d.ts +13 -0
- package/dist/widgets/stream-birth.d.ts.map +1 -0
- package/dist/widgets/stream-birth.js +70 -0
- package/dist/widgets/stream-birth.js.map +1 -0
- package/dist/widgets/syntax-boot.d.ts +25 -0
- package/dist/widgets/syntax-boot.d.ts.map +1 -0
- package/dist/widgets/syntax-boot.js +181 -0
- package/dist/widgets/syntax-boot.js.map +1 -0
- package/dist/widgets/text.d.ts +16 -0
- package/dist/widgets/text.d.ts.map +1 -0
- package/dist/widgets/text.js +14 -0
- package/dist/widgets/text.js.map +1 -0
- package/dist/widgets/transcript.d.ts +44 -0
- package/dist/widgets/transcript.d.ts.map +1 -0
- package/dist/widgets/transcript.js +106 -0
- package/dist/widgets/transcript.js.map +1 -0
- package/doom.vert +1840 -0
- package/fonts/DejaVuSans.ttf +0 -0
- package/fonts/DejaVuSansMono.ttf +0 -0
- package/fonts/LICENSE-DejaVu.txt +187 -0
- package/fonts/README.md +6 -0
- package/gradient.vert +75 -0
- package/package.json +146 -3
|
@@ -0,0 +1,980 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ./markdown-expand.js — streaming-markdown → LayoutNode trees.
|
|
3
|
+
* Custom renderer builds layout nodes (not HTML).
|
|
4
|
+
*/
|
|
5
|
+
import { BLOCKQUOTE, CHECKBOX, CHECKED, CODE_BLOCK, CODE_FENCE, CODE_INLINE, DOCUMENT, EQUATION_BLOCK, EQUATION_INLINE, HEADING_1, HEADING_2, HEADING_3, HEADING_4, HEADING_5, HEADING_6, HREF, IMAGE, ITALIC_AST, ITALIC_UND, LANG, LINE_BREAK, LINK, LIST_ITEM, LIST_ORDERED, LIST_UNORDERED, PARAGRAPH, parser as smdParser, parser_end, parser_write, RAW_URL, RULE, SRC, START, STRIKE, STRONG_AST, STRONG_UND, TABLE, TABLE_CELL, TABLE_ROW, } from "streaming-markdown";
|
|
6
|
+
import { guessLang, highlightCodeSync, runsToStyle } from "./syntax.js";
|
|
7
|
+
import { guardContent } from "../../buffer/index.js";
|
|
8
|
+
import { INDICATION_CONTENT_INSET } from "../../layout/index.js";
|
|
9
|
+
import { measureGridDims } from "../../layout/measure.js";
|
|
10
|
+
import { wrapText } from "../../layout/text.js";
|
|
11
|
+
import { FgP } from "../../lexicon/index.js";
|
|
12
|
+
export function createStreamingMarkdown(opts) {
|
|
13
|
+
const key = opts?.key ?? "md";
|
|
14
|
+
const plainCode = opts?.plainCode ?? false;
|
|
15
|
+
const builder = createBuilder(key, plainCode, opts?.width, opts?.style);
|
|
16
|
+
const renderer = {
|
|
17
|
+
data: builder,
|
|
18
|
+
add_token: builderAddToken,
|
|
19
|
+
end_token: builderEndToken,
|
|
20
|
+
add_text: builderAddText,
|
|
21
|
+
set_attr: builderSetAttr,
|
|
22
|
+
};
|
|
23
|
+
const p = smdParser(renderer);
|
|
24
|
+
// Thread the parser into the builder so `snapshotNodes`/`projectOpen` can
|
|
25
|
+
// read the SMD look-ahead buffer (p.text + p.pending) to compensate for the
|
|
26
|
+
// trailing char(s) SMD holds back until the next write resolves the token.
|
|
27
|
+
builder.parser = p;
|
|
28
|
+
return {
|
|
29
|
+
write(chunk) {
|
|
30
|
+
// Guard BEFORE parser_write: CSI bodies contain `[` which streaming-markdown
|
|
31
|
+
// treats as link openers ("before\x1b[2Jafter" → "before2Jafter", fg=link).
|
|
32
|
+
// Buffer put also guards at paint; this keeps the MD AST itself honest.
|
|
33
|
+
parser_write(p, guardContent(chunk));
|
|
34
|
+
},
|
|
35
|
+
end() {
|
|
36
|
+
parser_end(p);
|
|
37
|
+
// streaming-markdown may leave the last block open; commit it.
|
|
38
|
+
flushOpenFrames(builder);
|
|
39
|
+
},
|
|
40
|
+
nodes() {
|
|
41
|
+
return snapshotNodes(builder);
|
|
42
|
+
},
|
|
43
|
+
root(rootOpts) {
|
|
44
|
+
return {
|
|
45
|
+
type: "box",
|
|
46
|
+
key: rootOpts?.key ?? key,
|
|
47
|
+
children: snapshotNodes(builder),
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** One-shot: write all + end, return root LayoutNode. */
|
|
53
|
+
export function markdownToLayout(src, opts) {
|
|
54
|
+
const stream = createStreamingMarkdown({
|
|
55
|
+
key: opts?.key,
|
|
56
|
+
width: opts?.width,
|
|
57
|
+
style: opts?.style,
|
|
58
|
+
});
|
|
59
|
+
stream.write(src);
|
|
60
|
+
stream.end();
|
|
61
|
+
return stream.root({ key: opts?.key });
|
|
62
|
+
}
|
|
63
|
+
function createBuilder(key, plainCode, width, style) {
|
|
64
|
+
const wrapWidth = width !== undefined && width > 0 ? Math.floor(width) : undefined;
|
|
65
|
+
return {
|
|
66
|
+
key,
|
|
67
|
+
plainCode,
|
|
68
|
+
width: wrapWidth,
|
|
69
|
+
baseStyle: voiceBase(style),
|
|
70
|
+
stack: [
|
|
71
|
+
{
|
|
72
|
+
token: DOCUMENT,
|
|
73
|
+
parts: [],
|
|
74
|
+
children: [],
|
|
75
|
+
itemCount: 0,
|
|
76
|
+
wrapWidth,
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
seq: 0,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/** Remaining wrap budget after an indication gutter (lead + glyph + gap). */
|
|
83
|
+
function insetWrapWidth(width) {
|
|
84
|
+
if (width === undefined || width <= 0)
|
|
85
|
+
return undefined;
|
|
86
|
+
return Math.max(1, width - INDICATION_CONTENT_INSET);
|
|
87
|
+
}
|
|
88
|
+
/** Commit any frames still open after parser_end (final unterminated block). */
|
|
89
|
+
function flushOpenFrames(data) {
|
|
90
|
+
while (data.stack.length > 1) {
|
|
91
|
+
const frame = data.stack.pop();
|
|
92
|
+
materialize(data, frame, top(data));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function nextKey(data, kind) {
|
|
96
|
+
return `${data.key}:${kind}-${data.seq++}`;
|
|
97
|
+
}
|
|
98
|
+
function top(data) {
|
|
99
|
+
return data.stack.at(-1);
|
|
100
|
+
}
|
|
101
|
+
/** Body voice — one HK-adjusted prominence. Headings lift to primary. */
|
|
102
|
+
function voiceBase(style) {
|
|
103
|
+
return {
|
|
104
|
+
...style,
|
|
105
|
+
role: style?.role ?? "foreground",
|
|
106
|
+
prominence: style?.prominence ?? FgP.secondary,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function fenceStyle(base) {
|
|
110
|
+
return { role: "code", prominence: base.prominence ?? FgP.secondary };
|
|
111
|
+
}
|
|
112
|
+
function styleFromStack(data) {
|
|
113
|
+
const s = { ...data.baseStyle };
|
|
114
|
+
for (const f of data.stack) {
|
|
115
|
+
switch (f.token) {
|
|
116
|
+
case HEADING_1:
|
|
117
|
+
case HEADING_2:
|
|
118
|
+
case HEADING_3:
|
|
119
|
+
case HEADING_4:
|
|
120
|
+
case HEADING_5:
|
|
121
|
+
case HEADING_6:
|
|
122
|
+
// Same role as body — hierarchy is prominence, not a heading hue.
|
|
123
|
+
s.prominence = FgP.primary;
|
|
124
|
+
break;
|
|
125
|
+
case STRONG_AST:
|
|
126
|
+
case STRONG_UND:
|
|
127
|
+
s.bold = true;
|
|
128
|
+
break;
|
|
129
|
+
case ITALIC_AST:
|
|
130
|
+
case ITALIC_UND:
|
|
131
|
+
// Real SGR 3 (voice inflection) — dim-as-italic proxy dies.
|
|
132
|
+
s.italic = true;
|
|
133
|
+
break;
|
|
134
|
+
case STRIKE:
|
|
135
|
+
// Real crossed-out (SGR 9), not dim-as-proxy — dim is italic/quote.
|
|
136
|
+
s.strike = true;
|
|
137
|
+
break;
|
|
138
|
+
case CODE_INLINE:
|
|
139
|
+
// Unspecified / unhighlighted source: code role (azure).
|
|
140
|
+
// Same prominence as body so H-K keeps it level with prose.
|
|
141
|
+
s.role = "code";
|
|
142
|
+
break;
|
|
143
|
+
case BLOCKQUOTE:
|
|
144
|
+
// Aside stays the body voice; gutter is furniture.
|
|
145
|
+
break;
|
|
146
|
+
case LINK:
|
|
147
|
+
case RAW_URL:
|
|
148
|
+
s.role = "accent";
|
|
149
|
+
s.underline = true;
|
|
150
|
+
break;
|
|
151
|
+
default:
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return s;
|
|
156
|
+
}
|
|
157
|
+
function isMdTable(node) {
|
|
158
|
+
return node.type === "grid";
|
|
159
|
+
}
|
|
160
|
+
function isMdQuote(node) {
|
|
161
|
+
return node.type === "indication";
|
|
162
|
+
}
|
|
163
|
+
/** Committed paragraph keys (`md:p-3`). Wrap rows are `p-3:w0` and stay nested. */
|
|
164
|
+
function isMdParagraph(node) {
|
|
165
|
+
return typeof node.key === "string" && /:p-\d+$/.test(node.key);
|
|
166
|
+
}
|
|
167
|
+
/** Paragraphs, tables, and quotes — 1-cell gap when not first/last. */
|
|
168
|
+
function needsFlowMargin(node) {
|
|
169
|
+
return isMdTable(node) || isMdQuote(node) || isMdParagraph(node);
|
|
170
|
+
}
|
|
171
|
+
function withFlowMargins(kids, key) {
|
|
172
|
+
const out = [];
|
|
173
|
+
for (const n of kids) {
|
|
174
|
+
const prev = out.at(-1);
|
|
175
|
+
if (prev && (needsFlowMargin(prev) || needsFlowMargin(n))) {
|
|
176
|
+
out.push({
|
|
177
|
+
type: "text",
|
|
178
|
+
key: `${key}:flow-gap-${out.length}`,
|
|
179
|
+
content: " ",
|
|
180
|
+
whiteSpace: "nowrap",
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
out.push(n);
|
|
184
|
+
}
|
|
185
|
+
return out;
|
|
186
|
+
}
|
|
187
|
+
function isHeading(t) {
|
|
188
|
+
return t >= HEADING_1 && t <= HEADING_6;
|
|
189
|
+
}
|
|
190
|
+
function isInline(t) {
|
|
191
|
+
switch (t) {
|
|
192
|
+
case CODE_INLINE:
|
|
193
|
+
case ITALIC_AST:
|
|
194
|
+
case ITALIC_UND:
|
|
195
|
+
case STRONG_AST:
|
|
196
|
+
case STRONG_UND:
|
|
197
|
+
case STRIKE:
|
|
198
|
+
case LINK:
|
|
199
|
+
case RAW_URL:
|
|
200
|
+
case IMAGE:
|
|
201
|
+
case EQUATION_INLINE:
|
|
202
|
+
case LINE_BREAK:
|
|
203
|
+
case CHECKBOX:
|
|
204
|
+
return true;
|
|
205
|
+
default:
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
function mergeParts(parts) {
|
|
210
|
+
const out = [];
|
|
211
|
+
for (const p of parts) {
|
|
212
|
+
if (!p.text)
|
|
213
|
+
continue;
|
|
214
|
+
const last = out.at(-1);
|
|
215
|
+
if (last && styleEqual(last.style, p.style)) {
|
|
216
|
+
last.text += p.text;
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
out.push({ text: p.text, style: { ...p.style } });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return out;
|
|
223
|
+
}
|
|
224
|
+
function rgbEqual(a, b) {
|
|
225
|
+
if (!a || !b)
|
|
226
|
+
return a === b;
|
|
227
|
+
return a.r === b.r && a.g === b.g && a.b === b.b;
|
|
228
|
+
}
|
|
229
|
+
function styleEqual(a, b) {
|
|
230
|
+
return (a.bold === b.bold &&
|
|
231
|
+
a.italic === b.italic &&
|
|
232
|
+
a.strike === b.strike &&
|
|
233
|
+
a.underline === b.underline &&
|
|
234
|
+
a.fg === b.fg &&
|
|
235
|
+
a.bg === b.bg &&
|
|
236
|
+
rgbEqual(a.fgRgb, b.fgRgb) &&
|
|
237
|
+
rgbEqual(a.bgRgb, b.bgRgb) &&
|
|
238
|
+
a.role === b.role &&
|
|
239
|
+
a.prominence === b.prominence &&
|
|
240
|
+
a.bgRole === b.bgRole &&
|
|
241
|
+
a.bgProminence === b.bgProminence &&
|
|
242
|
+
a.href === b.href);
|
|
243
|
+
}
|
|
244
|
+
function joinParts(parts) {
|
|
245
|
+
return parts.map((p) => p.text).join("");
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Soft-wrap styled parts to `width` display columns.
|
|
249
|
+
* Break offsets come from wrapText pre-wrap (last space, then grapheme) so
|
|
250
|
+
* mixed-style runs and plain text share one wrap. Independent column-cut
|
|
251
|
+
* splits words. Hard `\n` always break.
|
|
252
|
+
*/
|
|
253
|
+
export function softWrapParts(parts, width) {
|
|
254
|
+
const w = Math.max(1, width);
|
|
255
|
+
const rows = [];
|
|
256
|
+
for (const hard of splitHardLines(mergeParts(parts))) {
|
|
257
|
+
const text = joinParts(hard);
|
|
258
|
+
const lines = wrapText(text, { width: w, whiteSpace: "pre-wrap" });
|
|
259
|
+
let offset = 0;
|
|
260
|
+
for (const line of lines) {
|
|
261
|
+
const slice = sliceParts(hard, offset, offset + line.length);
|
|
262
|
+
rows.push(slice.length > 0 ? slice : [{ text: " ", style: {} }]);
|
|
263
|
+
offset += line.length;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return rows.length > 0 ? rows : [[{ text: " ", style: {} }]];
|
|
267
|
+
}
|
|
268
|
+
function splitHardLines(parts) {
|
|
269
|
+
const lines = [[]];
|
|
270
|
+
for (const p of parts) {
|
|
271
|
+
const chunks = p.text.split("\n");
|
|
272
|
+
for (const [ci, chunk_] of chunks.entries()) {
|
|
273
|
+
if (ci > 0)
|
|
274
|
+
lines.push([]);
|
|
275
|
+
const chunk = chunk_;
|
|
276
|
+
if (chunk.length > 0) {
|
|
277
|
+
lines.at(-1).push({ text: chunk, style: p.style });
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return lines;
|
|
282
|
+
}
|
|
283
|
+
function sliceParts(parts, start, end) {
|
|
284
|
+
if (end <= start)
|
|
285
|
+
return [];
|
|
286
|
+
const out = [];
|
|
287
|
+
let i = 0;
|
|
288
|
+
for (const p of parts) {
|
|
289
|
+
const pe = i + p.text.length;
|
|
290
|
+
if (pe <= start) {
|
|
291
|
+
i = pe;
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
if (i >= end)
|
|
295
|
+
break;
|
|
296
|
+
const a = Math.max(0, start - i);
|
|
297
|
+
const b = Math.min(p.text.length, end - i);
|
|
298
|
+
if (b > a)
|
|
299
|
+
out.push({ text: p.text.slice(a, b), style: p.style });
|
|
300
|
+
i = pe;
|
|
301
|
+
}
|
|
302
|
+
return out;
|
|
303
|
+
}
|
|
304
|
+
function rowToNode(parts, key) {
|
|
305
|
+
const merged = mergeParts(parts);
|
|
306
|
+
if (merged.length === 0) {
|
|
307
|
+
return { type: "text", key, content: " ", whiteSpace: "nowrap" };
|
|
308
|
+
}
|
|
309
|
+
if (merged.length === 1) {
|
|
310
|
+
const only = merged[0];
|
|
311
|
+
return {
|
|
312
|
+
type: "text",
|
|
313
|
+
key,
|
|
314
|
+
content: only.text,
|
|
315
|
+
// Row already width-cut — nowrap preserves edge spaces within the segment.
|
|
316
|
+
whiteSpace: "nowrap",
|
|
317
|
+
style: only.style,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
return {
|
|
321
|
+
type: "flex",
|
|
322
|
+
key,
|
|
323
|
+
style: { direction: "row", gap: 0 },
|
|
324
|
+
children: merged.map((p, i) => ({
|
|
325
|
+
type: "text",
|
|
326
|
+
key: `${key}:${i}`,
|
|
327
|
+
content: p.text,
|
|
328
|
+
whiteSpace: "nowrap",
|
|
329
|
+
style: p.style,
|
|
330
|
+
})),
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
function partsToNode(parts, key, width) {
|
|
334
|
+
const merged = mergeParts(parts);
|
|
335
|
+
if (merged.length === 0) {
|
|
336
|
+
return { type: "text", key, content: "" };
|
|
337
|
+
}
|
|
338
|
+
// Soft-wrap when we know the content column budget (preserves mid-line styles).
|
|
339
|
+
if (width !== undefined && width > 0) {
|
|
340
|
+
const rows = softWrapParts(merged, width);
|
|
341
|
+
if (rows.length === 1)
|
|
342
|
+
return rowToNode(rows[0], key);
|
|
343
|
+
return {
|
|
344
|
+
type: "box",
|
|
345
|
+
key,
|
|
346
|
+
children: rows.map((row, i) => rowToNode(row, `${key}:w${i}`)),
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
// No width: single style → pre-wrap (layout soft-wraps at measure).
|
|
350
|
+
// Multi-style → nowrap flex row (style-preserving; callers should pass width
|
|
351
|
+
// so long mixed paragraphs soft-wrap instead of clipping).
|
|
352
|
+
if (merged.length === 1) {
|
|
353
|
+
const only = merged[0];
|
|
354
|
+
return {
|
|
355
|
+
type: "text",
|
|
356
|
+
key,
|
|
357
|
+
content: only.text,
|
|
358
|
+
whiteSpace: "pre-wrap",
|
|
359
|
+
style: only.style,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
return rowToNode(merged, key);
|
|
363
|
+
}
|
|
364
|
+
/** Trim leading/trailing whitespace across part runs (GFM table cell padding). */
|
|
365
|
+
function trimParts(parts) {
|
|
366
|
+
if (parts.length === 0)
|
|
367
|
+
return parts;
|
|
368
|
+
const copy = parts.map((p) => ({ text: p.text, style: { ...p.style } }));
|
|
369
|
+
// leading
|
|
370
|
+
while (copy.length > 0 && copy[0].text.trimStart() !== copy[0].text) {
|
|
371
|
+
copy[0].text = copy[0].text.trimStart();
|
|
372
|
+
if (!copy[0].text)
|
|
373
|
+
copy.shift();
|
|
374
|
+
}
|
|
375
|
+
// trailing
|
|
376
|
+
while (copy.length > 0) {
|
|
377
|
+
const last = copy.at(-1);
|
|
378
|
+
const trimmed = last.text.trimEnd();
|
|
379
|
+
if (trimmed === last.text)
|
|
380
|
+
break;
|
|
381
|
+
if (!trimmed) {
|
|
382
|
+
copy.pop();
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
last.text = trimmed;
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
388
|
+
return copy;
|
|
389
|
+
}
|
|
390
|
+
function asTableHeaderCell(node) {
|
|
391
|
+
if (node.type === "text") {
|
|
392
|
+
return {
|
|
393
|
+
...node,
|
|
394
|
+
style: { ...node.style, prominence: FgP.primary, bold: true },
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
if (node.type === "flex" || node.type === "box") {
|
|
398
|
+
return {
|
|
399
|
+
...node,
|
|
400
|
+
children: (node.children ?? []).map(asTableHeaderCell),
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
return node;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Fence lines → styled rows. Sync-safe: highlightCodeSync falls back to plain
|
|
407
|
+
* when the highlighter isn't warm, and `guessLang` fills in when the fence has
|
|
408
|
+
* no info string. Returns undefined when there is nothing beyond plain text —
|
|
409
|
+
* callers keep the cheaper single-node-per-line path.
|
|
410
|
+
*/
|
|
411
|
+
function highlightedFenceRows(data, code, lang, width = data.width) {
|
|
412
|
+
if (data.plainCode)
|
|
413
|
+
return undefined;
|
|
414
|
+
const effLang = lang || guessLang(code);
|
|
415
|
+
if (!effLang)
|
|
416
|
+
return undefined;
|
|
417
|
+
const stripped = code.replace(/\n$/, "");
|
|
418
|
+
const hl = highlightCodeSync(stripped, { lang: effLang });
|
|
419
|
+
if (!hl.some((line) => line.some((run) => run.color || run.bold || run.italic))) {
|
|
420
|
+
return undefined;
|
|
421
|
+
}
|
|
422
|
+
const rows = [];
|
|
423
|
+
for (const line of hl) {
|
|
424
|
+
const parts = line.map((run) => ({
|
|
425
|
+
text: run.text,
|
|
426
|
+
style: { ...fenceStyle(data.baseStyle), ...runsToStyle(run) },
|
|
427
|
+
}));
|
|
428
|
+
if (width === undefined) {
|
|
429
|
+
rows.push(parts);
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
rows.push(...softWrapParts(parts, width));
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
return rows;
|
|
436
|
+
}
|
|
437
|
+
function plainCodeNode(data, code, lang, width = data.width) {
|
|
438
|
+
const lines = code.replace(/\n$/, "").split("\n");
|
|
439
|
+
const fenceKey = nextKey(data, lang ? `fence-${lang}` : "fence");
|
|
440
|
+
const rows = highlightedFenceRows(data, code, lang, width);
|
|
441
|
+
if (rows) {
|
|
442
|
+
return {
|
|
443
|
+
type: "indentation_exception",
|
|
444
|
+
key: fenceKey,
|
|
445
|
+
kind: "code_pad",
|
|
446
|
+
children: rows.map((parts, j) => rowToNode(parts, `${fenceKey}:${j}`)),
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
const node = {
|
|
450
|
+
type: "indentation_exception",
|
|
451
|
+
key: fenceKey,
|
|
452
|
+
kind: "code_pad",
|
|
453
|
+
children: lines.map((l, j) => ({
|
|
454
|
+
type: "text",
|
|
455
|
+
key: `${fenceKey}:${j}`,
|
|
456
|
+
content: l.length > 0 ? l : " ",
|
|
457
|
+
// Soft-wrap long fence lines at measure width (not nowrap clip).
|
|
458
|
+
whiteSpace: "pre-wrap",
|
|
459
|
+
style: fenceStyle(data.baseStyle),
|
|
460
|
+
})),
|
|
461
|
+
};
|
|
462
|
+
return node;
|
|
463
|
+
}
|
|
464
|
+
// ── renderer callbacks ──────────────────────────────────────────────────────
|
|
465
|
+
function builderAddToken(data, type) {
|
|
466
|
+
if (type === DOCUMENT)
|
|
467
|
+
return;
|
|
468
|
+
const parent = top(data);
|
|
469
|
+
data.stack.push({
|
|
470
|
+
token: type,
|
|
471
|
+
parts: [],
|
|
472
|
+
children: [],
|
|
473
|
+
itemCount: 0,
|
|
474
|
+
wrapWidth: type === BLOCKQUOTE ? insetWrapWidth(parent.wrapWidth) : parent.wrapWidth,
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
function builderSetAttr(data, type, value) {
|
|
478
|
+
const frame = top(data);
|
|
479
|
+
switch (type) {
|
|
480
|
+
case HREF:
|
|
481
|
+
// Guard so CSI/OSC in URL cannot leak into displayed text / paint.
|
|
482
|
+
frame.href = guardContent(value);
|
|
483
|
+
break;
|
|
484
|
+
case SRC:
|
|
485
|
+
frame.src = guardContent(value);
|
|
486
|
+
break;
|
|
487
|
+
case LANG:
|
|
488
|
+
// streaming-markdown sets class-like lang on fence; may be bare "ts".
|
|
489
|
+
// Sanitize BEFORE stripping the `language-` prefix so the regex runs
|
|
490
|
+
// on clean text (CSI bodies can contain `[` etc.).
|
|
491
|
+
frame.lang = guardContent(value)
|
|
492
|
+
.replace(/^language-/, "")
|
|
493
|
+
.trim();
|
|
494
|
+
break;
|
|
495
|
+
case CHECKED:
|
|
496
|
+
frame.checked = true;
|
|
497
|
+
break;
|
|
498
|
+
case START: {
|
|
499
|
+
const n = Number.parseInt(value, 10);
|
|
500
|
+
frame.start = Number.isFinite(n) ? n : 1;
|
|
501
|
+
break;
|
|
502
|
+
}
|
|
503
|
+
default:
|
|
504
|
+
break;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
function builderAddText(data, text) {
|
|
508
|
+
const frame = top(data);
|
|
509
|
+
frame.parts.push({ text, style: styleFromStack(data) });
|
|
510
|
+
}
|
|
511
|
+
function builderEndToken(data) {
|
|
512
|
+
if (data.stack.length <= 1)
|
|
513
|
+
return;
|
|
514
|
+
const frame = data.stack.pop();
|
|
515
|
+
const parent = top(data);
|
|
516
|
+
materialize(data, frame, parent);
|
|
517
|
+
}
|
|
518
|
+
function materialize(data, frame, parent) {
|
|
519
|
+
const t = frame.token;
|
|
520
|
+
// void / inline tokens that bubble parts upward
|
|
521
|
+
if (t === LINE_BREAK) {
|
|
522
|
+
parent.parts.push({ text: "\n", style: styleFromStack(data) });
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
if (t === CHECKBOX) {
|
|
526
|
+
const mark = frame.checked ? "[x] " : "[ ] ";
|
|
527
|
+
parent.parts.push({
|
|
528
|
+
text: mark,
|
|
529
|
+
style: styleFromStack(data),
|
|
530
|
+
});
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
if (t === CODE_INLINE ||
|
|
534
|
+
t === ITALIC_AST ||
|
|
535
|
+
t === ITALIC_UND ||
|
|
536
|
+
t === STRONG_AST ||
|
|
537
|
+
t === STRONG_UND ||
|
|
538
|
+
t === STRIKE ||
|
|
539
|
+
t === EQUATION_INLINE) {
|
|
540
|
+
parent.parts.push(...frame.parts);
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
if (t === LINK || t === RAW_URL) {
|
|
544
|
+
// Label (or autolink text) only. Destination rides OSC 8 on the
|
|
545
|
+
// accent run — HREF arrives after body text, so stamp at close.
|
|
546
|
+
if (frame.href) {
|
|
547
|
+
for (const p of frame.parts) {
|
|
548
|
+
p.style = { ...p.style, href: frame.href };
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
parent.parts.push(...frame.parts);
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
if (t === IMAGE) {
|
|
555
|
+
const alt = joinParts(frame.parts) || "image";
|
|
556
|
+
parent.parts.push({
|
|
557
|
+
text: frame.src ? `` : `![${alt}]`,
|
|
558
|
+
// Alt/src stay visible — image has no OSC 8 cell to hide behind.
|
|
559
|
+
style: { role: "muted", prominence: FgP.ghost },
|
|
560
|
+
});
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
if (isHeading(t) || t === PARAGRAPH || t === EQUATION_BLOCK) {
|
|
564
|
+
// headings → bold text; paragraphs → text (styles already in parts)
|
|
565
|
+
if (frame.parts.length > 0 || frame.children.length === 0) {
|
|
566
|
+
parent.children.push(partsToNode(frame.parts, nextKey(data, isHeading(t) ? "h" : "p"), frame.wrapWidth));
|
|
567
|
+
}
|
|
568
|
+
parent.children.push(...frame.children);
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
if (t === CODE_FENCE || t === CODE_BLOCK) {
|
|
572
|
+
const code = joinParts(frame.parts);
|
|
573
|
+
parent.children.push(plainCodeNode(data, code, frame.lang, frame.wrapWidth));
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
if (t === BLOCKQUOTE) {
|
|
577
|
+
const rawKids = frame.children.length > 0
|
|
578
|
+
? frame.children
|
|
579
|
+
: frame.parts.length > 0
|
|
580
|
+
? [partsToNode(frame.parts, nextKey(data, "p"), frame.wrapWidth)]
|
|
581
|
+
: [];
|
|
582
|
+
// Blank `>` lines are paragraph separators, not empty paragraphs.
|
|
583
|
+
// Paragraph flow-margin reifies the 1-cell bar-only row:
|
|
584
|
+
// │ first
|
|
585
|
+
// │ ← gap
|
|
586
|
+
// │ second
|
|
587
|
+
const kids = withFlowMargins(rawKids, nextKey(data, "bq-flow"));
|
|
588
|
+
parent.children.push({
|
|
589
|
+
type: "indication",
|
|
590
|
+
key: nextKey(data, "bq"),
|
|
591
|
+
gutter: { kind: "rule", glyph: "│" },
|
|
592
|
+
// Furniture — not the body voice. Ghost so the bar recedes
|
|
593
|
+
// instead of inheriting paragraph prominence.
|
|
594
|
+
style: { role: "border", prominence: FgP.ghost },
|
|
595
|
+
children: kids,
|
|
596
|
+
});
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
if (t === RULE) {
|
|
600
|
+
parent.children.push({
|
|
601
|
+
type: "text",
|
|
602
|
+
key: nextKey(data, "hr"),
|
|
603
|
+
content: "───",
|
|
604
|
+
style: { role: "border", prominence: FgP.ghost },
|
|
605
|
+
});
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
if (t === LIST_ITEM) {
|
|
609
|
+
const ordered = parent.token === LIST_ORDERED;
|
|
610
|
+
const start = parent.start ?? 1;
|
|
611
|
+
const idx = parent.itemCount;
|
|
612
|
+
parent.itemCount += 1;
|
|
613
|
+
const prefix = ordered ? `${start + idx}. ` : "• ";
|
|
614
|
+
const body = joinParts(frame.parts);
|
|
615
|
+
// If nested block children exist without leading text, still show prefix line
|
|
616
|
+
const lineKey = nextKey(data, "li");
|
|
617
|
+
if (body || frame.children.length === 0) {
|
|
618
|
+
parent.children.push(partsToNode([{ text: prefix, style: data.baseStyle }, ...frame.parts], lineKey, frame.wrapWidth));
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
parent.children.push({
|
|
622
|
+
type: "text",
|
|
623
|
+
key: lineKey,
|
|
624
|
+
content: prefix.trimEnd(),
|
|
625
|
+
style: data.baseStyle,
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
parent.children.push(...frame.children);
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
if (t === LIST_ORDERED || t === LIST_UNORDERED) {
|
|
632
|
+
// pass children up; list itself is transparent container
|
|
633
|
+
parent.children.push(...frame.children);
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
if (t === TABLE_CELL) {
|
|
637
|
+
// Prefer structured children (nested blocks rare); else parts → text/flex.
|
|
638
|
+
// SMD cell text includes GFM padding spaces — trim edges.
|
|
639
|
+
// Do not wrap at document width here — tableGridNode wraps to column tracks.
|
|
640
|
+
const cellKey = nextKey(data, "td");
|
|
641
|
+
if (frame.children.length > 0 && frame.parts.length === 0) {
|
|
642
|
+
parent.children.push({
|
|
643
|
+
type: "box",
|
|
644
|
+
key: cellKey,
|
|
645
|
+
children: frame.children,
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
else {
|
|
649
|
+
parent.children.push(partsToNode(trimParts(frame.parts), cellKey));
|
|
650
|
+
}
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
if (t === TABLE_ROW) {
|
|
654
|
+
// Cells are already LayoutNodes on frame.children (one per TABLE_CELL).
|
|
655
|
+
const cells = frame.children;
|
|
656
|
+
if (parent.colCount === undefined) {
|
|
657
|
+
parent.colCount = Math.max(1, cells.length);
|
|
658
|
+
}
|
|
659
|
+
const cols = parent.colCount;
|
|
660
|
+
// Pad / trim to column count so grid stays rectangular
|
|
661
|
+
const normalized = [];
|
|
662
|
+
for (let i = 0; i < cols; i++) {
|
|
663
|
+
normalized.push(cells[i] ?? {
|
|
664
|
+
type: "text",
|
|
665
|
+
key: nextKey(data, "td-empty"),
|
|
666
|
+
content: "",
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
parent.children.push(...normalized);
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
if (t === TABLE) {
|
|
673
|
+
parent.children.push(tableGridNode(nextKey(data, "table"), frame.children, Math.max(1, frame.colCount ?? 1), frame.wrapWidth));
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
// fallback: bubble children + parts
|
|
677
|
+
if (frame.parts.length > 0) {
|
|
678
|
+
parent.children.push(partsToNode(frame.parts, nextKey(data, "blk"), frame.wrapWidth));
|
|
679
|
+
}
|
|
680
|
+
parent.children.push(...frame.children);
|
|
681
|
+
}
|
|
682
|
+
// ── partial snapshot for live streaming ─────────────────────────────────────
|
|
683
|
+
function snapshotNodes(data) {
|
|
684
|
+
if (data.stack.length === 1) {
|
|
685
|
+
const kids = data.stack[0].children;
|
|
686
|
+
return kids.length > 0
|
|
687
|
+
? withFlowMargins(kids, data.key)
|
|
688
|
+
: [{ type: "text", key: `${data.key}:empty`, content: "" }];
|
|
689
|
+
}
|
|
690
|
+
// Project open frames into a temporary tree without mutating stack.
|
|
691
|
+
const committed = [...data.stack[0].children];
|
|
692
|
+
const open = projectOpen(data, 1, pendingTail(data));
|
|
693
|
+
const merged = committed.concat(open);
|
|
694
|
+
return merged.length > 0
|
|
695
|
+
? withFlowMargins(merged, data.key)
|
|
696
|
+
: [{ type: "text", key: `${data.key}:empty`, content: "" }];
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* SMD holds the most recent char(s) in a look-ahead buffer and only resolves
|
|
700
|
+
* `add_text` when the NEXT char determines the token. So the deepest open
|
|
701
|
+
* frame's `parts` is always missing the trailing text the user just typed.
|
|
702
|
+
*
|
|
703
|
+
* `parser.text` = accumulated text awaiting flush; `parser.pending` = the
|
|
704
|
+
* residual look-ahead (the last char(s) consumed but not yet committed). After
|
|
705
|
+
* `parser_write` returns, `parser.text` is already flushed (so usually ""),
|
|
706
|
+
* while `parser.pending` holds the dangling tail. We project BOTH onto the
|
|
707
|
+
* deepest frame so a live snapshot shows the full input — without mutating the
|
|
708
|
+
* real `frame.parts` or the parser state.
|
|
709
|
+
*/
|
|
710
|
+
function pendingTail(data) {
|
|
711
|
+
const p = data.parser;
|
|
712
|
+
if (!p)
|
|
713
|
+
return "";
|
|
714
|
+
return (p.text ?? "") + (p.pending ?? "");
|
|
715
|
+
}
|
|
716
|
+
/** `frame.parts` with the SMD pending tail appended (projection-only copy). */
|
|
717
|
+
function partsWithTail(frame, data, tail, isDeepest) {
|
|
718
|
+
if (!isDeepest || !tail)
|
|
719
|
+
return frame.parts;
|
|
720
|
+
// Append as literal text styled like the current stack (matches what SMD
|
|
721
|
+
// would emit once the token resolves). Partial syntax (lone `[`, `*`, …)
|
|
722
|
+
// is treated as literal — that's what renders once flushed, which is the
|
|
723
|
+
// goal: the last typed char appears.
|
|
724
|
+
return [...frame.parts, { text: tail, style: styleFromStack(data) }];
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Open inlines keep parts on their own frames until end_token bubbles them
|
|
728
|
+
* into the parent. Live snapshot must splice the same way: projecting each
|
|
729
|
+
* inline as a sibling layout node stacks box rows, so the word after an
|
|
730
|
+
* unclosed ` / * / ** jumps to the next line until the closer arrives.
|
|
731
|
+
*/
|
|
732
|
+
function partsThroughOpenInlines(data, idx, tail) {
|
|
733
|
+
const parts = [];
|
|
734
|
+
for (let i = idx; i < data.stack.length; i++) {
|
|
735
|
+
const frame = data.stack[i];
|
|
736
|
+
if (i > idx && !isInline(frame.token))
|
|
737
|
+
break;
|
|
738
|
+
parts.push(...partsWithTail(frame, data, tail, i === data.stack.length - 1));
|
|
739
|
+
}
|
|
740
|
+
return parts;
|
|
741
|
+
}
|
|
742
|
+
function skipOpenInlines(data, idx) {
|
|
743
|
+
let i = idx;
|
|
744
|
+
while (i < data.stack.length && isInline(data.stack[i].token))
|
|
745
|
+
i++;
|
|
746
|
+
return i;
|
|
747
|
+
}
|
|
748
|
+
function mdTableGridStyle(cols) {
|
|
749
|
+
return {
|
|
750
|
+
columns: Array.from({ length: Math.max(1, cols) }, () => "auto"),
|
|
751
|
+
lines: "inner",
|
|
752
|
+
// Furniture, not voice — no outer frame (lines=inner).
|
|
753
|
+
lineStyle: { role: "border", prominence: FgP.ghost },
|
|
754
|
+
cellPad: { x: 1 },
|
|
755
|
+
columnGap: 1,
|
|
756
|
+
rowGap: 1,
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
function isInlineCell(node) {
|
|
760
|
+
if (node.type === "text")
|
|
761
|
+
return true;
|
|
762
|
+
if (node.type === "flex" || node.type === "box") {
|
|
763
|
+
return (node.children ?? []).every(isInlineCell);
|
|
764
|
+
}
|
|
765
|
+
return false;
|
|
766
|
+
}
|
|
767
|
+
function flattenParts(node) {
|
|
768
|
+
if (node.type === "text")
|
|
769
|
+
return [{ text: node.content, style: node.style ?? {} }];
|
|
770
|
+
if (node.type === "flex" || node.type === "box") {
|
|
771
|
+
return (node.children ?? []).flatMap(flattenParts);
|
|
772
|
+
}
|
|
773
|
+
return [];
|
|
774
|
+
}
|
|
775
|
+
function wrapCellToWidth(node, width) {
|
|
776
|
+
if (isInlineCell(node)) {
|
|
777
|
+
const parts = flattenParts(node);
|
|
778
|
+
if (parts.length === 0)
|
|
779
|
+
return node;
|
|
780
|
+
return partsToNode(parts, node.key ?? "td", width);
|
|
781
|
+
}
|
|
782
|
+
if (node.type === "indication") {
|
|
783
|
+
const inner = Math.max(1, width - INDICATION_CONTENT_INSET);
|
|
784
|
+
return { ...node, children: (node.children ?? []).map((c) => wrapCellToWidth(c, inner)) };
|
|
785
|
+
}
|
|
786
|
+
if (node.type === "box" || node.type === "flex" || node.type === "indentation_exception") {
|
|
787
|
+
return { ...node, children: (node.children ?? []).map((c) => wrapCellToWidth(c, width)) };
|
|
788
|
+
}
|
|
789
|
+
return node;
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* Wrap inline cells to the same column inner widths layout will assign.
|
|
793
|
+
* `partsToNode(width)` freezes nowrap rows — doing that at document width
|
|
794
|
+
* makes the grid clip instead of reflowing the long column.
|
|
795
|
+
*/
|
|
796
|
+
function wrapTableCells(cells, cols, width) {
|
|
797
|
+
const body = [...cells];
|
|
798
|
+
const n = Math.max(1, cols);
|
|
799
|
+
if (width === undefined || width <= 0 || body.length === 0)
|
|
800
|
+
return body;
|
|
801
|
+
const dims = measureGridDims({
|
|
802
|
+
type: "grid",
|
|
803
|
+
style: mdTableGridStyle(n),
|
|
804
|
+
children: body,
|
|
805
|
+
}, width);
|
|
806
|
+
return body.map((cell, i) => {
|
|
807
|
+
const innerW = Math.max(1, (dims.colWidths[i % n] ?? 1) - dims.padX * 2);
|
|
808
|
+
return wrapCellToWidth(cell, innerW);
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
/** GFM table as a grid. Header row (first `cols` cells) is bold. */
|
|
812
|
+
function tableGridNode(key, cells, cols, width) {
|
|
813
|
+
const n = Math.max(1, cols);
|
|
814
|
+
const body = wrapTableCells(cells, n, width);
|
|
815
|
+
for (let i = 0; i < n && i < body.length; i++) {
|
|
816
|
+
body[i] = asTableHeaderCell(body[i]);
|
|
817
|
+
}
|
|
818
|
+
return {
|
|
819
|
+
type: "grid",
|
|
820
|
+
key,
|
|
821
|
+
style: mdTableGridStyle(n),
|
|
822
|
+
children: body,
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
/** SMD holds `|` / newline until the next char; those are delimiters, not cell text. */
|
|
826
|
+
function tableCellTail(tail) {
|
|
827
|
+
if (/^[|\n]+$/.test(tail))
|
|
828
|
+
return "";
|
|
829
|
+
return tail;
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* Live TABLE snapshot: closed cells already sit on the table frame (full rows)
|
|
833
|
+
* and the open row. Incomplete last cell is included when it has text; leftover
|
|
834
|
+
* columns stay empty (grid pads). Separator pending on TABLE is ignored.
|
|
835
|
+
*/
|
|
836
|
+
function projectLiveTable(data, idx, tail) {
|
|
837
|
+
const table = data.stack[idx];
|
|
838
|
+
const openCells = [];
|
|
839
|
+
const row = data.stack[idx + 1];
|
|
840
|
+
if (row?.token === TABLE_ROW) {
|
|
841
|
+
openCells.push(...row.children);
|
|
842
|
+
const cellIdx = idx + 2;
|
|
843
|
+
if (data.stack[cellIdx]?.token === TABLE_CELL) {
|
|
844
|
+
const live = projectLiveTableCell(data, cellIdx, tail);
|
|
845
|
+
if (live)
|
|
846
|
+
openCells.push(live);
|
|
847
|
+
}
|
|
848
|
+
if (table.colCount !== undefined) {
|
|
849
|
+
openCells.length = Math.min(openCells.length, table.colCount);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
const cells = [...table.children, ...openCells];
|
|
853
|
+
if (cells.length === 0)
|
|
854
|
+
return [];
|
|
855
|
+
const cols = Math.max(1, table.colCount ?? cells.length);
|
|
856
|
+
return [tableGridNode(`${data.key}:live-table`, cells, cols, table.wrapWidth)];
|
|
857
|
+
}
|
|
858
|
+
function projectLiveTableCell(data, cellIdx, tail) {
|
|
859
|
+
const cell = data.stack[cellIdx];
|
|
860
|
+
const parts = [];
|
|
861
|
+
for (let i = cellIdx; i < data.stack.length; i++) {
|
|
862
|
+
const isDeepest = i === data.stack.length - 1;
|
|
863
|
+
const cellTail = isDeepest ? tableCellTail(tail) : "";
|
|
864
|
+
parts.push(...partsWithTail(data.stack[i], data, cellTail, isDeepest));
|
|
865
|
+
}
|
|
866
|
+
const trimmed = trimParts(parts);
|
|
867
|
+
if (trimmed.length === 0 && cell.children.length === 0)
|
|
868
|
+
return undefined;
|
|
869
|
+
if (cell.children.length === 0) {
|
|
870
|
+
return partsToNode(trimmed, `${data.key}:live-td`);
|
|
871
|
+
}
|
|
872
|
+
return {
|
|
873
|
+
type: "box",
|
|
874
|
+
key: `${data.key}:live-td`,
|
|
875
|
+
children: [...(trimmed.length > 0 ? [partsToNode(trimmed, `${data.key}:live-td-p`)] : []), ...cell.children],
|
|
876
|
+
};
|
|
877
|
+
}
|
|
878
|
+
function projectOpen(data, idx, tail) {
|
|
879
|
+
if (idx >= data.stack.length)
|
|
880
|
+
return [];
|
|
881
|
+
const frame = data.stack[idx];
|
|
882
|
+
const t = frame.token;
|
|
883
|
+
// Open TABLE never materializes a grid (that happens on end_token). Project
|
|
884
|
+
// closed cells + the current cell into a grid; drop empty in-progress cells
|
|
885
|
+
// and never paint the `|---` separator / trailing `|` as prose.
|
|
886
|
+
if (t === TABLE) {
|
|
887
|
+
return projectLiveTable(data, idx, tail);
|
|
888
|
+
}
|
|
889
|
+
if (t === TABLE_ROW || t === TABLE_CELL) {
|
|
890
|
+
return [];
|
|
891
|
+
}
|
|
892
|
+
// Skip still-open inlines: they splice into this frame's parts (see
|
|
893
|
+
// partsThroughOpenInlines). Recursing into them used to emit a sibling
|
|
894
|
+
// layout node, which a box stacks as a new row.
|
|
895
|
+
const deeper = projectOpen(data, skipOpenInlines(data, idx + 1), tail);
|
|
896
|
+
if (t === CODE_FENCE || t === CODE_BLOCK) {
|
|
897
|
+
const parts = partsThroughOpenInlines(data, idx, tail);
|
|
898
|
+
const code = joinParts(parts);
|
|
899
|
+
return [plainCodeNodeLive(data, code, frame.lang, frame.wrapWidth), ...deeper];
|
|
900
|
+
}
|
|
901
|
+
if (isHeading(t) || t === PARAGRAPH) {
|
|
902
|
+
const parts = partsThroughOpenInlines(data, idx, tail);
|
|
903
|
+
const nodes = [];
|
|
904
|
+
if (parts.length > 0) {
|
|
905
|
+
nodes.push(partsToNode(parts, `${data.key}:live-${idx}`, frame.wrapWidth));
|
|
906
|
+
}
|
|
907
|
+
nodes.push(...frame.children, ...deeper);
|
|
908
|
+
return nodes;
|
|
909
|
+
}
|
|
910
|
+
if (t === LIST_ITEM) {
|
|
911
|
+
const parent = data.stack[idx - 1];
|
|
912
|
+
const ordered = parent?.token === LIST_ORDERED;
|
|
913
|
+
const start = parent?.start ?? 1;
|
|
914
|
+
const n = parent?.itemCount ?? 0;
|
|
915
|
+
const prefix = ordered ? `${start + n}. ` : "• ";
|
|
916
|
+
const parts = partsThroughOpenInlines(data, idx, tail);
|
|
917
|
+
return [
|
|
918
|
+
partsToNode([{ text: prefix, style: data.baseStyle }, ...parts], `${data.key}:live-li-${idx}`, frame.wrapWidth),
|
|
919
|
+
...frame.children,
|
|
920
|
+
...deeper,
|
|
921
|
+
];
|
|
922
|
+
}
|
|
923
|
+
if (t === BLOCKQUOTE) {
|
|
924
|
+
const parts = partsThroughOpenInlines(data, idx, tail);
|
|
925
|
+
return [
|
|
926
|
+
{
|
|
927
|
+
type: "indication",
|
|
928
|
+
key: `${data.key}:live-bq-${idx}`,
|
|
929
|
+
gutter: { kind: "rule", glyph: "│" },
|
|
930
|
+
style: { role: "border", prominence: FgP.ghost },
|
|
931
|
+
children: [
|
|
932
|
+
...frame.children,
|
|
933
|
+
...(parts.length > 0 ? [partsToNode(parts, `${data.key}:live-bq-p-${idx}`, frame.wrapWidth)] : []),
|
|
934
|
+
...deeper,
|
|
935
|
+
],
|
|
936
|
+
},
|
|
937
|
+
];
|
|
938
|
+
}
|
|
939
|
+
if (isInline(t)) {
|
|
940
|
+
// First open frame is an inline (no paragraph yet). Fold nested inlines
|
|
941
|
+
// into one node — never a sibling per span.
|
|
942
|
+
const parts = partsThroughOpenInlines(data, idx, tail);
|
|
943
|
+
if (parts.length > 0) {
|
|
944
|
+
return [partsToNode(parts, `${data.key}:live-in-${idx}`, frame.wrapWidth), ...deeper];
|
|
945
|
+
}
|
|
946
|
+
return deeper;
|
|
947
|
+
}
|
|
948
|
+
const parts = partsThroughOpenInlines(data, idx, tail);
|
|
949
|
+
return [
|
|
950
|
+
...frame.children,
|
|
951
|
+
...(parts.length > 0 ? [partsToNode(parts, `${data.key}:live-${idx}`, frame.wrapWidth)] : []),
|
|
952
|
+
...deeper,
|
|
953
|
+
];
|
|
954
|
+
}
|
|
955
|
+
/** Live code fence for open-block snapshot projection (no key seq bump). */
|
|
956
|
+
function plainCodeNodeLive(data, code, lang, width = data.width) {
|
|
957
|
+
const lines = code.replace(/\n$/, "").split("\n");
|
|
958
|
+
const fenceKey = `${data.key}:live-fence${lang ? `-${lang}` : ""}`;
|
|
959
|
+
const rows = highlightedFenceRows(data, code, lang, width);
|
|
960
|
+
if (rows) {
|
|
961
|
+
return {
|
|
962
|
+
type: "indentation_exception",
|
|
963
|
+
key: fenceKey,
|
|
964
|
+
kind: "code_pad",
|
|
965
|
+
children: rows.map((parts, j) => rowToNode(parts, `${fenceKey}:${j}`)),
|
|
966
|
+
};
|
|
967
|
+
}
|
|
968
|
+
return {
|
|
969
|
+
type: "indentation_exception",
|
|
970
|
+
key: fenceKey,
|
|
971
|
+
kind: "code_pad",
|
|
972
|
+
children: lines.map((l, j) => ({
|
|
973
|
+
type: "text",
|
|
974
|
+
key: `${fenceKey}:${j}`,
|
|
975
|
+
content: l,
|
|
976
|
+
style: fenceStyle(data.baseStyle),
|
|
977
|
+
})),
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
//# sourceMappingURL=markdown-expand.js.map
|