@inhuman.tools/quickdraw 0.0.0-stage → 0.2.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 +27 -0
- package/dist/runtime/agents_preview.d.ts.map +1 -0
- package/dist/runtime/agents_preview.js +122 -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 +147 -3
|
@@ -0,0 +1,1106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Widget-module diff projection for prepare() and storybook.
|
|
3
|
+
* The terminal projection is expand_diff in packages/quickdraw/rust/qd.
|
|
4
|
+
*
|
|
5
|
+
* Structure: vendored pure-parse slice of @pierre/diffs@1.2.12
|
|
6
|
+
* (`./pierre-parse` — Apache-2.0, see that directory's NOTICE).
|
|
7
|
+
* Intra-line (word-alt): diffWordsWithSpace from `diff` (same algo Pierre uses).
|
|
8
|
+
* Syntax: ./syntax.js (sync after warmHighlighter).
|
|
9
|
+
* Visual: add/del rows carry full-pane mist wash (empty cells of the
|
|
10
|
+
* half, not just glyphs). Word-alt spans step to panel. Context / elision
|
|
11
|
+
* occupy with transparent cast so overlay tape does not bleed, without a
|
|
12
|
+
* slab. Line numbers, ▌ gutter.
|
|
13
|
+
*
|
|
14
|
+
* AUTO MODE. Split only when a hunk contains an edited cluster (a change
|
|
15
|
+
* block with both deletions and additions). Pure addition / removal blocks
|
|
16
|
+
* stay unified even when they fit a half-pane — a blank opposite side is
|
|
17
|
+
* not a comparison. Given an edited cluster, split iff every *painted*
|
|
18
|
+
* line (word-alt spans, not raw source; elided context omitted) fits one
|
|
19
|
+
* split pane's code column at this `width`. Pane = floor((width − 1) / 2),
|
|
20
|
+
* minus gutter + line-number digits + trailing space (same chrome
|
|
21
|
+
* `makeRow` subtracts). Otherwise unified. A width-only cutoff (e.g. 88
|
|
22
|
+
* cols) is rejected: it keeps a 20-column edit stacked at the 80-col TUI
|
|
23
|
+
* default, and it splits a 200-column rewrite on a wide terminal.
|
|
24
|
+
*
|
|
25
|
+
* Deleted runs stay intact. Collapsing them to a first-entity "…" hides
|
|
26
|
+
* the old state, and the keep-vs-omit cut has no stable grain.
|
|
27
|
+
*
|
|
28
|
+
* Missing final newline is not a painted edit (git still records it). An
|
|
29
|
+
* extra blank line at EOF is a real line and still shows.
|
|
30
|
+
*
|
|
31
|
+
* PAINT FOLD. Two-file parse keeps both sides whole (`PARSE_CONTEXT`) so
|
|
32
|
+
* shiki sees real source — a hunk-sliced join is not a file, and tokens
|
|
33
|
+
* go wrong on any mid-file edit. Line numbers stay the hunk `@@` origins
|
|
34
|
+
* (plus `lineStart` for a span). Display context is a later elision: keep
|
|
35
|
+
* change-adjacent lines, emit `·· N unchanged ··` for the rest. Leading
|
|
36
|
+
* context keeps its tail; trailing keeps its head; a run between edits
|
|
37
|
+
* keeps both ends. `context: "all"` skips that elision. Rejected: feeding
|
|
38
|
+
* `context` into `createTwoFilesPatch` — that cuts before highlight.
|
|
39
|
+
*
|
|
40
|
+
* No dependency on the published @pierre/diffs barrel (which loads browser
|
|
41
|
+
* CodeView and touches navigator at import time).
|
|
42
|
+
*/
|
|
43
|
+
import { diffWordsWithSpace } from "diff";
|
|
44
|
+
import { parseDiffFromFile, parsePatchFiles, } from "./pierre-parse/index.js";
|
|
45
|
+
import { highlightCodeSync, isHighlighterReady, runsToStyle } from "./syntax.js";
|
|
46
|
+
import { BgP, FgP } from "../../lexicon/index.js";
|
|
47
|
+
import { displayWidth } from "../../measure/index.js";
|
|
48
|
+
const DEFAULT_CONTEXT = 3;
|
|
49
|
+
/** jsdiff context large enough that a two-file parse is one whole-file hunk. */
|
|
50
|
+
const PARSE_CONTEXT = 1_000_000;
|
|
51
|
+
const GUTTER = "▌";
|
|
52
|
+
const MAX_LINE_DIFF_LEN = 1000;
|
|
53
|
+
/** ▌ + digits + trailing space — same chrome `makeRow` subtracts from `rowW`. */
|
|
54
|
+
function rowChromeWidth(numW) {
|
|
55
|
+
return 1 + numW + 1;
|
|
56
|
+
}
|
|
57
|
+
/** One split pane, including chrome. Gap of 1 between panes. */
|
|
58
|
+
function splitHalfWidth(width) {
|
|
59
|
+
return Math.max(8, Math.floor((width - 1) / 2));
|
|
60
|
+
}
|
|
61
|
+
function splitContentWidth(width, numW) {
|
|
62
|
+
return Math.max(1, splitHalfWidth(width) - rowChromeWidth(numW));
|
|
63
|
+
}
|
|
64
|
+
// ── theme styles ────────────────────────────────────────────────────────────
|
|
65
|
+
// Authoring intent only — resolveStyle (paint-time) turns role/bgRole into
|
|
66
|
+
// concrete color. No hex/rgb baked here (Post-audit "Single resolve API").
|
|
67
|
+
function chromeStyle(extra = {}) {
|
|
68
|
+
// chrome is already tier "recede"; FgP.ghost is the one prominence step
|
|
69
|
+
// down from that — no separate dim authoring on top.
|
|
70
|
+
return { role: "chrome", prominence: FgP.ghost, ...extra };
|
|
71
|
+
}
|
|
72
|
+
function headerStyle() {
|
|
73
|
+
return { role: "chrome", bold: true };
|
|
74
|
+
}
|
|
75
|
+
/** Row wash for a diff side — bgRole resolved via the BG ladder. */
|
|
76
|
+
function rowWashStyle(role, emphasis) {
|
|
77
|
+
// mist = atmosphere toward ground (the OSI-transparent trick). wash sat
|
|
78
|
+
// near the selection fill target, so selected-vs-row missed the JND.
|
|
79
|
+
// panel stays the intra-line word-alt step.
|
|
80
|
+
return { bgRole: role, bgProminence: emphasis ? BgP.panel : BgP.mist };
|
|
81
|
+
}
|
|
82
|
+
function stripNl(s) {
|
|
83
|
+
return s.replace(/\r?\n$/, "");
|
|
84
|
+
}
|
|
85
|
+
/** Paint: a missing final newline is not a line edit. Empty stays empty. */
|
|
86
|
+
function withTrailingNl(s) {
|
|
87
|
+
if (s.length === 0 || s.endsWith("\n"))
|
|
88
|
+
return s;
|
|
89
|
+
return `${s}\n`;
|
|
90
|
+
}
|
|
91
|
+
function elideLabel(n) {
|
|
92
|
+
return `·· ${n} unchanged ··`;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Soft-wrap span runs to `width` display columns.
|
|
96
|
+
* Newlines always break; long runs never clip — wrap mid-span by grapheme.
|
|
97
|
+
*/
|
|
98
|
+
function softWrapSpans(spans, width) {
|
|
99
|
+
const w = Math.max(1, width);
|
|
100
|
+
const segmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
101
|
+
const cells = [];
|
|
102
|
+
for (const sp of spans) {
|
|
103
|
+
const chunks = sp.text.split("\n");
|
|
104
|
+
for (const [ci, chunk] of chunks.entries()) {
|
|
105
|
+
if (ci > 0)
|
|
106
|
+
cells.push({ ch: "\n" });
|
|
107
|
+
for (const { segment } of segmenter.segment(chunk)) {
|
|
108
|
+
if (!segment)
|
|
109
|
+
continue;
|
|
110
|
+
cells.push({
|
|
111
|
+
ch: segment,
|
|
112
|
+
emphasis: sp.emphasis,
|
|
113
|
+
color: sp.color,
|
|
114
|
+
bold: sp.bold,
|
|
115
|
+
italic: sp.italic,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const rows = [];
|
|
121
|
+
let line = [];
|
|
122
|
+
let lineW = 0;
|
|
123
|
+
const flush = () => {
|
|
124
|
+
rows.push(cellsToSpans(line));
|
|
125
|
+
line = [];
|
|
126
|
+
lineW = 0;
|
|
127
|
+
};
|
|
128
|
+
for (const c of cells) {
|
|
129
|
+
if (c.ch === "\n") {
|
|
130
|
+
flush();
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
const cw = Math.max(0, displayWidth(c.ch));
|
|
134
|
+
if (cw === 0) {
|
|
135
|
+
line.push(c);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (lineW + cw > w && line.length > 0)
|
|
139
|
+
flush();
|
|
140
|
+
// single wide grapheme wider than w: still emit (better than drop)
|
|
141
|
+
line.push(c);
|
|
142
|
+
lineW += cw;
|
|
143
|
+
}
|
|
144
|
+
if (line.length > 0 || rows.length === 0)
|
|
145
|
+
flush();
|
|
146
|
+
return rows;
|
|
147
|
+
}
|
|
148
|
+
function cellsToSpans(cells) {
|
|
149
|
+
if (cells.length === 0)
|
|
150
|
+
return [{ text: " " }];
|
|
151
|
+
const out = [];
|
|
152
|
+
let cur = null;
|
|
153
|
+
for (const c of cells) {
|
|
154
|
+
if (cur &&
|
|
155
|
+
!!cur.emphasis === !!c.emphasis &&
|
|
156
|
+
cur.color === c.color &&
|
|
157
|
+
!!cur.bold === !!c.bold &&
|
|
158
|
+
!!cur.italic === !!c.italic) {
|
|
159
|
+
cur.text += c.ch;
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
if (cur)
|
|
163
|
+
out.push(cur);
|
|
164
|
+
cur = {
|
|
165
|
+
text: c.ch,
|
|
166
|
+
emphasis: c.emphasis,
|
|
167
|
+
color: c.color,
|
|
168
|
+
bold: c.bold,
|
|
169
|
+
italic: c.italic,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (cur)
|
|
174
|
+
out.push(cur);
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Pierre word-alt: diffWordsWithSpace + join adjacent changed clusters.
|
|
179
|
+
* Mirrors computeLineDiffDecorations in @pierre/diffs.
|
|
180
|
+
*/
|
|
181
|
+
function wordAltSpans(oldLine, newLine, side) {
|
|
182
|
+
if (oldLine.length > MAX_LINE_DIFF_LEN || newLine.length > MAX_LINE_DIFF_LEN) {
|
|
183
|
+
return [
|
|
184
|
+
{
|
|
185
|
+
text: side === "del" ? oldLine : newLine,
|
|
186
|
+
emphasis: true,
|
|
187
|
+
},
|
|
188
|
+
];
|
|
189
|
+
}
|
|
190
|
+
const parts = diffWordsWithSpace(oldLine, newLine);
|
|
191
|
+
// word-alt: join adjacent same-polarity changed items separated by single space
|
|
192
|
+
const joined = [];
|
|
193
|
+
for (const item of parts) {
|
|
194
|
+
const last = joined.at(-1);
|
|
195
|
+
if (last &&
|
|
196
|
+
item.added === last.added &&
|
|
197
|
+
item.removed === last.removed &&
|
|
198
|
+
(item.added || item.removed) &&
|
|
199
|
+
last.value.endsWith(" ") === false &&
|
|
200
|
+
item.value.startsWith(" ") === false) {
|
|
201
|
+
// fuse adjacent changed words (Pierre enableJoin)
|
|
202
|
+
last.value += item.value;
|
|
203
|
+
last.count = (last.count ?? 0) + (item.count ?? 0);
|
|
204
|
+
}
|
|
205
|
+
else if (last &&
|
|
206
|
+
item.added === last.added &&
|
|
207
|
+
item.removed === last.removed &&
|
|
208
|
+
(item.added || item.removed) &&
|
|
209
|
+
last.value.endsWith(" ") &&
|
|
210
|
+
!item.value.startsWith(" ")) {
|
|
211
|
+
last.value += item.value;
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
joined.push({ ...item });
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const out = [];
|
|
218
|
+
for (const item of joined) {
|
|
219
|
+
if (side === "del") {
|
|
220
|
+
if (item.added)
|
|
221
|
+
continue;
|
|
222
|
+
out.push({ text: item.value, emphasis: !!item.removed });
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
if (item.removed)
|
|
226
|
+
continue;
|
|
227
|
+
out.push({ text: item.value, emphasis: !!item.added });
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return out.length > 0 ? out : [{ text: side === "del" ? oldLine : newLine }];
|
|
231
|
+
}
|
|
232
|
+
/** Overlay syntax tokens onto word-alt spans (fg from shiki, bg from emphasis). */
|
|
233
|
+
function composeHighlight(spans, hlLine) {
|
|
234
|
+
if (!hlLine || hlLine.length === 0)
|
|
235
|
+
return spans;
|
|
236
|
+
// Flatten highlight to character colors, then re-slice by span boundaries
|
|
237
|
+
const chars = [];
|
|
238
|
+
for (const run of hlLine) {
|
|
239
|
+
for (let i = 0; i < run.text.length; i++) {
|
|
240
|
+
chars.push({
|
|
241
|
+
color: run.color,
|
|
242
|
+
bold: run.bold,
|
|
243
|
+
italic: run.italic,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
let offset = 0;
|
|
248
|
+
const out = [];
|
|
249
|
+
for (const span of spans) {
|
|
250
|
+
let i = 0;
|
|
251
|
+
while (i < span.text.length) {
|
|
252
|
+
const base = chars[offset + i] ?? {};
|
|
253
|
+
let j = i + 1;
|
|
254
|
+
while (j < span.text.length &&
|
|
255
|
+
chars[offset + j]?.color === base.color &&
|
|
256
|
+
chars[offset + j]?.bold === base.bold &&
|
|
257
|
+
chars[offset + j]?.italic === base.italic) {
|
|
258
|
+
j++;
|
|
259
|
+
}
|
|
260
|
+
out.push({
|
|
261
|
+
text: span.text.slice(i, j),
|
|
262
|
+
emphasis: span.emphasis,
|
|
263
|
+
color: base.color,
|
|
264
|
+
bold: base.bold,
|
|
265
|
+
italic: base.italic,
|
|
266
|
+
});
|
|
267
|
+
i = j;
|
|
268
|
+
}
|
|
269
|
+
offset += span.text.length;
|
|
270
|
+
}
|
|
271
|
+
return out;
|
|
272
|
+
}
|
|
273
|
+
function spanStyle(span, kind) {
|
|
274
|
+
if (kind === "ctx") {
|
|
275
|
+
// Context CODE is voice, not furniture: recede one prominence step, don't
|
|
276
|
+
// crush to chrome/ghost — ghost turns tokens to mud. Line numbers and
|
|
277
|
+
// elision rows stay chromeStyle.
|
|
278
|
+
const st = { role: "foreground", prominence: FgP.secondary };
|
|
279
|
+
if (span.color) {
|
|
280
|
+
// Token RGB is hue/chroma; resolver recasts AL onto this role.
|
|
281
|
+
const rgb = runsToStyle({ text: "", color: span.color }).fgRgb;
|
|
282
|
+
if (rgb)
|
|
283
|
+
st.fgRgb = rgb;
|
|
284
|
+
}
|
|
285
|
+
if (span.bold)
|
|
286
|
+
st.bold = true;
|
|
287
|
+
if (span.italic)
|
|
288
|
+
st.italic = true;
|
|
289
|
+
return st;
|
|
290
|
+
}
|
|
291
|
+
const role = kind === "add" ? "diff_add" : "diff_del";
|
|
292
|
+
const st = {
|
|
293
|
+
role,
|
|
294
|
+
...rowWashStyle(role, span.emphasis),
|
|
295
|
+
};
|
|
296
|
+
if (span.color) {
|
|
297
|
+
// Token RGB is hue/chroma; resolver recasts AL onto this role.
|
|
298
|
+
const rgb = runsToStyle({ text: "", color: span.color }).fgRgb;
|
|
299
|
+
if (rgb)
|
|
300
|
+
st.fgRgb = rgb;
|
|
301
|
+
}
|
|
302
|
+
if (span.bold)
|
|
303
|
+
st.bold = true;
|
|
304
|
+
if (span.italic)
|
|
305
|
+
st.italic = true;
|
|
306
|
+
return st;
|
|
307
|
+
}
|
|
308
|
+
function padNum(n, width) {
|
|
309
|
+
if (n === null || n <= 0)
|
|
310
|
+
return " ".repeat(Math.max(0, width));
|
|
311
|
+
const s = String(n);
|
|
312
|
+
return s.length >= width ? s : s.padStart(width, " ");
|
|
313
|
+
}
|
|
314
|
+
function maxPaintedLineNo(lines) {
|
|
315
|
+
let best = 1;
|
|
316
|
+
for (const item of lines) {
|
|
317
|
+
if ("elided" in item)
|
|
318
|
+
continue;
|
|
319
|
+
if (item.oldNo != null && item.oldNo > best)
|
|
320
|
+
best = item.oldNo;
|
|
321
|
+
if (item.newNo != null && item.newNo > best)
|
|
322
|
+
best = item.newNo;
|
|
323
|
+
}
|
|
324
|
+
return best;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Full-width washed row(s): soft-wrap code spans (newlines + width).
|
|
328
|
+
* Never clip mid-line with nowrap overflow.
|
|
329
|
+
*
|
|
330
|
+
* Selection: gutter/nums are chrome (`userSelect: none`); code spans are
|
|
331
|
+
* `"text"`. Optional {@link DiffLineRef} stamps the logical git line onto
|
|
332
|
+
* descendants for copy (full source text, not painted wrap).
|
|
333
|
+
*/
|
|
334
|
+
function makeRow(opts) {
|
|
335
|
+
const { kind, spans, key, rowW, oldNo, newNo, numW, diffLine } = opts;
|
|
336
|
+
const wash = kind === "add" ? rowWashStyle("diff_add") : kind === "del" ? rowWashStyle("diff_del") : undefined;
|
|
337
|
+
const gutterChar = kind === "add" || kind === "del" ? GUTTER : " ";
|
|
338
|
+
const gutterStyle = kind === "add" ? { role: "diff_add", ...wash } : kind === "del" ? { role: "diff_del", ...wash } : chromeStyle(wash);
|
|
339
|
+
let numText;
|
|
340
|
+
switch (kind) {
|
|
341
|
+
case "del": {
|
|
342
|
+
numText = `${padNum(oldNo, numW)} `;
|
|
343
|
+
break;
|
|
344
|
+
}
|
|
345
|
+
case "add": {
|
|
346
|
+
numText = `${padNum(newNo, numW)} `;
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
349
|
+
case "ctx": {
|
|
350
|
+
numText = `${padNum(oldNo ?? newNo, numW)} `;
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
default:
|
|
354
|
+
numText = `${" ".repeat(numW)} `;
|
|
355
|
+
}
|
|
356
|
+
const prefixW = rowChromeWidth(numW);
|
|
357
|
+
const contentW = Math.max(1, rowW - prefixW);
|
|
358
|
+
const wrapped = spans.length === 0 ? [[{ text: " " }]] : softWrapSpans(spans, contentW);
|
|
359
|
+
const lineNodes = wrapped.map((lineSpans, li) => {
|
|
360
|
+
const kids = [
|
|
361
|
+
{
|
|
362
|
+
type: "text",
|
|
363
|
+
key: `${key}:g${li}`,
|
|
364
|
+
content: li === 0 ? gutterChar : " ",
|
|
365
|
+
whiteSpace: "nowrap",
|
|
366
|
+
userSelect: "none",
|
|
367
|
+
style: gutterStyle,
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
type: "text",
|
|
371
|
+
key: `${key}:n${li}`,
|
|
372
|
+
content: li === 0 ? numText : " ".repeat(numText.length),
|
|
373
|
+
whiteSpace: "nowrap",
|
|
374
|
+
userSelect: "none",
|
|
375
|
+
style: chromeStyle(wash),
|
|
376
|
+
},
|
|
377
|
+
];
|
|
378
|
+
for (const [i, sp] of lineSpans.entries()) {
|
|
379
|
+
kids.push({
|
|
380
|
+
type: "text",
|
|
381
|
+
key: `${key}:t${li}_${i}`,
|
|
382
|
+
content: sp.text.length > 0 ? sp.text : " ",
|
|
383
|
+
whiteSpace: "nowrap",
|
|
384
|
+
userSelect: kind === "blank" ? "none" : "text",
|
|
385
|
+
style: spanStyle(sp, kind === "blank" ? "ctx" : kind),
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
return {
|
|
389
|
+
type: "flex",
|
|
390
|
+
key: `${key}:row${li}`,
|
|
391
|
+
style: { direction: "row", gap: 0, width: rowW },
|
|
392
|
+
paintReady: true,
|
|
393
|
+
measured: { w: rowW, h: 1, atW: rowW },
|
|
394
|
+
children: kids,
|
|
395
|
+
};
|
|
396
|
+
});
|
|
397
|
+
return {
|
|
398
|
+
type: "box",
|
|
399
|
+
key,
|
|
400
|
+
// Structure is chrome — only `:t` code spans are selectable content.
|
|
401
|
+
// If the box is `"text"`, free-path selection paints trailing empty cells
|
|
402
|
+
// across the half (and the gap to the partner half in split).
|
|
403
|
+
userSelect: "none",
|
|
404
|
+
diffLine,
|
|
405
|
+
paintReady: true,
|
|
406
|
+
measured: { w: rowW, h: lineNodes.length, atW: rowW },
|
|
407
|
+
style: {
|
|
408
|
+
width: rowW,
|
|
409
|
+
background: wash ?? { cast: "transparent" },
|
|
410
|
+
overflow: "hidden",
|
|
411
|
+
},
|
|
412
|
+
children: lineNodes,
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
function elideRow(n, key, rowW) {
|
|
416
|
+
return {
|
|
417
|
+
type: "box",
|
|
418
|
+
key,
|
|
419
|
+
userSelect: "none",
|
|
420
|
+
style: { width: rowW, height: 1, background: { cast: "transparent" } },
|
|
421
|
+
children: [
|
|
422
|
+
{
|
|
423
|
+
type: "text",
|
|
424
|
+
key: `${key}:c`,
|
|
425
|
+
content: elideLabel(n),
|
|
426
|
+
userSelect: "none",
|
|
427
|
+
style: chromeStyle(),
|
|
428
|
+
},
|
|
429
|
+
],
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
function diffStamp(diffKey, lineIndex, kind, text, opts) {
|
|
433
|
+
return {
|
|
434
|
+
diffKey,
|
|
435
|
+
lineIndex,
|
|
436
|
+
kind,
|
|
437
|
+
text,
|
|
438
|
+
side: opts?.side,
|
|
439
|
+
oldNo: opts?.oldNo ?? null,
|
|
440
|
+
newNo: opts?.newNo ?? null,
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
function maxPaintedLineWidth(lines) {
|
|
444
|
+
let best = 0;
|
|
445
|
+
for (const item of lines) {
|
|
446
|
+
if ("elided" in item)
|
|
447
|
+
continue;
|
|
448
|
+
best = Math.max(best, displayWidth(item.spans.map((s) => s.text).join("")));
|
|
449
|
+
}
|
|
450
|
+
return best;
|
|
451
|
+
}
|
|
452
|
+
function hasEditedCluster(meta) {
|
|
453
|
+
for (const hunk of meta.hunks) {
|
|
454
|
+
for (const block of hunk.hunkContent) {
|
|
455
|
+
if (block.type === "change" && block.deletions > 0 && block.additions > 0)
|
|
456
|
+
return true;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
return false;
|
|
460
|
+
}
|
|
461
|
+
function resolveDiffMode(mode, width, meta, lines) {
|
|
462
|
+
if (mode !== "auto")
|
|
463
|
+
return mode;
|
|
464
|
+
// No in-place replacement: split would be a blank half next to pure add/del.
|
|
465
|
+
if (!hasEditedCluster(meta))
|
|
466
|
+
return "unified";
|
|
467
|
+
const numW = String(maxLineNo(meta)).length;
|
|
468
|
+
return maxPaintedLineWidth(lines) <= splitContentWidth(width, numW) ? "split" : "unified";
|
|
469
|
+
}
|
|
470
|
+
function contextBlockEdge(blocks, index) {
|
|
471
|
+
let changeBefore = false;
|
|
472
|
+
let changeAfter = false;
|
|
473
|
+
for (const [i, block] of blocks.entries()) {
|
|
474
|
+
if (block.type !== "change")
|
|
475
|
+
continue;
|
|
476
|
+
if (i < index)
|
|
477
|
+
changeBefore = true;
|
|
478
|
+
if (i > index)
|
|
479
|
+
changeAfter = true;
|
|
480
|
+
}
|
|
481
|
+
if (changeBefore && changeAfter)
|
|
482
|
+
return "middle";
|
|
483
|
+
if (!changeBefore && changeAfter)
|
|
484
|
+
return "leading";
|
|
485
|
+
if (changeBefore && !changeAfter)
|
|
486
|
+
return "trailing";
|
|
487
|
+
return "middle";
|
|
488
|
+
}
|
|
489
|
+
function elideContextIndices(count, ctx, edge) {
|
|
490
|
+
if (ctx === "all" || count === 0) {
|
|
491
|
+
return Array.from({ length: count }, (_, i) => ({ kind: "line", i }));
|
|
492
|
+
}
|
|
493
|
+
const all = () => Array.from({ length: count }, (_, i) => ({ kind: "line", i }));
|
|
494
|
+
if (edge === "leading") {
|
|
495
|
+
if (count <= ctx)
|
|
496
|
+
return all();
|
|
497
|
+
const keepFrom = count - ctx;
|
|
498
|
+
return [
|
|
499
|
+
{ kind: "elide", n: keepFrom },
|
|
500
|
+
...Array.from({ length: ctx }, (_, i) => ({ kind: "line", i: keepFrom + i })),
|
|
501
|
+
];
|
|
502
|
+
}
|
|
503
|
+
if (edge === "trailing") {
|
|
504
|
+
if (count <= ctx)
|
|
505
|
+
return all();
|
|
506
|
+
return [
|
|
507
|
+
...Array.from({ length: ctx }, (_, i) => ({ kind: "line", i })),
|
|
508
|
+
{ kind: "elide", n: count - ctx },
|
|
509
|
+
];
|
|
510
|
+
}
|
|
511
|
+
if (count <= ctx * 2 + 1)
|
|
512
|
+
return all();
|
|
513
|
+
const out = [];
|
|
514
|
+
for (let i = 0; i < ctx; i++)
|
|
515
|
+
out.push({ kind: "line", i });
|
|
516
|
+
const mid = count - ctx * 2;
|
|
517
|
+
if (mid > 0)
|
|
518
|
+
out.push({ kind: "elide", n: mid });
|
|
519
|
+
for (let i = count - ctx; i < count; i++)
|
|
520
|
+
out.push({ kind: "line", i });
|
|
521
|
+
return out;
|
|
522
|
+
}
|
|
523
|
+
function buildLines(meta, ctx, lineDiffType, hl) {
|
|
524
|
+
const out = [];
|
|
525
|
+
// Display line numbers are REAL 1-based file lines, not array indices.
|
|
526
|
+
// `additionLines`/`deletionLines` are compact (only diff-touched + context
|
|
527
|
+
// lines), so array index + 1 is wrong whenever a hunk starts past file
|
|
528
|
+
// line 1. Instead, seed a per-side file-line cursor from each hunk's
|
|
529
|
+
// `deletionStart` (old side) / `additionStart` (new side) — the 1-based
|
|
530
|
+
// line from the `@@ -X,X +X,X @@` header — and advance it as we emit rows.
|
|
531
|
+
for (let hi = 0; hi < meta.hunks.length; hi++) {
|
|
532
|
+
const hunk = meta.hunks[hi];
|
|
533
|
+
if (hunk.collapsedBefore > 0) {
|
|
534
|
+
out.push({ elided: hunk.collapsedBefore });
|
|
535
|
+
}
|
|
536
|
+
let oldCursor = hunk.deletionStart;
|
|
537
|
+
let newCursor = hunk.additionStart;
|
|
538
|
+
for (const [bi, block] of hunk.hunkContent.entries()) {
|
|
539
|
+
if (block.type === "context") {
|
|
540
|
+
const b = block;
|
|
541
|
+
for (const p of elideContextIndices(b.lines, ctx, contextBlockEdge(hunk.hunkContent, bi))) {
|
|
542
|
+
if (p.kind === "elide") {
|
|
543
|
+
// Folded lines still consume file lines on both sides even
|
|
544
|
+
// though we don't render them; the cursors are advanced in
|
|
545
|
+
// bulk after the loop via `+= b.lines`.
|
|
546
|
+
out.push({ elided: p.n });
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
const aIdx = b.additionLineIndex + p.i;
|
|
550
|
+
const dIdx = b.deletionLineIndex + p.i;
|
|
551
|
+
const oldNo = oldCursor + p.i;
|
|
552
|
+
const newNo = newCursor + p.i;
|
|
553
|
+
const text = stripNl(aIdx < meta.additionLines.length ? (meta.additionLines[aIdx] ?? "") : (meta.deletionLines[dIdx] ?? ""));
|
|
554
|
+
let spans = [{ text }];
|
|
555
|
+
const tokens = aIdx < meta.additionLines.length ? hl("add", newNo, aIdx) : hl("del", oldNo, dIdx);
|
|
556
|
+
if (tokens)
|
|
557
|
+
spans = composeHighlight(spans, tokens);
|
|
558
|
+
out.push({
|
|
559
|
+
kind: "ctx",
|
|
560
|
+
spans,
|
|
561
|
+
oldNo,
|
|
562
|
+
newNo,
|
|
563
|
+
rawText: text,
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
oldCursor += b.lines;
|
|
567
|
+
newCursor += b.lines;
|
|
568
|
+
}
|
|
569
|
+
else {
|
|
570
|
+
const b = block;
|
|
571
|
+
const delN = b.deletions;
|
|
572
|
+
const addN = b.additions;
|
|
573
|
+
// Pair min(del,add) for word-alt; remainder pure add/del
|
|
574
|
+
const paired = lineDiffType === "none" ? 0 : Math.min(delN, addN);
|
|
575
|
+
for (let i = 0; i < delN; i++) {
|
|
576
|
+
const dIdx = b.deletionLineIndex + i;
|
|
577
|
+
const dText = stripNl(meta.deletionLines[dIdx] ?? "");
|
|
578
|
+
let spans;
|
|
579
|
+
if (i < paired) {
|
|
580
|
+
const aIdx = b.additionLineIndex + i;
|
|
581
|
+
const aText = stripNl(meta.additionLines[aIdx] ?? "");
|
|
582
|
+
spans = wordAltSpans(dText, aText, "del");
|
|
583
|
+
}
|
|
584
|
+
else {
|
|
585
|
+
spans = [{ text: dText, emphasis: true }];
|
|
586
|
+
}
|
|
587
|
+
const oldNo = oldCursor + i;
|
|
588
|
+
spans = composeHighlight(spans, hl("del", oldNo, dIdx));
|
|
589
|
+
out.push({
|
|
590
|
+
kind: "del",
|
|
591
|
+
spans,
|
|
592
|
+
oldNo,
|
|
593
|
+
newNo: null,
|
|
594
|
+
rawText: dText,
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
for (let i = 0; i < addN; i++) {
|
|
598
|
+
const aIdx = b.additionLineIndex + i;
|
|
599
|
+
const aText = stripNl(meta.additionLines[aIdx] ?? "");
|
|
600
|
+
let spans;
|
|
601
|
+
if (i < paired) {
|
|
602
|
+
const dIdx = b.deletionLineIndex + i;
|
|
603
|
+
const dText = stripNl(meta.deletionLines[dIdx] ?? "");
|
|
604
|
+
spans = wordAltSpans(dText, aText, "add");
|
|
605
|
+
}
|
|
606
|
+
else {
|
|
607
|
+
spans = [{ text: aText, emphasis: true }];
|
|
608
|
+
}
|
|
609
|
+
const newNo = newCursor + i;
|
|
610
|
+
spans = composeHighlight(spans, hl("add", newNo, aIdx));
|
|
611
|
+
out.push({
|
|
612
|
+
kind: "add",
|
|
613
|
+
spans,
|
|
614
|
+
oldNo: null,
|
|
615
|
+
newNo,
|
|
616
|
+
rawText: aText,
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
oldCursor += delN;
|
|
620
|
+
newCursor += addN;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
return out;
|
|
625
|
+
}
|
|
626
|
+
function projectUnified(lines, rowW, numW, keyBase) {
|
|
627
|
+
const rows = [];
|
|
628
|
+
let ri = 0;
|
|
629
|
+
let lineIndex = 0;
|
|
630
|
+
for (const item of lines) {
|
|
631
|
+
if ("elided" in item) {
|
|
632
|
+
rows.push(elideRow(item.elided, `${keyBase}:f${ri++}`, rowW));
|
|
633
|
+
continue;
|
|
634
|
+
}
|
|
635
|
+
const fullText = item.spans.map((s) => s.text).join("");
|
|
636
|
+
const stampKind = item.kind === "blank" ? null : item.kind;
|
|
637
|
+
rows.push(makeRow({
|
|
638
|
+
kind: item.kind,
|
|
639
|
+
spans: item.spans,
|
|
640
|
+
key: `${keyBase}:u${ri++}`,
|
|
641
|
+
rowW,
|
|
642
|
+
oldNo: item.oldNo,
|
|
643
|
+
newNo: item.newNo,
|
|
644
|
+
numW,
|
|
645
|
+
diffLine: stampKind
|
|
646
|
+
? diffStamp(keyBase, lineIndex++, stampKind, item.rawText ?? fullText, {
|
|
647
|
+
oldNo: item.oldNo,
|
|
648
|
+
newNo: item.newNo,
|
|
649
|
+
})
|
|
650
|
+
: undefined,
|
|
651
|
+
}));
|
|
652
|
+
}
|
|
653
|
+
return rows;
|
|
654
|
+
}
|
|
655
|
+
function projectSplit(meta, ctx, lineDiffType, hl, width, numW, keyBase) {
|
|
656
|
+
// Build paired visual rows for split (left=old, right=new)
|
|
657
|
+
const halfW = splitHalfWidth(width);
|
|
658
|
+
const rows = [];
|
|
659
|
+
let ri = 0;
|
|
660
|
+
// Git emission order (all dels then all adds per change block), NOT visual
|
|
661
|
+
// interleave — so copy never emits -+-+.
|
|
662
|
+
let lineIndex = 0;
|
|
663
|
+
const leftLine = (kind, spans, oldNo, key, diffLine) => makeRow({
|
|
664
|
+
kind,
|
|
665
|
+
spans,
|
|
666
|
+
key,
|
|
667
|
+
rowW: halfW,
|
|
668
|
+
oldNo,
|
|
669
|
+
newNo: null,
|
|
670
|
+
numW,
|
|
671
|
+
diffLine,
|
|
672
|
+
});
|
|
673
|
+
const rightLine = (kind, spans, newNo, key, diffLine) => makeRow({
|
|
674
|
+
kind,
|
|
675
|
+
spans,
|
|
676
|
+
key,
|
|
677
|
+
rowW: halfW,
|
|
678
|
+
oldNo: null,
|
|
679
|
+
newNo,
|
|
680
|
+
numW,
|
|
681
|
+
diffLine,
|
|
682
|
+
});
|
|
683
|
+
const blankHalf = (key) => makeRow({
|
|
684
|
+
kind: "blank",
|
|
685
|
+
spans: [{ text: " " }],
|
|
686
|
+
key,
|
|
687
|
+
rowW: halfW,
|
|
688
|
+
oldNo: null,
|
|
689
|
+
newNo: null,
|
|
690
|
+
numW,
|
|
691
|
+
});
|
|
692
|
+
for (let hi = 0; hi < meta.hunks.length; hi++) {
|
|
693
|
+
const hunk = meta.hunks[hi];
|
|
694
|
+
if (hunk.collapsedBefore > 0) {
|
|
695
|
+
rows.push(elideRow(hunk.collapsedBefore, `${keyBase}:sf${ri++}`, width));
|
|
696
|
+
}
|
|
697
|
+
// Display line numbers are REAL 1-based file lines derived from the
|
|
698
|
+
// hunk's `deletionStart` (left/old) / `additionStart` (right/new), not
|
|
699
|
+
// array indices into the compact per-side arrays. Advance per side.
|
|
700
|
+
let oldCursor = hunk.deletionStart;
|
|
701
|
+
let newCursor = hunk.additionStart;
|
|
702
|
+
for (const [bi, block] of hunk.hunkContent.entries()) {
|
|
703
|
+
if (block.type === "context") {
|
|
704
|
+
const b = block;
|
|
705
|
+
for (const p of elideContextIndices(b.lines, ctx, contextBlockEdge(hunk.hunkContent, bi))) {
|
|
706
|
+
if (p.kind === "elide") {
|
|
707
|
+
rows.push(elideRow(p.n, `${keyBase}:sf${ri++}`, width));
|
|
708
|
+
continue;
|
|
709
|
+
}
|
|
710
|
+
const aIdx = b.additionLineIndex + p.i;
|
|
711
|
+
const dIdx = b.deletionLineIndex + p.i;
|
|
712
|
+
const oldNo = oldCursor + p.i;
|
|
713
|
+
const newNo = newCursor + p.i;
|
|
714
|
+
const lText = stripNl(meta.deletionLines[dIdx] ?? meta.additionLines[aIdx] ?? "");
|
|
715
|
+
const rText = stripNl(meta.additionLines[aIdx] ?? meta.deletionLines[dIdx] ?? "");
|
|
716
|
+
let lSpans = [{ text: lText }];
|
|
717
|
+
let rSpans = [{ text: rText }];
|
|
718
|
+
lSpans = composeHighlight(lSpans, hl("del", oldNo, dIdx) ?? hl("add", newNo, aIdx));
|
|
719
|
+
rSpans = composeHighlight(rSpans, hl("add", newNo, aIdx) ?? hl("del", oldNo, dIdx));
|
|
720
|
+
// Shared lineIndex: both halves are one git ` ` line (copy dedup + mirror).
|
|
721
|
+
const li = lineIndex++;
|
|
722
|
+
rows.push({
|
|
723
|
+
type: "flex",
|
|
724
|
+
key: `${keyBase}:s${ri}`,
|
|
725
|
+
style: { direction: "row", gap: 1, width },
|
|
726
|
+
children: [
|
|
727
|
+
leftLine("ctx", lSpans, oldNo, `${keyBase}:s${ri}:L`, diffStamp(keyBase, li, "ctx", lText, {
|
|
728
|
+
side: "L",
|
|
729
|
+
oldNo,
|
|
730
|
+
newNo,
|
|
731
|
+
})),
|
|
732
|
+
rightLine("ctx", rSpans, newNo, `${keyBase}:s${ri}:R`, diffStamp(keyBase, li, "ctx", rText, {
|
|
733
|
+
side: "R",
|
|
734
|
+
oldNo,
|
|
735
|
+
newNo,
|
|
736
|
+
})),
|
|
737
|
+
],
|
|
738
|
+
});
|
|
739
|
+
ri++;
|
|
740
|
+
}
|
|
741
|
+
oldCursor += b.lines;
|
|
742
|
+
newCursor += b.lines;
|
|
743
|
+
}
|
|
744
|
+
else {
|
|
745
|
+
const b = block;
|
|
746
|
+
const paired = lineDiffType === "none" ? 0 : Math.min(b.deletions, b.additions);
|
|
747
|
+
const n = Math.max(b.deletions, b.additions);
|
|
748
|
+
// Pre-assign git lineIndex: dels first, then adds (unified order).
|
|
749
|
+
const delBase = lineIndex;
|
|
750
|
+
const addBase = lineIndex + b.deletions;
|
|
751
|
+
lineIndex += b.deletions + b.additions;
|
|
752
|
+
for (let i = 0; i < n; i++) {
|
|
753
|
+
let left;
|
|
754
|
+
let right;
|
|
755
|
+
if (i < b.deletions) {
|
|
756
|
+
const dIdx = b.deletionLineIndex + i;
|
|
757
|
+
const dText = stripNl(meta.deletionLines[dIdx] ?? "");
|
|
758
|
+
let spans;
|
|
759
|
+
if (i < paired) {
|
|
760
|
+
const aText = stripNl(meta.additionLines[b.additionLineIndex + i] ?? "");
|
|
761
|
+
spans = wordAltSpans(dText, aText, "del");
|
|
762
|
+
}
|
|
763
|
+
else {
|
|
764
|
+
spans = [{ text: dText, emphasis: true }];
|
|
765
|
+
}
|
|
766
|
+
spans = composeHighlight(spans, hl("del", oldCursor + i, dIdx));
|
|
767
|
+
left = leftLine("del", spans, oldCursor + i, `${keyBase}:s${ri}:L`, diffStamp(keyBase, delBase + i, "del", dText, {
|
|
768
|
+
side: "L",
|
|
769
|
+
oldNo: oldCursor + i,
|
|
770
|
+
newNo: null,
|
|
771
|
+
}));
|
|
772
|
+
}
|
|
773
|
+
else {
|
|
774
|
+
left = blankHalf(`${keyBase}:s${ri}:L`);
|
|
775
|
+
}
|
|
776
|
+
if (i < b.additions) {
|
|
777
|
+
const aIdx = b.additionLineIndex + i;
|
|
778
|
+
const aText = stripNl(meta.additionLines[aIdx] ?? "");
|
|
779
|
+
let spans;
|
|
780
|
+
if (i < paired) {
|
|
781
|
+
const dText = stripNl(meta.deletionLines[b.deletionLineIndex + i] ?? "");
|
|
782
|
+
spans = wordAltSpans(dText, aText, "add");
|
|
783
|
+
}
|
|
784
|
+
else {
|
|
785
|
+
spans = [{ text: aText, emphasis: true }];
|
|
786
|
+
}
|
|
787
|
+
spans = composeHighlight(spans, hl("add", newCursor + i, aIdx));
|
|
788
|
+
right = rightLine("add", spans, newCursor + i, `${keyBase}:s${ri}:R`, diffStamp(keyBase, addBase + i, "add", aText, {
|
|
789
|
+
side: "R",
|
|
790
|
+
oldNo: null,
|
|
791
|
+
newNo: newCursor + i,
|
|
792
|
+
}));
|
|
793
|
+
}
|
|
794
|
+
else {
|
|
795
|
+
right = blankHalf(`${keyBase}:s${ri}:R`);
|
|
796
|
+
}
|
|
797
|
+
rows.push({
|
|
798
|
+
type: "flex",
|
|
799
|
+
key: `${keyBase}:s${ri}`,
|
|
800
|
+
style: { direction: "row", gap: 1, width },
|
|
801
|
+
children: [left, right],
|
|
802
|
+
});
|
|
803
|
+
ri++;
|
|
804
|
+
}
|
|
805
|
+
oldCursor += b.deletions;
|
|
806
|
+
newCursor += b.additions;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
return rows;
|
|
811
|
+
}
|
|
812
|
+
function langFromPath(path) {
|
|
813
|
+
const dot = path.lastIndexOf(".");
|
|
814
|
+
if (dot === -1 || dot === path.length - 1)
|
|
815
|
+
return undefined;
|
|
816
|
+
switch (path.slice(dot + 1).toLowerCase()) {
|
|
817
|
+
case "ts":
|
|
818
|
+
case "mts":
|
|
819
|
+
case "cts":
|
|
820
|
+
return "typescript";
|
|
821
|
+
case "tsx":
|
|
822
|
+
return "tsx";
|
|
823
|
+
case "js":
|
|
824
|
+
case "mjs":
|
|
825
|
+
case "cjs":
|
|
826
|
+
return "javascript";
|
|
827
|
+
case "jsx":
|
|
828
|
+
return "jsx";
|
|
829
|
+
case "scm":
|
|
830
|
+
return "scm";
|
|
831
|
+
case "json":
|
|
832
|
+
return "json";
|
|
833
|
+
case "md":
|
|
834
|
+
case "mdx":
|
|
835
|
+
return "markdown";
|
|
836
|
+
case "py":
|
|
837
|
+
return "python";
|
|
838
|
+
case "rs":
|
|
839
|
+
return "rust";
|
|
840
|
+
case "go":
|
|
841
|
+
return "go";
|
|
842
|
+
case "sh":
|
|
843
|
+
return "bash";
|
|
844
|
+
case "css":
|
|
845
|
+
return "css";
|
|
846
|
+
case "html":
|
|
847
|
+
case "htm":
|
|
848
|
+
return "html";
|
|
849
|
+
case "yml":
|
|
850
|
+
case "yaml":
|
|
851
|
+
return "yaml";
|
|
852
|
+
case "toml":
|
|
853
|
+
return "toml";
|
|
854
|
+
default:
|
|
855
|
+
return undefined;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
function highlightLang(language) {
|
|
859
|
+
if (!language)
|
|
860
|
+
return undefined;
|
|
861
|
+
if (language === "ts" || language === "mts" || language === "cts")
|
|
862
|
+
return "typescript";
|
|
863
|
+
if (language === "js" || language === "mjs" || language === "cjs")
|
|
864
|
+
return "javascript";
|
|
865
|
+
if (language === "scheme" || language === "arrival")
|
|
866
|
+
return "scm";
|
|
867
|
+
return language;
|
|
868
|
+
}
|
|
869
|
+
/** Drop the terminator so shiki line count matches painted file lines. */
|
|
870
|
+
function sourceForHighlight(code) {
|
|
871
|
+
const body = withTrailingNl(code);
|
|
872
|
+
return body.endsWith("\n") ? body.slice(0, -1) : body;
|
|
873
|
+
}
|
|
874
|
+
function highlightCode(code, language, noHighlight) {
|
|
875
|
+
const lang = highlightLang(language);
|
|
876
|
+
if (noHighlight || !lang || !isHighlighterReady() || code.length === 0)
|
|
877
|
+
return null;
|
|
878
|
+
try {
|
|
879
|
+
return highlightCodeSync(sourceForHighlight(code), { lang });
|
|
880
|
+
}
|
|
881
|
+
catch {
|
|
882
|
+
return null;
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
function highlightSides(meta, language, noHighlight) {
|
|
886
|
+
if (noHighlight || !language || !isHighlighterReady()) {
|
|
887
|
+
return { hlAdd: null, hlDel: null };
|
|
888
|
+
}
|
|
889
|
+
const lang = highlightLang(language);
|
|
890
|
+
try {
|
|
891
|
+
const addCode = meta.additionLines.map(stripNl).join("\n");
|
|
892
|
+
const delCode = meta.deletionLines.map(stripNl).join("\n");
|
|
893
|
+
return {
|
|
894
|
+
hlAdd: meta.additionLines.length > 0 ? highlightCodeSync(addCode, { lang }) : null,
|
|
895
|
+
hlDel: meta.deletionLines.length > 0 ? highlightCodeSync(delCode, { lang }) : null,
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
catch {
|
|
899
|
+
return { hlAdd: null, hlDel: null };
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
function hlPickFromSides(hlAdd, hlDel, fileIndexed, lineOrigin) {
|
|
903
|
+
return (side, fileLine, compactIdx) => {
|
|
904
|
+
const lines = side === "add" ? hlAdd : hlDel;
|
|
905
|
+
if (!lines)
|
|
906
|
+
return undefined;
|
|
907
|
+
if (fileIndexed) {
|
|
908
|
+
if (fileLine == null)
|
|
909
|
+
return undefined;
|
|
910
|
+
const i = fileLine - lineOrigin;
|
|
911
|
+
return i >= 0 ? lines[i] : undefined;
|
|
912
|
+
}
|
|
913
|
+
return lines[compactIdx];
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
function maxLineNo(meta) {
|
|
917
|
+
// Highest display line number = the true largest file line across hunks.
|
|
918
|
+
// Walk each hunk the same way the renderers do: seed per-side file-line
|
|
919
|
+
// cursors from `deletionStart`/`additionStart` and advance through blocks.
|
|
920
|
+
// Falls back to array length when there are no hunks (defensive).
|
|
921
|
+
let best = Math.max(meta.additionLines.length, meta.deletionLines.length, 1);
|
|
922
|
+
for (const hunk of meta.hunks) {
|
|
923
|
+
let oldCursor = hunk.deletionStart;
|
|
924
|
+
let newCursor = hunk.additionStart;
|
|
925
|
+
for (const block of hunk.hunkContent) {
|
|
926
|
+
if (block.type === "context") {
|
|
927
|
+
const b = block;
|
|
928
|
+
oldCursor += b.lines;
|
|
929
|
+
newCursor += b.lines;
|
|
930
|
+
}
|
|
931
|
+
else {
|
|
932
|
+
const b = block;
|
|
933
|
+
oldCursor += b.deletions;
|
|
934
|
+
newCursor += b.additions;
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
// cursors now point one past the last line; the last line number is cursor-1
|
|
938
|
+
if (oldCursor - 1 > best)
|
|
939
|
+
best = oldCursor - 1;
|
|
940
|
+
if (newCursor - 1 > best)
|
|
941
|
+
best = newCursor - 1;
|
|
942
|
+
}
|
|
943
|
+
return Math.max(best, 1);
|
|
944
|
+
}
|
|
945
|
+
function projectMeta(meta, opts) {
|
|
946
|
+
const language = opts.language ?? meta.lang ?? langFromPath(opts.path);
|
|
947
|
+
const fileIndexed = opts.sourceOld !== undefined || opts.sourceNew !== undefined;
|
|
948
|
+
const sides = fileIndexed
|
|
949
|
+
? {
|
|
950
|
+
hlAdd: highlightCode(opts.sourceNew ?? "", language, opts.noHighlight),
|
|
951
|
+
hlDel: highlightCode(opts.sourceOld ?? "", language, opts.noHighlight),
|
|
952
|
+
}
|
|
953
|
+
: highlightSides(meta, language, opts.noHighlight);
|
|
954
|
+
const hl = hlPickFromSides(sides.hlAdd, sides.hlDel, fileIndexed, opts.lineOrigin ?? 1);
|
|
955
|
+
const header = {
|
|
956
|
+
type: "text",
|
|
957
|
+
key: `${opts.key}:hdr`,
|
|
958
|
+
content: `${opts.path} · proposed`,
|
|
959
|
+
userSelect: "none",
|
|
960
|
+
style: headerStyle(),
|
|
961
|
+
};
|
|
962
|
+
let body;
|
|
963
|
+
if (meta.hunks.length === 0) {
|
|
964
|
+
body = [
|
|
965
|
+
{
|
|
966
|
+
type: "text",
|
|
967
|
+
key: `${opts.key}:empty`,
|
|
968
|
+
content: meta.additionLines.length === 0 && meta.deletionLines.length === 0 ? "(empty)" : "no changes",
|
|
969
|
+
style: chromeStyle(),
|
|
970
|
+
},
|
|
971
|
+
];
|
|
972
|
+
}
|
|
973
|
+
else {
|
|
974
|
+
const lines = buildLines(meta, opts.context, opts.lineDiffType, hl);
|
|
975
|
+
const numW = String(Math.max(maxLineNo(meta), maxPaintedLineNo(lines))).length;
|
|
976
|
+
const mode = resolveDiffMode(opts.mode, opts.width, meta, lines);
|
|
977
|
+
body =
|
|
978
|
+
mode === "split"
|
|
979
|
+
? projectSplit(meta, opts.context, opts.lineDiffType, hl, opts.width, numW, opts.key)
|
|
980
|
+
: projectUnified(lines, opts.width, numW, opts.key);
|
|
981
|
+
}
|
|
982
|
+
const squeezeN = Math.max(0, Math.floor(opts.stickyBottomRows ?? 0));
|
|
983
|
+
const bodyNode = squeezeN > 0 && body.length > 0
|
|
984
|
+
? {
|
|
985
|
+
type: "box",
|
|
986
|
+
key: `${opts.key}:squeeze`,
|
|
987
|
+
style: {
|
|
988
|
+
width: opts.width,
|
|
989
|
+
squeeze: { head: squeezeN, tail: squeezeN },
|
|
990
|
+
},
|
|
991
|
+
children: body,
|
|
992
|
+
}
|
|
993
|
+
: {
|
|
994
|
+
type: "flex",
|
|
995
|
+
key: `${opts.key}:body`,
|
|
996
|
+
style: { direction: "column", gap: 0, width: opts.width },
|
|
997
|
+
children: body,
|
|
998
|
+
};
|
|
999
|
+
return {
|
|
1000
|
+
type: "indentation_exception",
|
|
1001
|
+
key: opts.key,
|
|
1002
|
+
kind: "diff",
|
|
1003
|
+
children: opts.hideHeader ? [bodyNode] : [header, bodyNode],
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
function emptyState(key, path, hideHeader = false) {
|
|
1007
|
+
const empty = {
|
|
1008
|
+
type: "text",
|
|
1009
|
+
key: `${key}:empty`,
|
|
1010
|
+
content: "(empty)",
|
|
1011
|
+
style: chromeStyle(),
|
|
1012
|
+
};
|
|
1013
|
+
return {
|
|
1014
|
+
type: "indentation_exception",
|
|
1015
|
+
key,
|
|
1016
|
+
kind: "diff",
|
|
1017
|
+
children: hideHeader
|
|
1018
|
+
? [empty]
|
|
1019
|
+
: [
|
|
1020
|
+
{
|
|
1021
|
+
type: "text",
|
|
1022
|
+
key: `${key}:hdr`,
|
|
1023
|
+
content: `${path} · proposed`,
|
|
1024
|
+
style: headerStyle(),
|
|
1025
|
+
},
|
|
1026
|
+
empty,
|
|
1027
|
+
],
|
|
1028
|
+
};
|
|
1029
|
+
}
|
|
1030
|
+
/** Shift hunk `@@` origins so span diffs paint file-absolute line numbers. */
|
|
1031
|
+
function withFileLineStart(meta, lineStart) {
|
|
1032
|
+
const origin = Math.trunc(lineStart ?? 1);
|
|
1033
|
+
const delta = origin > 1 ? origin - 1 : 0;
|
|
1034
|
+
if (delta === 0 || meta.hunks.length === 0)
|
|
1035
|
+
return meta;
|
|
1036
|
+
return {
|
|
1037
|
+
...meta,
|
|
1038
|
+
hunks: meta.hunks.map((hunk) => ({
|
|
1039
|
+
...hunk,
|
|
1040
|
+
deletionStart: hunk.deletionStart + delta,
|
|
1041
|
+
additionStart: hunk.additionStart + delta,
|
|
1042
|
+
})),
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
function displayContext(context) {
|
|
1046
|
+
if (context === "all")
|
|
1047
|
+
return "all";
|
|
1048
|
+
if (typeof context === "number" && Number.isFinite(context) && context >= 0)
|
|
1049
|
+
return context;
|
|
1050
|
+
return DEFAULT_CONTEXT;
|
|
1051
|
+
}
|
|
1052
|
+
function lineOriginOf(lineStart) {
|
|
1053
|
+
const origin = Math.trunc(lineStart ?? 1);
|
|
1054
|
+
return Math.max(origin, 1);
|
|
1055
|
+
}
|
|
1056
|
+
/** Sync layout — word-alt + line numbers + full-width wash; syntax if highlighter warm. */
|
|
1057
|
+
export function buildDiffLayout(opts) {
|
|
1058
|
+
const key = opts.key ?? "diff";
|
|
1059
|
+
const path = opts.path ?? "file";
|
|
1060
|
+
const width = Math.max(1, opts.width | 0);
|
|
1061
|
+
const ctxOpt = displayContext(opts.context);
|
|
1062
|
+
const lineDiffType = opts.lineDiffType ?? "word-alt";
|
|
1063
|
+
if (opts.old === "" && opts.new === "") {
|
|
1064
|
+
return emptyState(key, path, opts.hideHeader === true);
|
|
1065
|
+
}
|
|
1066
|
+
const meta = withFileLineStart(parseDiffFromFile({ name: path, contents: withTrailingNl(opts.old) }, { name: path, contents: withTrailingNl(opts.new) }, { context: PARSE_CONTEXT }), opts.lineStart);
|
|
1067
|
+
return projectMeta(meta, {
|
|
1068
|
+
mode: opts.mode ?? "auto",
|
|
1069
|
+
width,
|
|
1070
|
+
context: ctxOpt,
|
|
1071
|
+
key,
|
|
1072
|
+
path: meta.name || path,
|
|
1073
|
+
lineDiffType,
|
|
1074
|
+
language: opts.language,
|
|
1075
|
+
noHighlight: opts.noHighlight,
|
|
1076
|
+
hideHeader: opts.hideHeader === true,
|
|
1077
|
+
stickyBottomRows: opts.stickyBottomRows,
|
|
1078
|
+
sourceOld: opts.old,
|
|
1079
|
+
sourceNew: opts.new,
|
|
1080
|
+
lineOrigin: lineOriginOf(opts.lineStart),
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
export function parsePatchToLayout(patch, width, opts = {}) {
|
|
1084
|
+
const key = opts.key ?? "patch";
|
|
1085
|
+
if (!patch.trim())
|
|
1086
|
+
return emptyState(key, "patch");
|
|
1087
|
+
const patches = parsePatchFiles(patch);
|
|
1088
|
+
const files = patches.flatMap((p) => p.files);
|
|
1089
|
+
if (files.length === 0)
|
|
1090
|
+
return emptyState(key, "patch");
|
|
1091
|
+
const ctxOpt = opts.context ?? DEFAULT_CONTEXT;
|
|
1092
|
+
const children = files.map((meta, i) => projectMeta(meta, {
|
|
1093
|
+
mode: opts.mode ?? "auto",
|
|
1094
|
+
width,
|
|
1095
|
+
context: ctxOpt,
|
|
1096
|
+
key: `${key}:${i}`,
|
|
1097
|
+
path: meta.name || `file-${i}`,
|
|
1098
|
+
lineDiffType: opts.lineDiffType ?? "word-alt",
|
|
1099
|
+
}));
|
|
1100
|
+
return {
|
|
1101
|
+
type: "box",
|
|
1102
|
+
key,
|
|
1103
|
+
children,
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
//# sourceMappingURL=diff-expand.js.map
|