@crowdedkingdoms/crowdyjs 8.22.0 → 9.0.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/MIGRATION.md +44 -0
- package/README.md +74 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/live-coding/assets/browser-authoring-index.json +1 -0
- package/dist/live-coding/assets/manifest.json +19 -0
- package/dist/live-coding/assets/tree-sitter-rust.wasm +0 -0
- package/dist/live-coding/assets/web-tree-sitter.wasm +0 -0
- package/dist/live-coding/browser-authoring-index.generated.d.ts +2 -0
- package/dist/live-coding/browser-authoring-index.generated.d.ts.map +1 -0
- package/dist/live-coding/browser-authoring-index.generated.js +5127 -0
- package/dist/live-coding/ide.d.ts +14 -7
- package/dist/live-coding/ide.d.ts.map +1 -1
- package/dist/live-coding/ide.js +296 -181
- package/dist/live-coding/index.d.ts +8 -0
- package/dist/live-coding/index.d.ts.map +1 -0
- package/dist/live-coding/index.js +7 -0
- package/dist/live-coding/lsp-protocol.d.ts +98 -0
- package/dist/live-coding/lsp-protocol.d.ts.map +1 -0
- package/dist/live-coding/lsp-protocol.js +70 -0
- package/dist/live-coding/monaco-services.d.ts +22 -0
- package/dist/live-coding/monaco-services.d.ts.map +1 -0
- package/dist/live-coding/monaco-services.js +69 -0
- package/dist/live-coding/platform-index.d.ts +29 -0
- package/dist/live-coding/platform-index.d.ts.map +1 -0
- package/dist/live-coding/platform-index.js +281 -0
- package/dist/live-coding/rust-analysis.d.ts +24 -0
- package/dist/live-coding/rust-analysis.d.ts.map +1 -0
- package/dist/live-coding/rust-analysis.js +312 -0
- package/dist/live-coding/rust-lsp-server.d.ts +43 -0
- package/dist/live-coding/rust-lsp-server.d.ts.map +1 -0
- package/dist/live-coding/rust-lsp-server.js +455 -0
- package/dist/live-coding/rust-lsp.worker.d.ts +2 -0
- package/dist/live-coding/rust-lsp.worker.d.ts.map +1 -0
- package/dist/live-coding/rust-lsp.worker.js +26 -0
- package/dist/live-coding/vfs.d.ts +41 -0
- package/dist/live-coding/vfs.d.ts.map +1 -0
- package/dist/live-coding/vfs.js +174 -0
- package/dist/live-coding/worker-transport.d.ts +60 -0
- package/dist/live-coding/worker-transport.d.ts.map +1 -0
- package/dist/live-coding/worker-transport.js +204 -0
- package/package.json +18 -6
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import { type LiveCodingHandle, type MountLiveCodingOptions } from './mount.js';
|
|
2
|
+
import { type PlatformIndex } from './platform-index.js';
|
|
2
3
|
export interface MountLiveCodingIDEOptions extends MountLiveCodingOptions {
|
|
3
|
-
/** Authenticated wss endpoint ending in /authoring-lsp. */
|
|
4
|
-
languageServiceUrl?: string;
|
|
5
|
-
/** Current app token or a getter. Tokens are sent only after WSS connects. */
|
|
6
|
-
appToken?: string | (() => string | null);
|
|
7
4
|
/** Consumer-provided Monaco editor worker (bundler-specific). */
|
|
8
5
|
editorWorkerFactory?: () => Worker;
|
|
6
|
+
/** Optional module-worker factory; one worker is created for this editor. */
|
|
7
|
+
languageWorkerFactory?: () => Worker;
|
|
8
|
+
/**
|
|
9
|
+
* Generated platform symbol index. The worker strictly validates its schema;
|
|
10
|
+
* omit it to use the byte-identical embedded game export.
|
|
11
|
+
*/
|
|
12
|
+
platformIndex?: PlatformIndex | unknown;
|
|
13
|
+
/** JSON-RPC request timeout; defaults to 3 seconds. */
|
|
14
|
+
languageRequestTimeoutMs?: number;
|
|
9
15
|
}
|
|
10
16
|
/**
|
|
11
|
-
* Lazy Monaco live-coding IDE
|
|
12
|
-
*
|
|
13
|
-
*
|
|
17
|
+
* Lazy Monaco live-coding IDE backed only by a browser module worker and local
|
|
18
|
+
* WASM parser assets. If Monaco, Worker, or WASM startup fails, the dependency-
|
|
19
|
+
* free textarea is mounted; there is deliberately no server fallback.
|
|
14
20
|
*/
|
|
15
21
|
export declare function mountLiveCodingIDE(el: HTMLElement, options: MountLiveCodingIDEOptions): Promise<LiveCodingHandle>;
|
|
22
|
+
export declare function isCurrentDiagnosticVersion(version: unknown, currentVersion: number): boolean;
|
|
16
23
|
//# sourceMappingURL=ide.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ide.d.ts","sourceRoot":"","sources":["../../src/live-coding/ide.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC5B,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"ide.d.ts","sourceRoot":"","sources":["../../src/live-coding/ide.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC5B,MAAM,YAAY,CAAC;AAUpB,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAC;AAY7B,MAAM,WAAW,yBAA0B,SAAQ,sBAAsB;IACvE,iEAAiE;IACjE,mBAAmB,CAAC,EAAE,MAAM,MAAM,CAAC;IACnC,6EAA6E;IAC7E,qBAAqB,CAAC,EAAE,MAAM,MAAM,CAAC;IACrC;;;OAGG;IACH,aAAa,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC;IACxC,uDAAuD;IACvD,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC;AAgBD;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,WAAW,EACf,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,gBAAgB,CAAC,CAwX3B;AA8GD,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,OAAO,EAChB,cAAc,EAAE,MAAM,GACrB,OAAO,CAKT"}
|
package/dist/live-coding/ide.js
CHANGED
|
@@ -1,46 +1,42 @@
|
|
|
1
1
|
import { LiveCodingController, } from './live-coding-controller.js';
|
|
2
2
|
import { mountLiveCoding, } from './mount.js';
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import { isRecord, } from './lsp-protocol.js';
|
|
4
|
+
import { loadPlatformIndex, } from './platform-index.js';
|
|
5
|
+
import { PLAYER_CODE_TEMPLATES } from './templates.js';
|
|
6
|
+
import { acquireMonacoWorkspace, ensureMonacoServicesInitialized, } from './monaco-services.js';
|
|
7
|
+
let monacoLanguagesRegistered = false;
|
|
5
8
|
/**
|
|
6
|
-
* Lazy Monaco live-coding IDE
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
+
* Lazy Monaco live-coding IDE backed only by a browser module worker and local
|
|
10
|
+
* WASM parser assets. If Monaco, Worker, or WASM startup fails, the dependency-
|
|
11
|
+
* free textarea is mounted; there is deliberately no server fallback.
|
|
9
12
|
*/
|
|
10
13
|
export async function mountLiveCodingIDE(el, options) {
|
|
11
|
-
|
|
12
|
-
if (!options.languageServiceUrl || !token) {
|
|
14
|
+
if (!options.languageWorkerFactory && typeof Worker === 'undefined') {
|
|
13
15
|
return mountLiveCoding(el, options);
|
|
14
16
|
}
|
|
15
17
|
if (options.editorWorkerFactory) {
|
|
16
18
|
globalThis.MonacoEnvironment = { getWorker: options.editorWorkerFactory };
|
|
17
19
|
}
|
|
20
|
+
let languageWorker = null;
|
|
21
|
+
let languageClient = null;
|
|
22
|
+
let releaseWorkspace = null;
|
|
23
|
+
let teardownMountedIde = null;
|
|
18
24
|
try {
|
|
19
|
-
const
|
|
25
|
+
const platformIndex = options.platformIndex === undefined
|
|
26
|
+
? undefined
|
|
27
|
+
: loadPlatformIndex(options.platformIndex);
|
|
28
|
+
const workerTransportPromise = import('./worker-transport.js');
|
|
29
|
+
await ensureMonacoServicesInitialized();
|
|
30
|
+
const [monaco, workerTransport] = await Promise.all([
|
|
20
31
|
import('@codingame/monaco-vscode-editor-api'),
|
|
21
|
-
|
|
22
|
-
import('vscode-ws-jsonrpc'),
|
|
23
|
-
import('monaco-languageclient/vscodeApiWrapper'),
|
|
24
|
-
import('monaco-languageclient/workerFactory'),
|
|
32
|
+
workerTransportPromise,
|
|
25
33
|
]);
|
|
26
|
-
if (!
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
json: JSON.stringify({
|
|
32
|
-
'workbench.colorTheme': 'Default Dark Modern',
|
|
33
|
-
'editor.wordBasedSuggestions': 'off',
|
|
34
|
-
}),
|
|
35
|
-
},
|
|
36
|
-
monacoWorkerFactory: workerFactoryModule.configureDefaultWorkerFactory,
|
|
37
|
-
});
|
|
38
|
-
vscodeServicesPromise = wrapper.start();
|
|
34
|
+
if (!monacoLanguagesRegistered) {
|
|
35
|
+
monaco.languages.register({ id: 'rust', extensions: ['.rs'] });
|
|
36
|
+
installRustSyntaxHighlighting(monaco);
|
|
37
|
+
monaco.languages.register({ id: 'toml', extensions: ['.toml'] });
|
|
38
|
+
monacoLanguagesRegistered = true;
|
|
39
39
|
}
|
|
40
|
-
await vscodeServicesPromise;
|
|
41
|
-
monaco.languages.register({ id: 'rust', extensions: ['.rs'] });
|
|
42
|
-
installRustSyntaxHighlighting(monaco);
|
|
43
|
-
monaco.languages.register({ id: 'toml', extensions: ['.toml'] });
|
|
44
40
|
const templates = options.templates ?? PLAYER_CODE_TEMPLATES;
|
|
45
41
|
const root = document.createElement('div');
|
|
46
42
|
root.className = 'ck-live-coding ck-live-coding-ide';
|
|
@@ -73,6 +69,10 @@ export async function mountLiveCodingIDE(el, options) {
|
|
|
73
69
|
...options,
|
|
74
70
|
onStatus: (value) => renderStatus(status, meter, value),
|
|
75
71
|
});
|
|
72
|
+
const workspaceLease = acquireMonacoWorkspace();
|
|
73
|
+
releaseWorkspace = workspaceLease.release;
|
|
74
|
+
const modelRootUri = workspaceLease.uri;
|
|
75
|
+
const ownsModel = (uri) => uri.toString().startsWith(`${modelRootUri}/`);
|
|
76
76
|
const editor = monaco.editor.create(editorHost, {
|
|
77
77
|
automaticLayout: true,
|
|
78
78
|
minimap: { enabled: false },
|
|
@@ -81,9 +81,7 @@ export async function mountLiveCodingIDE(el, options) {
|
|
|
81
81
|
tabSize: 2,
|
|
82
82
|
});
|
|
83
83
|
let models = [];
|
|
84
|
-
|
|
85
|
-
let socket = null;
|
|
86
|
-
let modelRootUri = 'file:///player-mod';
|
|
84
|
+
const languageDisposables = [];
|
|
87
85
|
const sourceJson = () => JSON.stringify(Object.fromEntries(models.map(({ path, model }) => [path, model.getValue()])));
|
|
88
86
|
const showModel = (path) => {
|
|
89
87
|
const found = models.find((entry) => entry.path === path);
|
|
@@ -94,16 +92,61 @@ export async function mountLiveCodingIDE(el, options) {
|
|
|
94
92
|
child.dataset.path === path ? 'true' : 'false';
|
|
95
93
|
}
|
|
96
94
|
};
|
|
97
|
-
const
|
|
98
|
-
for (const entry of models)
|
|
95
|
+
const closeModels = () => {
|
|
96
|
+
for (const entry of models) {
|
|
97
|
+
if (entry.path.endsWith('.rs')) {
|
|
98
|
+
void languageClient
|
|
99
|
+
?.notify('textDocument/didClose', {
|
|
100
|
+
textDocument: { uri: entry.model.uri.toString() },
|
|
101
|
+
})
|
|
102
|
+
.catch(() => { });
|
|
103
|
+
}
|
|
104
|
+
entry.changeSubscription.dispose();
|
|
99
105
|
entry.model.dispose();
|
|
106
|
+
}
|
|
100
107
|
models = [];
|
|
108
|
+
};
|
|
109
|
+
const openModel = (entry) => {
|
|
110
|
+
if (!entry.path.endsWith('.rs'))
|
|
111
|
+
return;
|
|
112
|
+
void languageClient
|
|
113
|
+
?.notify('textDocument/didOpen', {
|
|
114
|
+
textDocument: {
|
|
115
|
+
uri: entry.model.uri.toString(),
|
|
116
|
+
languageId: 'rust',
|
|
117
|
+
version: entry.model.getVersionId(),
|
|
118
|
+
text: entry.model.getValue(),
|
|
119
|
+
},
|
|
120
|
+
})
|
|
121
|
+
.catch(() => { });
|
|
122
|
+
};
|
|
123
|
+
const setFiles = (sourceFilesJson) => {
|
|
124
|
+
closeModels();
|
|
101
125
|
tabs.replaceChildren();
|
|
102
126
|
const files = parseFiles(sourceFilesJson);
|
|
103
127
|
for (const [path, content] of Object.entries(files)) {
|
|
104
128
|
const uri = monaco.Uri.parse(`${modelRootUri}/${path}`);
|
|
105
129
|
const model = monaco.editor.createModel(content, path.endsWith('.rs') ? 'rust' : path.endsWith('.toml') ? 'toml' : 'plaintext', uri);
|
|
106
|
-
|
|
130
|
+
const entry = {
|
|
131
|
+
path,
|
|
132
|
+
model,
|
|
133
|
+
changeSubscription: { dispose: () => { } },
|
|
134
|
+
};
|
|
135
|
+
entry.changeSubscription = model.onDidChangeContent(() => {
|
|
136
|
+
if (!path.endsWith('.rs'))
|
|
137
|
+
return;
|
|
138
|
+
void languageClient
|
|
139
|
+
?.notify('textDocument/didChange', {
|
|
140
|
+
textDocument: {
|
|
141
|
+
uri: model.uri.toString(),
|
|
142
|
+
version: model.getVersionId(),
|
|
143
|
+
},
|
|
144
|
+
contentChanges: [{ text: model.getValue() }],
|
|
145
|
+
})
|
|
146
|
+
.catch(() => { });
|
|
147
|
+
});
|
|
148
|
+
models.push(entry);
|
|
149
|
+
openModel(entry);
|
|
107
150
|
const tab = button(path);
|
|
108
151
|
tab.dataset.path = path;
|
|
109
152
|
tab.addEventListener('click', () => showModel(path));
|
|
@@ -116,9 +159,8 @@ export async function mountLiveCodingIDE(el, options) {
|
|
|
116
159
|
const refreshTemplates = () => {
|
|
117
160
|
template.replaceChildren();
|
|
118
161
|
const matching = templates.filter((item) => item.target === target.value);
|
|
119
|
-
for (const item of matching)
|
|
162
|
+
for (const item of matching)
|
|
120
163
|
template.append(new Option(item.title, item.id));
|
|
121
|
-
}
|
|
122
164
|
if (matching[0])
|
|
123
165
|
setFiles(matching[0].sourceFilesJson);
|
|
124
166
|
};
|
|
@@ -144,117 +186,178 @@ export async function mountLiveCodingIDE(el, options) {
|
|
|
144
186
|
draft.addEventListener('click', () => doDeploy(true));
|
|
145
187
|
stop.addEventListener('click', () => controller.stop());
|
|
146
188
|
const markerSubscription = monaco.editor.onDidChangeMarkers(() => {
|
|
147
|
-
const markers = monaco.editor.getModelMarkers({});
|
|
189
|
+
const markers = monaco.editor.getModelMarkers({ owner: 'crowdy-rust' });
|
|
148
190
|
const errors = markers.filter((marker) => marker.severity === monaco.MarkerSeverity.Error).length;
|
|
149
191
|
const warnings = markers.filter((marker) => marker.severity === monaco.MarkerSeverity.Warning).length;
|
|
150
192
|
problems.textContent = `${errors} error(s) · ${warnings} warning(s)`;
|
|
151
193
|
});
|
|
194
|
+
let tornDown = false;
|
|
195
|
+
teardownMountedIde = (graceful) => {
|
|
196
|
+
if (tornDown)
|
|
197
|
+
return;
|
|
198
|
+
tornDown = true;
|
|
199
|
+
markerSubscription.dispose();
|
|
200
|
+
for (const disposable of languageDisposables)
|
|
201
|
+
disposable.dispose();
|
|
202
|
+
controller.stop();
|
|
203
|
+
closeModels();
|
|
204
|
+
if (graceful)
|
|
205
|
+
languageClient?.shutdown();
|
|
206
|
+
else
|
|
207
|
+
languageClient?.dispose();
|
|
208
|
+
editor.dispose();
|
|
209
|
+
root.remove();
|
|
210
|
+
releaseWorkspace?.();
|
|
211
|
+
releaseWorkspace = null;
|
|
212
|
+
};
|
|
152
213
|
refreshTemplates();
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
214
|
+
languageWorker =
|
|
215
|
+
options.languageWorkerFactory?.() ??
|
|
216
|
+
workerTransport.createDefaultRustLanguageWorker();
|
|
217
|
+
languageClient = new workerTransport.WorkerLanguageClient(languageWorker, {
|
|
218
|
+
requestTimeoutMs: options.languageRequestTimeoutMs,
|
|
219
|
+
});
|
|
220
|
+
languageDisposables.push(languageClient.onNotification('textDocument/publishDiagnostics', (params) => {
|
|
221
|
+
if (!isRecord(params) || typeof params.uri !== 'string')
|
|
222
|
+
return;
|
|
223
|
+
const model = monaco.editor.getModel(monaco.Uri.parse(params.uri));
|
|
224
|
+
if (!model)
|
|
225
|
+
return;
|
|
226
|
+
if (!isCurrentDiagnosticVersion(params.version, model.getVersionId())) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const diagnostics = Array.isArray(params.diagnostics)
|
|
230
|
+
? params.diagnostics
|
|
231
|
+
: [];
|
|
232
|
+
monaco.editor.setModelMarkers(model, 'crowdy-rust', diagnostics.map((diagnostic) => ({
|
|
233
|
+
...toMonacoRange(diagnostic.range),
|
|
234
|
+
severity: diagnosticSeverity(monaco, diagnostic.severity),
|
|
235
|
+
message: diagnostic.message,
|
|
236
|
+
code: diagnostic.code,
|
|
237
|
+
source: diagnostic.source,
|
|
238
|
+
})));
|
|
239
|
+
}));
|
|
240
|
+
await languageClient.initialize({
|
|
241
|
+
processId: null,
|
|
242
|
+
clientInfo: { name: 'CrowdyJS Monaco', version: '1' },
|
|
243
|
+
rootUri: modelRootUri,
|
|
244
|
+
capabilities: {
|
|
245
|
+
general: { positionEncodings: ['utf-16'] },
|
|
246
|
+
textDocument: {
|
|
247
|
+
completion: {},
|
|
248
|
+
hover: { contentFormat: ['markdown', 'plaintext'] },
|
|
249
|
+
documentSymbol: {},
|
|
250
|
+
definition: {},
|
|
251
|
+
publishDiagnostics: { versionSupport: true },
|
|
169
252
|
},
|
|
170
253
|
},
|
|
171
|
-
|
|
254
|
+
initializationOptions: {
|
|
255
|
+
...(platformIndex === undefined
|
|
256
|
+
? {}
|
|
257
|
+
: { platformIndex }),
|
|
258
|
+
},
|
|
172
259
|
});
|
|
173
|
-
|
|
260
|
+
for (const entry of models)
|
|
261
|
+
openModel(entry);
|
|
262
|
+
languageDisposables.push(monaco.languages.registerCompletionItemProvider('rust', {
|
|
263
|
+
triggerCharacters: [':', '.'],
|
|
264
|
+
provideCompletionItems: async (model, position) => {
|
|
265
|
+
if (!ownsModel(model.uri))
|
|
266
|
+
return { suggestions: [] };
|
|
267
|
+
const word = model.getWordUntilPosition(position);
|
|
268
|
+
const range = {
|
|
269
|
+
startLineNumber: position.lineNumber,
|
|
270
|
+
startColumn: word.startColumn,
|
|
271
|
+
endLineNumber: position.lineNumber,
|
|
272
|
+
endColumn: position.column,
|
|
273
|
+
};
|
|
274
|
+
const response = (await languageClient?.request('textDocument/completion', lspDocumentPosition(model.uri.toString(), position)));
|
|
275
|
+
return {
|
|
276
|
+
suggestions: (response ?? []).map((item) => ({
|
|
277
|
+
label: item.label,
|
|
278
|
+
kind: completionKind(monaco, item.kind),
|
|
279
|
+
detail: item.detail,
|
|
280
|
+
documentation: item.documentation,
|
|
281
|
+
insertText: item.insertText ?? item.label,
|
|
282
|
+
range,
|
|
283
|
+
})),
|
|
284
|
+
};
|
|
285
|
+
},
|
|
286
|
+
}), monaco.languages.registerHoverProvider('rust', {
|
|
287
|
+
provideHover: async (model, position) => {
|
|
288
|
+
if (!ownsModel(model.uri))
|
|
289
|
+
return null;
|
|
290
|
+
const response = (await languageClient?.request('textDocument/hover', lspDocumentPosition(model.uri.toString(), position)));
|
|
291
|
+
if (!response)
|
|
292
|
+
return null;
|
|
293
|
+
return {
|
|
294
|
+
contents: [{ value: response.contents.value }],
|
|
295
|
+
range: response.range
|
|
296
|
+
? new monaco.Range(response.range.start.line + 1, response.range.start.character + 1, response.range.end.line + 1, response.range.end.character + 1)
|
|
297
|
+
: undefined,
|
|
298
|
+
};
|
|
299
|
+
},
|
|
300
|
+
}), monaco.languages.registerDocumentSymbolProvider('rust', {
|
|
301
|
+
provideDocumentSymbols: async (model) => {
|
|
302
|
+
if (!ownsModel(model.uri))
|
|
303
|
+
return [];
|
|
304
|
+
const response = (await languageClient?.request('textDocument/documentSymbol', { textDocument: { uri: model.uri.toString() } }));
|
|
305
|
+
return (response ?? []).map((symbol) => ({
|
|
306
|
+
name: symbol.name,
|
|
307
|
+
detail: symbol.detail ?? '',
|
|
308
|
+
kind: symbolKind(monaco, symbol.kind),
|
|
309
|
+
tags: [],
|
|
310
|
+
range: toMonacoRange(symbol.range),
|
|
311
|
+
selectionRange: toMonacoRange(symbol.selectionRange),
|
|
312
|
+
}));
|
|
313
|
+
},
|
|
314
|
+
}), monaco.languages.registerDefinitionProvider('rust', {
|
|
315
|
+
provideDefinition: async (model, position) => {
|
|
316
|
+
if (!ownsModel(model.uri))
|
|
317
|
+
return null;
|
|
318
|
+
const response = (await languageClient?.request('textDocument/definition', lspDocumentPosition(model.uri.toString(), position)));
|
|
319
|
+
if (!response)
|
|
320
|
+
return null;
|
|
321
|
+
return {
|
|
322
|
+
uri: monaco.Uri.parse(response.uri),
|
|
323
|
+
range: toMonacoRange(response.range),
|
|
324
|
+
};
|
|
325
|
+
},
|
|
326
|
+
}));
|
|
174
327
|
void controller.refreshUsage().catch(() => { });
|
|
175
328
|
return {
|
|
176
329
|
controller,
|
|
177
|
-
destroy: () =>
|
|
178
|
-
markerSubscription.dispose();
|
|
179
|
-
controller.stop();
|
|
180
|
-
void languageClient?.stop().catch(() => { });
|
|
181
|
-
socket?.close();
|
|
182
|
-
editor.dispose();
|
|
183
|
-
for (const entry of models)
|
|
184
|
-
entry.model.dispose();
|
|
185
|
-
root.remove();
|
|
186
|
-
},
|
|
330
|
+
destroy: () => teardownMountedIde?.(true),
|
|
187
331
|
};
|
|
188
332
|
}
|
|
189
333
|
catch (error) {
|
|
190
|
-
|
|
334
|
+
if (teardownMountedIde) {
|
|
335
|
+
teardownMountedIde(false);
|
|
336
|
+
}
|
|
337
|
+
else {
|
|
338
|
+
languageClient?.dispose();
|
|
339
|
+
if (!languageClient)
|
|
340
|
+
languageWorker?.terminate();
|
|
341
|
+
releaseWorkspace?.();
|
|
342
|
+
releaseWorkspace = null;
|
|
343
|
+
}
|
|
344
|
+
console.warn('Browser Rust IDE unavailable; using textarea fallback', error);
|
|
191
345
|
el.replaceChildren();
|
|
192
346
|
return mountLiveCoding(el, options);
|
|
193
347
|
}
|
|
194
348
|
}
|
|
195
349
|
function installRustSyntaxHighlighting(monaco) {
|
|
196
350
|
const keywords = new Set([
|
|
197
|
-
'as',
|
|
198
|
-
'
|
|
199
|
-
'
|
|
200
|
-
'
|
|
201
|
-
'
|
|
202
|
-
'continue',
|
|
203
|
-
'crate',
|
|
204
|
-
'dyn',
|
|
205
|
-
'else',
|
|
206
|
-
'enum',
|
|
207
|
-
'extern',
|
|
208
|
-
'false',
|
|
209
|
-
'fn',
|
|
210
|
-
'for',
|
|
211
|
-
'if',
|
|
212
|
-
'impl',
|
|
213
|
-
'in',
|
|
214
|
-
'let',
|
|
215
|
-
'loop',
|
|
216
|
-
'match',
|
|
217
|
-
'mod',
|
|
218
|
-
'move',
|
|
219
|
-
'mut',
|
|
220
|
-
'pub',
|
|
221
|
-
'ref',
|
|
222
|
-
'return',
|
|
223
|
-
'self',
|
|
224
|
-
'static',
|
|
225
|
-
'struct',
|
|
226
|
-
'super',
|
|
227
|
-
'trait',
|
|
228
|
-
'true',
|
|
229
|
-
'type',
|
|
230
|
-
'unsafe',
|
|
231
|
-
'use',
|
|
232
|
-
'where',
|
|
233
|
-
'while',
|
|
351
|
+
'as', 'async', 'await', 'break', 'const', 'continue', 'crate', 'dyn',
|
|
352
|
+
'else', 'enum', 'extern', 'false', 'fn', 'for', 'if', 'impl', 'in',
|
|
353
|
+
'let', 'loop', 'match', 'mod', 'move', 'mut', 'pub', 'ref', 'return',
|
|
354
|
+
'self', 'static', 'struct', 'super', 'trait', 'true', 'type', 'unsafe',
|
|
355
|
+
'use', 'where', 'while',
|
|
234
356
|
]);
|
|
235
357
|
const types = new Set([
|
|
236
|
-
'Self',
|
|
237
|
-
'
|
|
238
|
-
'
|
|
239
|
-
'Option',
|
|
240
|
-
'Result',
|
|
241
|
-
'bool',
|
|
242
|
-
'char',
|
|
243
|
-
'str',
|
|
244
|
-
'usize',
|
|
245
|
-
'isize',
|
|
246
|
-
'u8',
|
|
247
|
-
'u16',
|
|
248
|
-
'u32',
|
|
249
|
-
'u64',
|
|
250
|
-
'u128',
|
|
251
|
-
'i8',
|
|
252
|
-
'i16',
|
|
253
|
-
'i32',
|
|
254
|
-
'i64',
|
|
255
|
-
'i128',
|
|
256
|
-
'f32',
|
|
257
|
-
'f64',
|
|
358
|
+
'Self', 'String', 'Vec', 'Option', 'Result', 'bool', 'char', 'str',
|
|
359
|
+
'usize', 'isize', 'u8', 'u16', 'u32', 'u64', 'u128', 'i8', 'i16',
|
|
360
|
+
'i32', 'i64', 'i128', 'f32', 'f64',
|
|
258
361
|
]);
|
|
259
362
|
const state = {
|
|
260
363
|
clone() {
|
|
@@ -272,25 +375,25 @@ function installRustSyntaxHighlighting(monaco) {
|
|
|
272
375
|
while (index < line.length) {
|
|
273
376
|
const rest = line.slice(index);
|
|
274
377
|
let match;
|
|
275
|
-
if ((match = rest.match(/^\s+/))) {
|
|
378
|
+
if ((match = rest.match(/^\s+/u))) {
|
|
276
379
|
tokens.push({ startIndex: index, scopes: '' });
|
|
277
380
|
}
|
|
278
|
-
else if ((match = rest.match(/^\/\/.*$/))) {
|
|
381
|
+
else if ((match = rest.match(/^\/\/.*$/u))) {
|
|
279
382
|
tokens.push({ startIndex: index, scopes: 'comment.rust' });
|
|
280
383
|
}
|
|
281
|
-
else if ((match = rest.match(/^\/\*.*?(?:\*\/|$)/))) {
|
|
384
|
+
else if ((match = rest.match(/^\/\*.*?(?:\*\/|$)/u))) {
|
|
282
385
|
tokens.push({ startIndex: index, scopes: 'comment.rust' });
|
|
283
386
|
}
|
|
284
|
-
else if ((match = rest.match(/^"(?:\\.|[^"\\])*"?/))) {
|
|
387
|
+
else if ((match = rest.match(/^"(?:\\.|[^"\\])*"?/u))) {
|
|
285
388
|
tokens.push({ startIndex: index, scopes: 'string.rust' });
|
|
286
389
|
}
|
|
287
|
-
else if ((match = rest.match(/^(?:0x[\da-fA-F_]+|\d[\d_]*)/))) {
|
|
390
|
+
else if ((match = rest.match(/^(?:0x[\da-fA-F_]+|\d[\d_]*)/u))) {
|
|
288
391
|
tokens.push({ startIndex: index, scopes: 'number.rust' });
|
|
289
392
|
}
|
|
290
|
-
else if ((match = rest.match(/^[A-Za-z_]\w*!/))) {
|
|
393
|
+
else if ((match = rest.match(/^[A-Za-z_]\w*!/u))) {
|
|
291
394
|
tokens.push({ startIndex: index, scopes: 'macro.rust' });
|
|
292
395
|
}
|
|
293
|
-
else if ((match = rest.match(/^[A-Za-z_]\w*/))) {
|
|
396
|
+
else if ((match = rest.match(/^[A-Za-z_]\w*/u))) {
|
|
294
397
|
const word = match[0];
|
|
295
398
|
tokens.push({
|
|
296
399
|
startIndex: index,
|
|
@@ -302,7 +405,7 @@ function installRustSyntaxHighlighting(monaco) {
|
|
|
302
405
|
});
|
|
303
406
|
}
|
|
304
407
|
else {
|
|
305
|
-
match = rest.match(/^./);
|
|
408
|
+
match = rest.match(/^./u);
|
|
306
409
|
tokens.push({ startIndex: index, scopes: 'delimiter.rust' });
|
|
307
410
|
}
|
|
308
411
|
index += match?.[0].length ?? 1;
|
|
@@ -311,65 +414,77 @@ function installRustSyntaxHighlighting(monaco) {
|
|
|
311
414
|
},
|
|
312
415
|
});
|
|
313
416
|
}
|
|
314
|
-
function resolveToken(token) {
|
|
315
|
-
const value = typeof token === 'function' ? token() : token;
|
|
316
|
-
return value && value.length > 0 ? value : null;
|
|
317
|
-
}
|
|
318
417
|
function parseFiles(sourceFilesJson) {
|
|
319
418
|
const parsed = JSON.parse(sourceFilesJson);
|
|
320
|
-
if (!
|
|
419
|
+
if (!isRecord(parsed))
|
|
321
420
|
throw new Error('sourceFilesJson must be an object');
|
|
322
|
-
}
|
|
323
421
|
return Object.fromEntries(Object.entries(parsed).map(([path, value]) => {
|
|
324
|
-
if (typeof value !== 'string'
|
|
422
|
+
if (typeof value !== 'string' ||
|
|
423
|
+
path.startsWith('/') ||
|
|
424
|
+
path.split('/').some((part) => part === '' || part === '.' || part === '..')) {
|
|
325
425
|
throw new Error(`Invalid source file ${path}`);
|
|
426
|
+
}
|
|
326
427
|
return [path, value];
|
|
327
428
|
}));
|
|
328
429
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
token,
|
|
338
|
-
appId,
|
|
339
|
-
sourceFilesJson,
|
|
340
|
-
}));
|
|
341
|
-
}, { once: true });
|
|
342
|
-
socket.addEventListener('message', (event) => {
|
|
343
|
-
try {
|
|
344
|
-
const message = JSON.parse(String(event.data));
|
|
345
|
-
if (message.type !== 'ready' || !message.workspaceUri) {
|
|
346
|
-
throw new Error('language service refused session');
|
|
347
|
-
}
|
|
348
|
-
workspaceUri = message.workspaceUri;
|
|
349
|
-
clearTimeout(timeout);
|
|
350
|
-
resolve();
|
|
351
|
-
}
|
|
352
|
-
catch (error) {
|
|
353
|
-
clearTimeout(timeout);
|
|
354
|
-
reject(error);
|
|
355
|
-
}
|
|
356
|
-
}, { once: true });
|
|
357
|
-
socket.addEventListener('close', (event) => {
|
|
358
|
-
clearTimeout(timeout);
|
|
359
|
-
reject(new Error(event.reason || 'language service closed'));
|
|
360
|
-
}, { once: true });
|
|
361
|
-
});
|
|
362
|
-
return { socket, workspaceUri };
|
|
430
|
+
function lspDocumentPosition(uri, position) {
|
|
431
|
+
return {
|
|
432
|
+
textDocument: { uri },
|
|
433
|
+
position: {
|
|
434
|
+
line: position.lineNumber - 1,
|
|
435
|
+
character: position.column - 1,
|
|
436
|
+
},
|
|
437
|
+
};
|
|
363
438
|
}
|
|
364
|
-
function
|
|
439
|
+
function toMonacoRange(range) {
|
|
365
440
|
return {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
dispose: () => socket.close(),
|
|
441
|
+
startLineNumber: range.start.line + 1,
|
|
442
|
+
startColumn: range.start.character + 1,
|
|
443
|
+
endLineNumber: range.end.line + 1,
|
|
444
|
+
endColumn: range.end.character + 1,
|
|
371
445
|
};
|
|
372
446
|
}
|
|
447
|
+
export function isCurrentDiagnosticVersion(version, currentVersion) {
|
|
448
|
+
return (version === undefined ||
|
|
449
|
+
(Number.isSafeInteger(version) && version === currentVersion));
|
|
450
|
+
}
|
|
451
|
+
function diagnosticSeverity(monaco, severity) {
|
|
452
|
+
return severity === 1
|
|
453
|
+
? monaco.MarkerSeverity.Error
|
|
454
|
+
: severity === 2
|
|
455
|
+
? monaco.MarkerSeverity.Warning
|
|
456
|
+
: severity === 3
|
|
457
|
+
? monaco.MarkerSeverity.Info
|
|
458
|
+
: monaco.MarkerSeverity.Hint;
|
|
459
|
+
}
|
|
460
|
+
function completionKind(monaco, kind) {
|
|
461
|
+
const kinds = monaco.languages.CompletionItemKind;
|
|
462
|
+
return ({
|
|
463
|
+
3: kinds.Function,
|
|
464
|
+
5: kinds.Field,
|
|
465
|
+
6: kinds.Variable,
|
|
466
|
+
7: kinds.Class,
|
|
467
|
+
9: kinds.Module,
|
|
468
|
+
13: kinds.Enum,
|
|
469
|
+
14: kinds.Keyword,
|
|
470
|
+
15: kinds.Snippet,
|
|
471
|
+
21: kinds.Constant,
|
|
472
|
+
}[kind] ?? kinds.Text);
|
|
473
|
+
}
|
|
474
|
+
function symbolKind(monaco, kind) {
|
|
475
|
+
const kinds = monaco.languages.SymbolKind;
|
|
476
|
+
return ({
|
|
477
|
+
2: kinds.Module,
|
|
478
|
+
5: kinds.Class,
|
|
479
|
+
6: kinds.Method,
|
|
480
|
+
10: kinds.Enum,
|
|
481
|
+
11: kinds.Interface,
|
|
482
|
+
12: kinds.Function,
|
|
483
|
+
13: kinds.Variable,
|
|
484
|
+
14: kinds.Constant,
|
|
485
|
+
23: kinds.Struct,
|
|
486
|
+
}[kind] ?? kinds.Object);
|
|
487
|
+
}
|
|
373
488
|
function select(values) {
|
|
374
489
|
const element = document.createElement('select');
|
|
375
490
|
for (const value of values)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { LiveCodingController, type LiveCodingControllerOptions, type LiveCodingStatus, type LiveCodingTarget, } from './live-coding-controller.js';
|
|
2
|
+
export { mountLiveCoding, type LiveCodingHandle, type MountLiveCodingOptions, } from './mount.js';
|
|
3
|
+
export { mountLiveCodingIDE, type MountLiveCodingIDEOptions, } from './ide.js';
|
|
4
|
+
export { PLAYER_CODE_TEMPLATES, templateById, type PlayerCodeTemplate, } from './templates.js';
|
|
5
|
+
export { EMBEDDED_PLATFORM_INDEX, MAX_PLATFORM_CRATES, MAX_PLATFORM_CRATE_FIELD_LENGTH, MAX_PLATFORM_INDEX_BYTES, computePlatformIndexContentHash, loadPlatformIndex, type PlatformCrate, type PlatformIndex, type PlatformSymbol, type PlatformSymbolKind, } from './platform-index.js';
|
|
6
|
+
export { DEFAULT_VFS_LIMITS, VfsLimitError, VirtualFileSystem, offsetAt, type VirtualDocument, type VirtualFileSystemLimits, } from './vfs.js';
|
|
7
|
+
export { WorkerLanguageClient, WorkerMessageReader, WorkerMessageWriter, createDefaultRustLanguageWorker, type LanguageWorkerLike, type WorkerLanguageClientOptions, } from './worker-transport.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/live-coding/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,KAAK,2BAA2B,EAChC,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,GACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,eAAe,EACf,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,GAC5B,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,kBAAkB,EAClB,KAAK,yBAAyB,GAC/B,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,qBAAqB,EACrB,YAAY,EACZ,KAAK,kBAAkB,GACxB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,+BAA+B,EAC/B,wBAAwB,EACxB,+BAA+B,EAC/B,iBAAiB,EACjB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,kBAAkB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,QAAQ,EACR,KAAK,eAAe,EACpB,KAAK,uBAAuB,GAC7B,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACnB,+BAA+B,EAC/B,KAAK,kBAAkB,EACvB,KAAK,2BAA2B,GACjC,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { LiveCodingController, } from './live-coding-controller.js';
|
|
2
|
+
export { mountLiveCoding, } from './mount.js';
|
|
3
|
+
export { mountLiveCodingIDE, } from './ide.js';
|
|
4
|
+
export { PLAYER_CODE_TEMPLATES, templateById, } from './templates.js';
|
|
5
|
+
export { EMBEDDED_PLATFORM_INDEX, MAX_PLATFORM_CRATES, MAX_PLATFORM_CRATE_FIELD_LENGTH, MAX_PLATFORM_INDEX_BYTES, computePlatformIndexContentHash, loadPlatformIndex, } from './platform-index.js';
|
|
6
|
+
export { DEFAULT_VFS_LIMITS, VfsLimitError, VirtualFileSystem, offsetAt, } from './vfs.js';
|
|
7
|
+
export { WorkerLanguageClient, WorkerMessageReader, WorkerMessageWriter, createDefaultRustLanguageWorker, } from './worker-transport.js';
|