@codingame/monaco-vscode-api 1.76.2 → 1.76.3-next.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 +2 -1
- package/dist/api.js +3 -860
- package/dist/{extHost.js → api2.js} +16555 -13467
- package/dist/async.js +107 -2
- package/dist/audioCue.js +105 -103
- package/dist/button.js +1 -1
- package/dist/cancellation.js +3 -0
- package/dist/configuration.js +7 -344
- package/dist/configuration2.js +339 -0
- package/dist/configurationRegistry.js +441 -0
- package/dist/contextkeys.js +211 -0
- package/dist/debug.d.ts +22 -0
- package/dist/debug.js +15842 -0
- package/dist/dialogs.js +855 -9
- package/dist/extensionResourceLoader.js +96 -0
- package/dist/extensions.d.ts +491 -0
- package/dist/extensions.js +70 -0
- package/dist/{tools.js → extensionsRegistry.js} +2 -30
- package/dist/files.js +1407 -334
- package/dist/iconv.js +43 -0
- package/dist/injection.js +1 -1
- package/dist/jschardet.js +7 -0
- package/dist/keybindings.d.ts +1 -485
- package/dist/keybindings.js +666 -679
- package/dist/labels.js +14 -0
- package/dist/languageConfiguration.d.ts +1 -2
- package/dist/languageConfiguration.js +9 -16
- package/dist/languageService.js +112 -8
- package/dist/languages.d.ts +1 -473
- package/dist/languages.js +2 -12
- package/dist/layout.js +4 -3
- package/dist/layoutService.js +1 -1
- package/dist/missing-services.js +4710 -74
- package/dist/modelEditor.d.ts +324 -2
- package/dist/modelEditor.js +15 -228
- package/dist/monaco.js +7 -72
- package/dist/notifications.js +75 -232
- package/dist/polyfill.js +10715 -2459
- package/dist/resources.js +197 -0
- package/dist/services.d.ts +924 -3
- package/dist/services.js +1 -2
- package/dist/services2.js +2436 -18
- package/dist/snippets.d.ts +1 -473
- package/dist/snippets.js +8 -867
- package/dist/snippetsService.js +868 -0
- package/dist/textFileEditorModel.js +2985 -0
- package/dist/textmate.d.ts +3 -475
- package/dist/textmate.js +19 -29
- package/dist/theme.d.ts +1 -3
- package/dist/theme.js +24 -70
- package/dist/tokenClassification.d.ts +1 -475
- package/dist/tokenClassification.js +11 -37
- package/dist/tokenClassificationRegistry.js +8 -4
- package/dist/variableResolver.js +1711 -0
- package/dist/workbenchThemeService.js +1 -1
- package/dist/workspaceContext.js +1 -3
- package/package.json +27 -12
- package/dist/contextkey.js +0 -419
- package/dist/dialog.web.contribution.js +0 -945
|
@@ -0,0 +1,868 @@
|
|
|
1
|
+
import { y as ISnippetsService, _ as __decorate, a as __param, n as IFileService, l as ITextFileService } from './services2.js';
|
|
2
|
+
import * as monacoSuggest from 'monaco-editor/esm/vs/editor/contrib/suggest/browser/suggest.js';
|
|
3
|
+
import { bU as IUserDataProfileService, bL as ILifecycleService } from './missing-services.js';
|
|
4
|
+
import { _ as isStringArray, p as parse, j as getNodeType, R as Range } from './polyfill.js';
|
|
5
|
+
import { extname as extname$1, basename as basename$1 } from 'monaco-editor/esm/vs/base/common/path.js';
|
|
6
|
+
import { Iterable } from 'monaco-editor/esm/vs/base/common/iterator.js';
|
|
7
|
+
import { isEqualOrParent, extname, basename, relativePath, joinPath } from 'monaco-editor/esm/vs/base/common/resources.js';
|
|
8
|
+
import { IdleValue } from 'monaco-editor/esm/vs/base/common/async.js';
|
|
9
|
+
import { isObject } from 'monaco-editor/esm/vs/base/common/types.js';
|
|
10
|
+
import { localize } from 'monaco-editor/esm/vs/nls.js';
|
|
11
|
+
import { SnippetParser, Placeholder, Variable, Text } from 'monaco-editor/esm/vs/editor/contrib/snippet/browser/snippetParser.js';
|
|
12
|
+
import { tail, insertInto } from 'monaco-editor/esm/vs/base/common/arrays.js';
|
|
13
|
+
import { KnownSnippetVariableNames } from 'monaco-editor/esm/vs/editor/contrib/snippet/browser/snippetVariables.js';
|
|
14
|
+
import { E as ExtensionsRegistry } from './extensionsRegistry.js';
|
|
15
|
+
import { l as languagesExtPoint } from './languageService.js';
|
|
16
|
+
import { CommandsRegistry } from 'monaco-editor/esm/vs/platform/commands/common/commands.js';
|
|
17
|
+
import { getWordAtText } from 'monaco-editor/esm/vs/editor/common/core/wordHelper.js';
|
|
18
|
+
import { isPatternInWord } from 'monaco-editor/esm/vs/base/common/filters.js';
|
|
19
|
+
import { compare, firstNonWhitespaceIndex, compareSubstring, isFalsyOrWhitespace } from 'monaco-editor/esm/vs/base/common/strings.js';
|
|
20
|
+
import { ILanguageService } from 'monaco-editor/esm/vs/editor/common/languages/language.js';
|
|
21
|
+
import { ILanguageConfigurationService } from 'monaco-editor/esm/vs/editor/common/languages/languageConfigurationRegistry.js';
|
|
22
|
+
import { MarkdownString } from 'monaco-editor/esm/vs/base/common/htmlContent.js';
|
|
23
|
+
import { StopWatch } from 'monaco-editor/esm/vs/base/common/stopwatch.js';
|
|
24
|
+
import { I as IExtensionResourceLoaderService } from './extensionResourceLoader.js';
|
|
25
|
+
import { DisposableStore, combinedDisposable } from 'monaco-editor/esm/vs/base/common/lifecycle.js';
|
|
26
|
+
import { ResourceMap } from 'monaco-editor/esm/vs/base/common/map.js';
|
|
27
|
+
import { IStorageService } from 'monaco-editor/esm/vs/platform/storage/common/storage.js';
|
|
28
|
+
import { IEnvironmentService } from 'monaco-editor/esm/vs/platform/environment/common/environment.js';
|
|
29
|
+
import { IWorkspaceContextService } from 'monaco-editor/esm/vs/platform/workspace/common/workspace.js';
|
|
30
|
+
import { ILogService } from 'monaco-editor/esm/vs/platform/log/common/log.js';
|
|
31
|
+
import { IInstantiationService } from 'monaco-editor/esm/vs/platform/instantiation/common/instantiation.js';
|
|
32
|
+
function setSnippetSuggestSupport (support) {
|
|
33
|
+
if (monacoSuggest.setSnippetSuggestSupport != null) {
|
|
34
|
+
monacoSuggest.setSnippetSuggestSupport(support);
|
|
35
|
+
} else {
|
|
36
|
+
console.error(
|
|
37
|
+
`setSnippetSuggestSupport does not exist in monaco-editor.
|
|
38
|
+
It's treeshaked out of monaco editor and needs to be reintroduced.
|
|
39
|
+
If you're using webpack, you can add a loader that will polyfill it:
|
|
40
|
+
\`\`\`
|
|
41
|
+
{
|
|
42
|
+
test: /node_modules\\/monaco-editor\\//,
|
|
43
|
+
loader: 'vscode/webpack-loader'
|
|
44
|
+
}
|
|
45
|
+
\`\`\`
|
|
46
|
+
`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
class SnippetBodyInsights {
|
|
50
|
+
constructor(body) {
|
|
51
|
+
this.isBogous = false;
|
|
52
|
+
this.isTrivial = false;
|
|
53
|
+
this.usesClipboardVariable = false;
|
|
54
|
+
this.usesSelectionVariable = false;
|
|
55
|
+
this.codeSnippet = body;
|
|
56
|
+
const textmateSnippet = ( (new SnippetParser())).parse(body, false);
|
|
57
|
+
const placeholders = ( (new Map()));
|
|
58
|
+
let placeholderMax = 0;
|
|
59
|
+
for (const placeholder of textmateSnippet.placeholders) {
|
|
60
|
+
placeholderMax = Math.max(placeholderMax, placeholder.index);
|
|
61
|
+
}
|
|
62
|
+
if (textmateSnippet.placeholders.length === 0) {
|
|
63
|
+
this.isTrivial = true;
|
|
64
|
+
}
|
|
65
|
+
else if (placeholderMax === 0) {
|
|
66
|
+
const last = tail(textmateSnippet.children);
|
|
67
|
+
this.isTrivial = last instanceof Placeholder && last.isFinalTabstop;
|
|
68
|
+
}
|
|
69
|
+
const stack = [...textmateSnippet.children];
|
|
70
|
+
while (stack.length > 0) {
|
|
71
|
+
const marker = stack.shift();
|
|
72
|
+
if (marker instanceof Variable) {
|
|
73
|
+
if (marker.children.length === 0 && !KnownSnippetVariableNames[marker.name]) {
|
|
74
|
+
const index = placeholders.has(marker.name) ? placeholders.get(marker.name) : ++placeholderMax;
|
|
75
|
+
placeholders.set(marker.name, index);
|
|
76
|
+
const synthetic = ( (new Placeholder(index))).appendChild(( (new Text(marker.name))));
|
|
77
|
+
textmateSnippet.replace(marker, [synthetic]);
|
|
78
|
+
this.isBogous = true;
|
|
79
|
+
}
|
|
80
|
+
switch (marker.name) {
|
|
81
|
+
case 'CLIPBOARD':
|
|
82
|
+
this.usesClipboardVariable = true;
|
|
83
|
+
break;
|
|
84
|
+
case 'SELECTION':
|
|
85
|
+
case 'TM_SELECTED_TEXT':
|
|
86
|
+
this.usesSelectionVariable = true;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
stack.push(...marker.children);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (this.isBogous) {
|
|
95
|
+
this.codeSnippet = textmateSnippet.toTextmateString();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
class Snippet {
|
|
100
|
+
constructor(isFileTemplate, scopes, name, prefix, description, body, source, snippetSource, snippetIdentifier, extensionId) {
|
|
101
|
+
this.isFileTemplate = isFileTemplate;
|
|
102
|
+
this.scopes = scopes;
|
|
103
|
+
this.name = name;
|
|
104
|
+
this.prefix = prefix;
|
|
105
|
+
this.description = description;
|
|
106
|
+
this.body = body;
|
|
107
|
+
this.source = source;
|
|
108
|
+
this.snippetSource = snippetSource;
|
|
109
|
+
this.snippetIdentifier = snippetIdentifier;
|
|
110
|
+
this.extensionId = extensionId;
|
|
111
|
+
this.prefixLow = prefix.toLowerCase();
|
|
112
|
+
this._bodyInsights = ( (new IdleValue(() => ( (new SnippetBodyInsights(this.body))))));
|
|
113
|
+
}
|
|
114
|
+
get codeSnippet() {
|
|
115
|
+
return this._bodyInsights.value.codeSnippet;
|
|
116
|
+
}
|
|
117
|
+
get isBogous() {
|
|
118
|
+
return this._bodyInsights.value.isBogous;
|
|
119
|
+
}
|
|
120
|
+
get isTrivial() {
|
|
121
|
+
return this._bodyInsights.value.isTrivial;
|
|
122
|
+
}
|
|
123
|
+
get needsClipboard() {
|
|
124
|
+
return this._bodyInsights.value.usesClipboardVariable;
|
|
125
|
+
}
|
|
126
|
+
get usesSelection() {
|
|
127
|
+
return this._bodyInsights.value.usesSelectionVariable;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function isJsonSerializedSnippet(thing) {
|
|
131
|
+
return isObject(thing) && Boolean(thing.body);
|
|
132
|
+
}
|
|
133
|
+
class SnippetFile {
|
|
134
|
+
constructor(source, location, defaultScopes, _extension, _fileService, _extensionResourceLoaderService) {
|
|
135
|
+
this.source = source;
|
|
136
|
+
this.location = location;
|
|
137
|
+
this.defaultScopes = defaultScopes;
|
|
138
|
+
this._extension = _extension;
|
|
139
|
+
this._fileService = _fileService;
|
|
140
|
+
this._extensionResourceLoaderService = _extensionResourceLoaderService;
|
|
141
|
+
this.data = [];
|
|
142
|
+
this.isGlobalSnippets = extname$1(location.path) === '.code-snippets';
|
|
143
|
+
this.isUserSnippets = !this._extension;
|
|
144
|
+
}
|
|
145
|
+
select(selector, bucket) {
|
|
146
|
+
if (this.isGlobalSnippets || !this.isUserSnippets) {
|
|
147
|
+
this._scopeSelect(selector, bucket);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
this._filepathSelect(selector, bucket);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
_filepathSelect(selector, bucket) {
|
|
154
|
+
if (selector + '.json' === basename$1(this.location.path)) {
|
|
155
|
+
bucket.push(...this.data);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
_scopeSelect(selector, bucket) {
|
|
159
|
+
for (const snippet of this.data) {
|
|
160
|
+
const len = snippet.scopes.length;
|
|
161
|
+
if (len === 0) {
|
|
162
|
+
bucket.push(snippet);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
for (let i = 0; i < len; i++) {
|
|
166
|
+
if (snippet.scopes[i] === selector) {
|
|
167
|
+
bucket.push(snippet);
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const idx = selector.lastIndexOf('.');
|
|
174
|
+
if (idx >= 0) {
|
|
175
|
+
this._scopeSelect(selector.substring(0, idx), bucket);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
async _load() {
|
|
179
|
+
if (this._extension) {
|
|
180
|
+
return this._extensionResourceLoaderService.readExtensionResource(this.location);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
const content = await this._fileService.readFile(this.location);
|
|
184
|
+
return (
|
|
185
|
+
(content.value.toString())
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
load() {
|
|
190
|
+
if (!this._loadPromise) {
|
|
191
|
+
this._loadPromise = Promise.resolve(this._load()).then(content => {
|
|
192
|
+
const data = parse(content);
|
|
193
|
+
if (getNodeType(data) === 'object') {
|
|
194
|
+
for (const [name, scopeOrTemplate] of Object.entries(data)) {
|
|
195
|
+
if (isJsonSerializedSnippet(scopeOrTemplate)) {
|
|
196
|
+
this._parseSnippet(name, scopeOrTemplate, this.data);
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
for (const [name, template] of Object.entries(scopeOrTemplate)) {
|
|
200
|
+
this._parseSnippet(name, template, this.data);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return this;
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
return this._loadPromise;
|
|
209
|
+
}
|
|
210
|
+
reset() {
|
|
211
|
+
this._loadPromise = undefined;
|
|
212
|
+
this.data.length = 0;
|
|
213
|
+
}
|
|
214
|
+
_parseSnippet(name, snippet, bucket) {
|
|
215
|
+
let { isFileTemplate, prefix, body, description } = snippet;
|
|
216
|
+
if (!prefix) {
|
|
217
|
+
prefix = '';
|
|
218
|
+
}
|
|
219
|
+
if (Array.isArray(body)) {
|
|
220
|
+
body = body.join('\n');
|
|
221
|
+
}
|
|
222
|
+
if (typeof body !== 'string') {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (Array.isArray(description)) {
|
|
226
|
+
description = description.join('\n');
|
|
227
|
+
}
|
|
228
|
+
let scopes;
|
|
229
|
+
if (this.defaultScopes) {
|
|
230
|
+
scopes = this.defaultScopes;
|
|
231
|
+
}
|
|
232
|
+
else if (typeof snippet.scope === 'string') {
|
|
233
|
+
scopes = ( (snippet.scope.split(',').map(s => s.trim()))).filter(Boolean);
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
scopes = [];
|
|
237
|
+
}
|
|
238
|
+
let source;
|
|
239
|
+
if (this._extension) {
|
|
240
|
+
source = this._extension.displayName || this._extension.name;
|
|
241
|
+
}
|
|
242
|
+
else if (this.source === 2 ) {
|
|
243
|
+
source = ( (localize('source.workspaceSnippetGlobal', "Workspace Snippet")));
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
if (this.isGlobalSnippets) {
|
|
247
|
+
source = ( (localize('source.userSnippetGlobal', "Global User Snippet")));
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
source = ( (localize('source.userSnippet', "User Snippet")));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
for (const _prefix of Iterable.wrap(prefix)) {
|
|
254
|
+
bucket.push(( (new Snippet(
|
|
255
|
+
Boolean(isFileTemplate),
|
|
256
|
+
scopes,
|
|
257
|
+
name,
|
|
258
|
+
_prefix,
|
|
259
|
+
description,
|
|
260
|
+
body,
|
|
261
|
+
source,
|
|
262
|
+
this.source,
|
|
263
|
+
this._extension ? `${relativePath(this._extension.extensionLocation, this.location)}/${name}` : `${basename$1(this.location.path)}/${name}`,
|
|
264
|
+
this._extension?.identifier
|
|
265
|
+
))));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
const markSnippetAsUsed = '_snippet.markAsUsed';
|
|
270
|
+
CommandsRegistry.registerCommand(markSnippetAsUsed, (accessor, ...args) => {
|
|
271
|
+
const snippetsService = accessor.get(ISnippetsService);
|
|
272
|
+
const [first] = args;
|
|
273
|
+
if (first instanceof Snippet) {
|
|
274
|
+
snippetsService.updateUsageTimestamp(first);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
class SnippetCompletion {
|
|
278
|
+
constructor(snippet, range) {
|
|
279
|
+
this.snippet = snippet;
|
|
280
|
+
this.label = { label: snippet.prefix, description: snippet.name };
|
|
281
|
+
this.detail = ( (localize(
|
|
282
|
+
'detail.snippet',
|
|
283
|
+
"{0} ({1})",
|
|
284
|
+
snippet.description || snippet.name,
|
|
285
|
+
snippet.source
|
|
286
|
+
)));
|
|
287
|
+
this.insertText = snippet.codeSnippet;
|
|
288
|
+
this.extensionId = snippet.extensionId;
|
|
289
|
+
this.range = range;
|
|
290
|
+
this.sortText = `${snippet.snippetSource === 3 ? 'z' : 'a'}-${snippet.prefix}`;
|
|
291
|
+
this.kind = 27 ;
|
|
292
|
+
this.insertTextRules = 4 ;
|
|
293
|
+
this.command = { id: markSnippetAsUsed, title: '', arguments: [snippet] };
|
|
294
|
+
}
|
|
295
|
+
resolve() {
|
|
296
|
+
this.documentation = ( (new MarkdownString())).appendCodeblock('', SnippetParser.asInsertText(this.snippet.codeSnippet));
|
|
297
|
+
return this;
|
|
298
|
+
}
|
|
299
|
+
static compareByLabel(a, b) {
|
|
300
|
+
return compare(a.label.label, b.label.label);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
let SnippetCompletionProvider = class SnippetCompletionProvider {
|
|
304
|
+
constructor(_languageService, _snippets, _languageConfigurationService) {
|
|
305
|
+
this._languageService = _languageService;
|
|
306
|
+
this._snippets = _snippets;
|
|
307
|
+
this._languageConfigurationService = _languageConfigurationService;
|
|
308
|
+
this._debugDisplayName = 'snippetCompletions';
|
|
309
|
+
}
|
|
310
|
+
async provideCompletionItems(model, position, context) {
|
|
311
|
+
const sw = ( (new StopWatch(true)));
|
|
312
|
+
const languageId = this._getLanguageIdAtPosition(model, position);
|
|
313
|
+
const languageConfig = this._languageConfigurationService.getLanguageConfiguration(languageId);
|
|
314
|
+
const snippets = ( (new Set(await this._snippets.getSnippets(languageId))));
|
|
315
|
+
const lineContentLow = model.getLineContent(position.lineNumber).toLowerCase();
|
|
316
|
+
const wordUntil = model.getWordUntilPosition(position).word.toLowerCase();
|
|
317
|
+
const suggestions = [];
|
|
318
|
+
const columnOffset = position.column - 1;
|
|
319
|
+
const triggerCharacterLow = context.triggerCharacter?.toLowerCase() ?? '';
|
|
320
|
+
snippet: for (const snippet of snippets) {
|
|
321
|
+
if (context.triggerKind === 1 && !snippet.prefixLow.startsWith(triggerCharacterLow)) {
|
|
322
|
+
continue snippet;
|
|
323
|
+
}
|
|
324
|
+
const word = getWordAtText(1, languageConfig.getWordDefinition(), snippet.prefixLow, 0);
|
|
325
|
+
if (wordUntil && word && !isPatternInWord(wordUntil, 0, wordUntil.length, snippet.prefixLow, 0, snippet.prefixLow.length)) {
|
|
326
|
+
continue snippet;
|
|
327
|
+
}
|
|
328
|
+
const minPos = firstNonWhitespaceIndex(snippet.prefixLow) === 0
|
|
329
|
+
? Math.max(0, model.getLineFirstNonWhitespaceColumn(position.lineNumber) - 1)
|
|
330
|
+
: 0;
|
|
331
|
+
column: for (let pos = Math.max(minPos, columnOffset - snippet.prefixLow.length); pos < lineContentLow.length; pos++) {
|
|
332
|
+
if (!isPatternInWord(lineContentLow, pos, columnOffset, snippet.prefixLow, 0, snippet.prefixLow.length)) {
|
|
333
|
+
continue column;
|
|
334
|
+
}
|
|
335
|
+
const prefixRestLen = snippet.prefixLow.length - (columnOffset - pos);
|
|
336
|
+
const endsWithPrefixRest = compareSubstring(lineContentLow, snippet.prefixLow, columnOffset, columnOffset + prefixRestLen, columnOffset - pos);
|
|
337
|
+
const startPosition = position.with(undefined, pos + 1);
|
|
338
|
+
if (wordUntil && position.equals(startPosition)) {
|
|
339
|
+
continue snippet;
|
|
340
|
+
}
|
|
341
|
+
let endColumn = endsWithPrefixRest === 0 ? position.column + prefixRestLen : position.column;
|
|
342
|
+
if (columnOffset < lineContentLow.length) {
|
|
343
|
+
const autoClosingPairs = languageConfig.getAutoClosingPairs();
|
|
344
|
+
const standardAutoClosingPairConditionals = autoClosingPairs.autoClosingPairsCloseSingleChar.get(lineContentLow[columnOffset]);
|
|
345
|
+
if (standardAutoClosingPairConditionals?.some(p =>
|
|
346
|
+
p.open === lineContentLow[startPosition.column - 1] &&
|
|
347
|
+
snippet.prefix.startsWith(p.open) &&
|
|
348
|
+
snippet.prefix[snippet.prefix.length - 1] === p.close)) {
|
|
349
|
+
endColumn++;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
const replace = Range.fromPositions(startPosition, { lineNumber: position.lineNumber, column: endColumn });
|
|
353
|
+
const insert = replace.setEndPosition(position.lineNumber, position.column);
|
|
354
|
+
suggestions.push(( (new SnippetCompletion(snippet, { replace, insert }))));
|
|
355
|
+
snippets.delete(snippet);
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (!triggerCharacterLow) {
|
|
360
|
+
const endsInWhitespace = /\s/.test(lineContentLow[position.column - 2]);
|
|
361
|
+
if (endsInWhitespace || !lineContentLow ) {
|
|
362
|
+
for (const snippet of snippets) {
|
|
363
|
+
const insert = Range.fromPositions(position);
|
|
364
|
+
const replace = lineContentLow.indexOf(snippet.prefixLow, columnOffset) === columnOffset ? insert.setEndPosition(position.lineNumber, position.column + snippet.prefixLow.length) : insert;
|
|
365
|
+
suggestions.push(( (new SnippetCompletion(snippet, { replace, insert }))));
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
suggestions.sort(SnippetCompletion.compareByLabel);
|
|
370
|
+
for (let i = 0; i < suggestions.length; i++) {
|
|
371
|
+
const item = suggestions[i];
|
|
372
|
+
let to = i + 1;
|
|
373
|
+
for (; to < suggestions.length && item.label === suggestions[to].label; to++) {
|
|
374
|
+
suggestions[to].label.label = ( (localize(
|
|
375
|
+
'snippetSuggest.longLabel',
|
|
376
|
+
"{0}, {1}",
|
|
377
|
+
suggestions[to].label.label,
|
|
378
|
+
suggestions[to].snippet.name
|
|
379
|
+
)));
|
|
380
|
+
}
|
|
381
|
+
if (to > i + 1) {
|
|
382
|
+
suggestions[i].label.label = ( (localize(
|
|
383
|
+
'snippetSuggest.longLabel',
|
|
384
|
+
"{0}, {1}",
|
|
385
|
+
suggestions[i].label.label,
|
|
386
|
+
suggestions[i].snippet.name
|
|
387
|
+
)));
|
|
388
|
+
i = to;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return {
|
|
392
|
+
suggestions,
|
|
393
|
+
duration: sw.elapsed()
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
resolveCompletionItem(item) {
|
|
397
|
+
return (item instanceof SnippetCompletion) ? item.resolve() : item;
|
|
398
|
+
}
|
|
399
|
+
_getLanguageIdAtPosition(model, position) {
|
|
400
|
+
model.tokenization.tokenizeIfCheap(position.lineNumber);
|
|
401
|
+
let languageId = model.getLanguageIdAtPosition(position.lineNumber, position.column);
|
|
402
|
+
if (!this._languageService.getLanguageName(languageId)) {
|
|
403
|
+
languageId = model.getLanguageId();
|
|
404
|
+
}
|
|
405
|
+
return languageId;
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
SnippetCompletionProvider = ( (__decorate([
|
|
409
|
+
( (__param(0, ILanguageService))),
|
|
410
|
+
( (__param(1, ISnippetsService))),
|
|
411
|
+
( (__param(2, ILanguageConfigurationService)))
|
|
412
|
+
], SnippetCompletionProvider)));
|
|
413
|
+
var snippetExt;
|
|
414
|
+
( ((function(snippetExt) {
|
|
415
|
+
function toValidSnippet(extension, snippet, languageService) {
|
|
416
|
+
if (isFalsyOrWhitespace(snippet.path)) {
|
|
417
|
+
extension.collector.error(( (localize(
|
|
418
|
+
'invalid.path.0',
|
|
419
|
+
"Expected string in `contributes.{0}.path`. Provided value: {1}",
|
|
420
|
+
extension.description.name,
|
|
421
|
+
String(snippet.path)
|
|
422
|
+
))));
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
425
|
+
if (isFalsyOrWhitespace(snippet.language) && !snippet.path.endsWith('.code-snippets')) {
|
|
426
|
+
extension.collector.error(( (localize(
|
|
427
|
+
'invalid.language.0',
|
|
428
|
+
"When omitting the language, the value of `contributes.{0}.path` must be a `.code-snippets`-file. Provided value: {1}",
|
|
429
|
+
extension.description.name,
|
|
430
|
+
String(snippet.path)
|
|
431
|
+
))));
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
if (!isFalsyOrWhitespace(snippet.language) && !languageService.isRegisteredLanguageId(snippet.language)) {
|
|
435
|
+
extension.collector.error(( (localize(
|
|
436
|
+
'invalid.language',
|
|
437
|
+
"Unknown language in `contributes.{0}.language`. Provided value: {1}",
|
|
438
|
+
extension.description.name,
|
|
439
|
+
String(snippet.language)
|
|
440
|
+
))));
|
|
441
|
+
return null;
|
|
442
|
+
}
|
|
443
|
+
const extensionLocation = extension.description.extensionLocation;
|
|
444
|
+
const snippetLocation = joinPath(extensionLocation, snippet.path);
|
|
445
|
+
if (!isEqualOrParent(snippetLocation, extensionLocation)) {
|
|
446
|
+
extension.collector.error(( (localize(
|
|
447
|
+
'invalid.path.1',
|
|
448
|
+
"Expected `contributes.{0}.path` ({1}) to be included inside extension's folder ({2}). This might make the extension non-portable.",
|
|
449
|
+
extension.description.name,
|
|
450
|
+
snippetLocation.path,
|
|
451
|
+
extensionLocation.path
|
|
452
|
+
))));
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
return {
|
|
456
|
+
language: snippet.language,
|
|
457
|
+
location: snippetLocation
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
snippetExt.toValidSnippet = toValidSnippet;
|
|
461
|
+
snippetExt.snippetsContribution = {
|
|
462
|
+
description: ( (localize('vscode.extension.contributes.snippets', 'Contributes snippets.'))),
|
|
463
|
+
type: 'array',
|
|
464
|
+
defaultSnippets: [{ body: [{ language: '', path: '' }] }],
|
|
465
|
+
items: {
|
|
466
|
+
type: 'object',
|
|
467
|
+
defaultSnippets: [{ body: { language: '${1:id}', path: './snippets/${2:id}.json.' } }],
|
|
468
|
+
properties: {
|
|
469
|
+
language: {
|
|
470
|
+
description: ( (localize(
|
|
471
|
+
'vscode.extension.contributes.snippets-language',
|
|
472
|
+
'Language identifier for which this snippet is contributed to.'
|
|
473
|
+
))),
|
|
474
|
+
type: 'string'
|
|
475
|
+
},
|
|
476
|
+
path: {
|
|
477
|
+
description: ( (localize(
|
|
478
|
+
'vscode.extension.contributes.snippets-path',
|
|
479
|
+
'Path of the snippets file. The path is relative to the extension folder and typically starts with \'./snippets/\'.'
|
|
480
|
+
))),
|
|
481
|
+
type: 'string'
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
snippetExt.point = ( (ExtensionsRegistry.registerExtensionPoint({
|
|
487
|
+
extensionPoint: 'snippets',
|
|
488
|
+
deps: [languagesExtPoint],
|
|
489
|
+
jsonSchema: snippetExt.snippetsContribution
|
|
490
|
+
})));
|
|
491
|
+
})(snippetExt || (snippetExt = {}))));
|
|
492
|
+
function watch(service, resource, callback) {
|
|
493
|
+
return combinedDisposable(service.watch(resource), service.onDidFilesChange(e => {
|
|
494
|
+
if (e.affects(resource)) {
|
|
495
|
+
callback();
|
|
496
|
+
}
|
|
497
|
+
}));
|
|
498
|
+
}
|
|
499
|
+
let SnippetEnablement = class SnippetEnablement {
|
|
500
|
+
constructor(_storageService) {
|
|
501
|
+
this._storageService = _storageService;
|
|
502
|
+
const raw = _storageService.get(SnippetEnablement._key, 0 , '');
|
|
503
|
+
let data;
|
|
504
|
+
try {
|
|
505
|
+
data = JSON.parse(raw);
|
|
506
|
+
}
|
|
507
|
+
catch { }
|
|
508
|
+
this._ignored = isStringArray(data) ? ( (new Set(data))) : ( (new Set()));
|
|
509
|
+
}
|
|
510
|
+
isIgnored(id) {
|
|
511
|
+
return this._ignored.has(id);
|
|
512
|
+
}
|
|
513
|
+
updateIgnored(id, value) {
|
|
514
|
+
let changed = false;
|
|
515
|
+
if (this._ignored.has(id) && !value) {
|
|
516
|
+
this._ignored.delete(id);
|
|
517
|
+
changed = true;
|
|
518
|
+
}
|
|
519
|
+
else if (!this._ignored.has(id) && value) {
|
|
520
|
+
this._ignored.add(id);
|
|
521
|
+
changed = true;
|
|
522
|
+
}
|
|
523
|
+
if (changed) {
|
|
524
|
+
this._storageService.store(SnippetEnablement._key, JSON.stringify(Array.from(this._ignored)), 0 , 0 );
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
SnippetEnablement._key = 'snippets.ignoredSnippets';
|
|
529
|
+
SnippetEnablement = ( (__decorate([
|
|
530
|
+
( (__param(0, IStorageService)))
|
|
531
|
+
], SnippetEnablement)));
|
|
532
|
+
let SnippetUsageTimestamps = class SnippetUsageTimestamps {
|
|
533
|
+
constructor(_storageService) {
|
|
534
|
+
this._storageService = _storageService;
|
|
535
|
+
const raw = _storageService.get(SnippetUsageTimestamps._key, 0 , '');
|
|
536
|
+
let data;
|
|
537
|
+
try {
|
|
538
|
+
data = JSON.parse(raw);
|
|
539
|
+
}
|
|
540
|
+
catch {
|
|
541
|
+
data = [];
|
|
542
|
+
}
|
|
543
|
+
this._usages = Array.isArray(data) ? ( (new Map(data))) : ( (new Map()));
|
|
544
|
+
}
|
|
545
|
+
getUsageTimestamp(id) {
|
|
546
|
+
return this._usages.get(id);
|
|
547
|
+
}
|
|
548
|
+
updateUsageTimestamp(id) {
|
|
549
|
+
this._usages.delete(id);
|
|
550
|
+
this._usages.set(id, Date.now());
|
|
551
|
+
const all = [...this._usages].slice(-100);
|
|
552
|
+
this._storageService.store(SnippetUsageTimestamps._key, JSON.stringify(all), 0 , 0 );
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
SnippetUsageTimestamps._key = 'snippets.usageTimestamps';
|
|
556
|
+
SnippetUsageTimestamps = ( (__decorate([
|
|
557
|
+
( (__param(0, IStorageService)))
|
|
558
|
+
], SnippetUsageTimestamps)));
|
|
559
|
+
let SnippetsService = class SnippetsService {
|
|
560
|
+
constructor(_environmentService, _userDataProfileService, _contextService, _languageService, _logService, _fileService, _textfileService, _extensionResourceLoaderService, lifecycleService, instantiationService, languageConfigurationService) {
|
|
561
|
+
this._environmentService = _environmentService;
|
|
562
|
+
this._userDataProfileService = _userDataProfileService;
|
|
563
|
+
this._contextService = _contextService;
|
|
564
|
+
this._languageService = _languageService;
|
|
565
|
+
this._logService = _logService;
|
|
566
|
+
this._fileService = _fileService;
|
|
567
|
+
this._textfileService = _textfileService;
|
|
568
|
+
this._extensionResourceLoaderService = _extensionResourceLoaderService;
|
|
569
|
+
this._disposables = ( (new DisposableStore()));
|
|
570
|
+
this._pendingWork = [];
|
|
571
|
+
this._files = ( (new ResourceMap()));
|
|
572
|
+
this._pendingWork.push(Promise.resolve(lifecycleService.when(3 ).then(() => {
|
|
573
|
+
this._initExtensionSnippets();
|
|
574
|
+
this._initUserSnippets();
|
|
575
|
+
this._initWorkspaceSnippets();
|
|
576
|
+
})));
|
|
577
|
+
setSnippetSuggestSupport(( (new SnippetCompletionProvider(this._languageService, this, languageConfigurationService))));
|
|
578
|
+
this._enablement = instantiationService.createInstance(SnippetEnablement);
|
|
579
|
+
this._usageTimestamps = instantiationService.createInstance(SnippetUsageTimestamps);
|
|
580
|
+
}
|
|
581
|
+
dispose() {
|
|
582
|
+
this._disposables.dispose();
|
|
583
|
+
}
|
|
584
|
+
isEnabled(snippet) {
|
|
585
|
+
return !this._enablement.isIgnored(snippet.snippetIdentifier);
|
|
586
|
+
}
|
|
587
|
+
updateEnablement(snippet, enabled) {
|
|
588
|
+
this._enablement.updateIgnored(snippet.snippetIdentifier, !enabled);
|
|
589
|
+
}
|
|
590
|
+
updateUsageTimestamp(snippet) {
|
|
591
|
+
this._usageTimestamps.updateUsageTimestamp(snippet.snippetIdentifier);
|
|
592
|
+
}
|
|
593
|
+
_joinSnippets() {
|
|
594
|
+
const promises = this._pendingWork.slice(0);
|
|
595
|
+
this._pendingWork.length = 0;
|
|
596
|
+
return Promise.all(promises);
|
|
597
|
+
}
|
|
598
|
+
async getSnippetFiles() {
|
|
599
|
+
await this._joinSnippets();
|
|
600
|
+
return (
|
|
601
|
+
(this._files.values())
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
async getSnippets(languageId, opts) {
|
|
605
|
+
await this._joinSnippets();
|
|
606
|
+
const result = [];
|
|
607
|
+
const promises = [];
|
|
608
|
+
if (languageId) {
|
|
609
|
+
if (this._languageService.isRegisteredLanguageId(languageId)) {
|
|
610
|
+
for (const file of ( (this._files.values()))) {
|
|
611
|
+
promises.push(file.load()
|
|
612
|
+
.then(file => file.select(languageId, result))
|
|
613
|
+
.catch(err => this._logService.error(err, ( (file.location.toString())))));
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
else {
|
|
618
|
+
for (const file of ( (this._files.values()))) {
|
|
619
|
+
promises.push(file.load()
|
|
620
|
+
.then(file => insertInto(result, result.length, file.data))
|
|
621
|
+
.catch(err => this._logService.error(err, ( (file.location.toString())))));
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
await Promise.all(promises);
|
|
625
|
+
return this._filterAndSortSnippets(result, opts);
|
|
626
|
+
}
|
|
627
|
+
getSnippetsSync(languageId, opts) {
|
|
628
|
+
const result = [];
|
|
629
|
+
if (this._languageService.isRegisteredLanguageId(languageId)) {
|
|
630
|
+
for (const file of ( (this._files.values()))) {
|
|
631
|
+
file.load().catch(_err => { });
|
|
632
|
+
file.select(languageId, result);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
return this._filterAndSortSnippets(result, opts);
|
|
636
|
+
}
|
|
637
|
+
_filterAndSortSnippets(snippets, opts) {
|
|
638
|
+
const result = [];
|
|
639
|
+
for (const snippet of snippets) {
|
|
640
|
+
if (!snippet.prefix && !opts?.includeNoPrefixSnippets) {
|
|
641
|
+
continue;
|
|
642
|
+
}
|
|
643
|
+
if (!this.isEnabled(snippet) && !opts?.includeDisabledSnippets) {
|
|
644
|
+
continue;
|
|
645
|
+
}
|
|
646
|
+
if (typeof opts?.fileTemplateSnippets === 'boolean' && opts.fileTemplateSnippets !== snippet.isFileTemplate) {
|
|
647
|
+
continue;
|
|
648
|
+
}
|
|
649
|
+
result.push(snippet);
|
|
650
|
+
}
|
|
651
|
+
return result.sort((a, b) => {
|
|
652
|
+
let result = 0;
|
|
653
|
+
if (!opts?.noRecencySort) {
|
|
654
|
+
const val1 = this._usageTimestamps.getUsageTimestamp(a.snippetIdentifier) ?? -1;
|
|
655
|
+
const val2 = this._usageTimestamps.getUsageTimestamp(b.snippetIdentifier) ?? -1;
|
|
656
|
+
result = val2 - val1;
|
|
657
|
+
}
|
|
658
|
+
if (result === 0) {
|
|
659
|
+
result = this._compareSnippet(a, b);
|
|
660
|
+
}
|
|
661
|
+
return result;
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
_compareSnippet(a, b) {
|
|
665
|
+
if (a.snippetSource < b.snippetSource) {
|
|
666
|
+
return -1;
|
|
667
|
+
}
|
|
668
|
+
else if (a.snippetSource > b.snippetSource) {
|
|
669
|
+
return 1;
|
|
670
|
+
}
|
|
671
|
+
else if (a.source < b.source) {
|
|
672
|
+
return -1;
|
|
673
|
+
}
|
|
674
|
+
else if (a.source > b.source) {
|
|
675
|
+
return 1;
|
|
676
|
+
}
|
|
677
|
+
else if (a.name > b.name) {
|
|
678
|
+
return 1;
|
|
679
|
+
}
|
|
680
|
+
else if (a.name < b.name) {
|
|
681
|
+
return -1;
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
return 0;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
_initExtensionSnippets() {
|
|
688
|
+
snippetExt.point.setHandler(extensions => {
|
|
689
|
+
for (const [key, value] of this._files) {
|
|
690
|
+
if (value.source === 3 ) {
|
|
691
|
+
this._files.delete(key);
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
for (const extension of extensions) {
|
|
695
|
+
for (const contribution of extension.value) {
|
|
696
|
+
const validContribution = snippetExt.toValidSnippet(extension, contribution, this._languageService);
|
|
697
|
+
if (!validContribution) {
|
|
698
|
+
continue;
|
|
699
|
+
}
|
|
700
|
+
const file = this._files.get(validContribution.location);
|
|
701
|
+
if (file) {
|
|
702
|
+
if (file.defaultScopes) {
|
|
703
|
+
file.defaultScopes.push(validContribution.language);
|
|
704
|
+
}
|
|
705
|
+
else {
|
|
706
|
+
file.defaultScopes = [];
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
else {
|
|
710
|
+
const file = ( (new SnippetFile(
|
|
711
|
+
3 ,
|
|
712
|
+
validContribution.location,
|
|
713
|
+
validContribution.language ? [validContribution.language] : undefined,
|
|
714
|
+
extension.description,
|
|
715
|
+
this._fileService,
|
|
716
|
+
this._extensionResourceLoaderService
|
|
717
|
+
)));
|
|
718
|
+
this._files.set(file.location, file);
|
|
719
|
+
if (this._environmentService.isExtensionDevelopment) {
|
|
720
|
+
file.load().then(file => {
|
|
721
|
+
if (file.data.some(snippet => snippet.isBogous)) {
|
|
722
|
+
extension.collector.warn(( (localize(
|
|
723
|
+
'badVariableUse',
|
|
724
|
+
"One or more snippets from the extension '{0}' very likely confuse snippet-variables and snippet-placeholders (see https://code.visualstudio.com/docs/editor/userdefinedsnippets#_snippet-syntax for more details)",
|
|
725
|
+
extension.description.name
|
|
726
|
+
))));
|
|
727
|
+
}
|
|
728
|
+
}, err => {
|
|
729
|
+
extension.collector.warn(( (localize(
|
|
730
|
+
'badFile',
|
|
731
|
+
"The snippet file \"{0}\" could not be read.",
|
|
732
|
+
(file.location.toString())
|
|
733
|
+
))));
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
_initWorkspaceSnippets() {
|
|
742
|
+
const disposables = ( (new DisposableStore()));
|
|
743
|
+
const updateWorkspaceSnippets = () => {
|
|
744
|
+
disposables.clear();
|
|
745
|
+
this._pendingWork.push(this._initWorkspaceFolderSnippets(this._contextService.getWorkspace(), disposables));
|
|
746
|
+
};
|
|
747
|
+
this._disposables.add(disposables);
|
|
748
|
+
this._disposables.add(this._contextService.onDidChangeWorkspaceFolders(updateWorkspaceSnippets));
|
|
749
|
+
this._disposables.add(this._contextService.onDidChangeWorkbenchState(updateWorkspaceSnippets));
|
|
750
|
+
updateWorkspaceSnippets();
|
|
751
|
+
}
|
|
752
|
+
async _initWorkspaceFolderSnippets(workspace, bucket) {
|
|
753
|
+
const promises = ( (workspace.folders.map(async (folder) => {
|
|
754
|
+
const snippetFolder = folder.toResource('.vscode');
|
|
755
|
+
const value = await this._fileService.exists(snippetFolder);
|
|
756
|
+
if (value) {
|
|
757
|
+
this._initFolderSnippets(2 , snippetFolder, bucket);
|
|
758
|
+
}
|
|
759
|
+
else {
|
|
760
|
+
bucket.add(this._fileService.onDidFilesChange(e => {
|
|
761
|
+
if (e.contains(snippetFolder, 1 )) {
|
|
762
|
+
this._initFolderSnippets(2 , snippetFolder, bucket);
|
|
763
|
+
}
|
|
764
|
+
}));
|
|
765
|
+
}
|
|
766
|
+
})));
|
|
767
|
+
await Promise.all(promises);
|
|
768
|
+
}
|
|
769
|
+
async _initUserSnippets() {
|
|
770
|
+
const disposables = ( (new DisposableStore()));
|
|
771
|
+
const updateUserSnippets = async () => {
|
|
772
|
+
disposables.clear();
|
|
773
|
+
const userSnippetsFolder = this._userDataProfileService.currentProfile.snippetsHome;
|
|
774
|
+
await this._fileService.createFolder(userSnippetsFolder);
|
|
775
|
+
await this._initFolderSnippets(1 , userSnippetsFolder, disposables);
|
|
776
|
+
};
|
|
777
|
+
this._disposables.add(disposables);
|
|
778
|
+
this._disposables.add(this._userDataProfileService.onDidChangeCurrentProfile(e => e.join((async () => {
|
|
779
|
+
if (e.preserveData) {
|
|
780
|
+
await this._fileService.copy(e.previous.snippetsHome, e.profile.snippetsHome);
|
|
781
|
+
}
|
|
782
|
+
this._pendingWork.push(updateUserSnippets());
|
|
783
|
+
})())));
|
|
784
|
+
await updateUserSnippets();
|
|
785
|
+
}
|
|
786
|
+
_initFolderSnippets(source, folder, bucket) {
|
|
787
|
+
const disposables = ( (new DisposableStore()));
|
|
788
|
+
const addFolderSnippets = async () => {
|
|
789
|
+
disposables.clear();
|
|
790
|
+
if (!(await this._fileService.exists(folder))) {
|
|
791
|
+
return;
|
|
792
|
+
}
|
|
793
|
+
try {
|
|
794
|
+
const stat = await this._fileService.resolve(folder);
|
|
795
|
+
for (const entry of stat.children || []) {
|
|
796
|
+
disposables.add(this._addSnippetFile(entry.resource, source));
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
catch (err) {
|
|
800
|
+
this._logService.error(`Failed snippets from folder '${( ( folder.toString()))}'`, err);
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
bucket.add(this._textfileService.files.onDidSave(e => {
|
|
804
|
+
if (isEqualOrParent(e.model.resource, folder)) {
|
|
805
|
+
addFolderSnippets();
|
|
806
|
+
}
|
|
807
|
+
}));
|
|
808
|
+
bucket.add(watch(this._fileService, folder, addFolderSnippets));
|
|
809
|
+
bucket.add(disposables);
|
|
810
|
+
return addFolderSnippets();
|
|
811
|
+
}
|
|
812
|
+
_addSnippetFile(uri, source) {
|
|
813
|
+
const ext = extname(uri);
|
|
814
|
+
if (source === 1 && ext === '.json') {
|
|
815
|
+
const langName = basename(uri).replace(/\.json/, '');
|
|
816
|
+
this._files.set(uri, ( (new SnippetFile(
|
|
817
|
+
source,
|
|
818
|
+
uri,
|
|
819
|
+
[langName],
|
|
820
|
+
undefined,
|
|
821
|
+
this._fileService,
|
|
822
|
+
this._extensionResourceLoaderService
|
|
823
|
+
))));
|
|
824
|
+
}
|
|
825
|
+
else if (ext === '.code-snippets') {
|
|
826
|
+
this._files.set(uri, ( (new SnippetFile(
|
|
827
|
+
source,
|
|
828
|
+
uri,
|
|
829
|
+
undefined,
|
|
830
|
+
undefined,
|
|
831
|
+
this._fileService,
|
|
832
|
+
this._extensionResourceLoaderService
|
|
833
|
+
))));
|
|
834
|
+
}
|
|
835
|
+
return {
|
|
836
|
+
dispose: () => this._files.delete(uri)
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
};
|
|
840
|
+
SnippetsService = ( (__decorate([
|
|
841
|
+
( (__param(0, IEnvironmentService))),
|
|
842
|
+
( (__param(1, IUserDataProfileService))),
|
|
843
|
+
( (__param(2, IWorkspaceContextService))),
|
|
844
|
+
( (__param(3, ILanguageService))),
|
|
845
|
+
( (__param(4, ILogService))),
|
|
846
|
+
( (__param(5, IFileService))),
|
|
847
|
+
( (__param(6, ITextFileService))),
|
|
848
|
+
( (__param(7, IExtensionResourceLoaderService))),
|
|
849
|
+
( (__param(8, ILifecycleService))),
|
|
850
|
+
( (__param(9, IInstantiationService))),
|
|
851
|
+
( (__param(10, ILanguageConfigurationService)))
|
|
852
|
+
], SnippetsService)));
|
|
853
|
+
function getNonWhitespacePrefix(model, position) {
|
|
854
|
+
const MAX_PREFIX_LENGTH = 100;
|
|
855
|
+
const line = model.getLineContent(position.lineNumber).substr(0, position.column - 1);
|
|
856
|
+
const minChIndex = Math.max(0, line.length - MAX_PREFIX_LENGTH);
|
|
857
|
+
for (let chIndex = line.length - 1; chIndex >= minChIndex; chIndex--) {
|
|
858
|
+
const ch = line.charAt(chIndex);
|
|
859
|
+
if (/\s/.test(ch)) {
|
|
860
|
+
return line.substr(chIndex + 1);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
if (minChIndex === 0) {
|
|
864
|
+
return line;
|
|
865
|
+
}
|
|
866
|
+
return '';
|
|
867
|
+
}
|
|
868
|
+
export { SnippetsService as S, SnippetCompletion as a, getNonWhitespacePrefix as g };
|