@volar/monaco 2.0.0-alpha.9 → 2.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/README.md +84 -26
- package/lib/ata.d.ts +2 -0
- package/lib/ata.js +228 -0
- package/lib/editor.js +6 -6
- package/lib/languages.js +1 -1
- package/lib/provider.js +2 -2
- package/package.json +4 -4
- package/worker.d.ts +20 -4
- package/worker.js +76 -92
package/README.md
CHANGED
|
@@ -22,15 +22,22 @@ We assume you already know:
|
|
|
22
22
|
// my-lang.worker.ts
|
|
23
23
|
import * as worker from 'monaco-editor-core/esm/vs/editor/editor.worker';
|
|
24
24
|
import type * as monaco from 'monaco-editor-core';
|
|
25
|
-
import {
|
|
25
|
+
import { createSimpleWorkerService, ServiceEnvironment } from '@volar/monaco/worker';
|
|
26
26
|
|
|
27
27
|
self.onmessage = () => {
|
|
28
28
|
worker.initialize((ctx: monaco.worker.IWorkerContext) => {
|
|
29
|
-
|
|
29
|
+
const env: ServiceEnvironment = {
|
|
30
|
+
workspaceFolder: 'file:///',
|
|
31
|
+
};
|
|
32
|
+
return createSimpleWorkerService({
|
|
30
33
|
workerContext: ctx,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
env,
|
|
35
|
+
languagePlugins: [
|
|
36
|
+
// ...
|
|
37
|
+
],
|
|
38
|
+
servicePlugins: [
|
|
39
|
+
// ...
|
|
40
|
+
],
|
|
34
41
|
});
|
|
35
42
|
});
|
|
36
43
|
};
|
|
@@ -41,29 +48,80 @@ self.onmessage = () => {
|
|
|
41
48
|
```diff
|
|
42
49
|
import * as worker from 'monaco-editor-core/esm/vs/editor/editor.worker';
|
|
43
50
|
import type * as monaco from 'monaco-editor-core';
|
|
44
|
-
import {
|
|
51
|
+
-import { createSimpleWorkerService, ServiceEnvironment } from '@volar/monaco/worker';
|
|
52
|
+
+import {
|
|
53
|
+
+ createTypeScriptWorkerService,
|
|
54
|
+
+ ServiceEnvironment,
|
|
55
|
+
+} from '@volar/monaco/worker';
|
|
45
56
|
+import * as ts from 'typescript';
|
|
46
|
-
+import
|
|
57
|
+
+import { create as createTypeScriptService } from 'volar-service-typescript';
|
|
47
58
|
|
|
48
59
|
self.onmessage = () => {
|
|
49
60
|
worker.initialize((ctx: monaco.worker.IWorkerContext) => {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
config: {
|
|
53
|
-
// ...Language Service Config of my-lang language support
|
|
54
|
-
+ services: {
|
|
55
|
-
+ typescript: createTypeScriptService({
|
|
56
|
-
+ // Enable auto fetch node_modules types
|
|
57
|
-
+ dtsHost: createJsDelivrDtsHost({ typescript: '4.9.5' }),
|
|
58
|
-
+ })
|
|
59
|
-
+ },
|
|
60
|
-
},
|
|
61
|
+
const env: ServiceEnvironment = {
|
|
62
|
+
workspaceFolder: 'file:///',
|
|
61
63
|
+ typescript: {
|
|
62
|
-
+
|
|
63
|
-
+
|
|
64
|
-
+ // ...tsconfig options
|
|
65
|
-
+ },
|
|
64
|
+
+ uriToFileName: uri => uri.substring('file://'.length),
|
|
65
|
+
+ fileNameToUri: fileName => 'file://' + fileName,
|
|
66
66
|
+ },
|
|
67
|
+
};
|
|
68
|
+
- return createSimpleWorkerService({
|
|
69
|
+
+ return createTypeScriptWorkerService({
|
|
70
|
+
+ typescript: ts,
|
|
71
|
+
+ compilerOptions: {
|
|
72
|
+
+ // ...
|
|
73
|
+
+ },
|
|
74
|
+
workerContext: ctx,
|
|
75
|
+
env,
|
|
76
|
+
languagePlugins: [
|
|
77
|
+
// ...
|
|
78
|
+
],
|
|
79
|
+
servicePlugins: [
|
|
80
|
+
// ...
|
|
81
|
+
+ createTypeScriptService(ts),
|
|
82
|
+
],
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### Add ATA Support for TypeScript
|
|
89
|
+
|
|
90
|
+
```diff
|
|
91
|
+
import * as worker from 'monaco-editor-core/esm/vs/editor/editor.worker';
|
|
92
|
+
import type * as monaco from 'monaco-editor-core';
|
|
93
|
+
import {
|
|
94
|
+
createTypeScriptWorkerService,
|
|
95
|
+
ServiceEnvironment,
|
|
96
|
+
+ activateAutomaticTypeAcquisition,
|
|
97
|
+
} from '@volar/monaco/worker';
|
|
98
|
+
import * as ts from 'typescript';
|
|
99
|
+
import { create as createTypeScriptService } from 'volar-service-typescript';
|
|
100
|
+
|
|
101
|
+
self.onmessage = () => {
|
|
102
|
+
worker.initialize((ctx: monaco.worker.IWorkerContext) => {
|
|
103
|
+
const env: ServiceEnvironment = {
|
|
104
|
+
workspaceFolder: 'file:///',
|
|
105
|
+
typescript: {
|
|
106
|
+
uriToFileName: uri => uri.substring('file://'.length),
|
|
107
|
+
fileNameToUri: fileName => 'file://' + fileName,
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
+ activateAutomaticTypeAcquisition(env);
|
|
111
|
+
return createTypeScriptWorkerService({
|
|
112
|
+
typescript: ts,
|
|
113
|
+
compilerOptions: {
|
|
114
|
+
// ...
|
|
115
|
+
},
|
|
116
|
+
workerContext: ctx,
|
|
117
|
+
env,
|
|
118
|
+
languagePlugins: [
|
|
119
|
+
// ...
|
|
120
|
+
],
|
|
121
|
+
servicePlugins: [
|
|
122
|
+
// ...
|
|
123
|
+
createTypeScriptService(ts),
|
|
124
|
+
],
|
|
67
125
|
});
|
|
68
126
|
});
|
|
69
127
|
};
|
|
@@ -90,7 +148,7 @@ import myWorker from './my-lang.worker?worker';
|
|
|
90
148
|
```ts
|
|
91
149
|
import type { LanguageService } from '@volar/language-service';
|
|
92
150
|
import { editor, languages, Uri } from 'monaco-editor-core';
|
|
93
|
-
import
|
|
151
|
+
import { activateMarkers, activateAutoInsertion, registerProviders } from '@volar/monaco';
|
|
94
152
|
|
|
95
153
|
languages.register({ id: 'my-lang', extensions: ['.my-lang'] });
|
|
96
154
|
|
|
@@ -99,7 +157,7 @@ languages.onLanguage('my-lang', () => {
|
|
|
99
157
|
moduleId: 'vs/language/my-lang/myLangWorker',
|
|
100
158
|
label: 'my-lang',
|
|
101
159
|
});
|
|
102
|
-
|
|
160
|
+
activateMarkers(
|
|
103
161
|
worker,
|
|
104
162
|
['my-lang'],
|
|
105
163
|
'my-lang-markers-owner',
|
|
@@ -108,14 +166,14 @@ languages.onLanguage('my-lang', () => {
|
|
|
108
166
|
editor
|
|
109
167
|
);
|
|
110
168
|
// auto close tags
|
|
111
|
-
|
|
169
|
+
activateAutoInsertion(
|
|
112
170
|
worker,
|
|
113
171
|
['my-lang'],
|
|
114
172
|
// sync files
|
|
115
173
|
() => [Uri.file('/Foo.my-lang'), Uri.file('/Bar.my-lang')],
|
|
116
174
|
editor
|
|
117
175
|
);
|
|
118
|
-
|
|
176
|
+
registerProviders(worker, ['my-lang'], languages)
|
|
119
177
|
});
|
|
120
178
|
```
|
|
121
179
|
|
package/lib/ata.d.ts
ADDED
package/lib/ata.js
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
export function activateAutomaticTypeAcquisition(env, onFetch) {
|
|
2
|
+
const textCache = new Map();
|
|
3
|
+
const jsonCache = new Map();
|
|
4
|
+
const npmFs = createJsDelivrNpmFileSystem();
|
|
5
|
+
const _fs = env.fs;
|
|
6
|
+
env.fs = {
|
|
7
|
+
async stat(uri) {
|
|
8
|
+
return await npmFs.stat(uri) ?? await _fs?.stat(uri);
|
|
9
|
+
},
|
|
10
|
+
async readDirectory(uri) {
|
|
11
|
+
return [
|
|
12
|
+
...await npmFs.readDirectory(uri),
|
|
13
|
+
...await _fs?.readDirectory(uri) ?? [],
|
|
14
|
+
];
|
|
15
|
+
},
|
|
16
|
+
async readFile(uri) {
|
|
17
|
+
return await npmFs.readFile(uri) ?? await _fs?.readFile(uri);
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
function createJsDelivrNpmFileSystem() {
|
|
21
|
+
const fetchResults = new Map();
|
|
22
|
+
const flatResults = new Map();
|
|
23
|
+
return {
|
|
24
|
+
async stat(uri) {
|
|
25
|
+
const fileName = env.typescript.uriToFileName(uri);
|
|
26
|
+
if (fileName === '/node_modules') {
|
|
27
|
+
return {
|
|
28
|
+
type: 2,
|
|
29
|
+
size: -1,
|
|
30
|
+
ctime: -1,
|
|
31
|
+
mtime: -1,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (fileName.startsWith('/node_modules/')) {
|
|
35
|
+
const path = uri.substring('/node_modules/'.length);
|
|
36
|
+
return await _stat(path);
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
async readFile(uri) {
|
|
40
|
+
const fileName = env.typescript.uriToFileName(uri);
|
|
41
|
+
if (fileName.startsWith('/node_modules/')) {
|
|
42
|
+
const path = uri.substring('/node_modules/'.length);
|
|
43
|
+
return await _readFile(path);
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
async readDirectory(uri) {
|
|
47
|
+
const fileName = env.typescript.uriToFileName(uri);
|
|
48
|
+
if (fileName.startsWith('/node_modules/')) {
|
|
49
|
+
const path = uri.substring('/node_modules/'.length);
|
|
50
|
+
return _readDirectory(path);
|
|
51
|
+
}
|
|
52
|
+
return [];
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
async function _stat(path) {
|
|
56
|
+
const pkgName = getPackageName(path);
|
|
57
|
+
if (!pkgName || !await isValidPackageName(pkgName)) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (!flatResults.has(pkgName)) {
|
|
61
|
+
flatResults.set(pkgName, flat(pkgName));
|
|
62
|
+
}
|
|
63
|
+
const flatResult = await flatResults.get(pkgName);
|
|
64
|
+
const filePath = path.slice(pkgName.length);
|
|
65
|
+
const file = flatResult.find(file => file.name === filePath);
|
|
66
|
+
if (file) {
|
|
67
|
+
return {
|
|
68
|
+
type: 1,
|
|
69
|
+
ctime: new Date(file.time).valueOf(),
|
|
70
|
+
mtime: new Date(file.time).valueOf(),
|
|
71
|
+
size: file.size,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
else if (flatResult.some(file => file.name.startsWith(filePath + '/'))) {
|
|
75
|
+
return {
|
|
76
|
+
type: 2,
|
|
77
|
+
ctime: -1,
|
|
78
|
+
mtime: -1,
|
|
79
|
+
size: -1,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function _readDirectory(path) {
|
|
84
|
+
const pkgName = getPackageName(path);
|
|
85
|
+
if (!pkgName || !await isValidPackageName(pkgName)) {
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
if (!flatResults.has(pkgName)) {
|
|
89
|
+
flatResults.set(pkgName, flat(pkgName));
|
|
90
|
+
}
|
|
91
|
+
const flatResult = await flatResults.get(pkgName);
|
|
92
|
+
const dirPath = path.slice(pkgName.length);
|
|
93
|
+
const files = flatResult
|
|
94
|
+
.filter(f => f.name.substring(0, f.name.lastIndexOf('/')) === dirPath)
|
|
95
|
+
.map(f => f.name.slice(dirPath.length + 1));
|
|
96
|
+
const dirs = flatResult
|
|
97
|
+
.filter(f => f.name.startsWith(dirPath + '/') && f.name.substring(dirPath.length + 1).split('/').length >= 2)
|
|
98
|
+
.map(f => f.name.slice(dirPath.length + 1).split('/')[0]);
|
|
99
|
+
return [
|
|
100
|
+
...files.map(f => [f, 1]),
|
|
101
|
+
...[...new Set(dirs)].map(f => [f, 2]),
|
|
102
|
+
];
|
|
103
|
+
}
|
|
104
|
+
async function _readFile(path) {
|
|
105
|
+
const pkgName = getPackageName(path);
|
|
106
|
+
if (!pkgName || !await isValidPackageName(pkgName)) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (!fetchResults.has(path)) {
|
|
110
|
+
fetchResults.set(path, (async () => {
|
|
111
|
+
if ((await _stat(path))?.type !== 1) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const text = await fetchText(`https://cdn.jsdelivr.net/npm/${path}`);
|
|
115
|
+
if (text !== undefined) {
|
|
116
|
+
onFetch?.(path, text);
|
|
117
|
+
}
|
|
118
|
+
return text;
|
|
119
|
+
})());
|
|
120
|
+
}
|
|
121
|
+
return await fetchResults.get(path);
|
|
122
|
+
}
|
|
123
|
+
async function flat(pkgNameWithVersion) {
|
|
124
|
+
let pkgName = pkgNameWithVersion;
|
|
125
|
+
let version = 'latest';
|
|
126
|
+
if (pkgNameWithVersion.substring(1).includes('@')) {
|
|
127
|
+
pkgName = pkgNameWithVersion.substring(0, pkgNameWithVersion.lastIndexOf('@'));
|
|
128
|
+
version = pkgNameWithVersion.substring(pkgNameWithVersion.lastIndexOf('@') + 1);
|
|
129
|
+
}
|
|
130
|
+
// resolve tag version
|
|
131
|
+
if (version === 'latest') {
|
|
132
|
+
const data = await fetchJson(`https://data.jsdelivr.com/v1/package/resolve/npm/${pkgName}@latest`);
|
|
133
|
+
if (!data?.version) {
|
|
134
|
+
return [];
|
|
135
|
+
}
|
|
136
|
+
version = data.version;
|
|
137
|
+
}
|
|
138
|
+
const flat = await fetchJson(`https://data.jsdelivr.com/v1/package/npm/${pkgName}@${version}/flat`);
|
|
139
|
+
if (!flat) {
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
return flat.files;
|
|
143
|
+
}
|
|
144
|
+
async function isValidPackageName(pkgName) {
|
|
145
|
+
// @aaa/bbb@latest -> @aaa/bbb
|
|
146
|
+
if (pkgName.substring(1).includes('@')) {
|
|
147
|
+
pkgName = pkgName.substring(0, pkgName.lastIndexOf('@'));
|
|
148
|
+
}
|
|
149
|
+
// ignore @aaa/node_modules
|
|
150
|
+
if (pkgName.endsWith('/node_modules')) {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
// hard code for known invalid package
|
|
154
|
+
if (pkgName.startsWith('@typescript/') || pkgName.startsWith('@types/typescript__')) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
// don't check @types if original package already having types
|
|
158
|
+
if (pkgName.startsWith('@types/')) {
|
|
159
|
+
let originalPkgName = pkgName.slice('@types/'.length);
|
|
160
|
+
if (originalPkgName.indexOf('__') >= 0) {
|
|
161
|
+
originalPkgName = '@' + originalPkgName.replace('__', '/');
|
|
162
|
+
}
|
|
163
|
+
const packageJson = await _readFile(`${originalPkgName}/package.json`);
|
|
164
|
+
if (packageJson) {
|
|
165
|
+
const packageJsonObj = JSON.parse(packageJson);
|
|
166
|
+
if (packageJsonObj.types || packageJsonObj.typings) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
const indexDts = await _stat(`${originalPkgName}/index.d.ts`);
|
|
170
|
+
if (indexDts?.type === 1) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* @example
|
|
180
|
+
* "a/b/c" -> "a"
|
|
181
|
+
* "@a/b/c" -> "@a/b"
|
|
182
|
+
* "@a/b@1.2.3/c" -> "@a/b@1.2.3"
|
|
183
|
+
*/
|
|
184
|
+
function getPackageName(path) {
|
|
185
|
+
const parts = path.split('/');
|
|
186
|
+
let pkgName = parts[0];
|
|
187
|
+
if (pkgName.startsWith('@')) {
|
|
188
|
+
if (parts.length < 2 || !parts[1]) {
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
pkgName += '/' + parts[2];
|
|
192
|
+
}
|
|
193
|
+
return pkgName;
|
|
194
|
+
}
|
|
195
|
+
async function fetchText(url) {
|
|
196
|
+
if (!textCache.has(url)) {
|
|
197
|
+
textCache.set(url, (async () => {
|
|
198
|
+
try {
|
|
199
|
+
const res = await fetch(url);
|
|
200
|
+
if (res.status === 200) {
|
|
201
|
+
return await res.text();
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
// ignore
|
|
206
|
+
}
|
|
207
|
+
})());
|
|
208
|
+
}
|
|
209
|
+
return await textCache.get(url);
|
|
210
|
+
}
|
|
211
|
+
async function fetchJson(url) {
|
|
212
|
+
if (!jsonCache.has(url)) {
|
|
213
|
+
jsonCache.set(url, (async () => {
|
|
214
|
+
try {
|
|
215
|
+
const res = await fetch(url);
|
|
216
|
+
if (res.status === 200) {
|
|
217
|
+
return await res.json();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
// ignore
|
|
222
|
+
}
|
|
223
|
+
})());
|
|
224
|
+
}
|
|
225
|
+
return await jsonCache.get(url);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=ata.js.map
|
package/lib/editor.js
CHANGED
|
@@ -3,7 +3,7 @@ import { markers } from './markers.js';
|
|
|
3
3
|
export function activateMarkers(worker, languages, markersOwn, getSyncUris, editor) {
|
|
4
4
|
const disposables = [];
|
|
5
5
|
const listener = new Map();
|
|
6
|
-
disposables.push(editor.onDidCreateModel(
|
|
6
|
+
disposables.push(editor.onDidCreateModel(model => hostingMarkers(model)), editor.onWillDisposeModel(stopHostingMarkers), editor.onDidChangeModelLanguage(event => {
|
|
7
7
|
stopHostingMarkers(event.model);
|
|
8
8
|
hostingMarkers(event.model);
|
|
9
9
|
}), {
|
|
@@ -16,7 +16,7 @@ export function activateMarkers(worker, languages, markersOwn, getSyncUris, edit
|
|
|
16
16
|
for (const model of editor.getModels()) {
|
|
17
17
|
hostingMarkers(model);
|
|
18
18
|
}
|
|
19
|
-
return { dispose: () => disposables.forEach(
|
|
19
|
+
return { dispose: () => disposables.forEach(d => d.dispose()) };
|
|
20
20
|
function stopHostingMarkers(model) {
|
|
21
21
|
editor.setModelMarkers(model, markersOwn, []);
|
|
22
22
|
const key = model.uri.toString();
|
|
@@ -76,7 +76,7 @@ export function activateAutoInsertion(worker, languages, getSyncUris, editor) {
|
|
|
76
76
|
const disposables = [];
|
|
77
77
|
const listener = new Map();
|
|
78
78
|
let timeout;
|
|
79
|
-
disposables.push(editor.onDidCreateModel(
|
|
79
|
+
disposables.push(editor.onDidCreateModel(model => hostingAutoInsertion(model)), editor.onWillDisposeModel(stopHostingAutoInsertion), editor.onDidChangeModelLanguage(event => {
|
|
80
80
|
stopHostingAutoInsertion(event.model);
|
|
81
81
|
hostingAutoInsertion(event.model);
|
|
82
82
|
}), {
|
|
@@ -90,7 +90,7 @@ export function activateAutoInsertion(worker, languages, getSyncUris, editor) {
|
|
|
90
90
|
for (const model of editor.getModels()) {
|
|
91
91
|
hostingAutoInsertion(model);
|
|
92
92
|
}
|
|
93
|
-
return { dispose: () => disposables.forEach(
|
|
93
|
+
return { dispose: () => disposables.forEach(d => d.dispose()) };
|
|
94
94
|
function stopHostingAutoInsertion(model) {
|
|
95
95
|
if (listener.has(model)) {
|
|
96
96
|
listener.get(model)?.dispose();
|
|
@@ -101,7 +101,7 @@ export function activateAutoInsertion(worker, languages, getSyncUris, editor) {
|
|
|
101
101
|
if (!languages.includes(model.getLanguageId?.() ?? model.getModeId?.())) {
|
|
102
102
|
return;
|
|
103
103
|
}
|
|
104
|
-
listener.set(model, model.onDidChangeContent(
|
|
104
|
+
listener.set(model, model.onDidChangeContent(e => {
|
|
105
105
|
if (model.isDisposed()) {
|
|
106
106
|
return;
|
|
107
107
|
}
|
|
@@ -137,7 +137,7 @@ export function activateAutoInsertion(worker, languages, getSyncUris, editor) {
|
|
|
137
137
|
if (model.getVersionId() !== version) {
|
|
138
138
|
return;
|
|
139
139
|
}
|
|
140
|
-
const codeEditor = editor.getEditors().find(
|
|
140
|
+
const codeEditor = editor.getEditors().find(e => e.getModel() === model);
|
|
141
141
|
if (codeEditor && edit && model.getVersionId() === version) {
|
|
142
142
|
if (typeof edit === 'string') {
|
|
143
143
|
codeEditor?.getContribution('snippetController2')?.insert(edit);
|
package/lib/languages.js
CHANGED
|
@@ -27,6 +27,6 @@ export async function registerProviders(worker, language, getSyncUris, languages
|
|
|
27
27
|
languages.registerDocumentSemanticTokensProvider(language, provider),
|
|
28
28
|
languages.registerDocumentRangeSemanticTokensProvider(language, provider),
|
|
29
29
|
];
|
|
30
|
-
return { dispose: () => disposables.forEach(
|
|
30
|
+
return { dispose: () => disposables.forEach(d => d.dispose()) };
|
|
31
31
|
}
|
|
32
32
|
//# sourceMappingURL=languages.js.map
|
package/lib/provider.js
CHANGED
|
@@ -245,8 +245,8 @@ export async function createLanguageFeaturesProvider(worker, getSyncUris) {
|
|
|
245
245
|
},
|
|
246
246
|
async provideSelectionRanges(model, positions) {
|
|
247
247
|
const languageService = await worker.withSyncedResources(getSyncUris());
|
|
248
|
-
const codeResults = await Promise.all(positions.map(
|
|
249
|
-
return codeResults.map(
|
|
248
|
+
const codeResults = await Promise.all(positions.map(position => languageService.getSelectionRanges(model.uri.toString(), [fromPosition(position)])));
|
|
249
|
+
return codeResults.map(codeResult => codeResult?.map(toSelectionRange) ?? []);
|
|
250
250
|
},
|
|
251
251
|
async provideSignatureHelp(model, position, _token, context) {
|
|
252
252
|
const languageService = await worker.withSyncedResources(getSyncUris());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volar/monaco",
|
|
3
|
-
"version": "2.0.0
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
"directory": "packages/monaco"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@volar/language-service": "2.0.0
|
|
17
|
-
"@volar/typescript": "2.0.0
|
|
16
|
+
"@volar/language-service": "2.0.0",
|
|
17
|
+
"@volar/typescript": "2.0.0",
|
|
18
18
|
"monaco-languageserver-types": "^0.3.2",
|
|
19
19
|
"monaco-types": "^0.1.0",
|
|
20
20
|
"vscode-uri": "^3.0.8"
|
|
@@ -22,5 +22,5 @@
|
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"monaco-editor-core": "latest"
|
|
24
24
|
},
|
|
25
|
-
"gitHead": "
|
|
25
|
+
"gitHead": "95217136d2727bb7304443d91cfde3dbe711369c"
|
|
26
26
|
}
|
package/worker.d.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
import { LanguagePlugin, ServicePlugin } from '@volar/language-service';
|
|
1
|
+
import { LanguagePlugin, ServicePlugin, type ServiceEnvironment } from '@volar/language-service';
|
|
2
2
|
import type * as monaco from 'monaco-types';
|
|
3
|
-
import type * as ts from 'typescript
|
|
4
|
-
export
|
|
3
|
+
import type * as ts from 'typescript';
|
|
4
|
+
export * from '@volar/language-service';
|
|
5
|
+
export * from './lib/ata.js';
|
|
6
|
+
export declare function createSimpleWorkerService<T = {}>({ env, workerContext, languagePlugins, servicePlugins, extraApis }: {
|
|
7
|
+
env: ServiceEnvironment;
|
|
8
|
+
workerContext: monaco.worker.IWorkerContext<any>;
|
|
9
|
+
languagePlugins?: LanguagePlugin[];
|
|
10
|
+
servicePlugins?: ServicePlugin[];
|
|
11
|
+
extraApis?: T;
|
|
12
|
+
}): {
|
|
5
13
|
getTriggerCharacters: () => string[];
|
|
6
14
|
getAutoFormatTriggerCharacters: () => string[];
|
|
7
15
|
getSignatureHelpTriggerCharacters: () => string[];
|
|
@@ -58,7 +66,15 @@ export declare function createSimpleWorkerService<T = {}>(languages: LanguagePlu
|
|
|
58
66
|
dispose: () => void;
|
|
59
67
|
context: import("@volar/language-service").ServiceContext;
|
|
60
68
|
} & T;
|
|
61
|
-
export declare function createTypeScriptWorkerService<T = {}>(
|
|
69
|
+
export declare function createTypeScriptWorkerService<T = {}>({ typecript: ts, compilerOptions, env, workerContext, languagePlugins, servicePlugins, extraApis }: {
|
|
70
|
+
typecript: typeof import('typescript');
|
|
71
|
+
compilerOptions: ts.CompilerOptions;
|
|
72
|
+
env: ServiceEnvironment;
|
|
73
|
+
workerContext: monaco.worker.IWorkerContext<any>;
|
|
74
|
+
languagePlugins?: LanguagePlugin[];
|
|
75
|
+
servicePlugins?: ServicePlugin[];
|
|
76
|
+
extraApis?: T;
|
|
77
|
+
}): {
|
|
62
78
|
getTriggerCharacters: () => string[];
|
|
63
79
|
getAutoFormatTriggerCharacters: () => string[];
|
|
64
80
|
getSignatureHelpTriggerCharacters: () => string[];
|
package/worker.js
CHANGED
|
@@ -1,104 +1,88 @@
|
|
|
1
|
-
import { createLanguageService as _createLanguageService,
|
|
2
|
-
import { URI } from 'vscode-uri';
|
|
1
|
+
import { createLanguageService as _createLanguageService, createFileRegistry, resolveCommonLanguageId, } from '@volar/language-service';
|
|
3
2
|
import { createLanguage, createSys } from '@volar/typescript';
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
export * from '@volar/language-service';
|
|
4
|
+
export * from './lib/ata.js';
|
|
5
|
+
export function createSimpleWorkerService({ env, workerContext, languagePlugins = [], servicePlugins = [], extraApis = {} }) {
|
|
6
|
+
const snapshots = new Map();
|
|
7
|
+
const files = createFileRegistry(languagePlugins, false, uri => {
|
|
8
|
+
const model = workerContext.getMirrorModels().find(model => model.uri.toString() === uri);
|
|
9
|
+
if (model) {
|
|
10
|
+
const cache = snapshots.get(model);
|
|
11
|
+
if (cache && cache[0] === model.version) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const text = model.getValue();
|
|
15
|
+
const snapshot = {
|
|
16
|
+
getText: (start, end) => text.substring(start, end),
|
|
17
|
+
getLength: () => text.length,
|
|
18
|
+
getChangeRange: () => undefined,
|
|
19
|
+
};
|
|
20
|
+
snapshots.set(model, [model.version, snapshot]);
|
|
21
|
+
files.set(uri, resolveCommonLanguageId(uri), snapshot);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
files.delete(uri);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
return createWorkerService({ files }, servicePlugins, env, extraApis);
|
|
28
|
+
}
|
|
29
|
+
export function createTypeScriptWorkerService({ typecript: ts, compilerOptions, env, workerContext, languagePlugins = [], servicePlugins = [], extraApis = {} }) {
|
|
30
|
+
let projectVersion = 0;
|
|
31
|
+
const modelSnapshot = new WeakMap();
|
|
32
|
+
const modelVersions = new Map();
|
|
33
|
+
const host = {
|
|
34
|
+
getCurrentDirectory() {
|
|
35
|
+
return env.typescript.uriToFileName(env.workspaceFolder);
|
|
36
|
+
},
|
|
37
|
+
getScriptFileNames() {
|
|
38
|
+
return workerContext.getMirrorModels().map(model => env.typescript.uriToFileName(model.uri.toString()));
|
|
39
|
+
},
|
|
40
|
+
getProjectVersion() {
|
|
41
|
+
const models = workerContext.getMirrorModels();
|
|
42
|
+
if (modelVersions.size === workerContext.getMirrorModels().length) {
|
|
43
|
+
if (models.every(model => modelVersions.get(model) === model.version)) {
|
|
44
|
+
return projectVersion.toString();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
modelVersions.clear();
|
|
48
|
+
for (const model of workerContext.getMirrorModels()) {
|
|
49
|
+
modelVersions.set(model, model.version);
|
|
50
|
+
}
|
|
51
|
+
projectVersion++;
|
|
52
|
+
return projectVersion.toString();
|
|
53
|
+
},
|
|
54
|
+
getScriptSnapshot(fileName) {
|
|
55
|
+
const uri = env.typescript.fileNameToUri(fileName);
|
|
56
|
+
const model = workerContext.getMirrorModels().find(model => model.uri.toString() === uri);
|
|
10
57
|
if (model) {
|
|
11
|
-
const cache =
|
|
58
|
+
const cache = modelSnapshot.get(model);
|
|
12
59
|
if (cache && cache[0] === model.version) {
|
|
13
|
-
return;
|
|
60
|
+
return cache[1];
|
|
14
61
|
}
|
|
15
62
|
const text = model.getValue();
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
files.updateSourceFile(fileName, resolveCommonLanguageId(fileName), snapshot);
|
|
63
|
+
modelSnapshot.set(model, [model.version, {
|
|
64
|
+
getText: (start, end) => text.substring(start, end),
|
|
65
|
+
getLength: () => text.length,
|
|
66
|
+
getChangeRange: () => undefined,
|
|
67
|
+
}]);
|
|
68
|
+
return modelSnapshot.get(model)?.[1];
|
|
23
69
|
}
|
|
24
|
-
else {
|
|
25
|
-
files.deleteSourceFile(fileName);
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
return { files };
|
|
29
|
-
}, extraApis);
|
|
30
|
-
}
|
|
31
|
-
export function createTypeScriptWorkerService(ts, languages, services, getMirrorModels, compilerOptions, extraApis = {}) {
|
|
32
|
-
return createWorkerService(services, env => {
|
|
33
|
-
let projectVersion = 0;
|
|
34
|
-
const modelSnapshot = new WeakMap();
|
|
35
|
-
const modelVersions = new Map();
|
|
36
|
-
const host = {
|
|
37
|
-
getCurrentDirectory() {
|
|
38
|
-
return env.uriToFileName(env.workspaceFolder.uri.toString(true));
|
|
39
|
-
},
|
|
40
|
-
getProjectVersion() {
|
|
41
|
-
const models = getMirrorModels();
|
|
42
|
-
if (modelVersions.size === getMirrorModels().length) {
|
|
43
|
-
if (models.every(model => modelVersions.get(model) === model.version)) {
|
|
44
|
-
return projectVersion.toString();
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
modelVersions.clear();
|
|
48
|
-
for (const model of getMirrorModels()) {
|
|
49
|
-
modelVersions.set(model, model.version);
|
|
50
|
-
}
|
|
51
|
-
projectVersion++;
|
|
52
|
-
return projectVersion.toString();
|
|
53
|
-
},
|
|
54
|
-
getScriptFileNames() {
|
|
55
|
-
const models = getMirrorModels();
|
|
56
|
-
return models.map(model => env.uriToFileName(model.uri.toString(true)));
|
|
57
|
-
},
|
|
58
|
-
getScriptSnapshot(fileName) {
|
|
59
|
-
const uri = env.fileNameToUri(fileName);
|
|
60
|
-
const model = getMirrorModels().find(model => model.uri.toString(true) === uri);
|
|
61
|
-
if (model) {
|
|
62
|
-
const cache = modelSnapshot.get(model);
|
|
63
|
-
if (cache && cache[0] === model.version) {
|
|
64
|
-
return cache[1];
|
|
65
|
-
}
|
|
66
|
-
const text = model.getValue();
|
|
67
|
-
modelSnapshot.set(model, [model.version, {
|
|
68
|
-
getText: (start, end) => text.substring(start, end),
|
|
69
|
-
getLength: () => text.length,
|
|
70
|
-
getChangeRange: () => undefined,
|
|
71
|
-
}]);
|
|
72
|
-
return modelSnapshot.get(model)?.[1];
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
getCompilationSettings() {
|
|
76
|
-
return compilerOptions;
|
|
77
|
-
},
|
|
78
|
-
getLanguageId: id => resolveCommonLanguageId(id),
|
|
79
|
-
};
|
|
80
|
-
const sys = createSys(ts, env, host.getCurrentDirectory());
|
|
81
|
-
const language = createLanguage(ts, sys, languages, undefined, host);
|
|
82
|
-
return language;
|
|
83
|
-
}, extraApis);
|
|
84
|
-
}
|
|
85
|
-
function createWorkerService(services, getLanguage, extraApis = {}) {
|
|
86
|
-
const env = {
|
|
87
|
-
workspaceFolder: {
|
|
88
|
-
uri: URI.file('/'),
|
|
89
|
-
name: '',
|
|
90
70
|
},
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
71
|
+
getCompilationSettings() {
|
|
72
|
+
return compilerOptions;
|
|
73
|
+
},
|
|
74
|
+
getLanguageId: id => resolveCommonLanguageId(id),
|
|
94
75
|
};
|
|
95
|
-
const
|
|
96
|
-
const
|
|
76
|
+
const sys = createSys(ts, env, host);
|
|
77
|
+
const languageContext = createLanguage(ts, sys, languagePlugins, undefined, host, {
|
|
78
|
+
fileNameToFileId: env.typescript.fileNameToUri,
|
|
79
|
+
fileIdToFileName: env.typescript.uriToFileName,
|
|
80
|
+
});
|
|
81
|
+
return createWorkerService(languageContext, servicePlugins, env, extraApis);
|
|
82
|
+
}
|
|
83
|
+
function createWorkerService(languageContext, servicePlugins, env, extraApis = {}) {
|
|
84
|
+
const languageService = _createLanguageService(languageContext, servicePlugins, env);
|
|
97
85
|
class WorkerService {
|
|
98
|
-
constructor() {
|
|
99
|
-
this.env = env;
|
|
100
|
-
this.project = language;
|
|
101
|
-
}
|
|
102
86
|
}
|
|
103
87
|
;
|
|
104
88
|
for (const api in languageService) {
|