@pyreon/code 0.6.0 → 0.7.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/lib/types/index.d.ts +326 -831
- package/lib/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/lib/types/dist.d.ts +0 -798
- package/lib/types/dist.d.ts.map +0 -1
- package/lib/types/dist10.d.ts +0 -67
- package/lib/types/dist10.d.ts.map +0 -1
- package/lib/types/dist11.d.ts +0 -126
- package/lib/types/dist11.d.ts.map +0 -1
- package/lib/types/dist12.d.ts +0 -21
- package/lib/types/dist12.d.ts.map +0 -1
- package/lib/types/dist13.d.ts +0 -404
- package/lib/types/dist13.d.ts.map +0 -1
- package/lib/types/dist14.d.ts +0 -292
- package/lib/types/dist14.d.ts.map +0 -1
- package/lib/types/dist15.d.ts +0 -132
- package/lib/types/dist15.d.ts.map +0 -1
- package/lib/types/dist2.d.ts +0 -15
- package/lib/types/dist2.d.ts.map +0 -1
- package/lib/types/dist3.d.ts +0 -106
- package/lib/types/dist3.d.ts.map +0 -1
- package/lib/types/dist4.d.ts +0 -67
- package/lib/types/dist4.d.ts.map +0 -1
- package/lib/types/dist5.d.ts +0 -95
- package/lib/types/dist5.d.ts.map +0 -1
- package/lib/types/dist6.d.ts +0 -330
- package/lib/types/dist6.d.ts.map +0 -1
- package/lib/types/dist7.d.ts +0 -15
- package/lib/types/dist7.d.ts.map +0 -1
- package/lib/types/dist8.d.ts +0 -15
- package/lib/types/dist8.d.ts.map +0 -1
- package/lib/types/dist9.d.ts +0 -635
- package/lib/types/dist9.d.ts.map +0 -1
- package/lib/types/index2.d.ts +0 -347
- package/lib/types/index2.d.ts.map +0 -1
package/lib/types/index.d.ts
CHANGED
|
@@ -1,852 +1,347 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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";
|
|
1
|
+
import { VNodeChild } from "@pyreon/core";
|
|
2
|
+
import { Extension } from "@codemirror/state";
|
|
3
|
+
import { EditorView } from "@codemirror/view";
|
|
4
|
+
import { Computed, Signal } from "@pyreon/reactivity";
|
|
10
5
|
|
|
11
|
-
//#region
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
6
|
+
//#region src/types.d.ts
|
|
7
|
+
type EditorLanguage = 'javascript' | 'typescript' | 'jsx' | 'tsx' | 'html' | 'css' | 'json' | 'markdown' | 'python' | 'rust' | 'sql' | 'xml' | 'yaml' | 'cpp' | 'java' | 'go' | 'php' | 'ruby' | 'shell' | 'plain';
|
|
8
|
+
type EditorTheme = 'light' | 'dark' | Extension;
|
|
9
|
+
interface EditorConfig {
|
|
10
|
+
/** Initial value */
|
|
11
|
+
value?: string;
|
|
12
|
+
/** Language for syntax highlighting — lazy-loaded */
|
|
13
|
+
language?: EditorLanguage;
|
|
14
|
+
/** Theme — 'light', 'dark', or a custom CodeMirror theme extension */
|
|
15
|
+
theme?: EditorTheme;
|
|
16
|
+
/** Show line numbers — default: true */
|
|
17
|
+
lineNumbers?: boolean;
|
|
18
|
+
/** Read-only mode — default: false */
|
|
19
|
+
readOnly?: boolean;
|
|
20
|
+
/** Enable code folding — default: true */
|
|
21
|
+
foldGutter?: boolean;
|
|
22
|
+
/** Enable bracket matching — default: true */
|
|
23
|
+
bracketMatching?: boolean;
|
|
24
|
+
/** Enable autocomplete — default: true */
|
|
25
|
+
autocomplete?: boolean;
|
|
26
|
+
/** Enable search (Cmd+F) — default: true */
|
|
27
|
+
search?: boolean;
|
|
28
|
+
/** Enable lint/diagnostics — default: false */
|
|
29
|
+
lint?: boolean;
|
|
30
|
+
/** Enable indent guides — default: true */
|
|
31
|
+
highlightIndentGuides?: boolean;
|
|
32
|
+
/** Vim keybinding mode — default: false */
|
|
33
|
+
vim?: boolean;
|
|
34
|
+
/** Emacs keybinding mode — default: false */
|
|
35
|
+
emacs?: boolean;
|
|
36
|
+
/** Tab size — default: 2 */
|
|
37
|
+
tabSize?: number;
|
|
38
|
+
/** Enable indent guides — default: true */
|
|
39
|
+
indentGuides?: boolean;
|
|
40
|
+
/** Enable line wrapping — default: false */
|
|
41
|
+
lineWrapping?: boolean;
|
|
42
|
+
/** Placeholder text when empty */
|
|
43
|
+
placeholder?: string;
|
|
44
|
+
/** Enable minimap — default: false */
|
|
45
|
+
minimap?: boolean;
|
|
46
|
+
/** Additional CodeMirror extensions */
|
|
47
|
+
extensions?: Extension[];
|
|
48
|
+
/** Called when value changes */
|
|
49
|
+
onChange?: (value: string) => void;
|
|
20
50
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
51
|
+
interface EditorInstance {
|
|
52
|
+
/** Current editor value — reactive signal */
|
|
53
|
+
value: Signal<string>;
|
|
54
|
+
/** Current language — reactive signal */
|
|
55
|
+
language: Signal<EditorLanguage>;
|
|
56
|
+
/** Current theme — reactive signal */
|
|
57
|
+
theme: Signal<EditorTheme>;
|
|
58
|
+
/** Read-only state — reactive signal */
|
|
59
|
+
readOnly: Signal<boolean>;
|
|
60
|
+
/** Cursor position — reactive */
|
|
61
|
+
cursor: Computed<{
|
|
62
|
+
line: number;
|
|
63
|
+
col: number;
|
|
64
|
+
}>;
|
|
65
|
+
/** Current selection — reactive */
|
|
66
|
+
selection: Computed<{
|
|
67
|
+
from: number;
|
|
68
|
+
to: number;
|
|
69
|
+
text: string;
|
|
70
|
+
}>;
|
|
71
|
+
/** Line count — reactive */
|
|
72
|
+
lineCount: Computed<number>;
|
|
73
|
+
/** Whether the editor has focus — reactive */
|
|
74
|
+
focused: Signal<boolean>;
|
|
75
|
+
/** The underlying CodeMirror EditorView — null until mounted */
|
|
76
|
+
view: Signal<EditorView | null>;
|
|
77
|
+
/** Focus the editor */
|
|
78
|
+
focus: () => void;
|
|
79
|
+
/** Insert text at cursor */
|
|
80
|
+
insert: (text: string) => void;
|
|
81
|
+
/** Replace selection */
|
|
82
|
+
replaceSelection: (text: string) => void;
|
|
83
|
+
/** Select a range */
|
|
84
|
+
select: (from: number, to: number) => void;
|
|
85
|
+
/** Select all */
|
|
86
|
+
selectAll: () => void;
|
|
87
|
+
/** Go to a specific line */
|
|
88
|
+
goToLine: (line: number) => void;
|
|
89
|
+
/** Undo */
|
|
90
|
+
undo: () => void;
|
|
91
|
+
/** Redo */
|
|
92
|
+
redo: () => void;
|
|
93
|
+
/** Fold all */
|
|
94
|
+
foldAll: () => void;
|
|
95
|
+
/** Unfold all */
|
|
96
|
+
unfoldAll: () => void;
|
|
97
|
+
/** Set diagnostics (lint errors/warnings) */
|
|
98
|
+
setDiagnostics: (diagnostics: Diagnostic[]) => void;
|
|
99
|
+
/** Clear all diagnostics */
|
|
100
|
+
clearDiagnostics: () => void;
|
|
101
|
+
/** Highlight a specific line (e.g., error line, current execution) */
|
|
102
|
+
highlightLine: (line: number, className: string) => void;
|
|
103
|
+
/** Clear all line highlights */
|
|
104
|
+
clearLineHighlights: () => void;
|
|
105
|
+
/** Set gutter markers (breakpoints, error icons) */
|
|
106
|
+
setGutterMarker: (line: number, marker: GutterMarker) => void;
|
|
107
|
+
/** Clear all gutter markers */
|
|
108
|
+
clearGutterMarkers: () => void;
|
|
109
|
+
/** Add a custom keybinding */
|
|
110
|
+
addKeybinding: (key: string, handler: () => boolean | undefined) => void;
|
|
111
|
+
/** Get the text of a specific line */
|
|
112
|
+
getLine: (line: number) => string;
|
|
113
|
+
/** Get word at cursor position */
|
|
114
|
+
getWordAtCursor: () => string;
|
|
115
|
+
/** Scroll to a specific position */
|
|
116
|
+
scrollTo: (pos: number) => void;
|
|
117
|
+
/** The editor configuration */
|
|
118
|
+
config: EditorConfig;
|
|
119
|
+
/** Dispose — clean up view and listeners */
|
|
120
|
+
dispose: () => void;
|
|
24
121
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
122
|
+
interface Diagnostic {
|
|
123
|
+
/** Start position (character offset) */
|
|
124
|
+
from: number;
|
|
125
|
+
/** End position (character offset) */
|
|
126
|
+
to: number;
|
|
127
|
+
/** Severity */
|
|
128
|
+
severity: 'error' | 'warning' | 'info' | 'hint';
|
|
129
|
+
/** Message */
|
|
130
|
+
message: string;
|
|
131
|
+
/** Optional source (e.g., "typescript", "eslint") */
|
|
132
|
+
source?: string;
|
|
29
133
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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]));
|
|
134
|
+
interface GutterMarker {
|
|
135
|
+
/** CSS class for the marker element */
|
|
136
|
+
class?: string;
|
|
137
|
+
/** Text content (e.g., emoji or icon) */
|
|
138
|
+
text?: string;
|
|
139
|
+
/** Tooltip on hover */
|
|
140
|
+
title?: string;
|
|
51
141
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
});
|
|
142
|
+
interface CodeEditorProps {
|
|
143
|
+
instance: EditorInstance;
|
|
144
|
+
style?: string;
|
|
145
|
+
class?: string;
|
|
83
146
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
}
|
|
147
|
+
interface DiffEditorProps {
|
|
148
|
+
/** Original (left) content */
|
|
149
|
+
original: string | Signal<string>;
|
|
150
|
+
/** Modified (right) content */
|
|
151
|
+
modified: string | Signal<string>;
|
|
152
|
+
/** Language for both panels */
|
|
153
|
+
language?: EditorLanguage;
|
|
154
|
+
/** Theme */
|
|
155
|
+
theme?: EditorTheme;
|
|
156
|
+
/** Show inline diff instead of side-by-side — default: false */
|
|
157
|
+
inline?: boolean;
|
|
158
|
+
/** Read-only — default: true */
|
|
159
|
+
readOnly?: boolean;
|
|
160
|
+
style?: string;
|
|
161
|
+
class?: string;
|
|
113
162
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
163
|
+
interface Tab {
|
|
164
|
+
/** Unique tab identifier — defaults to name */
|
|
165
|
+
id?: string;
|
|
166
|
+
/** File name displayed in the tab */
|
|
167
|
+
name: string;
|
|
168
|
+
/** Language for syntax highlighting */
|
|
169
|
+
language?: EditorLanguage;
|
|
170
|
+
/** File content */
|
|
171
|
+
value: string;
|
|
172
|
+
/** Whether the tab has unsaved changes */
|
|
173
|
+
modified?: boolean;
|
|
174
|
+
/** Whether the tab can be closed — default: true */
|
|
175
|
+
closable?: boolean;
|
|
176
|
+
}
|
|
177
|
+
interface TabbedEditorConfig {
|
|
178
|
+
/** Initial tabs */
|
|
179
|
+
tabs?: Tab[];
|
|
180
|
+
/** Theme — 'light', 'dark', or custom */
|
|
181
|
+
theme?: EditorTheme;
|
|
182
|
+
/** Editor config applied to all tabs */
|
|
183
|
+
editorConfig?: Omit<EditorConfig, 'value' | 'language' | 'theme'>;
|
|
184
|
+
}
|
|
185
|
+
interface TabbedEditorInstance {
|
|
186
|
+
/** The underlying editor instance */
|
|
187
|
+
editor: EditorInstance;
|
|
188
|
+
/** All open tabs — reactive */
|
|
189
|
+
tabs: Signal<Tab[]>;
|
|
190
|
+
/** Active tab — reactive */
|
|
191
|
+
activeTab: Computed<Tab | null>;
|
|
192
|
+
/** Active tab ID — reactive */
|
|
193
|
+
activeTabId: Signal<string>;
|
|
194
|
+
/** Open a new tab (or switch to it if already open) */
|
|
195
|
+
openTab: (tab: Tab) => void;
|
|
196
|
+
/** Close a tab by ID */
|
|
197
|
+
closeTab: (id: string) => void;
|
|
198
|
+
/** Switch to a tab by ID */
|
|
199
|
+
switchTab: (id: string) => void;
|
|
200
|
+
/** Rename a tab */
|
|
201
|
+
renameTab: (id: string, name: string) => void;
|
|
202
|
+
/** Mark a tab as modified/saved */
|
|
203
|
+
setModified: (id: string, modified: boolean) => void;
|
|
204
|
+
/** Reorder tabs */
|
|
205
|
+
moveTab: (fromIndex: number, toIndex: number) => void;
|
|
206
|
+
/** Get tab by ID */
|
|
207
|
+
getTab: (id: string) => Tab | undefined;
|
|
208
|
+
/** Close all tabs */
|
|
209
|
+
closeAll: () => void;
|
|
210
|
+
/** Close all tabs except the given one */
|
|
211
|
+
closeOthers: (id: string) => void;
|
|
212
|
+
/** Dispose */
|
|
213
|
+
dispose: () => void;
|
|
214
|
+
}
|
|
215
|
+
interface TabbedEditorProps {
|
|
216
|
+
instance: TabbedEditorInstance;
|
|
217
|
+
style?: string;
|
|
218
|
+
class?: string;
|
|
119
219
|
}
|
|
120
|
-
|
|
121
220
|
//#endregion
|
|
122
|
-
//#region src/
|
|
221
|
+
//#region src/components/code-editor.d.ts
|
|
123
222
|
/**
|
|
124
|
-
*
|
|
125
|
-
|
|
126
|
-
|
|
223
|
+
* Code editor component — mounts a CodeMirror 6 instance.
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* ```tsx
|
|
227
|
+
* const editor = createEditor({
|
|
228
|
+
* value: 'const x = 1',
|
|
229
|
+
* language: 'typescript',
|
|
230
|
+
* theme: 'dark',
|
|
231
|
+
* })
|
|
232
|
+
*
|
|
233
|
+
* <CodeEditor instance={editor} style="height: 400px" />
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
declare function CodeEditor(props: CodeEditorProps): VNodeChild;
|
|
237
|
+
//#endregion
|
|
238
|
+
//#region src/components/diff-editor.d.ts
|
|
127
239
|
/**
|
|
128
|
-
*
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
240
|
+
* Side-by-side or inline diff editor using @codemirror/merge.
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```tsx
|
|
244
|
+
* <DiffEditor
|
|
245
|
+
* original="const x = 1"
|
|
246
|
+
* modified="const x = 2"
|
|
247
|
+
* language="typescript"
|
|
248
|
+
* theme="dark"
|
|
249
|
+
* style="height: 400px"
|
|
250
|
+
* />
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
253
|
+
declare function DiffEditor(props: DiffEditorProps): VNodeChild;
|
|
136
254
|
//#endregion
|
|
137
|
-
//#region src/components/
|
|
255
|
+
//#region src/components/tabbed-editor.d.ts
|
|
138
256
|
/**
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
|
|
257
|
+
* Tabbed code editor component — renders tab bar + editor.
|
|
258
|
+
* Headless styling — the tab bar is a plain div with button tabs.
|
|
259
|
+
* Consumers can style via CSS classes.
|
|
260
|
+
*
|
|
261
|
+
* @example
|
|
262
|
+
* ```tsx
|
|
263
|
+
* const editor = createTabbedEditor({
|
|
264
|
+
* tabs: [
|
|
265
|
+
* { name: 'index.ts', language: 'typescript', value: 'const x = 1' },
|
|
266
|
+
* { name: 'style.css', language: 'css', value: '.app { }' },
|
|
267
|
+
* ],
|
|
268
|
+
* theme: 'dark',
|
|
269
|
+
* })
|
|
270
|
+
*
|
|
271
|
+
* <TabbedEditor instance={editor} style="height: 500px" />
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
274
|
+
declare function TabbedEditor(props: TabbedEditorProps): VNodeChild;
|
|
209
275
|
//#endregion
|
|
210
|
-
//#region src/
|
|
276
|
+
//#region src/editor.d.ts
|
|
211
277
|
/**
|
|
212
|
-
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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
|
-
|
|
278
|
+
* Create a reactive code editor instance.
|
|
279
|
+
*
|
|
280
|
+
* The editor state (value, language, theme, cursor, selection) is backed
|
|
281
|
+
* by signals. The CodeMirror EditorView is created when mounted via
|
|
282
|
+
* the `<CodeEditor>` component.
|
|
283
|
+
*
|
|
284
|
+
* @param config - Editor configuration
|
|
285
|
+
* @returns A reactive EditorInstance
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* ```tsx
|
|
289
|
+
* const editor = createEditor({
|
|
290
|
+
* value: 'const x = 1',
|
|
291
|
+
* language: 'typescript',
|
|
292
|
+
* theme: 'dark',
|
|
293
|
+
* })
|
|
294
|
+
*
|
|
295
|
+
* editor.value() // reactive
|
|
296
|
+
* editor.value.set('new') // updates editor
|
|
297
|
+
*
|
|
298
|
+
* <CodeEditor instance={editor} />
|
|
299
|
+
* ```
|
|
300
|
+
*/
|
|
301
|
+
declare function createEditor(config?: EditorConfig): EditorInstance;
|
|
279
302
|
//#endregion
|
|
280
|
-
//#region src/
|
|
303
|
+
//#region src/languages.d.ts
|
|
281
304
|
/**
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
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
|
-
}
|
|
305
|
+
* Load a language extension. Returns cached if already loaded.
|
|
306
|
+
* Language grammars are lazy-imported — zero cost until used.
|
|
307
|
+
*
|
|
308
|
+
* @example
|
|
309
|
+
* ```ts
|
|
310
|
+
* const ext = await loadLanguage('typescript')
|
|
311
|
+
* ```
|
|
312
|
+
*/
|
|
313
|
+
declare function loadLanguage(language: EditorLanguage): Promise<Extension>;
|
|
334
314
|
/**
|
|
335
|
-
*
|
|
336
|
-
|
|
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
|
-
|
|
315
|
+
* Get available languages.
|
|
316
|
+
*/
|
|
317
|
+
declare function getAvailableLanguages(): EditorLanguage[];
|
|
384
318
|
//#endregion
|
|
385
|
-
//#region src/
|
|
319
|
+
//#region src/minimap.d.ts
|
|
386
320
|
/**
|
|
387
|
-
*
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
*
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
*
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
*
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
*
|
|
409
|
-
*/
|
|
410
|
-
function
|
|
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
|
-
|
|
321
|
+
* CodeMirror 6 minimap extension.
|
|
322
|
+
* Renders a canvas-based code overview on the right side of the editor.
|
|
323
|
+
*
|
|
324
|
+
* @example
|
|
325
|
+
* ```ts
|
|
326
|
+
* import { minimapExtension } from '@pyreon/code'
|
|
327
|
+
* // Add to editor extensions
|
|
328
|
+
* ```
|
|
329
|
+
*/
|
|
330
|
+
declare function minimapExtension(): Extension;
|
|
331
|
+
//#endregion
|
|
332
|
+
//#region src/themes.d.ts
|
|
333
|
+
/**
|
|
334
|
+
* Light theme — clean, minimal.
|
|
335
|
+
*/
|
|
336
|
+
declare const lightTheme: Extension;
|
|
337
|
+
/**
|
|
338
|
+
* Dark theme — VS Code inspired.
|
|
339
|
+
*/
|
|
340
|
+
declare const darkTheme: Extension;
|
|
341
|
+
/**
|
|
342
|
+
* Resolve a theme value to a CodeMirror extension.
|
|
343
|
+
*/
|
|
344
|
+
declare function resolveTheme(theme: EditorTheme): Extension;
|
|
850
345
|
//#endregion
|
|
851
|
-
export { CodeEditor, DiffEditor, TabbedEditor, createEditor, darkTheme, getAvailableLanguages, lightTheme, loadLanguage, minimapExtension, resolveTheme
|
|
852
|
-
//# sourceMappingURL=
|
|
346
|
+
export { CodeEditor, type CodeEditorProps, DiffEditor, type DiffEditorProps, type EditorConfig, type EditorInstance, type EditorLanguage, type EditorTheme, type GutterMarker, type Tab, TabbedEditor, type TabbedEditorConfig, type TabbedEditorInstance, type TabbedEditorProps, createEditor, darkTheme, getAvailableLanguages, lightTheme, loadLanguage, minimapExtension, resolveTheme };
|
|
347
|
+
//# sourceMappingURL=index2.d.ts.map
|