@pyreon/code 0.5.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 +21 -0
- package/lib/analysis/index.js.html +5406 -0
- package/lib/dist-B5vB-rif.js +3904 -0
- package/lib/dist-B5vB-rif.js.map +1 -0
- package/lib/dist-BAfzu5eu.js +1428 -0
- package/lib/dist-BAfzu5eu.js.map +1 -0
- package/lib/dist-BLlV_D16.js +1166 -0
- package/lib/dist-BLlV_D16.js.map +1 -0
- package/lib/dist-BNmKLTu8.js +373 -0
- package/lib/dist-BNmKLTu8.js.map +1 -0
- package/lib/dist-BZtTlC1J.js +692 -0
- package/lib/dist-BZtTlC1J.js.map +1 -0
- package/lib/dist-CTDqGIAf.js +856 -0
- package/lib/dist-CTDqGIAf.js.map +1 -0
- package/lib/dist-CTPisNZp.js +83 -0
- package/lib/dist-CTPisNZp.js.map +1 -0
- package/lib/dist-Ce2tvOxv.js +379 -0
- package/lib/dist-Ce2tvOxv.js.map +1 -0
- package/lib/dist-CttF0OTv.js +465 -0
- package/lib/dist-CttF0OTv.js.map +1 -0
- package/lib/dist-DS2tluW9.js +818 -0
- package/lib/dist-DS2tluW9.js.map +1 -0
- package/lib/dist-DUNx9ldu.js +460 -0
- package/lib/dist-DUNx9ldu.js.map +1 -0
- package/lib/dist-Dej_yf3k.js +473 -0
- package/lib/dist-Dej_yf3k.js.map +1 -0
- package/lib/dist-DshStUxU.js +283 -0
- package/lib/dist-DshStUxU.js.map +1 -0
- package/lib/dist-qTrOe7xY.js +461 -0
- package/lib/dist-qTrOe7xY.js.map +1 -0
- package/lib/dist-v09vikKr.js +2421 -0
- package/lib/dist-v09vikKr.js.map +1 -0
- package/lib/index.js +915 -0
- package/lib/index.js.map +1 -0
- package/lib/types/dist.d.ts +798 -0
- package/lib/types/dist.d.ts.map +1 -0
- package/lib/types/dist10.d.ts +67 -0
- package/lib/types/dist10.d.ts.map +1 -0
- package/lib/types/dist11.d.ts +126 -0
- package/lib/types/dist11.d.ts.map +1 -0
- package/lib/types/dist12.d.ts +21 -0
- package/lib/types/dist12.d.ts.map +1 -0
- package/lib/types/dist13.d.ts +404 -0
- package/lib/types/dist13.d.ts.map +1 -0
- package/lib/types/dist14.d.ts +292 -0
- package/lib/types/dist14.d.ts.map +1 -0
- package/lib/types/dist15.d.ts +132 -0
- package/lib/types/dist15.d.ts.map +1 -0
- package/lib/types/dist2.d.ts +15 -0
- package/lib/types/dist2.d.ts.map +1 -0
- package/lib/types/dist3.d.ts +106 -0
- package/lib/types/dist3.d.ts.map +1 -0
- package/lib/types/dist4.d.ts +67 -0
- package/lib/types/dist4.d.ts.map +1 -0
- package/lib/types/dist5.d.ts +95 -0
- package/lib/types/dist5.d.ts.map +1 -0
- package/lib/types/dist6.d.ts +330 -0
- package/lib/types/dist6.d.ts.map +1 -0
- package/lib/types/dist7.d.ts +15 -0
- package/lib/types/dist7.d.ts.map +1 -0
- package/lib/types/dist8.d.ts +15 -0
- package/lib/types/dist8.d.ts.map +1 -0
- package/lib/types/dist9.d.ts +635 -0
- package/lib/types/dist9.d.ts.map +1 -0
- package/lib/types/index.d.ts +852 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index2.d.ts +347 -0
- package/lib/types/index2.d.ts.map +1 -0
- package/package.json +79 -0
- package/src/components/code-editor.tsx +42 -0
- package/src/components/diff-editor.tsx +97 -0
- package/src/components/tabbed-editor.tsx +86 -0
- package/src/editor.ts +652 -0
- package/src/index.ts +52 -0
- package/src/languages.ts +77 -0
- package/src/minimap.ts +160 -0
- package/src/tabbed-editor.ts +231 -0
- package/src/tests/code.test.ts +505 -0
- package/src/themes.ts +87 -0
- package/src/types.ts +253 -0
|
@@ -0,0 +1,852 @@
|
|
|
1
|
+
import { bracketMatching, defaultHighlightStyle, foldGutter, foldKeymap, indentOnInput, indentUnit, syntaxHighlighting } from "@codemirror/language";
|
|
2
|
+
import { MergeView } from "@codemirror/merge";
|
|
3
|
+
import { Compartment, EditorState } from "@codemirror/state";
|
|
4
|
+
import { Decoration, EditorView, GutterMarker, ViewPlugin, crosshairCursor, drawSelection, dropCursor, gutter, highlightActiveLine, highlightActiveLineGutter, keymap, lineNumbers, placeholder, rectangularSelection } from "@codemirror/view";
|
|
5
|
+
import { autocompletion, closeBrackets, closeBracketsKeymap, completionKeymap } from "@codemirror/autocomplete";
|
|
6
|
+
import { defaultKeymap, history, historyKeymap, indentWithTab, redo, undo } from "@codemirror/commands";
|
|
7
|
+
import { lintKeymap, setDiagnostics } from "@codemirror/lint";
|
|
8
|
+
import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";
|
|
9
|
+
import { computed, effect, signal } from "@pyreon/reactivity";
|
|
10
|
+
|
|
11
|
+
//#region \0rolldown/runtime.js
|
|
12
|
+
|
|
13
|
+
function h(type, props, ...children) {
|
|
14
|
+
return {
|
|
15
|
+
type,
|
|
16
|
+
props: props ?? EMPTY_PROPS,
|
|
17
|
+
children: normalizeChildren(children),
|
|
18
|
+
key: props?.key ?? null
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function normalizeChildren(children) {
|
|
22
|
+
for (let i = 0; i < children.length; i++) if (Array.isArray(children[i])) return flattenChildren(children);
|
|
23
|
+
return children;
|
|
24
|
+
}
|
|
25
|
+
function flattenChildren(children) {
|
|
26
|
+
const result = [];
|
|
27
|
+
for (const child of children) if (Array.isArray(child)) result.push(...flattenChildren(child));else result.push(child);
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* JSX automatic runtime.
|
|
32
|
+
*
|
|
33
|
+
* When tsconfig has `"jsxImportSource": "@pyreon/core"`, the TS/bundler compiler
|
|
34
|
+
* rewrites JSX to imports from this file automatically:
|
|
35
|
+
* <div class="x" /> → jsx("div", { class: "x" })
|
|
36
|
+
*/
|
|
37
|
+
function jsx(type, props, key) {
|
|
38
|
+
const {
|
|
39
|
+
children,
|
|
40
|
+
...rest
|
|
41
|
+
} = props;
|
|
42
|
+
const propsWithKey = key != null ? {
|
|
43
|
+
...rest,
|
|
44
|
+
key
|
|
45
|
+
} : rest;
|
|
46
|
+
if (typeof type === "function") return h(type, children !== void 0 ? {
|
|
47
|
+
...propsWithKey,
|
|
48
|
+
children
|
|
49
|
+
} : propsWithKey);
|
|
50
|
+
return h(type, propsWithKey, ...(children === void 0 ? [] : Array.isArray(children) ? children : [children]));
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/components/code-editor.tsx
|
|
54
|
+
/**
|
|
55
|
+
* Code editor component — mounts a CodeMirror 6 instance.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```tsx
|
|
59
|
+
* const editor = createEditor({
|
|
60
|
+
* value: 'const x = 1',
|
|
61
|
+
* language: 'typescript',
|
|
62
|
+
* theme: 'dark',
|
|
63
|
+
* })
|
|
64
|
+
*
|
|
65
|
+
* <CodeEditor instance={editor} style="height: 400px" />
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
function CodeEditor(props) {
|
|
69
|
+
const {
|
|
70
|
+
instance
|
|
71
|
+
} = props;
|
|
72
|
+
const containerRef = el => {
|
|
73
|
+
if (!el) return;
|
|
74
|
+
const mountable = instance;
|
|
75
|
+
if (mountable._mount) mountable._mount(el);
|
|
76
|
+
};
|
|
77
|
+
const baseStyle = `width: 100%; height: 100%; overflow: hidden; ${props.style ?? ""}`;
|
|
78
|
+
return /* @__PURE__ */jsx("div", {
|
|
79
|
+
ref: containerRef,
|
|
80
|
+
class: `pyreon-code-editor ${props.class ?? ""}`,
|
|
81
|
+
style: baseStyle
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
//#endregion
|
|
86
|
+
//#region src/languages.ts
|
|
87
|
+
/**
|
|
88
|
+
* Language extension loaders — lazy-loaded on demand.
|
|
89
|
+
* Only the requested language is imported, keeping the initial bundle small.
|
|
90
|
+
*/
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Load a language extension. Returns cached if already loaded.
|
|
94
|
+
* Language grammars are lazy-imported — zero cost until used.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* const ext = await loadLanguage('typescript')
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
async function loadLanguage(language) {
|
|
102
|
+
const cached = loaded.get(language);
|
|
103
|
+
if (cached) return cached;
|
|
104
|
+
const loader = languageLoaders[language];
|
|
105
|
+
if (!loader) return [];
|
|
106
|
+
try {
|
|
107
|
+
const ext = await loader();
|
|
108
|
+
loaded.set(language, ext);
|
|
109
|
+
return ext;
|
|
110
|
+
} catch {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get available languages.
|
|
116
|
+
*/
|
|
117
|
+
function getAvailableLanguages() {
|
|
118
|
+
return Object.keys(languageLoaders);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/themes.ts
|
|
123
|
+
/**
|
|
124
|
+
* Light theme — clean, minimal.
|
|
125
|
+
*/
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Resolve a theme value to a CodeMirror extension.
|
|
129
|
+
*/
|
|
130
|
+
function resolveTheme(theme) {
|
|
131
|
+
if (theme === "light") return lightTheme;
|
|
132
|
+
if (theme === "dark") return darkTheme;
|
|
133
|
+
return theme;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
//#endregion
|
|
137
|
+
//#region src/components/diff-editor.tsx
|
|
138
|
+
/**
|
|
139
|
+
* Side-by-side or inline diff editor using @codemirror/merge.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```tsx
|
|
143
|
+
* <DiffEditor
|
|
144
|
+
* original="const x = 1"
|
|
145
|
+
* modified="const x = 2"
|
|
146
|
+
* language="typescript"
|
|
147
|
+
* theme="dark"
|
|
148
|
+
* style="height: 400px"
|
|
149
|
+
* />
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
function DiffEditor(props) {
|
|
153
|
+
const {
|
|
154
|
+
original,
|
|
155
|
+
modified,
|
|
156
|
+
language = "plain",
|
|
157
|
+
theme = "light",
|
|
158
|
+
readOnly = true,
|
|
159
|
+
inline = false
|
|
160
|
+
} = props;
|
|
161
|
+
const containerRef = async el => {
|
|
162
|
+
if (!el) return;
|
|
163
|
+
const langExt = await loadLanguage(language);
|
|
164
|
+
const themeExt = resolveTheme(theme);
|
|
165
|
+
const extensions = [syntaxHighlighting(defaultHighlightStyle, {
|
|
166
|
+
fallback: true
|
|
167
|
+
}), langExt, themeExt, EditorView.editable.of(!readOnly), EditorState.readOnly.of(readOnly)];
|
|
168
|
+
const originalText = typeof original === "string" ? original : original();
|
|
169
|
+
const modifiedText = typeof modified === "string" ? modified : modified();
|
|
170
|
+
el.innerHTML = "";
|
|
171
|
+
if (inline) new MergeView({
|
|
172
|
+
a: {
|
|
173
|
+
doc: originalText,
|
|
174
|
+
extensions
|
|
175
|
+
},
|
|
176
|
+
b: {
|
|
177
|
+
doc: modifiedText,
|
|
178
|
+
extensions
|
|
179
|
+
},
|
|
180
|
+
parent: el,
|
|
181
|
+
collapseUnchanged: {
|
|
182
|
+
margin: 3,
|
|
183
|
+
minSize: 4
|
|
184
|
+
}
|
|
185
|
+
});else new MergeView({
|
|
186
|
+
a: {
|
|
187
|
+
doc: originalText,
|
|
188
|
+
extensions
|
|
189
|
+
},
|
|
190
|
+
b: {
|
|
191
|
+
doc: modifiedText,
|
|
192
|
+
extensions
|
|
193
|
+
},
|
|
194
|
+
parent: el,
|
|
195
|
+
collapseUnchanged: {
|
|
196
|
+
margin: 3,
|
|
197
|
+
minSize: 4
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
const baseStyle = `width: 100%; height: 100%; overflow: hidden; ${props.style ?? ""}`;
|
|
202
|
+
return /* @__PURE__ */jsx("div", {
|
|
203
|
+
ref: containerRef,
|
|
204
|
+
class: `pyreon-diff-editor ${props.class ?? ""}`,
|
|
205
|
+
style: baseStyle
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
//#endregion
|
|
210
|
+
//#region src/components/tabbed-editor.tsx
|
|
211
|
+
/**
|
|
212
|
+
* Tabbed code editor component — renders tab bar + editor.
|
|
213
|
+
* Headless styling — the tab bar is a plain div with button tabs.
|
|
214
|
+
* Consumers can style via CSS classes.
|
|
215
|
+
*
|
|
216
|
+
* @example
|
|
217
|
+
* ```tsx
|
|
218
|
+
* const editor = createTabbedEditor({
|
|
219
|
+
* tabs: [
|
|
220
|
+
* { name: 'index.ts', language: 'typescript', value: 'const x = 1' },
|
|
221
|
+
* { name: 'style.css', language: 'css', value: '.app { }' },
|
|
222
|
+
* ],
|
|
223
|
+
* theme: 'dark',
|
|
224
|
+
* })
|
|
225
|
+
*
|
|
226
|
+
* <TabbedEditor instance={editor} style="height: 500px" />
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
function TabbedEditor(props) {
|
|
230
|
+
const {
|
|
231
|
+
instance
|
|
232
|
+
} = props;
|
|
233
|
+
const containerStyle = `display: flex; flex-direction: column; width: 100%; height: 100%; ${props.style ?? ""}`;
|
|
234
|
+
const tabBarStyle = "display: flex; overflow-x: auto; background: #f1f5f9; border-bottom: 1px solid #e2e8f0; min-height: 34px; flex-shrink: 0;";
|
|
235
|
+
return /* @__PURE__ */jsxs("div", {
|
|
236
|
+
class: `pyreon-tabbed-editor ${props.class ?? ""}`,
|
|
237
|
+
style: containerStyle,
|
|
238
|
+
children: [() => {
|
|
239
|
+
const tabs = instance.tabs();
|
|
240
|
+
const activeId = instance.activeTabId();
|
|
241
|
+
return /* @__PURE__ */jsx("div", {
|
|
242
|
+
class: "pyreon-tabbed-editor-tabs",
|
|
243
|
+
style: tabBarStyle,
|
|
244
|
+
children: tabs.map(tab => {
|
|
245
|
+
const id = tab.id ?? tab.name;
|
|
246
|
+
const isActive = id === activeId;
|
|
247
|
+
const tabStyle = `display: flex; align-items: center; gap: 6px; padding: 6px 12px; border: none; background: ${isActive ? "white" : "transparent"}; border-bottom: ${isActive ? "2px solid #3b82f6" : "2px solid transparent"}; cursor: pointer; font-size: 13px; color: ${isActive ? "#1e293b" : "#64748b"}; white-space: nowrap; position: relative; font-family: inherit;`;
|
|
248
|
+
return /* @__PURE__ */jsxs("button", {
|
|
249
|
+
type: "button",
|
|
250
|
+
class: `pyreon-tab ${isActive ? "active" : ""} ${tab.modified ? "modified" : ""}`,
|
|
251
|
+
style: tabStyle,
|
|
252
|
+
onClick: () => instance.switchTab(id),
|
|
253
|
+
children: [/* @__PURE__ */jsx("span", {
|
|
254
|
+
children: tab.name
|
|
255
|
+
}), tab.modified && /* @__PURE__ */jsx("span", {
|
|
256
|
+
style: "width: 6px; height: 6px; border-radius: 50%; background: #f59e0b; flex-shrink: 0;",
|
|
257
|
+
title: "Modified"
|
|
258
|
+
}), tab.closable !== false && /* @__PURE__ */jsx("span", {
|
|
259
|
+
style: "font-size: 14px; line-height: 1; opacity: 0.5; cursor: pointer; padding: 0 2px; margin-left: 2px;",
|
|
260
|
+
title: "Close",
|
|
261
|
+
onClick: e => {
|
|
262
|
+
e.stopPropagation();
|
|
263
|
+
instance.closeTab(id);
|
|
264
|
+
},
|
|
265
|
+
children: "×"
|
|
266
|
+
})]
|
|
267
|
+
}, id);
|
|
268
|
+
})
|
|
269
|
+
});
|
|
270
|
+
}, /* @__PURE__ */jsx("div", {
|
|
271
|
+
style: "flex: 1; min-height: 0;",
|
|
272
|
+
children: /* @__PURE__ */jsx(CodeEditor, {
|
|
273
|
+
instance: instance.editor
|
|
274
|
+
})
|
|
275
|
+
})]
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
//#endregion
|
|
280
|
+
//#region src/minimap.ts
|
|
281
|
+
/**
|
|
282
|
+
* Canvas-based minimap extension for CodeMirror 6.
|
|
283
|
+
* Renders a scaled-down overview of the document on the right side.
|
|
284
|
+
*/
|
|
285
|
+
|
|
286
|
+
function createMinimapCanvas() {
|
|
287
|
+
const canvas = document.createElement("canvas");
|
|
288
|
+
canvas.style.cssText = `position: absolute; right: 0; top: 0; width: ${MINIMAP_WIDTH}px; height: 100%; cursor: pointer; z-index: 5;`;
|
|
289
|
+
canvas.width = MINIMAP_WIDTH * 2;
|
|
290
|
+
return canvas;
|
|
291
|
+
}
|
|
292
|
+
function renderMinimap(canvas, view) {
|
|
293
|
+
const ctx = canvas.getContext("2d");
|
|
294
|
+
if (!ctx) return;
|
|
295
|
+
const doc = view.state.doc;
|
|
296
|
+
const totalLines = doc.lines;
|
|
297
|
+
const height = canvas.clientHeight;
|
|
298
|
+
canvas.height = height * 2;
|
|
299
|
+
const isDark = view.dom.classList.contains("cm-dark");
|
|
300
|
+
const bg = isDark ? MINIMAP_BG : MINIMAP_BG_LIGHT;
|
|
301
|
+
const textColor = isDark ? TEXT_COLOR : TEXT_COLOR_LIGHT;
|
|
302
|
+
const scale = 2;
|
|
303
|
+
ctx.setTransform(scale, 0, 0, scale, 0, 0);
|
|
304
|
+
ctx.fillStyle = bg;
|
|
305
|
+
ctx.fillRect(0, 0, MINIMAP_WIDTH, height);
|
|
306
|
+
const contentHeight = totalLines * LINE_HEIGHT;
|
|
307
|
+
const scrollFraction = contentHeight > height ? view.scrollDOM.scrollTop / (view.scrollDOM.scrollHeight - view.scrollDOM.clientHeight || 1) : 0;
|
|
308
|
+
const offset = contentHeight > height ? scrollFraction * (contentHeight - height) : 0;
|
|
309
|
+
ctx.fillStyle = textColor;
|
|
310
|
+
const startLine = Math.max(1, Math.floor(offset / LINE_HEIGHT));
|
|
311
|
+
const endLine = Math.min(totalLines, startLine + Math.ceil(height / LINE_HEIGHT) + 1);
|
|
312
|
+
for (let i = startLine; i <= endLine; i++) {
|
|
313
|
+
const line = doc.line(i);
|
|
314
|
+
const y = (i - 1) * LINE_HEIGHT - offset;
|
|
315
|
+
if (y < -LINE_HEIGHT || y > height) continue;
|
|
316
|
+
const text = line.text;
|
|
317
|
+
let x = 4;
|
|
318
|
+
for (let j = 0; j < Math.min(text.length, 60); j++) {
|
|
319
|
+
if (text[j] !== " " && text[j] !== " ") ctx.fillRect(x, y, CHAR_WIDTH, 1.5);
|
|
320
|
+
x += CHAR_WIDTH;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
const viewportTop = view.scrollDOM.scrollTop;
|
|
324
|
+
const viewportHeight = view.scrollDOM.clientHeight;
|
|
325
|
+
const docHeight = view.scrollDOM.scrollHeight || 1;
|
|
326
|
+
const vpY = viewportTop / docHeight * Math.min(contentHeight, height);
|
|
327
|
+
const vpH = viewportHeight / docHeight * Math.min(contentHeight, height);
|
|
328
|
+
ctx.fillStyle = VIEWPORT_COLOR;
|
|
329
|
+
ctx.fillRect(0, vpY, MINIMAP_WIDTH, vpH);
|
|
330
|
+
ctx.strokeStyle = VIEWPORT_BORDER;
|
|
331
|
+
ctx.lineWidth = 1;
|
|
332
|
+
ctx.strokeRect(.5, vpY + .5, MINIMAP_WIDTH - 1, vpH - 1);
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* CodeMirror 6 minimap extension.
|
|
336
|
+
* Renders a canvas-based code overview on the right side of the editor.
|
|
337
|
+
*
|
|
338
|
+
* @example
|
|
339
|
+
* ```ts
|
|
340
|
+
* import { minimapExtension } from '@pyreon/code'
|
|
341
|
+
* // Add to editor extensions
|
|
342
|
+
* ```
|
|
343
|
+
*/
|
|
344
|
+
function minimapExtension() {
|
|
345
|
+
return [ViewPlugin.fromClass(class {
|
|
346
|
+
canvas;
|
|
347
|
+
view;
|
|
348
|
+
animFrame = null;
|
|
349
|
+
constructor(view) {
|
|
350
|
+
this.view = view;
|
|
351
|
+
this.canvas = createMinimapCanvas();
|
|
352
|
+
view.dom.style.position = "relative";
|
|
353
|
+
view.dom.appendChild(this.canvas);
|
|
354
|
+
this.canvas.addEventListener("click", e => {
|
|
355
|
+
const rect = this.canvas.getBoundingClientRect();
|
|
356
|
+
const scrollTarget = (e.clientY - rect.top) / rect.height * (view.scrollDOM.scrollHeight - view.scrollDOM.clientHeight);
|
|
357
|
+
view.scrollDOM.scrollTo({
|
|
358
|
+
top: scrollTarget,
|
|
359
|
+
behavior: "smooth"
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
this.render();
|
|
363
|
+
}
|
|
364
|
+
render() {
|
|
365
|
+
renderMinimap(this.canvas, this.view);
|
|
366
|
+
}
|
|
367
|
+
update(update) {
|
|
368
|
+
if (update.docChanged || update.viewportChanged || update.geometryChanged) {
|
|
369
|
+
if (this.animFrame) cancelAnimationFrame(this.animFrame);
|
|
370
|
+
this.animFrame = requestAnimationFrame(() => this.render());
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
destroy() {
|
|
374
|
+
if (this.animFrame) cancelAnimationFrame(this.animFrame);
|
|
375
|
+
this.canvas.remove();
|
|
376
|
+
}
|
|
377
|
+
}), EditorView.theme({
|
|
378
|
+
".cm-scroller": {
|
|
379
|
+
paddingRight: `${MINIMAP_WIDTH + 8}px`
|
|
380
|
+
}
|
|
381
|
+
})];
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
//#endregion
|
|
385
|
+
//#region src/editor.ts
|
|
386
|
+
/**
|
|
387
|
+
* Create a reactive code editor instance.
|
|
388
|
+
*
|
|
389
|
+
* The editor state (value, language, theme, cursor, selection) is backed
|
|
390
|
+
* by signals. The CodeMirror EditorView is created when mounted via
|
|
391
|
+
* the `<CodeEditor>` component.
|
|
392
|
+
*
|
|
393
|
+
* @param config - Editor configuration
|
|
394
|
+
* @returns A reactive EditorInstance
|
|
395
|
+
*
|
|
396
|
+
* @example
|
|
397
|
+
* ```tsx
|
|
398
|
+
* const editor = createEditor({
|
|
399
|
+
* value: 'const x = 1',
|
|
400
|
+
* language: 'typescript',
|
|
401
|
+
* theme: 'dark',
|
|
402
|
+
* })
|
|
403
|
+
*
|
|
404
|
+
* editor.value() // reactive
|
|
405
|
+
* editor.value.set('new') // updates editor
|
|
406
|
+
*
|
|
407
|
+
* <CodeEditor instance={editor} />
|
|
408
|
+
* ```
|
|
409
|
+
*/
|
|
410
|
+
function createEditor(config = {}) {
|
|
411
|
+
const {
|
|
412
|
+
value: initialValue = "",
|
|
413
|
+
language: initialLanguage = "plain",
|
|
414
|
+
theme: initialTheme = "light",
|
|
415
|
+
lineNumbers: showLineNumbers = true,
|
|
416
|
+
readOnly: initialReadOnly = false,
|
|
417
|
+
foldGutter: showFoldGutter = true,
|
|
418
|
+
bracketMatching: enableBracketMatching = true,
|
|
419
|
+
autocomplete: enableAutocomplete = true,
|
|
420
|
+
search: _enableSearch = true,
|
|
421
|
+
highlightIndentGuides: enableIndentGuides = true,
|
|
422
|
+
vim: enableVim = false,
|
|
423
|
+
emacs: enableEmacs = false,
|
|
424
|
+
tabSize: configTabSize = 2,
|
|
425
|
+
lineWrapping: enableLineWrapping = false,
|
|
426
|
+
placeholder: placeholderText,
|
|
427
|
+
minimap: enableMinimap = false,
|
|
428
|
+
extensions: userExtensions = [],
|
|
429
|
+
onChange
|
|
430
|
+
} = config;
|
|
431
|
+
const value = signal(initialValue);
|
|
432
|
+
const language = signal(initialLanguage);
|
|
433
|
+
const theme = signal(initialTheme);
|
|
434
|
+
const readOnly = signal(initialReadOnly);
|
|
435
|
+
const focused = signal(false);
|
|
436
|
+
const view = signal(null);
|
|
437
|
+
const docVersion = signal(0);
|
|
438
|
+
const languageCompartment = new Compartment();
|
|
439
|
+
const themeCompartment = new Compartment();
|
|
440
|
+
const readOnlyCompartment = new Compartment();
|
|
441
|
+
const extraKeymapCompartment = new Compartment();
|
|
442
|
+
const keyModeCompartment = new Compartment();
|
|
443
|
+
const cursor = computed(() => {
|
|
444
|
+
docVersion();
|
|
445
|
+
const v = view.peek();
|
|
446
|
+
if (!v) return {
|
|
447
|
+
line: 1,
|
|
448
|
+
col: 1
|
|
449
|
+
};
|
|
450
|
+
const pos = v.state.selection.main.head;
|
|
451
|
+
const line = v.state.doc.lineAt(pos);
|
|
452
|
+
return {
|
|
453
|
+
line: line.number,
|
|
454
|
+
col: pos - line.from + 1
|
|
455
|
+
};
|
|
456
|
+
});
|
|
457
|
+
const selection = computed(() => {
|
|
458
|
+
docVersion();
|
|
459
|
+
const v = view.peek();
|
|
460
|
+
if (!v) return {
|
|
461
|
+
from: 0,
|
|
462
|
+
to: 0,
|
|
463
|
+
text: ""
|
|
464
|
+
};
|
|
465
|
+
const sel = v.state.selection.main;
|
|
466
|
+
return {
|
|
467
|
+
from: sel.from,
|
|
468
|
+
to: sel.to,
|
|
469
|
+
text: v.state.sliceDoc(sel.from, sel.to)
|
|
470
|
+
};
|
|
471
|
+
});
|
|
472
|
+
const lineCount = computed(() => {
|
|
473
|
+
docVersion();
|
|
474
|
+
const v = view.peek();
|
|
475
|
+
return v ? v.state.doc.lines : initialValue.split("\n").length;
|
|
476
|
+
});
|
|
477
|
+
const lineHighlights = /* @__PURE__ */new Map();
|
|
478
|
+
const lineHighlightField = ViewPlugin.fromClass(class {
|
|
479
|
+
decorations;
|
|
480
|
+
constructor(editorView) {
|
|
481
|
+
this.decorations = this.buildDecos(editorView);
|
|
482
|
+
}
|
|
483
|
+
buildDecos(editorView) {
|
|
484
|
+
const ranges = [];
|
|
485
|
+
for (const [lineNum, cls] of lineHighlights) if (lineNum >= 1 && lineNum <= editorView.state.doc.lines) {
|
|
486
|
+
const lineInfo = editorView.state.doc.line(lineNum);
|
|
487
|
+
ranges.push({
|
|
488
|
+
from: lineInfo.from,
|
|
489
|
+
deco: Decoration.line({
|
|
490
|
+
class: cls
|
|
491
|
+
})
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
return Decoration.set(ranges.sort((a, b) => a.from - b.from).map(d => d.deco.range(d.from)));
|
|
495
|
+
}
|
|
496
|
+
update(upd) {
|
|
497
|
+
if (upd.docChanged || upd.viewportChanged) this.decorations = this.buildDecos(upd.view);
|
|
498
|
+
}
|
|
499
|
+
}, {
|
|
500
|
+
decorations: plugin => plugin.decorations
|
|
501
|
+
});
|
|
502
|
+
const gutterMarkers = /* @__PURE__ */new Map();
|
|
503
|
+
class CustomGutterMarker extends GutterMarker {
|
|
504
|
+
markerText;
|
|
505
|
+
markerTitle;
|
|
506
|
+
markerClass;
|
|
507
|
+
constructor(opts) {
|
|
508
|
+
super();
|
|
509
|
+
this.markerText = opts.text ?? "";
|
|
510
|
+
this.markerTitle = opts.title ?? "";
|
|
511
|
+
this.markerClass = opts.class ?? "";
|
|
512
|
+
}
|
|
513
|
+
toDOM() {
|
|
514
|
+
const el = document.createElement("span");
|
|
515
|
+
el.textContent = this.markerText;
|
|
516
|
+
el.title = this.markerTitle;
|
|
517
|
+
if (this.markerClass) el.className = this.markerClass;
|
|
518
|
+
el.style.cssText = "cursor: pointer; display: inline-block; width: 100%; text-align: center;";
|
|
519
|
+
return el;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
const gutterMarkerExtension = gutter({
|
|
523
|
+
class: "pyreon-code-gutter-markers",
|
|
524
|
+
lineMarker: (gutterView, line) => {
|
|
525
|
+
const lineNo = gutterView.state.doc.lineAt(line.from).number;
|
|
526
|
+
const marker = gutterMarkers.get(lineNo);
|
|
527
|
+
if (!marker) return null;
|
|
528
|
+
return new CustomGutterMarker(marker);
|
|
529
|
+
},
|
|
530
|
+
initialSpacer: () => new CustomGutterMarker({
|
|
531
|
+
text: " "
|
|
532
|
+
})
|
|
533
|
+
});
|
|
534
|
+
function buildExtensions(langExt) {
|
|
535
|
+
const exts = [history(), drawSelection(), dropCursor(), rectangularSelection(), crosshairCursor(), highlightActiveLine(), highlightActiveLineGutter(), highlightSelectionMatches(), indentOnInput(), syntaxHighlighting(defaultHighlightStyle, {
|
|
536
|
+
fallback: true
|
|
537
|
+
}), indentUnit.of(" ".repeat(configTabSize)), keymap.of([...closeBracketsKeymap, ...defaultKeymap, ...searchKeymap, ...historyKeymap, ...foldKeymap, ...completionKeymap, ...lintKeymap, indentWithTab]), languageCompartment.of(langExt), themeCompartment.of(resolveTheme(initialTheme)), readOnlyCompartment.of(EditorState.readOnly.of(initialReadOnly)), extraKeymapCompartment.of([]), keyModeCompartment.of([]), EditorView.updateListener.of(update => {
|
|
538
|
+
if (update.docChanged) {
|
|
539
|
+
const newValue = update.state.doc.toString();
|
|
540
|
+
if (newValue !== value.peek()) {
|
|
541
|
+
value.set(newValue);
|
|
542
|
+
onChange?.(newValue);
|
|
543
|
+
}
|
|
544
|
+
docVersion.update(v => v + 1);
|
|
545
|
+
}
|
|
546
|
+
if (update.selectionSet) docVersion.update(v => v + 1);
|
|
547
|
+
if (update.focusChanged) focused.set(update.view.hasFocus);
|
|
548
|
+
})];
|
|
549
|
+
if (showLineNumbers) exts.push(lineNumbers());
|
|
550
|
+
if (showFoldGutter) exts.push(foldGutter());
|
|
551
|
+
if (enableBracketMatching) exts.push(bracketMatching(), closeBrackets());
|
|
552
|
+
if (enableAutocomplete) exts.push(autocompletion());
|
|
553
|
+
if (enableLineWrapping) exts.push(EditorView.lineWrapping);
|
|
554
|
+
if (enableIndentGuides) exts.push(EditorView.theme({
|
|
555
|
+
".cm-line": {
|
|
556
|
+
backgroundImage: "linear-gradient(to right, #e5e7eb 1px, transparent 1px)",
|
|
557
|
+
backgroundSize: `${configTabSize}ch 100%`,
|
|
558
|
+
backgroundPosition: "0 0"
|
|
559
|
+
}
|
|
560
|
+
}));
|
|
561
|
+
if (placeholderText) exts.push(placeholder(placeholderText));
|
|
562
|
+
if (enableMinimap) exts.push(minimapExtension());
|
|
563
|
+
exts.push(lineHighlightField);
|
|
564
|
+
exts.push(gutterMarkerExtension);
|
|
565
|
+
exts.push(...userExtensions);
|
|
566
|
+
return exts;
|
|
567
|
+
}
|
|
568
|
+
let mounted = false;
|
|
569
|
+
async function mount(parent) {
|
|
570
|
+
if (mounted) return;
|
|
571
|
+
const extensions = buildExtensions(await loadLanguage(language.peek()));
|
|
572
|
+
const editorView = new EditorView({
|
|
573
|
+
state: EditorState.create({
|
|
574
|
+
doc: value.peek(),
|
|
575
|
+
extensions
|
|
576
|
+
}),
|
|
577
|
+
parent
|
|
578
|
+
});
|
|
579
|
+
view.set(editorView);
|
|
580
|
+
mounted = true;
|
|
581
|
+
effect(() => {
|
|
582
|
+
const val = value();
|
|
583
|
+
const v = view.peek();
|
|
584
|
+
if (!v) return;
|
|
585
|
+
const current = v.state.doc.toString();
|
|
586
|
+
if (val !== current) v.dispatch({
|
|
587
|
+
changes: {
|
|
588
|
+
from: 0,
|
|
589
|
+
to: current.length,
|
|
590
|
+
insert: val
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
});
|
|
594
|
+
effect(() => {
|
|
595
|
+
const lang = language();
|
|
596
|
+
const v = view.peek();
|
|
597
|
+
if (!v) return;
|
|
598
|
+
loadLanguage(lang).then(ext => {
|
|
599
|
+
v.dispatch({
|
|
600
|
+
effects: languageCompartment.reconfigure(ext)
|
|
601
|
+
});
|
|
602
|
+
});
|
|
603
|
+
});
|
|
604
|
+
effect(() => {
|
|
605
|
+
const t = theme();
|
|
606
|
+
const v = view.peek();
|
|
607
|
+
if (!v) return;
|
|
608
|
+
v.dispatch({
|
|
609
|
+
effects: themeCompartment.reconfigure(resolveTheme(t))
|
|
610
|
+
});
|
|
611
|
+
});
|
|
612
|
+
effect(() => {
|
|
613
|
+
const ro = readOnly();
|
|
614
|
+
const v = view.peek();
|
|
615
|
+
if (!v) return;
|
|
616
|
+
v.dispatch({
|
|
617
|
+
effects: readOnlyCompartment.reconfigure(EditorState.readOnly.of(ro))
|
|
618
|
+
});
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
function focus() {
|
|
622
|
+
view.peek()?.focus();
|
|
623
|
+
}
|
|
624
|
+
function insert(text) {
|
|
625
|
+
const v = view.peek();
|
|
626
|
+
if (!v) return;
|
|
627
|
+
const pos = v.state.selection.main.head;
|
|
628
|
+
v.dispatch({
|
|
629
|
+
changes: {
|
|
630
|
+
from: pos,
|
|
631
|
+
insert: text
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
function replaceSelection(text) {
|
|
636
|
+
const v = view.peek();
|
|
637
|
+
if (!v) return;
|
|
638
|
+
v.dispatch(v.state.replaceSelection(text));
|
|
639
|
+
}
|
|
640
|
+
function select(from, to) {
|
|
641
|
+
const v = view.peek();
|
|
642
|
+
if (!v) return;
|
|
643
|
+
v.dispatch({
|
|
644
|
+
selection: {
|
|
645
|
+
anchor: from,
|
|
646
|
+
head: to
|
|
647
|
+
}
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
function selectAll() {
|
|
651
|
+
const v = view.peek();
|
|
652
|
+
if (!v) return;
|
|
653
|
+
v.dispatch({
|
|
654
|
+
selection: {
|
|
655
|
+
anchor: 0,
|
|
656
|
+
head: v.state.doc.length
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
function goToLine(line) {
|
|
661
|
+
const v = view.peek();
|
|
662
|
+
if (!v) return;
|
|
663
|
+
const lineInfo = v.state.doc.line(Math.min(Math.max(1, line), v.state.doc.lines));
|
|
664
|
+
v.dispatch({
|
|
665
|
+
selection: {
|
|
666
|
+
anchor: lineInfo.from
|
|
667
|
+
},
|
|
668
|
+
scrollIntoView: true
|
|
669
|
+
});
|
|
670
|
+
v.focus();
|
|
671
|
+
}
|
|
672
|
+
function undo$1() {
|
|
673
|
+
const v = view.peek();
|
|
674
|
+
if (v) undo(v);
|
|
675
|
+
}
|
|
676
|
+
function redo$1() {
|
|
677
|
+
const v = view.peek();
|
|
678
|
+
if (v) redo(v);
|
|
679
|
+
}
|
|
680
|
+
function foldAll() {
|
|
681
|
+
const v = view.peek();
|
|
682
|
+
if (!v) return;
|
|
683
|
+
const {
|
|
684
|
+
foldAll: foldAllCmd
|
|
685
|
+
} = __require("@codemirror/language");
|
|
686
|
+
foldAllCmd(v);
|
|
687
|
+
}
|
|
688
|
+
function unfoldAll() {
|
|
689
|
+
const v = view.peek();
|
|
690
|
+
if (!v) return;
|
|
691
|
+
const {
|
|
692
|
+
unfoldAll: unfoldAllCmd
|
|
693
|
+
} = __require("@codemirror/language");
|
|
694
|
+
unfoldAllCmd(v);
|
|
695
|
+
}
|
|
696
|
+
function setDiagnostics$1(diagnostics) {
|
|
697
|
+
const v = view.peek();
|
|
698
|
+
if (!v) return;
|
|
699
|
+
v.dispatch(setDiagnostics(v.state, diagnostics.map(d => ({
|
|
700
|
+
from: d.from,
|
|
701
|
+
to: d.to,
|
|
702
|
+
severity: d.severity === "hint" ? "info" : d.severity,
|
|
703
|
+
message: d.message,
|
|
704
|
+
source: d.source
|
|
705
|
+
}))));
|
|
706
|
+
}
|
|
707
|
+
function clearDiagnostics() {
|
|
708
|
+
const v = view.peek();
|
|
709
|
+
if (!v) return;
|
|
710
|
+
v.dispatch(setDiagnostics(v.state, []));
|
|
711
|
+
}
|
|
712
|
+
function highlightLine(line, className) {
|
|
713
|
+
lineHighlights.set(line, className);
|
|
714
|
+
const v = view.peek();
|
|
715
|
+
if (v) v.dispatch({
|
|
716
|
+
effects: []
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
function clearLineHighlights() {
|
|
720
|
+
lineHighlights.clear();
|
|
721
|
+
const v = view.peek();
|
|
722
|
+
if (v) v.dispatch({
|
|
723
|
+
effects: []
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
function setGutterMarker(line, marker) {
|
|
727
|
+
gutterMarkers.set(line, marker);
|
|
728
|
+
const v = view.peek();
|
|
729
|
+
if (v) v.dispatch({
|
|
730
|
+
effects: []
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
function clearGutterMarkers() {
|
|
734
|
+
gutterMarkers.clear();
|
|
735
|
+
const v = view.peek();
|
|
736
|
+
if (v) v.dispatch({
|
|
737
|
+
effects: []
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
const customKeybindings = [];
|
|
741
|
+
function addKeybinding(key, handler) {
|
|
742
|
+
customKeybindings.push({
|
|
743
|
+
key,
|
|
744
|
+
run: () => {
|
|
745
|
+
handler();
|
|
746
|
+
return true;
|
|
747
|
+
}
|
|
748
|
+
});
|
|
749
|
+
const v = view.peek();
|
|
750
|
+
if (!v) return;
|
|
751
|
+
v.dispatch({
|
|
752
|
+
effects: extraKeymapCompartment.reconfigure(keymap.of(customKeybindings))
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
function getLine(line) {
|
|
756
|
+
const v = view.peek();
|
|
757
|
+
if (!v) return "";
|
|
758
|
+
const clamped = Math.min(Math.max(1, line), v.state.doc.lines);
|
|
759
|
+
return v.state.doc.line(clamped).text;
|
|
760
|
+
}
|
|
761
|
+
function getWordAtCursor() {
|
|
762
|
+
const v = view.peek();
|
|
763
|
+
if (!v) return "";
|
|
764
|
+
const pos = v.state.selection.main.head;
|
|
765
|
+
const line = v.state.doc.lineAt(pos);
|
|
766
|
+
const col = pos - line.from;
|
|
767
|
+
const text = line.text;
|
|
768
|
+
let start = col;
|
|
769
|
+
let end = col;
|
|
770
|
+
while (start > 0 && /\w/.test(text[start - 1])) start--;
|
|
771
|
+
while (end < text.length && /\w/.test(text[end])) end++;
|
|
772
|
+
return text.slice(start, end);
|
|
773
|
+
}
|
|
774
|
+
function scrollTo(pos) {
|
|
775
|
+
const v = view.peek();
|
|
776
|
+
if (!v) return;
|
|
777
|
+
v.dispatch({
|
|
778
|
+
effects: EditorView.scrollIntoView(pos, {
|
|
779
|
+
y: "center"
|
|
780
|
+
})
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
async function loadKeyMode() {
|
|
784
|
+
const v = view.peek();
|
|
785
|
+
if (!v) return;
|
|
786
|
+
const vimPkg = "@replit/codemirror-vim";
|
|
787
|
+
const emacsPkg = "@replit/codemirror-emacs";
|
|
788
|
+
if (enableVim) try {
|
|
789
|
+
const mod = await import(/* @vite-ignore */
|
|
790
|
+
vimPkg);
|
|
791
|
+
v.dispatch({
|
|
792
|
+
effects: keyModeCompartment.reconfigure(mod.vim())
|
|
793
|
+
});
|
|
794
|
+
} catch {}
|
|
795
|
+
if (enableEmacs) try {
|
|
796
|
+
const mod = await import(/* @vite-ignore */
|
|
797
|
+
emacsPkg);
|
|
798
|
+
v.dispatch({
|
|
799
|
+
effects: keyModeCompartment.reconfigure(mod.emacs())
|
|
800
|
+
});
|
|
801
|
+
} catch {}
|
|
802
|
+
}
|
|
803
|
+
function dispose() {
|
|
804
|
+
const v = view.peek();
|
|
805
|
+
if (v) {
|
|
806
|
+
v.destroy();
|
|
807
|
+
view.set(null);
|
|
808
|
+
mounted = false;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
return {
|
|
812
|
+
value,
|
|
813
|
+
language,
|
|
814
|
+
theme,
|
|
815
|
+
readOnly,
|
|
816
|
+
cursor,
|
|
817
|
+
selection,
|
|
818
|
+
lineCount,
|
|
819
|
+
focused,
|
|
820
|
+
view,
|
|
821
|
+
focus,
|
|
822
|
+
insert,
|
|
823
|
+
replaceSelection,
|
|
824
|
+
select,
|
|
825
|
+
selectAll,
|
|
826
|
+
goToLine,
|
|
827
|
+
undo: undo$1,
|
|
828
|
+
redo: redo$1,
|
|
829
|
+
foldAll,
|
|
830
|
+
unfoldAll,
|
|
831
|
+
setDiagnostics: setDiagnostics$1,
|
|
832
|
+
clearDiagnostics,
|
|
833
|
+
highlightLine,
|
|
834
|
+
clearLineHighlights,
|
|
835
|
+
setGutterMarker,
|
|
836
|
+
clearGutterMarkers,
|
|
837
|
+
addKeybinding,
|
|
838
|
+
getLine,
|
|
839
|
+
getWordAtCursor,
|
|
840
|
+
scrollTo,
|
|
841
|
+
config,
|
|
842
|
+
dispose,
|
|
843
|
+
_mount: async parent => {
|
|
844
|
+
await mount(parent);
|
|
845
|
+
await loadKeyMode();
|
|
846
|
+
}
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
//#endregion
|
|
851
|
+
export { CodeEditor, DiffEditor, TabbedEditor, createEditor, darkTheme, getAvailableLanguages, lightTheme, loadLanguage, minimapExtension, resolveTheme, __exportAll as t };
|
|
852
|
+
//# sourceMappingURL=index.d.ts.map
|