@kabmo-labs/kabmo 0.8.0 → 0.9.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/README.md +7 -0
- package/dist/client/index.html +1 -1
- package/dist/client/index.js +314 -314
- package/dist/client/static/js/{index-qwpvd9fv.js → index-bpptfkz2.js} +922 -892
- package/dist/client/static/js/index-k315p1e8.css +1 -0
- package/package.json +9 -1
- package/src/client/components/common/code-surface/documents.test.ts +120 -0
- package/src/client/components/common/code-surface/documents.ts +201 -0
- package/src/client/components/common/code-surface/extensions.test.ts +110 -0
- package/src/client/components/common/code-surface/extensions.ts +162 -0
- package/src/client/components/common/code-surface/handle.ts +102 -0
- package/src/client/components/common/code-surface/index.tsx +253 -314
- package/src/client/components/common/code-surface/keymap.test.ts +133 -0
- package/src/client/components/common/code-surface/keymap.ts +267 -0
- package/src/client/components/common/code-surface/marks.ts +74 -0
- package/src/client/components/common/code-surface/shiki.ts +234 -0
- package/src/client/components/common/code-surface/sync.test.ts +185 -0
- package/src/client/components/common/code-surface/sync.ts +58 -0
- package/src/client/components/common/code-surface/theme.test.ts +202 -0
- package/src/client/components/common/code-surface/theme.ts +111 -0
- package/src/client/components/common/editor-view-buttons/index.test.tsx +148 -0
- package/src/client/components/common/editor-view-buttons/index.tsx +109 -0
- package/src/client/components/common/shell-update-button/Modal.tsx +163 -0
- package/src/client/components/common/shell-update-button/index.test.tsx +251 -0
- package/src/client/components/common/shell-update-button/index.tsx +125 -0
- package/src/client/components/common/toolbar-row/index.test.tsx +166 -0
- package/src/client/components/common/toolbar-row/index.tsx +189 -0
- package/src/client/components/layout/desktop-layout/WorkspacePanels.tsx +41 -78
- package/src/client/components/layout/desktop-layout/index.tsx +47 -67
- package/src/client/components/layout/desktop-layout/resizer/index.tsx +6 -3
- package/src/client/components/layout/session-sidebar/Footer.tsx +8 -15
- package/src/client/components/mobile/LayoutWrapper.tsx +1 -0
- package/src/client/components/mobile/mobile-right-sidebar/FullDiff.tsx +3 -0
- package/src/client/components/mobile/mobile-right-sidebar/FullEditor.tsx +63 -38
- package/src/client/components/mobile/mobile-right-sidebar/OutlineButton.test.tsx +137 -0
- package/src/client/components/mobile/mobile-right-sidebar/OutlineButton.tsx +14 -3
- package/src/client/components/mobile/mobile-session-sidebar/Footer.tsx +9 -21
- package/src/client/components/settings/Modal.tsx +8 -0
- package/src/client/components/settings/categories/AppearanceSettings.tsx +3 -0
- package/src/client/components/settings/categories/appearance-settings/EditorThemeSection.test.tsx +167 -0
- package/src/client/components/settings/categories/appearance-settings/EditorThemeSection.tsx +184 -0
- package/src/client/components/settings/categories/project-settings/WorktreeSettings.tsx +8 -2
- package/src/client/components/workspace/chat-timeline/EmptyWorkspacePrompt.tsx +16 -8
- package/src/client/components/workspace/chat-timeline/SystemNotice.tsx +9 -4
- package/src/client/components/workspace/chat-timeline/TaskResultContent.tsx +9 -7
- package/src/client/components/workspace/chat-timeline/target-picker/WorkspacePicker.test.tsx +132 -0
- package/src/client/components/workspace/chat-timeline/target-picker/WorkspacePicker.tsx +120 -0
- package/src/client/components/workspace/chat-timeline/target-picker/WorktreePicker.test.tsx +319 -0
- package/src/client/components/workspace/chat-timeline/target-picker/WorktreePicker.tsx +285 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/ask-panel/index.test.ts +2 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/hashline-patch/index.tsx +34 -29
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/AstEdit.tsx +11 -9
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Bash.tsx +10 -7
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Edit.tsx +25 -8
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Eval.tsx +8 -11
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/FileMatches.test.ts +114 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/FileMatches.tsx +111 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Read.tsx +7 -7
- package/src/client/components/workspace/chat-timeline/tool-renderers/panels/SearchTool.tsx +9 -59
- package/src/client/components/workspace/chat-timeline/tool-renderers/shared/ArtifactBody.tsx +2 -7
- package/src/client/components/workspace/chat-timeline/tool-renderers/shared/DiffView.test.ts +27 -28
- package/src/client/components/workspace/chat-timeline/tool-renderers/shared/DiffView.tsx +39 -26
- package/src/client/components/workspace/chat-timeline/tool-renderers/shared/ExcerptCode.tsx +8 -8
- package/src/client/components/workspace/chat-timeline/tool-renderers/shared/HighlightedCode.tsx +35 -0
- package/src/client/components/workspace/chat-timeline/tool-renderers/shared/JsonCodeBlock.tsx +4 -4
- package/src/client/components/workspace/diff-panel/MergeDiffView.tsx +179 -0
- package/src/client/components/workspace/diff-panel/ThemedMergeDiffView.tsx +24 -0
- package/src/client/components/workspace/diff-panel/Toolbar.tsx +224 -186
- package/src/client/components/workspace/diff-panel/ToolbarSegments.tsx +98 -0
- package/src/client/components/workspace/diff-panel/index.tsx +76 -145
- package/src/client/components/workspace/diff-panel/merge.ts +315 -0
- package/src/client/components/workspace/editor/Body.tsx +4 -7
- package/src/client/components/workspace/editor/CommandPalette.tsx +2 -2
- package/src/client/components/workspace/editor/FileDocument.tsx +58 -63
- package/src/client/components/workspace/editor/FilePane.tsx +4 -7
- package/src/client/components/workspace/editor/FindWidget.tsx +7 -2
- package/src/client/components/workspace/editor/Toolbar.tsx +220 -123
- package/src/client/components/workspace/editor/index.tsx +7 -9
- package/src/client/components/workspace/file-explorer/OutlineSection.test.tsx +18 -0
- package/src/client/components/workspace/file-explorer/OutlineSection.tsx +10 -3
- package/src/client/components/workspace/search-panel/Body.tsx +1 -1
- package/src/client/components/workspace/worktree-modal/index.test.tsx +118 -0
- package/src/client/hooks/chat/omp/reconnect.test.ts +338 -0
- package/src/client/hooks/chat/omp/reconnect.ts +187 -0
- package/src/client/hooks/chat/omp/run-liveness.test.ts +71 -0
- package/src/client/hooks/chat/omp/run-liveness.ts +65 -0
- package/src/client/hooks/chat/omp/session-list.activity.test.ts +114 -0
- package/src/client/hooks/chat/omp/session-list.test-util.ts +164 -0
- package/src/client/hooks/chat/omp/session-list.test.ts +30 -150
- package/src/client/hooks/chat/omp/session-list.tsx +69 -9
- package/src/client/hooks/chat/timeline/generating.ts +19 -2
- package/src/client/hooks/chat/timeline/index.ts +19 -24
- package/src/client/hooks/chat/timeline/lost-run.test.ts +329 -0
- package/src/client/hooks/chat/timeline/lost-run.ts +177 -0
- package/src/client/hooks/chat/timeline/session-load.test-util.ts +205 -0
- package/src/client/hooks/chat/timeline/session-load.test.ts +61 -162
- package/src/client/hooks/chat/timeline/session-load.ts +69 -37
- package/src/client/hooks/chat/timeline/session-switch.test.ts +65 -0
- package/src/client/hooks/chat/timeline/session-switch.ts +63 -0
- package/src/client/hooks/code/deferred-highlight.test.ts +182 -0
- package/src/client/hooks/code/deferred-highlight.ts +129 -0
- package/src/client/hooks/editor/find-state.ts +1 -1
- package/src/client/hooks/editor/theme.test.ts +206 -0
- package/src/client/hooks/editor/theme.ts +82 -0
- package/src/client/hooks/editor/use-editor-drop.test.ts +101 -0
- package/src/client/hooks/editor/use-editor-drop.ts +67 -14
- package/src/client/hooks/editor/use-editor-find.ts +7 -7
- package/src/client/hooks/editor/use-outline-view.test.ts +182 -0
- package/src/client/hooks/editor/use-outline-view.ts +94 -7
- package/src/client/hooks/editor/use-scroll-restore.test.ts +55 -2
- package/src/client/hooks/editor/use-scroll-restore.ts +124 -4
- package/src/client/hooks/editor/use-search-reveal.ts +1 -1
- package/src/client/hooks/ui/settings-modal.ts +56 -0
- package/src/client/hooks/ui/updates/shell-download.test.ts +2 -0
- package/src/client/hooks/ui/updates/shell-download.ts +55 -14
- package/src/client/hooks/ui/updates/shell-offer.test.ts +26 -0
- package/src/client/hooks/ui/updates/shell-update.test.ts +140 -0
- package/src/client/hooks/ui/updates/shell-update.ts +119 -0
- package/src/client/hooks/workspace/diff-file.ts +29 -10
- package/src/client/hooks/workspace/diff-git-actions.ts +147 -0
- package/src/client/hooks/workspace/editor-view.ts +61 -0
- package/src/client/hooks/workspace/file-tabs.test.ts +62 -5
- package/src/client/hooks/workspace/file-tabs.ts +24 -11
- package/src/client/hooks/workspace/navbar-session-actions.ts +72 -0
- package/src/client/hooks/workspace/worktree/index.ts +20 -5
- package/src/client/lib/desktop/bridge.ts +45 -0
- package/src/client/lib/search-reveal.ts +1 -1
- package/src/client/main.tsx +5 -1
- package/src/client/tailwind.css +37 -8
- package/src/server/lib/auth/guard.test.ts +28 -0
- package/src/server/lib/auth/guard.ts +10 -0
- package/src/server/lib/fs/worktree/create.ts +2 -3
- package/src/server/lib/fs/worktree/list.ts +13 -0
- package/src/server/lib/fs/worktree/remove.ts +3 -3
- package/src/server/lib/lifecycle/claim-port.test.ts +156 -0
- package/src/server/lib/lifecycle/port-guard.test.ts +20 -164
- package/src/server/lib/lifecycle/port-guard.ts +39 -7
- package/src/server/lib/lifecycle/probe-health.test.ts +166 -0
- package/src/server/lib/lifecycle/probe.test.ts +77 -164
- package/src/server/lib/lifecycle/probe.ts +121 -13
- package/src/server/lib/omp/rpc/frame-fold-signals.test.ts +112 -0
- package/src/server/lib/omp/rpc/frame-fold.ts +10 -5
- package/src/server/lib/omp/session/sidebar-activity.server.test.ts +162 -0
- package/src/server/lib/omp/session/sidebar-activity.server.ts +70 -0
- package/src/server/lib/omp/session/telemetry/compute.ts +13 -1
- package/src/server/lib/omp/session/telemetry.test.ts +33 -0
- package/src/server/lib/realtime/signals.server.ts +10 -0
- package/src/server/lib/realtime/topics/catalog.server.ts +4 -1
- package/src/server/lib/realtime/topics.server.ts +16 -0
- package/src/server/lib/updates/shell-assets.ts +94 -3
- package/src/server/lib/updates/shell-cache.ts +105 -0
- package/src/server/lib/updates/shell-pages.test.ts +33 -2
- package/src/server/lib/updates/shell-pages.ts +17 -5
- package/src/server/lib/updates/shell-release-desktop.test.ts +166 -0
- package/src/server/lib/updates/shell-release.test.ts +10 -27
- package/src/server/lib/updates/shell-release.ts +107 -111
- package/src/server/routes/fs/git-merge.test.ts +11 -1
- package/src/server/routes/fs/read.test.ts +24 -7
- package/src/server/routes/fs/scope.test.ts +15 -10
- package/src/server/routes/fs/scope.ts +3 -14
- package/src/server/routes/updates/android.ts +6 -1
- package/src/server/routes/updates/desktop.ts +29 -7
- package/src/server/routes/updates/ios.ts +5 -1
- package/src/server/routes/worktrees/list.ts +11 -1
- package/src/server/routes/worktrees/routes.test.ts +17 -0
- package/src/shared/lib/chat/timeline/omp-callbacks.test.ts +36 -0
- package/src/shared/lib/chat/timeline/omp-callbacks.ts +18 -0
- package/src/shared/lib/chat/timeline/run-signals.test.ts +2 -0
- package/src/shared/lib/code/editor/comment-syntax.test.ts +37 -0
- package/src/shared/lib/code/editor/comment-syntax.ts +55 -0
- package/src/shared/lib/code/editor/find-replace.test.ts +134 -0
- package/src/shared/lib/code/editor/{find.ts → find-replace.ts} +23 -107
- package/src/shared/lib/code/editor/{find.test.ts → find-scan.test.ts} +19 -73
- package/src/shared/lib/code/editor/find-scan.ts +177 -0
- package/src/shared/lib/code/editor/keymap.ts +3 -3
- package/src/shared/lib/code/editor/lines.test.ts +7 -55
- package/src/shared/lib/code/editor/lines.ts +8 -48
- package/src/shared/lib/code/editor/marks.test.ts +4 -5
- package/src/shared/lib/code/editor/marks.ts +13 -25
- package/src/shared/lib/code/editor/theme-loader.ts +97 -0
- package/src/shared/lib/code/editor/themes.generated.ts +156 -0
- package/src/shared/lib/code/editor/themes.test.ts +165 -0
- package/src/shared/lib/code/editor/themes.ts +165 -0
- package/src/shared/lib/code/highlight-memo.test.ts +103 -0
- package/src/shared/lib/code/highlight-memo.ts +149 -0
- package/src/shared/lib/code/highlighter-warmup.ts +112 -0
- package/src/shared/lib/code/highlighter.ts +3 -1
- package/src/shared/lib/code/idle.ts +37 -0
- package/src/shared/lib/code/outline/rows.test.ts +96 -0
- package/src/shared/lib/code/outline/rows.ts +94 -0
- package/src/shared/lib/code/syntax-highlight.test.ts +1 -79
- package/src/shared/lib/code/syntax-highlight.ts +2 -3
- package/src/shared/lib/fs/file-kind-classify.test.ts +25 -11
- package/src/shared/lib/fs/file-kind.ts +47 -13
- package/src/shared/lib/fs/file-url.test.ts +52 -0
- package/src/shared/lib/fs/file-url.ts +37 -0
- package/src/shared/lib/fs/patch-sides.test.ts +114 -0
- package/src/shared/lib/fs/patch-sides.ts +139 -0
- package/src/shared/lib/realtime/protocol.ts +16 -0
- package/src/shared/lib/ui/toolbar-overflow.test.ts +83 -0
- package/src/shared/lib/ui/toolbar-overflow.ts +86 -0
- package/src/shared/lib/updates/shell-arch.ts +54 -0
- package/src/shared/lib/updates/shell-ua.ts +4 -4
- package/src/shared/lib/workspace/editor-view-mode.test.ts +70 -0
- package/src/shared/lib/workspace/editor-view-mode.ts +48 -0
- package/src/shared/lib/workspace/panel-widths.test.ts +30 -0
- package/src/shared/lib/workspace/panel-widths.ts +25 -5
- package/src/shared/lib/workspace/session-state/cache.ts +159 -0
- package/src/shared/lib/workspace/session-state/harness.test-util.ts +55 -0
- package/src/shared/lib/workspace/session-state/merge.ts +100 -0
- package/src/shared/lib/workspace/session-state/store-load.test.ts +206 -0
- package/src/shared/lib/workspace/session-state/store.test.ts +17 -139
- package/src/shared/lib/workspace/session-state/store.ts +92 -130
- package/src/shared/lib/workspace/workspace-panel-widths.ts +124 -0
- package/src/shared/types/realtime.ts +29 -0
- package/src/shared/types/settings/state.ts +10 -0
- package/src/test-support/loopback.ts +183 -0
- package/dist/client/static/js/index-gtbpewr7.css +0 -1
- package/src/client/components/common/code-editor/handler.test.ts +0 -274
- package/src/client/components/common/code-editor/handler.ts +0 -175
- package/src/client/components/common/code-editor/index.tsx +0 -314
- package/src/client/components/common/code-surface/measure.ts +0 -148
- package/src/client/components/workspace/chat-timeline/target-picker/index.test.tsx +0 -227
- package/src/client/components/workspace/chat-timeline/target-picker/index.tsx +0 -260
- package/src/client/components/workspace/diff-panel/SplitView.tsx +0 -209
- package/src/client/components/workspace/diff-panel/UnifiedView.tsx +0 -150
- package/src/client/hooks/editor/scroll-container.test.ts +0 -102
- package/src/client/hooks/editor/scroll-container.ts +0 -26
- package/src/client/hooks/editor/use-code-window.ts +0 -100
- package/src/client/hooks/editor/use-editor-history.test.ts +0 -216
- package/src/client/hooks/editor/use-editor-history.ts +0 -134
- package/src/client/hooks/editor/use-occurrences.test.ts +0 -236
- package/src/client/hooks/editor/use-occurrences.ts +0 -98
- package/src/shared/lib/code/editor/commands.test.ts +0 -155
- package/src/shared/lib/code/editor/commands.ts +0 -260
- package/src/shared/lib/code/editor/edits.test.ts +0 -100
- package/src/shared/lib/code/editor/edits.ts +0 -122
- package/src/shared/lib/code/editor/history.test.ts +0 -118
- package/src/shared/lib/code/editor/history.ts +0 -101
- package/src/shared/lib/code/editor/layers.test.ts +0 -77
- package/src/shared/lib/code/editor/layers.ts +0 -67
- package/src/shared/lib/code/editor/line-edits.test.ts +0 -131
- package/src/shared/lib/code/editor/line-edits.ts +0 -159
- package/src/shared/lib/code/editor/occurrences.test.ts +0 -117
- package/src/shared/lib/code/editor/occurrences.ts +0 -111
- package/src/shared/lib/code/editor/reset-css.test.ts +0 -35
- package/src/shared/lib/code/editor/reset-css.ts +0 -32
- package/src/shared/lib/code/editor/text-commands.test.ts +0 -178
- package/src/shared/lib/code/editor/text-commands.ts +0 -154
- package/src/shared/lib/code/lazy-window.test.ts +0 -161
- package/src/shared/lib/code/lazy-window.ts +0 -156
- package/src/shared/lib/code/windowed-highlight.ts +0 -114
- package/src/shared/lib/fs/diff-parser.test.ts +0 -116
- package/src/shared/lib/fs/diff-parser.ts +0 -213
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* GENERATED by `scripts/editor-themes.mjs` — do not edit by hand.
|
|
8
|
+
*
|
|
9
|
+
* One row per theme shipped by `@shikijs/themes`, in id order. Each row carries
|
|
10
|
+
* the colours the editor CHROME needs (surface, gutter, selection, cursor, find,
|
|
11
|
+
* border, the diff bands) plus three syntax accents for the picker's swatch, so
|
|
12
|
+
* the settings grid can draw 65 cards without fetching a theme module.
|
|
13
|
+
*
|
|
14
|
+
* The field order is the tuple's type (`EditorThemeRow` in `./themes.ts`).
|
|
15
|
+
* `themes.test.ts` re-derives every value from the installed package and fails on
|
|
16
|
+
* drift, so a `@shikijs/themes` bump surfaces as a test failure rather than a
|
|
17
|
+
* picker showing colours the package no longer ships.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** `[id, label, variant, bg, fg, gutterFg, selection, cursor, find, findCurrent, border, added, removed, addedGutter, removedGutter, keyword, string, comment]` */
|
|
21
|
+
export const EDITOR_THEME_ROWS = [
|
|
22
|
+
['andromeeda', 'Andromeeda', 'dark', '#23262E', '#D5CED9', '#746f77', '#3D4352', '#FFF', '#f39d1256', '#59b8b377', '#1B1D23', '#29BF1220', '#F21B3F20', '#9BC53DBB', '#FC644DBB', '#c74ded', '#96E072', '#A0A1A7cc'],
|
|
23
|
+
['aurora-x', 'Aurora X', 'dark', '#07090F', '#576daf', '#262e47bb', '#262E47', '#86A5FF', '#576daf', '#262E47', '#15182B', '#64d3892c', '#dd50742c', '#2ea043', '#f85149', '#C792EA', '#C3E88D', '#546E7A'],
|
|
24
|
+
['ayu-dark', 'Ayu Dark', 'dark', '#10141c', '#bfbdb6', '#5a6378a6', '#3388ff40', '#e6b450', '#4c4126', '#4c412680', '#1b1f29', '#70bf561f', '#f26d781f', '#70bf56', '#f26d78', '#ff8f40', '#aad94c', '#5a6673'],
|
|
25
|
+
['ayu-light', 'Ayu Light', 'light', '#fcfcfc', '#5c6166', '#828e9f66', '#035bd626', '#f29718', '#ffe294', '#ffe29480', '#6b7d8f1f', '#6cbf431f', '#ff73831f', '#6cbf43', '#ff7383', '#fa8532', '#86b300', '#adaeb1'],
|
|
26
|
+
['ayu-mirage', 'Ayu Mirage', 'dark', '#242936', '#cccac2', '#707a8c80', '#409fff40', '#ffcc66', '#736950', '#73695066', '#171b24', '#87d96c1f', '#f279831f', '#87d96c', '#f27983', '#ffa659', '#d5ff80', '#6e7c8f'],
|
|
27
|
+
['catppuccin-frappe', 'Catppuccin Frappé', 'dark', '#303446', '#c6d0f5', '#838ba7', '#949cbb40', '#f2d5cf', '#674b59', '#506373', '#626880', '#a6d18926', '#e7828426', '#a6d189', '#e78284', '#ca9ee6', '#a6d189', '#949cbb'],
|
|
28
|
+
['catppuccin-latte', 'Catppuccin Latte', 'light', '#eff1f5', '#4c4f69', '#8c8fa1', '#7c7f934d', '#dc8a78', '#e6adbd', '#a9daf0', '#acb0be', '#40a02b26', '#d20f3926', '#40a02b', '#d20f39', '#8839ef', '#40a02b', '#7c7f93'],
|
|
29
|
+
['catppuccin-macchiato', 'Catppuccin Macchiato', 'dark', '#24273a', '#cad3f5', '#8087a2', '#939ab740', '#f4dbd6', '#604456', '#455c6d', '#5b6078', '#a6da9526', '#ed879626', '#a6da95', '#ed8796', '#c6a0f6', '#a6da95', '#939ab7'],
|
|
30
|
+
['catppuccin-mocha', 'Catppuccin Mocha', 'dark', '#1e1e2e', '#cdd6f4', '#7f849c', '#9399b240', '#f5e0dc', '#5e3f53', '#3e5767', '#585b70', '#a6e3a126', '#f38ba826', '#a6e3a1', '#f38ba8', '#cba6f7', '#a6e3a1', '#9399b2'],
|
|
31
|
+
['dark-plus', 'Dark Plus', 'dark', '#1E1E1E', '#D4D4D4', 'color-mix(in srgb, #D4D4D4 38%, #1E1E1E)', 'color-mix(in srgb, #D4D4D4 22%, #1E1E1E)', '#D4D4D4', 'color-mix(in srgb, #D4D4D4 18%, #1E1E1E)', 'color-mix(in srgb, #D4D4D4 30%, #1E1E1E)', 'color-mix(in srgb, #D4D4D4 16%, #1E1E1E)', 'color-mix(in srgb, #2ea043 22%, #1E1E1E)', 'color-mix(in srgb, #f85149 22%, #1E1E1E)', '#2ea043', '#f85149', '#569cd6', '#ce9178', '#6A9955'],
|
|
32
|
+
['dracula', 'Dracula Theme', 'dark', '#282A36', '#F8F8F2', '#6272A4', '#44475A', '#F8F8F2', '#FFB86C80', '#FFFFFF40', '#BD93F9', '#50FA7B20', '#FF555550', '#50FA7B80', '#FF555580', '#FF79C6', '#F1FA8C', '#6272A4'],
|
|
33
|
+
['dracula-soft', 'Dracula Theme Soft', 'dark', '#282A36', '#f6f6f4', '#7b7f8b', '#44475A', '#f6f6f4', '#FFB86C80', '#FFFFFF40', '#bf9eee', '#50FA7B20', '#FF555550', '#50FA7B80', '#FF555580', '#f286c4', '#e7ee98', '#7b7f8b'],
|
|
34
|
+
['everforest-dark', 'Everforest Dark', 'dark', '#2d353b', '#d3c6aa', '#7f897da0', '#475258c0', '#d3c6aa', '#d77f4840', '#899c4040', '#2d353b', '#569d7930', '#da636230', '#899c40a0', '#da6362a0', '#e67e80', '#dbbc7f', '#859289'],
|
|
35
|
+
['everforest-light', 'Everforest Light', 'light', '#fdf6e3', '#5c6a72', '#a4ad9ea0', '#e6e2cca0', '#5c6a72', '#f3945940', '#a4bb4a40', '#fdf6e3', '#6ec39830', '#f1706f30', '#a4bb4aa0', '#f1706fa0', '#f85552', '#dfa000', '#939f91'],
|
|
36
|
+
['github-dark', 'GitHub Dark', 'dark', '#24292e', '#e1e4e8', '#444d56', '#3392FF44', '#c8e1ff', '#ffd33d44', '#ffd33d22', '#1b1f23', '#28a74530', '#d73a4930', '#28a745', '#ea4a5a', '#f97583', '#9ecbff', '#6a737d'],
|
|
37
|
+
['github-dark-default', 'GitHub Dark Default', 'dark', '#0d1117', '#e6edf3', '#6e7681', 'color-mix(in srgb, #e6edf3 22%, #0d1117)', '#2f81f7', '#9e6a03', '#f2cc6080', '#30363d', '#23863626', '#da363326', '#2ea04366', '#f8514966', '#ff7b72', '#a5d6ff', '#8b949e'],
|
|
38
|
+
['github-dark-dimmed', 'GitHub Dark Dimmed', 'dark', '#22272e', '#adbac7', '#636e7b', 'color-mix(in srgb, #adbac7 22%, #22272e)', '#539bf5', '#966600', '#eac55f80', '#444c56', '#347d3926', '#c93c3726', '#46954a66', '#e5534b66', '#f47067', '#96d0ff', '#768390'],
|
|
39
|
+
['github-dark-high-contrast', 'GitHub Dark High Contrast', 'dark', '#0a0c10', '#f0f3f6', '#9ea7b3', '#ffffff', '#71b7ff', '#e09b13', '#fbd66980', '#7a828e', '#09b43a26', '#ff6a6926', '#09b43a', '#ff6a69', '#ff9492', '#addcff', '#bdc4cc'],
|
|
40
|
+
['github-light', 'GitHub Light', 'light', '#fff', '#24292e', '#1b1f234d', '#0366d625', '#044289', '#ffdf5d', '#ffdf5d66', '#e1e4e8', '#34d05822', '#d73a4922', '#28a745', '#d73a49', '#d73a49', '#032f62', '#6a737d'],
|
|
41
|
+
['github-light-default', 'GitHub Light Default', 'light', '#ffffff', '#1f2328', '#8c959f', 'color-mix(in srgb, #1f2328 22%, #ffffff)', '#0969da', '#bf8700', '#fae17d80', '#d0d7de', '#aceebb4d', '#ffcecb4d', '#4ac26b66', '#ff818266', '#cf222e', '#0a3069', '#6e7781'],
|
|
42
|
+
['github-light-high-contrast', 'GitHub Light High Contrast', 'light', '#ffffff', '#0e1116', '#88929d', '#0e1116', '#0349b4', '#744500', '#f0ce5380', '#20252c', '#82e5964d', '#ffc1bc4d', '#26a148', '#ee5a5d', '#a0111f', '#032563', '#66707b'],
|
|
43
|
+
['gruvbox-dark-hard', 'Gruvbox Dark Hard', 'dark', '#1d2021', '#ebdbb2', '#665c54', '#689d6a40', '#ebdbb2', '#83a59870', '#fe801930', '#3c3836', '#b8bb2630', '#fb493430', '#b8bb26', '#fb4934', '#fb4934', '#b8bb26', '#928374'],
|
|
44
|
+
['gruvbox-dark-medium', 'Gruvbox Dark Medium', 'dark', '#282828', '#ebdbb2', '#665c54', '#689d6a40', '#ebdbb2', '#83a59870', '#fe801930', '#3c3836', '#b8bb2630', '#fb493430', '#b8bb26', '#fb4934', '#fb4934', '#b8bb26', '#928374'],
|
|
45
|
+
['gruvbox-dark-soft', 'Gruvbox Dark Soft', 'dark', '#32302f', '#ebdbb2', '#665c54', '#689d6a40', '#ebdbb2', '#83a59870', '#fe801930', '#3c3836', '#b8bb2630', '#fb493430', '#b8bb26', '#fb4934', '#fb4934', '#b8bb26', '#928374'],
|
|
46
|
+
['gruvbox-light-hard', 'Gruvbox Light Hard', 'light', '#f9f5d7', '#3c3836', '#bdae93', '#689d6a40', '#3c3836', '#07667870', '#af3a0330', '#ebdbb2', '#79740e30', '#9d000630', '#79740e', '#9d0006', '#9d0006', '#79740e', '#928374'],
|
|
47
|
+
['gruvbox-light-medium', 'Gruvbox Light Medium', 'light', '#fbf1c7', '#3c3836', '#bdae93', '#689d6a40', '#3c3836', '#07667870', '#af3a0330', '#ebdbb2', '#79740e30', '#9d000630', '#79740e', '#9d0006', '#9d0006', '#79740e', '#928374'],
|
|
48
|
+
['gruvbox-light-soft', 'Gruvbox Light Soft', 'light', '#f2e5bc', '#3c3836', '#bdae93', '#689d6a40', '#3c3836', '#07667870', '#af3a0330', '#ebdbb2', '#79740e30', '#9d000630', '#79740e', '#9d0006', '#9d0006', '#79740e', '#928374'],
|
|
49
|
+
['horizon', 'Horizon', 'dark', '#1C1E26', '#D5D8DA', '#D5D8DA1A', '#2E303EB3', '#E95378', '#6C6F9380', '#6C6F934D', 'color-mix(in srgb, #D5D8DA 16%, #1C1E26)', '#09F7A01A', '#F43E5C1A', '#09F7A0B3', '#F43E5CB3', '#B877DBE6', '#FAB795E6', '#BBBBBB4D'],
|
|
50
|
+
['horizon-bright', 'Horizon Bright', 'light', '#FDF0ED', '#06060C', '#06060C1A', '#F9CBBE80', '#E84A72', '#F9CEC380', '#F9CEC34D', 'color-mix(in srgb, #06060C 16%, #FDF0ED)', '#07DA8C1A', '#F43E5C1A', '#07DA8CB3', '#F43E5CB3', '#8A31B9', '#F6661E', '#33333380'],
|
|
51
|
+
['houston', 'Houston', 'dark', '#17191e', '#eef0f9', '#545864', '#ad5dca44', '#aeafad', '#515c6a', '#ea5c0055', '#17191e', '#4bf3c824', '#dc365724', '#4bf3c8', '#f06788', '#54b9ff', '#ffd493', '#eef0f98f'],
|
|
52
|
+
['kanagawa-dragon', 'Kanagawa Dragon', 'dark', '#181616', '#C5C9C5', '#625E5A', '#223249', '#C5C9C5', '#2D4F67', '#2D4F6780', '#0D0C0C', '#2B332880', 'color-mix(in srgb, #C34043 22%, #181616)', '#76946A', '#C34043', '#8992A7', '#8A9A7B', '#737C73'],
|
|
53
|
+
['kanagawa-lotus', 'Kanagawa Lotus', 'light', '#F2ECBC', '#545464', '#766B90', '#C7D7E0', '#545464', '#B5CBD2', '#B5CBD280', '#D5CEA3', '#B7D0AE80', 'color-mix(in srgb, #D7474B 22%, #F2ECBC)', '#6E915F', '#D7474B', '#624C83', '#6F894E', '#716E61'],
|
|
54
|
+
['kanagawa-wave', 'Kanagawa Wave', 'dark', '#1F1F28', '#DCD7BA', '#54546D', '#223249', '#DCD7BA', '#2D4F67', '#2D4F6780', '#16161D', '#2B332880', 'color-mix(in srgb, #C34043 22%, #1F1F28)', '#76946A', '#C34043', '#957FB8', '#98BB6C', '#727169'],
|
|
55
|
+
['laserwave', 'LaserWave', 'dark', '#27212e', '#ffffff', 'color-mix(in srgb, #ffffff 38%, #27212e)', '#eb64b927', '#ffffff', '#40b4c48c', '#40b4c460', 'color-mix(in srgb, #ffffff 16%, #27212e)', '#74dfc423', '#eb64b940', '#74dfc4', '#eb64B9', '#a96bc0', '#b4dce7', '#91889b'],
|
|
56
|
+
['light-plus', 'Light Plus', 'light', '#FFFFFF', '#000000', 'color-mix(in srgb, #000000 38%, #FFFFFF)', 'color-mix(in srgb, #000000 22%, #FFFFFF)', '#000000', 'color-mix(in srgb, #000000 18%, #FFFFFF)', 'color-mix(in srgb, #000000 30%, #FFFFFF)', 'color-mix(in srgb, #000000 16%, #FFFFFF)', 'color-mix(in srgb, #2ea043 22%, #FFFFFF)', 'color-mix(in srgb, #f85149 22%, #FFFFFF)', '#2ea043', '#f85149', '#0000ff', '#a31515', '#008000'],
|
|
57
|
+
['material-theme', 'Material Theme', 'dark', '#263238', '#EEFFFF', '#465A64', '#80CBC420', '#FFCC00', '#000000', '#00000050', '#26323860', '#89DDFF20', '#ff9cac20', '#C3E88D60', '#f0717860', '#89DDFF', '#C3E88D', '#546E7A'],
|
|
58
|
+
['material-theme-darker', 'Material Theme Darker', 'dark', '#212121', '#EEFFFF', '#424242', '#61616150', '#FFCC00', '#000000', '#00000050', '#21212160', '#89DDFF20', '#ff9cac20', '#C3E88D60', '#f0717860', '#89DDFF', '#C3E88D', '#545454'],
|
|
59
|
+
['material-theme-lighter', 'Material Theme Lighter', 'light', '#FAFAFA', '#90A4AE', '#CFD8DC', '#80CBC440', '#272727', '#00000020', '#00000010', '#FAFAFA60', '#39ADB520', '#FF537020', '#91B85960', '#E5393560', '#39ADB5', '#91B859', '#90A4AE'],
|
|
60
|
+
['material-theme-ocean', 'Material Theme Ocean', 'dark', '#0F111A', '#babed8', '#3B3F5180', '#717CB450', '#FFCC00', '#000000', '#00000050', '#0F111A60', '#89DDFF20', '#ff9cac20', '#C3E88D60', '#f0717860', '#89DDFF', '#C3E88D', '#464B5D'],
|
|
61
|
+
['material-theme-palenight', 'Material Theme Palenight', 'dark', '#292D3E', '#babed8', '#3A3F58', '#717CB450', '#FFCC00', '#000000', '#00000050', '#292D3E60', '#89DDFF20', '#ff9cac20', '#C3E88D60', '#f0717860', '#89DDFF', '#C3E88D', '#676E95'],
|
|
62
|
+
['min-dark', 'Min Dark', 'dark', '#1f1f1f', '#888888', '#727272', 'color-mix(in srgb, #888888 22%, #1f1f1f)', '#888888', 'color-mix(in srgb, #888888 18%, #1f1f1f)', 'color-mix(in srgb, #888888 30%, #1f1f1f)', 'color-mix(in srgb, #888888 16%, #1f1f1f)', '#3a632a4b', '#88063852', '#2ea043', '#f85149', '#f97583', '#9db1c5', '#6b737c'],
|
|
63
|
+
['min-light', 'Min Light', 'light', '#ffffff', '#212121', '#CCC', 'color-mix(in srgb, #212121 22%, #ffffff)', '#212121', 'color-mix(in srgb, #212121 18%, #ffffff)', 'color-mix(in srgb, #212121 30%, #ffffff)', '#f4f4f4', '#b7e7a44b', '#e597af52', '#2ea043', '#f85149', '#D32F2F', '#2b5581', '#c2c3c5'],
|
|
64
|
+
['monokai', 'Monokai', 'dark', '#272822', '#f8f8f2', '#90908a', '#878b9180', '#f8f8f0', 'color-mix(in srgb, #f8f8f2 18%, #272822)', 'color-mix(in srgb, #f8f8f2 30%, #272822)', '#414339', '#4b661680', '#90274A70', '#2ea043', '#f85149', '#F92672', '#E6DB74', '#88846f'],
|
|
65
|
+
['night-owl', 'Night Owl', 'dark', '#011627', '#d6deeb', '#4b6479', '#1d3b53', '#80a4c2', '#5f7e9779', '#1085bb5d', '#5f7e97', '#99b76d23', '#ef535033', '#9CCC65', '#EF5350', '#c792ea', '#ecc48d', '#637777'],
|
|
66
|
+
['night-owl-light', 'Night Owl Light', 'light', '#FBFBFB', '#403f53', '#90A7B2', '#E0E0E0', '#90A7B2', '#93A1A16c', '#93a1a16c', '#d9d9d9', 'color-mix(in srgb, #49d0c5 22%, #FBFBFB)', 'color-mix(in srgb, #f76e6e 22%, #FBFBFB)', '#49d0c5', '#f76e6e', '#994cc3', '#4876d6', '#989fb1'],
|
|
67
|
+
['nord', 'Nord', 'dark', '#2e3440', '#d8dee9', '#4c566a', '#434c5ecc', '#d8dee9', '#88c0d066', '#88c0d033', '#3b4252', '#81a1c133', '#bf616a4d', '#a3be8c', '#bf616a', '#81A1C1', '#A3BE8C', '#616E88'],
|
|
68
|
+
['one-dark-pro', 'One Dark Pro', 'dark', '#282c34', '#abb2bf', '#495162', '#67769660', '#528bff', '#d19a6644', '#ffffff22', '#3e4452', '#00809b33', 'color-mix(in srgb, #9A353D 22%, #282c34)', '#109868', '#9A353D', '#c678dd', '#98c379', '#7f848e'],
|
|
69
|
+
['one-light', 'One Light', 'light', '#FAFAFA', '#383A42', '#9D9D9F', '#E5E5E6', '#526FFF', 'color-mix(in srgb, #383A42 18%, #FAFAFA)', '#526FFF33', 'color-mix(in srgb, #383A42 16%, #FAFAFA)', '#00809B33', 'color-mix(in srgb, #f85149 22%, #FAFAFA)', '#2ea043', '#f85149', '#A626A4', '#50A14F', '#A0A1A7'],
|
|
70
|
+
['plastic', 'Plastic', 'dark', '#21252B', '#A9B2C3', '#5F6672', '#A9B2C333', '#A9B2C3', '#00000000', '#00000000', '#0D1117', '#CBF6AC0D', '#FF9FA80D', '#98C379', '#E06C75', '#E06C75', '#98C379', '#5F6672'],
|
|
71
|
+
['poimandres', 'Poimandres', 'dark', '#1b1e28', '#a6accd', '#767c9d50', '#717cb425', '#a6accd', '#ADD7FF40', '#ADD7FF40', '#00000030', '#50647715', '#d0679d20', '#5fb3a140', '#d0679d40', '#a6accd', '#5DE4c7', '#767c9dB0'],
|
|
72
|
+
['red', 'Red', 'dark', '#390000', '#F8F8F8', '#ff777788', '#750000', '#970000', 'color-mix(in srgb, #F8F8F8 18%, #390000)', 'color-mix(in srgb, #F8F8F8 30%, #390000)', 'color-mix(in srgb, #F8F8F8 16%, #390000)', 'color-mix(in srgb, #2ea043 22%, #390000)', 'color-mix(in srgb, #f85149 22%, #390000)', '#2ea043', '#f85149', '#f12727ff', '#cd8d8dff', '#e7c0c0ff'],
|
|
73
|
+
['rose-pine', 'Rosé Pine', 'dark', '#191724', '#e0def4', '#908caa', '#6e6a8633', '#6e6a86', '#f6c17733', '#6e6a8666', '#0000', '#9ccfd826', '#eb6f9226', '#9ccfd8', '#eb6f92', '#31748f', '#f6c177', '#6e6a86'],
|
|
74
|
+
['rose-pine-dawn', 'Rosé Pine Dawn', 'light', '#faf4ed', '#575279', '#797593', '#6e6a8614', '#9893a5', '#ea9d3433', '#6e6a8626', '#0000', '#56949f26', '#b4637a26', '#56949f', '#b4637a', '#286983', '#ea9d34', '#9893a5'],
|
|
75
|
+
['rose-pine-moon', 'Rosé Pine Moon', 'dark', '#232136', '#e0def4', '#908caa', '#817c9c26', '#6e6a86', '#f6c17733', '#817c9c4d', '#0000', '#9ccfd826', '#eb6f9226', '#9ccfd8', '#eb6f92', '#3e8fb0', '#f6c177', '#6e6a86'],
|
|
76
|
+
['slack-dark', 'Slack Dark', 'dark', '#222222', '#E6E6E6', 'color-mix(in srgb, #E6E6E6 38%, #222222)', 'color-mix(in srgb, #E6E6E6 22%, #222222)', '#E6E6E6', 'color-mix(in srgb, #E6E6E6 18%, #222222)', 'color-mix(in srgb, #E6E6E6 30%, #222222)', 'color-mix(in srgb, #E6E6E6 16%, #222222)', 'color-mix(in srgb, #2ea043 22%, #222222)', 'color-mix(in srgb, #f85149 22%, #222222)', '#2ea043', '#f85149', '#569cd6', '#ce9178', '#6A9955'],
|
|
77
|
+
['slack-ochin', 'Slack Ochin', 'light', '#FFF', '#000', '#b9b9b9', '#AED4FB', '#000', '#AED4FB', '#AED4FB', '#2D3E4C', 'color-mix(in srgb, #2ea043 22%, #FFF)', 'color-mix(in srgb, #f85149 22%, #FFF)', '#2ea043', '#f85149', '#7b30d0', '#a44185', '#357b42'],
|
|
78
|
+
['snazzy-light', 'Snazzy Light', 'light', '#FAFBFC', '#565869', '#9194A2aa', '#2DAE5822', '#565869', '#00E6E06A', '#00E6E02A', 'color-mix(in srgb, #565869 16%, #FAFBFC)', '#2DAE5824', '#FFAEAC44', '#2DAE58', '#FF5C57', '#F767BB', '#CF9C00', '#ADB1C2'],
|
|
79
|
+
['solarized-dark', 'Solarized Dark', 'dark', '#002B36', '#839496', 'color-mix(in srgb, #839496 38%, #002B36)', '#274642', '#D30102', 'color-mix(in srgb, #839496 18%, #002B36)', 'color-mix(in srgb, #839496 30%, #002B36)', '#2b2b4a', 'color-mix(in srgb, #2ea043 22%, #002B36)', 'color-mix(in srgb, #f85149 22%, #002B36)', '#2ea043', '#f85149', '#859900', '#2AA198', '#586E75'],
|
|
80
|
+
['solarized-light', 'Solarized Light', 'light', '#FDF6E3', '#657B83', 'color-mix(in srgb, #657B83 38%, #FDF6E3)', '#EEE8D5', '#657B83', 'color-mix(in srgb, #657B83 18%, #FDF6E3)', 'color-mix(in srgb, #657B83 30%, #FDF6E3)', '#DDD6C1', 'color-mix(in srgb, #2ea043 22%, #FDF6E3)', 'color-mix(in srgb, #f85149 22%, #FDF6E3)', '#2ea043', '#f85149', '#859900', '#2AA198', '#93A1A1'],
|
|
81
|
+
['synthwave-84', 'Synthwave \'84', 'dark', '#262335', '#ffffff', '#ffffff73', '#ffffff20', '#f97e72', '#D18616bb', '#D1861655', 'color-mix(in srgb, #ffffff 16%, #262335)', '#0beb9935', '#fe445035', '#206d4bd6', '#fa2e46a4', '#fede5d', '#ff8b39', '#848bbd'],
|
|
82
|
+
['tokyo-night', 'Tokyo Night', 'dark', '#1a1b26', '#a9b1d6', '#363b54', '#515c7e4d', '#c0caf5', '#3d59a166', '#3d59a166', '#101014', '#41a6b520', '#db4b4b22', '#164846', '#823c41', '#bb9af7', '#9ece6a', '#51597d'],
|
|
83
|
+
['vesper', 'Vesper', 'dark', '#101010', '#FFF', '#505050', '#FFFFFF25', '#FFF', 'color-mix(in srgb, #FFF 18%, #101010)', 'color-mix(in srgb, #FFF 30%, #101010)', 'color-mix(in srgb, #FFF 16%, #101010)', '#99FFE415', '#FF808015', '#99FFE4', '#FF8080', '#A0A0A0', '#99FFE4', '#8b8b8b94'],
|
|
84
|
+
['vitesse-black', 'Vitesse Black', 'dark', '#000', '#dbd7cacc', '#dedcd550', '#eeeeee18', '#dbd7cacc', '#e6cc7722', '#e6cc7744', '#191919', '#4d937550', '#ab595950', '#4d9375', '#cb7676', '#4d9375', '#c98a7d', '#758575dd'],
|
|
85
|
+
['vitesse-dark', 'Vitesse Dark', 'dark', '#121212', '#dbd7caee', '#dedcd550', '#eeeeee18', '#dbd7caee', '#e6cc7722', '#e6cc7744', '#191919', '#4d937550', '#ab595950', '#4d9375', '#cb7676', '#4d9375', '#c98a7d', '#758575dd'],
|
|
86
|
+
['vitesse-light', 'Vitesse Light', 'light', '#ffffff', '#393a34', '#393a3450', '#22222218', '#393a34', '#e6cc7744', '#e6cc7766', '#f0f0f0', '#1c6b4830', '#ab595940', '#1e754f', '#ab5959', '#1e754f', '#b56959', '#a0ada0'],
|
|
87
|
+
] as const;
|
|
88
|
+
|
|
89
|
+
/** Lazy module loaders, so a theme nobody selects is never downloaded. */
|
|
90
|
+
export const EDITOR_THEME_LOADERS: Record<string, () => Promise<unknown>> = {
|
|
91
|
+
'andromeeda': () => import('@shikijs/themes/andromeeda'),
|
|
92
|
+
'aurora-x': () => import('@shikijs/themes/aurora-x'),
|
|
93
|
+
'ayu-dark': () => import('@shikijs/themes/ayu-dark'),
|
|
94
|
+
'ayu-light': () => import('@shikijs/themes/ayu-light'),
|
|
95
|
+
'ayu-mirage': () => import('@shikijs/themes/ayu-mirage'),
|
|
96
|
+
'catppuccin-frappe': () => import('@shikijs/themes/catppuccin-frappe'),
|
|
97
|
+
'catppuccin-latte': () => import('@shikijs/themes/catppuccin-latte'),
|
|
98
|
+
'catppuccin-macchiato': () => import('@shikijs/themes/catppuccin-macchiato'),
|
|
99
|
+
'catppuccin-mocha': () => import('@shikijs/themes/catppuccin-mocha'),
|
|
100
|
+
'dark-plus': () => import('@shikijs/themes/dark-plus'),
|
|
101
|
+
'dracula': () => import('@shikijs/themes/dracula'),
|
|
102
|
+
'dracula-soft': () => import('@shikijs/themes/dracula-soft'),
|
|
103
|
+
'everforest-dark': () => import('@shikijs/themes/everforest-dark'),
|
|
104
|
+
'everforest-light': () => import('@shikijs/themes/everforest-light'),
|
|
105
|
+
'github-dark': () => import('@shikijs/themes/github-dark'),
|
|
106
|
+
'github-dark-default': () => import('@shikijs/themes/github-dark-default'),
|
|
107
|
+
'github-dark-dimmed': () => import('@shikijs/themes/github-dark-dimmed'),
|
|
108
|
+
'github-dark-high-contrast': () => import('@shikijs/themes/github-dark-high-contrast'),
|
|
109
|
+
'github-light': () => import('@shikijs/themes/github-light'),
|
|
110
|
+
'github-light-default': () => import('@shikijs/themes/github-light-default'),
|
|
111
|
+
'github-light-high-contrast': () => import('@shikijs/themes/github-light-high-contrast'),
|
|
112
|
+
'gruvbox-dark-hard': () => import('@shikijs/themes/gruvbox-dark-hard'),
|
|
113
|
+
'gruvbox-dark-medium': () => import('@shikijs/themes/gruvbox-dark-medium'),
|
|
114
|
+
'gruvbox-dark-soft': () => import('@shikijs/themes/gruvbox-dark-soft'),
|
|
115
|
+
'gruvbox-light-hard': () => import('@shikijs/themes/gruvbox-light-hard'),
|
|
116
|
+
'gruvbox-light-medium': () => import('@shikijs/themes/gruvbox-light-medium'),
|
|
117
|
+
'gruvbox-light-soft': () => import('@shikijs/themes/gruvbox-light-soft'),
|
|
118
|
+
'horizon': () => import('@shikijs/themes/horizon'),
|
|
119
|
+
'horizon-bright': () => import('@shikijs/themes/horizon-bright'),
|
|
120
|
+
'houston': () => import('@shikijs/themes/houston'),
|
|
121
|
+
'kanagawa-dragon': () => import('@shikijs/themes/kanagawa-dragon'),
|
|
122
|
+
'kanagawa-lotus': () => import('@shikijs/themes/kanagawa-lotus'),
|
|
123
|
+
'kanagawa-wave': () => import('@shikijs/themes/kanagawa-wave'),
|
|
124
|
+
'laserwave': () => import('@shikijs/themes/laserwave'),
|
|
125
|
+
'light-plus': () => import('@shikijs/themes/light-plus'),
|
|
126
|
+
'material-theme': () => import('@shikijs/themes/material-theme'),
|
|
127
|
+
'material-theme-darker': () => import('@shikijs/themes/material-theme-darker'),
|
|
128
|
+
'material-theme-lighter': () => import('@shikijs/themes/material-theme-lighter'),
|
|
129
|
+
'material-theme-ocean': () => import('@shikijs/themes/material-theme-ocean'),
|
|
130
|
+
'material-theme-palenight': () => import('@shikijs/themes/material-theme-palenight'),
|
|
131
|
+
'min-dark': () => import('@shikijs/themes/min-dark'),
|
|
132
|
+
'min-light': () => import('@shikijs/themes/min-light'),
|
|
133
|
+
'monokai': () => import('@shikijs/themes/monokai'),
|
|
134
|
+
'night-owl': () => import('@shikijs/themes/night-owl'),
|
|
135
|
+
'night-owl-light': () => import('@shikijs/themes/night-owl-light'),
|
|
136
|
+
'nord': () => import('@shikijs/themes/nord'),
|
|
137
|
+
'one-dark-pro': () => import('@shikijs/themes/one-dark-pro'),
|
|
138
|
+
'one-light': () => import('@shikijs/themes/one-light'),
|
|
139
|
+
'plastic': () => import('@shikijs/themes/plastic'),
|
|
140
|
+
'poimandres': () => import('@shikijs/themes/poimandres'),
|
|
141
|
+
'red': () => import('@shikijs/themes/red'),
|
|
142
|
+
'rose-pine': () => import('@shikijs/themes/rose-pine'),
|
|
143
|
+
'rose-pine-dawn': () => import('@shikijs/themes/rose-pine-dawn'),
|
|
144
|
+
'rose-pine-moon': () => import('@shikijs/themes/rose-pine-moon'),
|
|
145
|
+
'slack-dark': () => import('@shikijs/themes/slack-dark'),
|
|
146
|
+
'slack-ochin': () => import('@shikijs/themes/slack-ochin'),
|
|
147
|
+
'snazzy-light': () => import('@shikijs/themes/snazzy-light'),
|
|
148
|
+
'solarized-dark': () => import('@shikijs/themes/solarized-dark'),
|
|
149
|
+
'solarized-light': () => import('@shikijs/themes/solarized-light'),
|
|
150
|
+
'synthwave-84': () => import('@shikijs/themes/synthwave-84'),
|
|
151
|
+
'tokyo-night': () => import('@shikijs/themes/tokyo-night'),
|
|
152
|
+
'vesper': () => import('@shikijs/themes/vesper'),
|
|
153
|
+
'vitesse-black': () => import('@shikijs/themes/vitesse-black'),
|
|
154
|
+
'vitesse-dark': () => import('@shikijs/themes/vitesse-dark'),
|
|
155
|
+
'vitesse-light': () => import('@shikijs/themes/vitesse-light'),
|
|
156
|
+
};
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The editor theme catalogue, and the one property that makes it trustworthy:
|
|
8
|
+
* every colour it ships is the INSTALLED package's own.
|
|
9
|
+
*
|
|
10
|
+
* The grid draws 65 cards without fetching a theme module, so its colours are
|
|
11
|
+
* data. Data generated from a dependency drifts the moment the dependency
|
|
12
|
+
* updates — silently, because the picker still renders, just with a palette the
|
|
13
|
+
* highlighter no longer has. These cases re-derive each row from
|
|
14
|
+
* `@shikijs/themes` itself, which is the only check that can fail on a version
|
|
15
|
+
* bump rather than on a typo.
|
|
16
|
+
*
|
|
17
|
+
* The remaining cases pin the two rules the surfaces depend on: `auto` resolves
|
|
18
|
+
* to no theme (so nothing changes for an install that never opens the picker),
|
|
19
|
+
* and an explicit theme names ITSELF in both Shiki slots — which is what makes
|
|
20
|
+
* the editor ignore the app's light/dark variant without a second CSS path.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { describe, expect, test } from 'bun:test';
|
|
24
|
+
import { readdirSync } from 'node:fs';
|
|
25
|
+
import { dirname, join } from 'node:path';
|
|
26
|
+
|
|
27
|
+
import {
|
|
28
|
+
EDITOR_AUTO_THEME_ID,
|
|
29
|
+
EDITOR_DEFAULT_THEME_ID,
|
|
30
|
+
EDITOR_THEMES,
|
|
31
|
+
EDITOR_THEME_LOADERS,
|
|
32
|
+
editorShikiThemes,
|
|
33
|
+
editorThemeVars,
|
|
34
|
+
isEditorThemeId,
|
|
35
|
+
resolveEditorTheme,
|
|
36
|
+
} from '@/shared/lib/code/editor/themes';
|
|
37
|
+
import { SHIKI_THEMES } from '@/shared/lib/code/shiki-themes';
|
|
38
|
+
|
|
39
|
+
/** The installed package's `dist`, resolved through the package itself so a
|
|
40
|
+
* hoisted or linked install resolves the same way the app's own imports do. */
|
|
41
|
+
const THEMES_DIR = join(dirname(Bun.resolveSync('@shikijs/themes/package.json', import.meta.dir)), 'dist');
|
|
42
|
+
|
|
43
|
+
/** The ids the installed package actually ships, in the generator's order. */
|
|
44
|
+
function installedIds(): string[] {
|
|
45
|
+
return readdirSync(THEMES_DIR)
|
|
46
|
+
.filter((file) => file.endsWith('.mjs') && file !== 'index.mjs')
|
|
47
|
+
.map((file) => file.slice(0, -'.mjs'.length))
|
|
48
|
+
.sort();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
describe('catalogue', () => {
|
|
52
|
+
test('one row per theme the installed package ships, in id order', () => {
|
|
53
|
+
expect(EDITOR_THEMES.map((theme) => theme.id)).toEqual(installedIds());
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('every row has a loader, and every loader has a row', () => {
|
|
57
|
+
expect(Object.keys(EDITOR_THEME_LOADERS).sort()).toEqual(EDITOR_THEMES.map((theme) => theme.id));
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('a label is never empty and never the raw id with dashes', () => {
|
|
61
|
+
for (const theme of EDITOR_THEMES) {
|
|
62
|
+
expect(theme.label.length).toBeGreaterThan(0);
|
|
63
|
+
expect(theme.variant === 'light' || theme.variant === 'dark').toBe(true);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('generated colours', () => {
|
|
69
|
+
test('the surface and the ink are the theme’s own', async () => {
|
|
70
|
+
for (const theme of EDITOR_THEMES) {
|
|
71
|
+
// Dynamic on purpose: the specifier is the row's own id, read at runtime
|
|
72
|
+
// from a 65-entry catalogue — a static import cannot name it.
|
|
73
|
+
const module = (await import(`@shikijs/themes/${theme.id}`)).default as {
|
|
74
|
+
colors?: Record<string, string>;
|
|
75
|
+
};
|
|
76
|
+
const colors = module.colors ?? {};
|
|
77
|
+
expect(theme.bg).toBe(colors['editor.background'] as string);
|
|
78
|
+
// Five themes ship no `editor.foreground`; the generator falls back to the
|
|
79
|
+
// theme's own `foreground`, which is still ITS colour and not a borrow.
|
|
80
|
+
const own =
|
|
81
|
+
colors['editor.foreground'] ?? colors['foreground'] ?? colors['terminal.foreground'] ?? theme.fg;
|
|
82
|
+
expect(theme.fg).toBe(own);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('a chrome colour the theme omits is a mix of its own ink and surface', () => {
|
|
87
|
+
for (const theme of EDITOR_THEMES) {
|
|
88
|
+
for (const value of [theme.gutterFg, theme.selection, theme.find, theme.border]) {
|
|
89
|
+
expect(value.length).toBeGreaterThan(0);
|
|
90
|
+
// Either the theme's own hex, or a `color-mix` over its own two colours
|
|
91
|
+
// — never a bare colour borrowed from another theme.
|
|
92
|
+
const isOwnHex = /^#[0-9a-f]{3,8}$/i.test(value);
|
|
93
|
+
const isOwnMix = value.startsWith('color-mix(') && value.includes(theme.bg);
|
|
94
|
+
expect(isOwnHex || isOwnMix).toBe(true);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('the three accents differ enough to tell two themes apart', () => {
|
|
100
|
+
for (const theme of EDITOR_THEMES) {
|
|
101
|
+
expect(theme.keyword).toMatch(/^#[0-9a-f]{3,8}$/i);
|
|
102
|
+
expect(theme.string).toMatch(/^#[0-9a-f]{3,8}$/i);
|
|
103
|
+
expect(theme.comment).toMatch(/^#[0-9a-f]{3,8}$/i);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
describe('resolution', () => {
|
|
109
|
+
test('auto is the default and resolves to no theme', () => {
|
|
110
|
+
expect(EDITOR_DEFAULT_THEME_ID).toBe(EDITOR_AUTO_THEME_ID);
|
|
111
|
+
expect(resolveEditorTheme(EDITOR_AUTO_THEME_ID)).toBeNull();
|
|
112
|
+
expect(resolveEditorTheme(undefined)).toBeNull();
|
|
113
|
+
expect(resolveEditorTheme(null)).toBeNull();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test('an id this build does not ship falls back to auto rather than half a theme', () => {
|
|
117
|
+
expect(resolveEditorTheme('no-such-theme')).toBeNull();
|
|
118
|
+
expect(isEditorThemeId('no-such-theme')).toBe(false);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test('a shipped id resolves to its own row', () => {
|
|
122
|
+
const dracula = resolveEditorTheme('dracula');
|
|
123
|
+
expect(dracula?.id).toBe('dracula');
|
|
124
|
+
expect(isEditorThemeId('dracula')).toBe(true);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe('shiki themes', () => {
|
|
129
|
+
test('auto keeps the app’s dual pair, so an app theme flip repaints', () => {
|
|
130
|
+
expect(editorShikiThemes(null)).toEqual(SHIKI_THEMES);
|
|
131
|
+
expect(editorShikiThemes(EDITOR_AUTO_THEME_ID)).toEqual(SHIKI_THEMES);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('an explicit theme names itself in BOTH slots', () => {
|
|
135
|
+
// Both slots carrying one theme is what makes the app's variant attribute
|
|
136
|
+
// harmless: `--shiki-light` and `--shiki-dark` hold the same value, so
|
|
137
|
+
// either selector paints the chosen theme.
|
|
138
|
+
expect(editorShikiThemes('dracula')).toEqual({ light: 'dracula', dark: 'dracula' });
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test('an unknown id keeps the app pair', () => {
|
|
142
|
+
expect(editorShikiThemes('no-such-theme')).toEqual(SHIKI_THEMES);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe('css variables', () => {
|
|
147
|
+
test('auto writes nothing, so every declaration keeps its palette fallback', () => {
|
|
148
|
+
expect(editorThemeVars(null)).toEqual({});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test('an explicit theme writes the surface, the gutter and the diff bands', () => {
|
|
152
|
+
const theme = resolveEditorTheme('nord');
|
|
153
|
+
expect(theme).not.toBeNull();
|
|
154
|
+
const vars = editorThemeVars(theme);
|
|
155
|
+
expect(vars['--editor-bg']).toBe(theme!.bg);
|
|
156
|
+
expect(vars['--editor-fg']).toBe(theme!.fg);
|
|
157
|
+
expect(vars['--editor-gutter-fg']).toBe(theme!.gutterFg);
|
|
158
|
+
expect(vars['--editor-selection']).toBe(theme!.selection);
|
|
159
|
+
expect(vars['--editor-find-current']).toBe(theme!.findCurrent);
|
|
160
|
+
expect(vars['--editor-added']).toBe(theme!.added);
|
|
161
|
+
expect(vars['--editor-removed-gutter']).toBe(theme!.removedGutter);
|
|
162
|
+
// Every key is a custom property, never a plain one.
|
|
163
|
+
for (const key of Object.keys(vars)) expect(key.startsWith('--editor-')).toBe(true);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The EDITOR's colour themes, independent of the app palette.
|
|
8
|
+
*
|
|
9
|
+
* CodeMirror can wear any of the 65 TextMate themes `@shikijs/themes` ships, and
|
|
10
|
+
* a reader who works in Dracula or Nord wants the code surface to say so while
|
|
11
|
+
* the console around it stays in the app's own palette. That separation is the
|
|
12
|
+
* whole feature: `SettingsState.editorTheme` is a second axis beside `theme`,
|
|
13
|
+
* and the editor paints its own surface, gutter, selection and tokens from it.
|
|
14
|
+
*
|
|
15
|
+
* Three rules keep it honest:
|
|
16
|
+
*
|
|
17
|
+
* - **`auto` is the default and means "the app's own palette".** Nothing changes
|
|
18
|
+
* for an install that never opens the picker: the surface stays transparent
|
|
19
|
+
* over the panel, the chrome reads `--theme-*`, and the tokenizer keeps the
|
|
20
|
+
* dual `one-light`/`one-dark-pro` pair the app variant selects.
|
|
21
|
+
* - **The data is generated, never typed.** `themes.generated.ts` is written by
|
|
22
|
+
* `scripts/editor-themes.mjs` from the installed package, so the picker's
|
|
23
|
+
* swatches are the theme's OWN colours and a `@shikijs/themes` bump cannot
|
|
24
|
+
* leave the grid showing a palette that no longer exists.
|
|
25
|
+
* - **A theme module is only fetched when it is selected.** The rows carry
|
|
26
|
+
* enough colour to draw the grid; `EDITOR_THEME_LOADERS` is what the
|
|
27
|
+
* highlighter calls, and 65 modules nobody picks are never downloaded.
|
|
28
|
+
*
|
|
29
|
+
* The picker's swatch shows the editor surface, the ink and three syntax
|
|
30
|
+
* accents — the five colours that actually tell two themes apart at 120px.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import { EDITOR_THEME_LOADERS, EDITOR_THEME_ROWS } from '@/shared/lib/code/editor/themes.generated';
|
|
34
|
+
import { SHIKI_THEMES } from '@/shared/lib/code/shiki-themes';
|
|
35
|
+
|
|
36
|
+
/** The setting value meaning "follow the app palette". */
|
|
37
|
+
export const EDITOR_AUTO_THEME_ID = 'auto';
|
|
38
|
+
|
|
39
|
+
/** What a settings row that predates this option holds. */
|
|
40
|
+
export const EDITOR_DEFAULT_THEME_ID = EDITOR_AUTO_THEME_ID;
|
|
41
|
+
|
|
42
|
+
export type EditorThemeVariant = 'light' | 'dark';
|
|
43
|
+
|
|
44
|
+
export interface EditorTheme {
|
|
45
|
+
/** Shiki's theme id, which is also the stored setting value. */
|
|
46
|
+
id: string;
|
|
47
|
+
label: string;
|
|
48
|
+
/** The theme's OWN light/dark verdict — never the app's. */
|
|
49
|
+
variant: EditorThemeVariant;
|
|
50
|
+
/** The editor surface and its ink. */
|
|
51
|
+
bg: string;
|
|
52
|
+
fg: string;
|
|
53
|
+
/** Line-number band. */
|
|
54
|
+
gutterFg: string;
|
|
55
|
+
/** Selection band, caret, and the two find-match bands. */
|
|
56
|
+
selection: string;
|
|
57
|
+
cursor: string;
|
|
58
|
+
find: string;
|
|
59
|
+
findCurrent: string;
|
|
60
|
+
/** Divider between the gutter and the text. */
|
|
61
|
+
border: string;
|
|
62
|
+
/** The two diff bands and their gutter markers. */
|
|
63
|
+
added: string;
|
|
64
|
+
removed: string;
|
|
65
|
+
addedGutter: string;
|
|
66
|
+
removedGutter: string;
|
|
67
|
+
/** Three syntax accents, for the picker's swatch only. */
|
|
68
|
+
keyword: string;
|
|
69
|
+
string: string;
|
|
70
|
+
comment: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* The tuple's field order, stated once so the generated rows and this mapping
|
|
75
|
+
* cannot drift: a column added to the generator without a field here is a type
|
|
76
|
+
* error rather than a silently shifted colour.
|
|
77
|
+
*/
|
|
78
|
+
type EditorThemeRow = (typeof EDITOR_THEME_ROWS)[number];
|
|
79
|
+
|
|
80
|
+
const FIELD_ORDER = [
|
|
81
|
+
'id',
|
|
82
|
+
'label',
|
|
83
|
+
'variant',
|
|
84
|
+
'bg',
|
|
85
|
+
'fg',
|
|
86
|
+
'gutterFg',
|
|
87
|
+
'selection',
|
|
88
|
+
'cursor',
|
|
89
|
+
'find',
|
|
90
|
+
'findCurrent',
|
|
91
|
+
'border',
|
|
92
|
+
'added',
|
|
93
|
+
'removed',
|
|
94
|
+
'addedGutter',
|
|
95
|
+
'removedGutter',
|
|
96
|
+
'keyword',
|
|
97
|
+
'string',
|
|
98
|
+
'comment',
|
|
99
|
+
] as const satisfies ReadonlyArray<keyof EditorTheme>;
|
|
100
|
+
|
|
101
|
+
function toTheme(row: EditorThemeRow): EditorTheme {
|
|
102
|
+
const theme = {} as EditorTheme;
|
|
103
|
+
FIELD_ORDER.forEach((field, index) => {
|
|
104
|
+
// The tuple and the field list are asserted equal by the types, so this
|
|
105
|
+
// cast is the only place the two meet.
|
|
106
|
+
(theme as unknown as Record<string, string>)[field] = row[index];
|
|
107
|
+
});
|
|
108
|
+
return theme;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Every theme the installed Shiki ships, in id order (the generator's order). */
|
|
112
|
+
export const EDITOR_THEMES: readonly EditorTheme[] = EDITOR_THEME_ROWS.map(toTheme);
|
|
113
|
+
|
|
114
|
+
const BY_ID = new Map(EDITOR_THEMES.map((theme) => [theme.id, theme]));
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* The theme a stored setting names, or `null` for `auto` — and for an id this
|
|
118
|
+
* build no longer ships (a downgrade, a hand-edited row), which must render the
|
|
119
|
+
* app palette rather than a half-applied theme.
|
|
120
|
+
*/
|
|
121
|
+
export function resolveEditorTheme(id: string | null | undefined): EditorTheme | null {
|
|
122
|
+
if (!id || id === EDITOR_AUTO_THEME_ID) return null;
|
|
123
|
+
return BY_ID.get(id) ?? null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** True when `id` is a theme this build can paint. */
|
|
127
|
+
export function isEditorThemeId(id: string): boolean {
|
|
128
|
+
return BY_ID.has(id);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* The two theme names Shiki tokenizes with.
|
|
133
|
+
*
|
|
134
|
+
* `auto` keeps the app's dual pair, so the variant attribute picks the palette
|
|
135
|
+
* exactly as it does for every other surface. An explicit theme names ITSELF
|
|
136
|
+
* for both slots — one theme, both custom properties, identical values — which
|
|
137
|
+
* is what makes the editor ignore the app variant without a second CSS path.
|
|
138
|
+
*/
|
|
139
|
+
export function editorShikiThemes(id: string | null | undefined): { light: string; dark: string } {
|
|
140
|
+
const theme = resolveEditorTheme(id);
|
|
141
|
+
if (!theme) return SHIKI_THEMES;
|
|
142
|
+
return { light: theme.id, dark: theme.id };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** The CSS custom properties an explicit theme writes, keyed by variable name. */
|
|
146
|
+
export function editorThemeVars(theme: EditorTheme | null): Record<string, string> {
|
|
147
|
+
if (!theme) return {};
|
|
148
|
+
return {
|
|
149
|
+
'--editor-bg': theme.bg,
|
|
150
|
+
'--editor-fg': theme.fg,
|
|
151
|
+
'--editor-gutter-fg': theme.gutterFg,
|
|
152
|
+
'--editor-selection': theme.selection,
|
|
153
|
+
'--editor-cursor': theme.cursor,
|
|
154
|
+
'--editor-find': theme.find,
|
|
155
|
+
'--editor-find-current': theme.findCurrent,
|
|
156
|
+
'--editor-border': theme.border,
|
|
157
|
+
'--editor-added': theme.added,
|
|
158
|
+
'--editor-removed': theme.removed,
|
|
159
|
+
'--editor-added-gutter': theme.addedGutter,
|
|
160
|
+
'--editor-removed-gutter': theme.removedGutter,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** The lazy module loaders, so the highlighter can fetch one theme on demand. */
|
|
165
|
+
export { EDITOR_THEME_LOADERS };
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The block memo in front of the tokenizer.
|
|
8
|
+
*
|
|
9
|
+
* Three properties matter and each was a decision:
|
|
10
|
+
*
|
|
11
|
+
* 1. **A repeat of the same `(language, code)` returns the same markup** — that
|
|
12
|
+
* is the whole point (a card closed and reopened re-tokenized a 1000-line
|
|
13
|
+
* read, measured as the dominant cost of its expand).
|
|
14
|
+
* 2. **A block whose grammar is not ready is NOT cached.** `highlightCode`
|
|
15
|
+
* answers escaped text in that state, and caching it would pin the plain
|
|
16
|
+
* fallback for the life of the entry.
|
|
17
|
+
* 3. **A find-in-progress bypasses the memo**, because its markup depends on the
|
|
18
|
+
* match ranges rather than on the code alone.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { beforeAll, beforeEach, describe, expect, test } from 'bun:test';
|
|
22
|
+
|
|
23
|
+
import { bootSyntax, onLanguageReady, requestLanguage } from '@/shared/lib/code/highlighter';
|
|
24
|
+
import {
|
|
25
|
+
clearHighlightMemo,
|
|
26
|
+
highlightBlock,
|
|
27
|
+
highlightBlockLines,
|
|
28
|
+
highlightMemoSize,
|
|
29
|
+
} from '@/shared/lib/code/highlight-memo';
|
|
30
|
+
|
|
31
|
+
const TOKEN = '--shiki-light:';
|
|
32
|
+
|
|
33
|
+
beforeAll(async () => {
|
|
34
|
+
Object.assign(globalThis, { window: globalThis });
|
|
35
|
+
await bootSyntax();
|
|
36
|
+
Reflect.deleteProperty(globalThis, 'window');
|
|
37
|
+
const { promise, resolve } = Promise.withResolvers<void>();
|
|
38
|
+
const settle = () => {
|
|
39
|
+
if (requestLanguage('json') && requestLanguage('typescript')) {
|
|
40
|
+
off();
|
|
41
|
+
resolve();
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const off = onLanguageReady(settle);
|
|
45
|
+
settle();
|
|
46
|
+
await promise;
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
beforeEach(() => clearHighlightMemo());
|
|
50
|
+
|
|
51
|
+
describe('highlightBlock', () => {
|
|
52
|
+
test('a repeated block returns the same markup and is held once', () => {
|
|
53
|
+
const code = 'const value = 1;\n';
|
|
54
|
+
const first = highlightBlock(code, 'typescript');
|
|
55
|
+
const second = highlightBlock(code, 'typescript');
|
|
56
|
+
|
|
57
|
+
expect(first).toBe(second);
|
|
58
|
+
expect(first).toContain(TOKEN);
|
|
59
|
+
expect(highlightMemoSize()).toBe(1);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('the same code in another language is a different entry', () => {
|
|
63
|
+
highlightBlock('{"a":1}', 'json');
|
|
64
|
+
highlightBlock('{"a":1}', 'typescript');
|
|
65
|
+
expect(highlightMemoSize()).toBe(2);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('a grammar that is not ready is never cached', () => {
|
|
69
|
+
const html = highlightBlock('const a = 1;', 'not-a-real-grammar');
|
|
70
|
+
// It still renders something — escaped text, via the javascript fallback —
|
|
71
|
+
// but caching that would freeze the fallback for good.
|
|
72
|
+
expect(html).toContain('const');
|
|
73
|
+
expect(highlightMemoSize()).toBe(0);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('a find-in-progress bypasses the memo', () => {
|
|
77
|
+
highlightBlock('const a = 1;', 'typescript', { marks: [{ start: 0, end: 5 }] });
|
|
78
|
+
expect(highlightMemoSize()).toBe(0);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('empty input is not an entry', () => {
|
|
82
|
+
expect(highlightBlock('', 'typescript')).toBe('');
|
|
83
|
+
expect(highlightMemoSize()).toBe(0);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test('the per-language bound holds', () => {
|
|
87
|
+
for (let index = 0; index < 30; index += 1) {
|
|
88
|
+
highlightBlock(`const value${index} = ${index};`, 'typescript');
|
|
89
|
+
}
|
|
90
|
+
expect(highlightMemoSize()).toBeLessThanOrEqual(24);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('highlightBlockLines', () => {
|
|
95
|
+
test('lines are cached and round-trip through the same key', () => {
|
|
96
|
+
const lines = highlightBlockLines('const a = 1;\nconst b = 2;', 'typescript');
|
|
97
|
+
expect(lines).toHaveLength(2);
|
|
98
|
+
expect(highlightMemoSize()).toBe(1);
|
|
99
|
+
|
|
100
|
+
const again = highlightBlockLines('const a = 1;\nconst b = 2;', 'typescript');
|
|
101
|
+
expect(again).toEqual(lines);
|
|
102
|
+
});
|
|
103
|
+
});
|