vscode-css-languageservice 6.0.1 → 6.1.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.
Files changed (87) hide show
  1. package/CHANGELOG.md +3 -1
  2. package/SECURITY.md +41 -0
  3. package/lib/esm/beautify/beautify-css.js +11 -4
  4. package/lib/esm/cssLanguageService.d.ts +38 -37
  5. package/lib/esm/cssLanguageService.js +73 -72
  6. package/lib/esm/cssLanguageTypes.d.ts +238 -238
  7. package/lib/esm/cssLanguageTypes.js +42 -42
  8. package/lib/esm/data/webCustomData.js +22089 -21959
  9. package/lib/esm/languageFacts/builtinData.js +142 -142
  10. package/lib/esm/languageFacts/colors.js +469 -469
  11. package/lib/esm/languageFacts/dataManager.js +88 -88
  12. package/lib/esm/languageFacts/dataProvider.js +73 -73
  13. package/lib/esm/languageFacts/entry.js +137 -137
  14. package/lib/esm/languageFacts/facts.js +8 -8
  15. package/lib/esm/parser/cssErrors.js +48 -48
  16. package/lib/esm/parser/cssNodes.js +1511 -1502
  17. package/lib/esm/parser/cssParser.js +1606 -1534
  18. package/lib/esm/parser/cssScanner.js +592 -592
  19. package/lib/esm/parser/cssSymbolScope.js +311 -311
  20. package/lib/esm/parser/lessParser.js +715 -714
  21. package/lib/esm/parser/lessScanner.js +57 -57
  22. package/lib/esm/parser/scssErrors.js +18 -18
  23. package/lib/esm/parser/scssParser.js +806 -796
  24. package/lib/esm/parser/scssScanner.js +95 -95
  25. package/lib/esm/services/cssCodeActions.js +77 -77
  26. package/lib/esm/services/cssCompletion.js +1054 -1054
  27. package/lib/esm/services/cssFolding.js +190 -190
  28. package/lib/esm/services/cssFormatter.js +136 -136
  29. package/lib/esm/services/cssHover.js +148 -148
  30. package/lib/esm/services/cssNavigation.js +441 -378
  31. package/lib/esm/services/cssSelectionRange.js +47 -47
  32. package/lib/esm/services/cssValidation.js +41 -41
  33. package/lib/esm/services/lessCompletion.js +378 -378
  34. package/lib/esm/services/lint.js +518 -518
  35. package/lib/esm/services/lintRules.js +76 -76
  36. package/lib/esm/services/lintUtil.js +196 -196
  37. package/lib/esm/services/pathCompletion.js +157 -157
  38. package/lib/esm/services/scssCompletion.js +354 -354
  39. package/lib/esm/services/scssNavigation.js +82 -82
  40. package/lib/esm/services/selectorPrinting.js +492 -492
  41. package/lib/esm/utils/arrays.js +40 -40
  42. package/lib/esm/utils/objects.js +11 -11
  43. package/lib/esm/utils/resources.js +11 -11
  44. package/lib/esm/utils/strings.js +102 -102
  45. package/lib/umd/beautify/beautify-css.js +11 -4
  46. package/lib/umd/cssLanguageService.d.ts +38 -37
  47. package/lib/umd/cssLanguageService.js +104 -99
  48. package/lib/umd/cssLanguageTypes.d.ts +238 -238
  49. package/lib/umd/cssLanguageTypes.js +89 -89
  50. package/lib/umd/data/webCustomData.js +22102 -21972
  51. package/lib/umd/languageFacts/builtinData.js +154 -154
  52. package/lib/umd/languageFacts/colors.js +492 -492
  53. package/lib/umd/languageFacts/dataManager.js +101 -101
  54. package/lib/umd/languageFacts/dataProvider.js +86 -86
  55. package/lib/umd/languageFacts/entry.js +152 -152
  56. package/lib/umd/languageFacts/facts.js +33 -29
  57. package/lib/umd/parser/cssErrors.js +61 -61
  58. package/lib/umd/parser/cssNodes.js +1597 -1587
  59. package/lib/umd/parser/cssParser.js +1619 -1547
  60. package/lib/umd/parser/cssScanner.js +606 -606
  61. package/lib/umd/parser/cssSymbolScope.js +328 -328
  62. package/lib/umd/parser/lessParser.js +728 -727
  63. package/lib/umd/parser/lessScanner.js +70 -70
  64. package/lib/umd/parser/scssErrors.js +31 -31
  65. package/lib/umd/parser/scssParser.js +819 -809
  66. package/lib/umd/parser/scssScanner.js +108 -108
  67. package/lib/umd/services/cssCodeActions.js +90 -90
  68. package/lib/umd/services/cssCompletion.js +1067 -1067
  69. package/lib/umd/services/cssFolding.js +203 -203
  70. package/lib/umd/services/cssFormatter.js +150 -150
  71. package/lib/umd/services/cssHover.js +161 -161
  72. package/lib/umd/services/cssNavigation.js +454 -391
  73. package/lib/umd/services/cssSelectionRange.js +60 -60
  74. package/lib/umd/services/cssValidation.js +54 -54
  75. package/lib/umd/services/lessCompletion.js +391 -391
  76. package/lib/umd/services/lint.js +531 -531
  77. package/lib/umd/services/lintRules.js +91 -91
  78. package/lib/umd/services/lintUtil.js +210 -210
  79. package/lib/umd/services/pathCompletion.js +171 -171
  80. package/lib/umd/services/scssCompletion.js +367 -367
  81. package/lib/umd/services/scssNavigation.js +95 -95
  82. package/lib/umd/services/selectorPrinting.js +510 -510
  83. package/lib/umd/utils/arrays.js +55 -55
  84. package/lib/umd/utils/objects.js +25 -25
  85. package/lib/umd/utils/resources.js +26 -26
  86. package/lib/umd/utils/strings.js +120 -120
  87. package/package.json +13 -12
@@ -1,1067 +1,1067 @@
1
- (function (factory) {
2
- if (typeof module === "object" && typeof module.exports === "object") {
3
- var v = factory(require, exports);
4
- if (v !== undefined) module.exports = v;
5
- }
6
- else if (typeof define === "function" && define.amd) {
7
- define(["require", "exports", "../parser/cssNodes", "../parser/cssSymbolScope", "../languageFacts/facts", "../utils/strings", "../cssLanguageTypes", "vscode-nls", "../utils/objects", "./pathCompletion"], factory);
8
- }
9
- })(function (require, exports) {
10
- /*---------------------------------------------------------------------------------------------
11
- * Copyright (c) Microsoft Corporation. All rights reserved.
12
- * Licensed under the MIT License. See License.txt in the project root for license information.
13
- *--------------------------------------------------------------------------------------------*/
14
- 'use strict';
15
- Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.CSSCompletion = void 0;
17
- const nodes = require("../parser/cssNodes");
18
- const cssSymbolScope_1 = require("../parser/cssSymbolScope");
19
- const languageFacts = require("../languageFacts/facts");
20
- const strings = require("../utils/strings");
21
- const cssLanguageTypes_1 = require("../cssLanguageTypes");
22
- const nls = require("vscode-nls");
23
- const objects_1 = require("../utils/objects");
24
- const pathCompletion_1 = require("./pathCompletion");
25
- const localize = nls.loadMessageBundle();
26
- const SnippetFormat = cssLanguageTypes_1.InsertTextFormat.Snippet;
27
- const retriggerCommand = {
28
- title: 'Suggest',
29
- command: 'editor.action.triggerSuggest'
30
- };
31
- var SortTexts;
32
- (function (SortTexts) {
33
- // char code 32, comes before everything
34
- SortTexts["Enums"] = " ";
35
- SortTexts["Normal"] = "d";
36
- SortTexts["VendorPrefixed"] = "x";
37
- SortTexts["Term"] = "y";
38
- SortTexts["Variable"] = "z";
39
- })(SortTexts || (SortTexts = {}));
40
- class CSSCompletion {
41
- constructor(variablePrefix = null, lsOptions, cssDataManager) {
42
- this.variablePrefix = variablePrefix;
43
- this.lsOptions = lsOptions;
44
- this.cssDataManager = cssDataManager;
45
- this.completionParticipants = [];
46
- }
47
- configure(settings) {
48
- this.defaultSettings = settings;
49
- }
50
- getSymbolContext() {
51
- if (!this.symbolContext) {
52
- this.symbolContext = new cssSymbolScope_1.Symbols(this.styleSheet);
53
- }
54
- return this.symbolContext;
55
- }
56
- setCompletionParticipants(registeredCompletionParticipants) {
57
- this.completionParticipants = registeredCompletionParticipants || [];
58
- }
59
- async doComplete2(document, position, styleSheet, documentContext, completionSettings = this.defaultSettings) {
60
- if (!this.lsOptions.fileSystemProvider || !this.lsOptions.fileSystemProvider.readDirectory) {
61
- return this.doComplete(document, position, styleSheet, completionSettings);
62
- }
63
- const participant = new pathCompletion_1.PathCompletionParticipant(this.lsOptions.fileSystemProvider.readDirectory);
64
- const contributedParticipants = this.completionParticipants;
65
- this.completionParticipants = [participant].concat(contributedParticipants);
66
- const result = this.doComplete(document, position, styleSheet, completionSettings);
67
- try {
68
- const pathCompletionResult = await participant.computeCompletions(document, documentContext);
69
- return {
70
- isIncomplete: result.isIncomplete || pathCompletionResult.isIncomplete,
71
- items: pathCompletionResult.items.concat(result.items)
72
- };
73
- }
74
- finally {
75
- this.completionParticipants = contributedParticipants;
76
- }
77
- }
78
- doComplete(document, position, styleSheet, documentSettings) {
79
- this.offset = document.offsetAt(position);
80
- this.position = position;
81
- this.currentWord = getCurrentWord(document, this.offset);
82
- this.defaultReplaceRange = cssLanguageTypes_1.Range.create(cssLanguageTypes_1.Position.create(this.position.line, this.position.character - this.currentWord.length), this.position);
83
- this.textDocument = document;
84
- this.styleSheet = styleSheet;
85
- this.documentSettings = documentSettings;
86
- try {
87
- const result = { isIncomplete: false, items: [] };
88
- this.nodePath = nodes.getNodePath(this.styleSheet, this.offset);
89
- for (let i = this.nodePath.length - 1; i >= 0; i--) {
90
- const node = this.nodePath[i];
91
- if (node instanceof nodes.Property) {
92
- this.getCompletionsForDeclarationProperty(node.getParent(), result);
93
- }
94
- else if (node instanceof nodes.Expression) {
95
- if (node.parent instanceof nodes.Interpolation) {
96
- this.getVariableProposals(null, result);
97
- }
98
- else {
99
- this.getCompletionsForExpression(node, result);
100
- }
101
- }
102
- else if (node instanceof nodes.SimpleSelector) {
103
- const parentRef = node.findAParent(nodes.NodeType.ExtendsReference, nodes.NodeType.Ruleset);
104
- if (parentRef) {
105
- if (parentRef.type === nodes.NodeType.ExtendsReference) {
106
- this.getCompletionsForExtendsReference(parentRef, node, result);
107
- }
108
- else {
109
- const parentRuleSet = parentRef;
110
- this.getCompletionsForSelector(parentRuleSet, parentRuleSet && parentRuleSet.isNested(), result);
111
- }
112
- }
113
- }
114
- else if (node instanceof nodes.FunctionArgument) {
115
- this.getCompletionsForFunctionArgument(node, node.getParent(), result);
116
- }
117
- else if (node instanceof nodes.Declarations) {
118
- this.getCompletionsForDeclarations(node, result);
119
- }
120
- else if (node instanceof nodes.VariableDeclaration) {
121
- this.getCompletionsForVariableDeclaration(node, result);
122
- }
123
- else if (node instanceof nodes.RuleSet) {
124
- this.getCompletionsForRuleSet(node, result);
125
- }
126
- else if (node instanceof nodes.Interpolation) {
127
- this.getCompletionsForInterpolation(node, result);
128
- }
129
- else if (node instanceof nodes.FunctionDeclaration) {
130
- this.getCompletionsForFunctionDeclaration(node, result);
131
- }
132
- else if (node instanceof nodes.MixinReference) {
133
- this.getCompletionsForMixinReference(node, result);
134
- }
135
- else if (node instanceof nodes.Function) {
136
- this.getCompletionsForFunctionArgument(null, node, result);
137
- }
138
- else if (node instanceof nodes.Supports) {
139
- this.getCompletionsForSupports(node, result);
140
- }
141
- else if (node instanceof nodes.SupportsCondition) {
142
- this.getCompletionsForSupportsCondition(node, result);
143
- }
144
- else if (node instanceof nodes.ExtendsReference) {
145
- this.getCompletionsForExtendsReference(node, null, result);
146
- }
147
- else if (node.type === nodes.NodeType.URILiteral) {
148
- this.getCompletionForUriLiteralValue(node, result);
149
- }
150
- else if (node.parent === null) {
151
- this.getCompletionForTopLevel(result);
152
- }
153
- else if (node.type === nodes.NodeType.StringLiteral && this.isImportPathParent(node.parent.type)) {
154
- this.getCompletionForImportPath(node, result);
155
- // } else if (node instanceof nodes.Variable) {
156
- // this.getCompletionsForVariableDeclaration()
157
- }
158
- else {
159
- continue;
160
- }
161
- if (result.items.length > 0 || this.offset > node.offset) {
162
- return this.finalize(result);
163
- }
164
- }
165
- this.getCompletionsForStylesheet(result);
166
- if (result.items.length === 0) {
167
- if (this.variablePrefix && this.currentWord.indexOf(this.variablePrefix) === 0) {
168
- this.getVariableProposals(null, result);
169
- }
170
- }
171
- return this.finalize(result);
172
- }
173
- finally {
174
- // don't hold on any state, clear symbolContext
175
- this.position = null;
176
- this.currentWord = null;
177
- this.textDocument = null;
178
- this.styleSheet = null;
179
- this.symbolContext = null;
180
- this.defaultReplaceRange = null;
181
- this.nodePath = null;
182
- }
183
- }
184
- isImportPathParent(type) {
185
- return type === nodes.NodeType.Import;
186
- }
187
- finalize(result) {
188
- return result;
189
- }
190
- findInNodePath(...types) {
191
- for (let i = this.nodePath.length - 1; i >= 0; i--) {
192
- const node = this.nodePath[i];
193
- if (types.indexOf(node.type) !== -1) {
194
- return node;
195
- }
196
- }
197
- return null;
198
- }
199
- getCompletionsForDeclarationProperty(declaration, result) {
200
- return this.getPropertyProposals(declaration, result);
201
- }
202
- getPropertyProposals(declaration, result) {
203
- const triggerPropertyValueCompletion = this.isTriggerPropertyValueCompletionEnabled;
204
- const completePropertyWithSemicolon = this.isCompletePropertyWithSemicolonEnabled;
205
- const properties = this.cssDataManager.getProperties();
206
- properties.forEach(entry => {
207
- let range;
208
- let insertText;
209
- let retrigger = false;
210
- if (declaration) {
211
- range = this.getCompletionRange(declaration.getProperty());
212
- insertText = entry.name;
213
- if (!(0, objects_1.isDefined)(declaration.colonPosition)) {
214
- insertText += ': ';
215
- retrigger = true;
216
- }
217
- }
218
- else {
219
- range = this.getCompletionRange(null);
220
- insertText = entry.name + ': ';
221
- retrigger = true;
222
- }
223
- // Empty .selector { | } case
224
- if (!declaration && completePropertyWithSemicolon) {
225
- insertText += '$0;';
226
- }
227
- // Cases such as .selector { p; } or .selector { p:; }
228
- if (declaration && !declaration.semicolonPosition) {
229
- if (completePropertyWithSemicolon && this.offset >= this.textDocument.offsetAt(range.end)) {
230
- insertText += '$0;';
231
- }
232
- }
233
- const item = {
234
- label: entry.name,
235
- documentation: languageFacts.getEntryDescription(entry, this.doesSupportMarkdown()),
236
- tags: isDeprecated(entry) ? [cssLanguageTypes_1.CompletionItemTag.Deprecated] : [],
237
- textEdit: cssLanguageTypes_1.TextEdit.replace(range, insertText),
238
- insertTextFormat: cssLanguageTypes_1.InsertTextFormat.Snippet,
239
- kind: cssLanguageTypes_1.CompletionItemKind.Property
240
- };
241
- if (!entry.restrictions) {
242
- retrigger = false;
243
- }
244
- if (triggerPropertyValueCompletion && retrigger) {
245
- item.command = retriggerCommand;
246
- }
247
- const relevance = typeof entry.relevance === 'number' ? Math.min(Math.max(entry.relevance, 0), 99) : 50;
248
- const sortTextSuffix = (255 - relevance).toString(16);
249
- const sortTextPrefix = strings.startsWith(entry.name, '-') ? SortTexts.VendorPrefixed : SortTexts.Normal;
250
- item.sortText = sortTextPrefix + '_' + sortTextSuffix;
251
- result.items.push(item);
252
- });
253
- this.completionParticipants.forEach(participant => {
254
- if (participant.onCssProperty) {
255
- participant.onCssProperty({
256
- propertyName: this.currentWord,
257
- range: this.defaultReplaceRange
258
- });
259
- }
260
- });
261
- return result;
262
- }
263
- get isTriggerPropertyValueCompletionEnabled() {
264
- return this.documentSettings?.triggerPropertyValueCompletion ?? true;
265
- }
266
- get isCompletePropertyWithSemicolonEnabled() {
267
- return this.documentSettings?.completePropertyWithSemicolon ?? true;
268
- }
269
- getCompletionsForDeclarationValue(node, result) {
270
- const propertyName = node.getFullPropertyName();
271
- const entry = this.cssDataManager.getProperty(propertyName);
272
- let existingNode = node.getValue() || null;
273
- while (existingNode && existingNode.hasChildren()) {
274
- existingNode = existingNode.findChildAtOffset(this.offset, false);
275
- }
276
- this.completionParticipants.forEach(participant => {
277
- if (participant.onCssPropertyValue) {
278
- participant.onCssPropertyValue({
279
- propertyName,
280
- propertyValue: this.currentWord,
281
- range: this.getCompletionRange(existingNode)
282
- });
283
- }
284
- });
285
- if (entry) {
286
- if (entry.restrictions) {
287
- for (const restriction of entry.restrictions) {
288
- switch (restriction) {
289
- case 'color':
290
- this.getColorProposals(entry, existingNode, result);
291
- break;
292
- case 'position':
293
- this.getPositionProposals(entry, existingNode, result);
294
- break;
295
- case 'repeat':
296
- this.getRepeatStyleProposals(entry, existingNode, result);
297
- break;
298
- case 'line-style':
299
- this.getLineStyleProposals(entry, existingNode, result);
300
- break;
301
- case 'line-width':
302
- this.getLineWidthProposals(entry, existingNode, result);
303
- break;
304
- case 'geometry-box':
305
- this.getGeometryBoxProposals(entry, existingNode, result);
306
- break;
307
- case 'box':
308
- this.getBoxProposals(entry, existingNode, result);
309
- break;
310
- case 'image':
311
- this.getImageProposals(entry, existingNode, result);
312
- break;
313
- case 'timing-function':
314
- this.getTimingFunctionProposals(entry, existingNode, result);
315
- break;
316
- case 'shape':
317
- this.getBasicShapeProposals(entry, existingNode, result);
318
- break;
319
- }
320
- }
321
- }
322
- this.getValueEnumProposals(entry, existingNode, result);
323
- this.getCSSWideKeywordProposals(entry, existingNode, result);
324
- this.getUnitProposals(entry, existingNode, result);
325
- }
326
- else {
327
- const existingValues = collectValues(this.styleSheet, node);
328
- for (const existingValue of existingValues.getEntries()) {
329
- result.items.push({
330
- label: existingValue,
331
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), existingValue),
332
- kind: cssLanguageTypes_1.CompletionItemKind.Value
333
- });
334
- }
335
- }
336
- this.getVariableProposals(existingNode, result);
337
- this.getTermProposals(entry, existingNode, result);
338
- return result;
339
- }
340
- getValueEnumProposals(entry, existingNode, result) {
341
- if (entry.values) {
342
- for (const value of entry.values) {
343
- let insertString = value.name;
344
- let insertTextFormat;
345
- if (strings.endsWith(insertString, ')')) {
346
- const from = insertString.lastIndexOf('(');
347
- if (from !== -1) {
348
- insertString = insertString.substr(0, from) + '($1)';
349
- insertTextFormat = SnippetFormat;
350
- }
351
- }
352
- let sortText = SortTexts.Enums;
353
- if (strings.startsWith(value.name, '-')) {
354
- sortText += SortTexts.VendorPrefixed;
355
- }
356
- const item = {
357
- label: value.name,
358
- documentation: languageFacts.getEntryDescription(value, this.doesSupportMarkdown()),
359
- tags: isDeprecated(entry) ? [cssLanguageTypes_1.CompletionItemTag.Deprecated] : [],
360
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertString),
361
- sortText,
362
- kind: cssLanguageTypes_1.CompletionItemKind.Value,
363
- insertTextFormat
364
- };
365
- result.items.push(item);
366
- }
367
- }
368
- return result;
369
- }
370
- getCSSWideKeywordProposals(entry, existingNode, result) {
371
- for (const keywords in languageFacts.cssWideKeywords) {
372
- result.items.push({
373
- label: keywords,
374
- documentation: languageFacts.cssWideKeywords[keywords],
375
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), keywords),
376
- kind: cssLanguageTypes_1.CompletionItemKind.Value
377
- });
378
- }
379
- for (const func in languageFacts.cssWideFunctions) {
380
- const insertText = moveCursorInsideParenthesis(func);
381
- result.items.push({
382
- label: func,
383
- documentation: languageFacts.cssWideFunctions[func],
384
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
385
- kind: cssLanguageTypes_1.CompletionItemKind.Function,
386
- insertTextFormat: SnippetFormat,
387
- command: strings.startsWith(func, 'var') ? retriggerCommand : undefined
388
- });
389
- }
390
- return result;
391
- }
392
- getCompletionsForInterpolation(node, result) {
393
- if (this.offset >= node.offset + 2) {
394
- this.getVariableProposals(null, result);
395
- }
396
- return result;
397
- }
398
- getVariableProposals(existingNode, result) {
399
- const symbols = this.getSymbolContext().findSymbolsAtOffset(this.offset, nodes.ReferenceType.Variable);
400
- for (const symbol of symbols) {
401
- const insertText = strings.startsWith(symbol.name, '--') ? `var(${symbol.name})` : symbol.name;
402
- const completionItem = {
403
- label: symbol.name,
404
- documentation: symbol.value ? strings.getLimitedString(symbol.value) : symbol.value,
405
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
406
- kind: cssLanguageTypes_1.CompletionItemKind.Variable,
407
- sortText: SortTexts.Variable
408
- };
409
- if (typeof completionItem.documentation === 'string' && isColorString(completionItem.documentation)) {
410
- completionItem.kind = cssLanguageTypes_1.CompletionItemKind.Color;
411
- }
412
- if (symbol.node.type === nodes.NodeType.FunctionParameter) {
413
- const mixinNode = (symbol.node.getParent());
414
- if (mixinNode.type === nodes.NodeType.MixinDeclaration) {
415
- completionItem.detail = localize('completion.argument', 'argument from \'{0}\'', mixinNode.getName());
416
- }
417
- }
418
- result.items.push(completionItem);
419
- }
420
- return result;
421
- }
422
- getVariableProposalsForCSSVarFunction(result) {
423
- const allReferencedVariables = new Set();
424
- this.styleSheet.acceptVisitor(new VariableCollector(allReferencedVariables, this.offset));
425
- let symbols = this.getSymbolContext().findSymbolsAtOffset(this.offset, nodes.ReferenceType.Variable);
426
- for (const symbol of symbols) {
427
- if (strings.startsWith(symbol.name, '--')) {
428
- const completionItem = {
429
- label: symbol.name,
430
- documentation: symbol.value ? strings.getLimitedString(symbol.value) : symbol.value,
431
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(null), symbol.name),
432
- kind: cssLanguageTypes_1.CompletionItemKind.Variable
433
- };
434
- if (typeof completionItem.documentation === 'string' && isColorString(completionItem.documentation)) {
435
- completionItem.kind = cssLanguageTypes_1.CompletionItemKind.Color;
436
- }
437
- result.items.push(completionItem);
438
- }
439
- allReferencedVariables.remove(symbol.name);
440
- }
441
- for (const name of allReferencedVariables.getEntries()) {
442
- if (strings.startsWith(name, '--')) {
443
- const completionItem = {
444
- label: name,
445
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(null), name),
446
- kind: cssLanguageTypes_1.CompletionItemKind.Variable
447
- };
448
- result.items.push(completionItem);
449
- }
450
- }
451
- return result;
452
- }
453
- getUnitProposals(entry, existingNode, result) {
454
- let currentWord = '0';
455
- if (this.currentWord.length > 0) {
456
- const numMatch = this.currentWord.match(/^-?\d[\.\d+]*/);
457
- if (numMatch) {
458
- currentWord = numMatch[0];
459
- result.isIncomplete = currentWord.length === this.currentWord.length;
460
- }
461
- }
462
- else if (this.currentWord.length === 0) {
463
- result.isIncomplete = true;
464
- }
465
- if (existingNode && existingNode.parent && existingNode.parent.type === nodes.NodeType.Term) {
466
- existingNode = existingNode.getParent(); // include the unary operator
467
- }
468
- if (entry.restrictions) {
469
- for (const restriction of entry.restrictions) {
470
- const units = languageFacts.units[restriction];
471
- if (units) {
472
- for (const unit of units) {
473
- const insertText = currentWord + unit;
474
- result.items.push({
475
- label: insertText,
476
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
477
- kind: cssLanguageTypes_1.CompletionItemKind.Unit
478
- });
479
- }
480
- }
481
- }
482
- }
483
- return result;
484
- }
485
- getCompletionRange(existingNode) {
486
- if (existingNode && existingNode.offset <= this.offset && this.offset <= existingNode.end) {
487
- const end = existingNode.end !== -1 ? this.textDocument.positionAt(existingNode.end) : this.position;
488
- const start = this.textDocument.positionAt(existingNode.offset);
489
- if (start.line === end.line) {
490
- return cssLanguageTypes_1.Range.create(start, end); // multi line edits are not allowed
491
- }
492
- }
493
- return this.defaultReplaceRange;
494
- }
495
- getColorProposals(entry, existingNode, result) {
496
- for (const color in languageFacts.colors) {
497
- result.items.push({
498
- label: color,
499
- documentation: languageFacts.colors[color],
500
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), color),
501
- kind: cssLanguageTypes_1.CompletionItemKind.Color
502
- });
503
- }
504
- for (const color in languageFacts.colorKeywords) {
505
- result.items.push({
506
- label: color,
507
- documentation: languageFacts.colorKeywords[color],
508
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), color),
509
- kind: cssLanguageTypes_1.CompletionItemKind.Value
510
- });
511
- }
512
- const colorValues = new Set();
513
- this.styleSheet.acceptVisitor(new ColorValueCollector(colorValues, this.offset));
514
- for (const color of colorValues.getEntries()) {
515
- result.items.push({
516
- label: color,
517
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), color),
518
- kind: cssLanguageTypes_1.CompletionItemKind.Color
519
- });
520
- }
521
- for (const p of languageFacts.colorFunctions) {
522
- let tabStop = 1;
523
- const replaceFunction = (_match, p1) => '${' + tabStop++ + ':' + p1 + '}';
524
- const insertText = p.func.replace(/\[?\$(\w+)\]?/g, replaceFunction);
525
- result.items.push({
526
- label: p.func.substr(0, p.func.indexOf('(')),
527
- detail: p.func,
528
- documentation: p.desc,
529
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
530
- insertTextFormat: SnippetFormat,
531
- kind: cssLanguageTypes_1.CompletionItemKind.Function
532
- });
533
- }
534
- return result;
535
- }
536
- getPositionProposals(entry, existingNode, result) {
537
- for (const position in languageFacts.positionKeywords) {
538
- result.items.push({
539
- label: position,
540
- documentation: languageFacts.positionKeywords[position],
541
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), position),
542
- kind: cssLanguageTypes_1.CompletionItemKind.Value
543
- });
544
- }
545
- return result;
546
- }
547
- getRepeatStyleProposals(entry, existingNode, result) {
548
- for (const repeat in languageFacts.repeatStyleKeywords) {
549
- result.items.push({
550
- label: repeat,
551
- documentation: languageFacts.repeatStyleKeywords[repeat],
552
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), repeat),
553
- kind: cssLanguageTypes_1.CompletionItemKind.Value
554
- });
555
- }
556
- return result;
557
- }
558
- getLineStyleProposals(entry, existingNode, result) {
559
- for (const lineStyle in languageFacts.lineStyleKeywords) {
560
- result.items.push({
561
- label: lineStyle,
562
- documentation: languageFacts.lineStyleKeywords[lineStyle],
563
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), lineStyle),
564
- kind: cssLanguageTypes_1.CompletionItemKind.Value
565
- });
566
- }
567
- return result;
568
- }
569
- getLineWidthProposals(entry, existingNode, result) {
570
- for (const lineWidth of languageFacts.lineWidthKeywords) {
571
- result.items.push({
572
- label: lineWidth,
573
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), lineWidth),
574
- kind: cssLanguageTypes_1.CompletionItemKind.Value
575
- });
576
- }
577
- return result;
578
- }
579
- getGeometryBoxProposals(entry, existingNode, result) {
580
- for (const box in languageFacts.geometryBoxKeywords) {
581
- result.items.push({
582
- label: box,
583
- documentation: languageFacts.geometryBoxKeywords[box],
584
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), box),
585
- kind: cssLanguageTypes_1.CompletionItemKind.Value
586
- });
587
- }
588
- return result;
589
- }
590
- getBoxProposals(entry, existingNode, result) {
591
- for (const box in languageFacts.boxKeywords) {
592
- result.items.push({
593
- label: box,
594
- documentation: languageFacts.boxKeywords[box],
595
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), box),
596
- kind: cssLanguageTypes_1.CompletionItemKind.Value
597
- });
598
- }
599
- return result;
600
- }
601
- getImageProposals(entry, existingNode, result) {
602
- for (const image in languageFacts.imageFunctions) {
603
- const insertText = moveCursorInsideParenthesis(image);
604
- result.items.push({
605
- label: image,
606
- documentation: languageFacts.imageFunctions[image],
607
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
608
- kind: cssLanguageTypes_1.CompletionItemKind.Function,
609
- insertTextFormat: image !== insertText ? SnippetFormat : void 0
610
- });
611
- }
612
- return result;
613
- }
614
- getTimingFunctionProposals(entry, existingNode, result) {
615
- for (const timing in languageFacts.transitionTimingFunctions) {
616
- const insertText = moveCursorInsideParenthesis(timing);
617
- result.items.push({
618
- label: timing,
619
- documentation: languageFacts.transitionTimingFunctions[timing],
620
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
621
- kind: cssLanguageTypes_1.CompletionItemKind.Function,
622
- insertTextFormat: timing !== insertText ? SnippetFormat : void 0
623
- });
624
- }
625
- return result;
626
- }
627
- getBasicShapeProposals(entry, existingNode, result) {
628
- for (const shape in languageFacts.basicShapeFunctions) {
629
- const insertText = moveCursorInsideParenthesis(shape);
630
- result.items.push({
631
- label: shape,
632
- documentation: languageFacts.basicShapeFunctions[shape],
633
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
634
- kind: cssLanguageTypes_1.CompletionItemKind.Function,
635
- insertTextFormat: shape !== insertText ? SnippetFormat : void 0
636
- });
637
- }
638
- return result;
639
- }
640
- getCompletionsForStylesheet(result) {
641
- const node = this.styleSheet.findFirstChildBeforeOffset(this.offset);
642
- if (!node) {
643
- return this.getCompletionForTopLevel(result);
644
- }
645
- if (node instanceof nodes.RuleSet) {
646
- return this.getCompletionsForRuleSet(node, result);
647
- }
648
- if (node instanceof nodes.Supports) {
649
- return this.getCompletionsForSupports(node, result);
650
- }
651
- return result;
652
- }
653
- getCompletionForTopLevel(result) {
654
- this.cssDataManager.getAtDirectives().forEach(entry => {
655
- result.items.push({
656
- label: entry.name,
657
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(null), entry.name),
658
- documentation: languageFacts.getEntryDescription(entry, this.doesSupportMarkdown()),
659
- tags: isDeprecated(entry) ? [cssLanguageTypes_1.CompletionItemTag.Deprecated] : [],
660
- kind: cssLanguageTypes_1.CompletionItemKind.Keyword
661
- });
662
- });
663
- this.getCompletionsForSelector(null, false, result);
664
- return result;
665
- }
666
- getCompletionsForRuleSet(ruleSet, result) {
667
- const declarations = ruleSet.getDeclarations();
668
- const isAfter = declarations && declarations.endsWith('}') && this.offset >= declarations.end;
669
- if (isAfter) {
670
- return this.getCompletionForTopLevel(result);
671
- }
672
- const isInSelectors = !declarations || this.offset <= declarations.offset;
673
- if (isInSelectors) {
674
- return this.getCompletionsForSelector(ruleSet, ruleSet.isNested(), result);
675
- }
676
- return this.getCompletionsForDeclarations(ruleSet.getDeclarations(), result);
677
- }
678
- getCompletionsForSelector(ruleSet, isNested, result) {
679
- const existingNode = this.findInNodePath(nodes.NodeType.PseudoSelector, nodes.NodeType.IdentifierSelector, nodes.NodeType.ClassSelector, nodes.NodeType.ElementNameSelector);
680
- if (!existingNode && this.hasCharacterAtPosition(this.offset - this.currentWord.length - 1, ':')) {
681
- // after the ':' of a pseudo selector, no node generated for just ':'
682
- this.currentWord = ':' + this.currentWord;
683
- if (this.hasCharacterAtPosition(this.offset - this.currentWord.length - 1, ':')) {
684
- this.currentWord = ':' + this.currentWord; // for '::'
685
- }
686
- this.defaultReplaceRange = cssLanguageTypes_1.Range.create(cssLanguageTypes_1.Position.create(this.position.line, this.position.character - this.currentWord.length), this.position);
687
- }
688
- const pseudoClasses = this.cssDataManager.getPseudoClasses();
689
- pseudoClasses.forEach(entry => {
690
- const insertText = moveCursorInsideParenthesis(entry.name);
691
- const item = {
692
- label: entry.name,
693
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
694
- documentation: languageFacts.getEntryDescription(entry, this.doesSupportMarkdown()),
695
- tags: isDeprecated(entry) ? [cssLanguageTypes_1.CompletionItemTag.Deprecated] : [],
696
- kind: cssLanguageTypes_1.CompletionItemKind.Function,
697
- insertTextFormat: entry.name !== insertText ? SnippetFormat : void 0
698
- };
699
- if (strings.startsWith(entry.name, ':-')) {
700
- item.sortText = SortTexts.VendorPrefixed;
701
- }
702
- result.items.push(item);
703
- });
704
- const pseudoElements = this.cssDataManager.getPseudoElements();
705
- pseudoElements.forEach(entry => {
706
- const insertText = moveCursorInsideParenthesis(entry.name);
707
- const item = {
708
- label: entry.name,
709
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
710
- documentation: languageFacts.getEntryDescription(entry, this.doesSupportMarkdown()),
711
- tags: isDeprecated(entry) ? [cssLanguageTypes_1.CompletionItemTag.Deprecated] : [],
712
- kind: cssLanguageTypes_1.CompletionItemKind.Function,
713
- insertTextFormat: entry.name !== insertText ? SnippetFormat : void 0
714
- };
715
- if (strings.startsWith(entry.name, '::-')) {
716
- item.sortText = SortTexts.VendorPrefixed;
717
- }
718
- result.items.push(item);
719
- });
720
- if (!isNested) { // show html tags only for top level
721
- for (const entry of languageFacts.html5Tags) {
722
- result.items.push({
723
- label: entry,
724
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), entry),
725
- kind: cssLanguageTypes_1.CompletionItemKind.Keyword
726
- });
727
- }
728
- for (const entry of languageFacts.svgElements) {
729
- result.items.push({
730
- label: entry,
731
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), entry),
732
- kind: cssLanguageTypes_1.CompletionItemKind.Keyword
733
- });
734
- }
735
- }
736
- const visited = {};
737
- visited[this.currentWord] = true;
738
- const docText = this.textDocument.getText();
739
- this.styleSheet.accept(n => {
740
- if (n.type === nodes.NodeType.SimpleSelector && n.length > 0) {
741
- const selector = docText.substr(n.offset, n.length);
742
- if (selector.charAt(0) === '.' && !visited[selector]) {
743
- visited[selector] = true;
744
- result.items.push({
745
- label: selector,
746
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), selector),
747
- kind: cssLanguageTypes_1.CompletionItemKind.Keyword
748
- });
749
- }
750
- return false;
751
- }
752
- return true;
753
- });
754
- if (ruleSet && ruleSet.isNested()) {
755
- const selector = ruleSet.getSelectors().findFirstChildBeforeOffset(this.offset);
756
- if (selector && ruleSet.getSelectors().getChildren().indexOf(selector) === 0) {
757
- this.getPropertyProposals(null, result);
758
- }
759
- }
760
- return result;
761
- }
762
- getCompletionsForDeclarations(declarations, result) {
763
- if (!declarations || this.offset === declarations.offset) { // incomplete nodes
764
- return result;
765
- }
766
- const node = declarations.findFirstChildBeforeOffset(this.offset);
767
- if (!node) {
768
- return this.getCompletionsForDeclarationProperty(null, result);
769
- }
770
- if (node instanceof nodes.AbstractDeclaration) {
771
- const declaration = node;
772
- if (!(0, objects_1.isDefined)(declaration.colonPosition) || this.offset <= declaration.colonPosition) {
773
- // complete property
774
- return this.getCompletionsForDeclarationProperty(declaration, result);
775
- }
776
- else if (((0, objects_1.isDefined)(declaration.semicolonPosition) && declaration.semicolonPosition < this.offset)) {
777
- if (this.offset === declaration.semicolonPosition + 1) {
778
- return result; // don't show new properties right after semicolon (see Bug 15421:[intellisense] [css] Be less aggressive when manually typing CSS)
779
- }
780
- // complete next property
781
- return this.getCompletionsForDeclarationProperty(null, result);
782
- }
783
- if (declaration instanceof nodes.Declaration) {
784
- // complete value
785
- return this.getCompletionsForDeclarationValue(declaration, result);
786
- }
787
- }
788
- else if (node instanceof nodes.ExtendsReference) {
789
- this.getCompletionsForExtendsReference(node, null, result);
790
- }
791
- else if (this.currentWord && this.currentWord[0] === '@') {
792
- this.getCompletionsForDeclarationProperty(null, result);
793
- }
794
- else if (node instanceof nodes.RuleSet) {
795
- this.getCompletionsForDeclarationProperty(null, result);
796
- }
797
- return result;
798
- }
799
- getCompletionsForVariableDeclaration(declaration, result) {
800
- if (this.offset && (0, objects_1.isDefined)(declaration.colonPosition) && this.offset > declaration.colonPosition) {
801
- this.getVariableProposals(declaration.getValue(), result);
802
- }
803
- return result;
804
- }
805
- getCompletionsForExpression(expression, result) {
806
- const parent = expression.getParent();
807
- if (parent instanceof nodes.FunctionArgument) {
808
- this.getCompletionsForFunctionArgument(parent, parent.getParent(), result);
809
- return result;
810
- }
811
- const declaration = expression.findParent(nodes.NodeType.Declaration);
812
- if (!declaration) {
813
- this.getTermProposals(undefined, null, result);
814
- return result;
815
- }
816
- const node = expression.findChildAtOffset(this.offset, true);
817
- if (!node) {
818
- return this.getCompletionsForDeclarationValue(declaration, result);
819
- }
820
- if (node instanceof nodes.NumericValue || node instanceof nodes.Identifier) {
821
- return this.getCompletionsForDeclarationValue(declaration, result);
822
- }
823
- return result;
824
- }
825
- getCompletionsForFunctionArgument(arg, func, result) {
826
- const identifier = func.getIdentifier();
827
- if (identifier && identifier.matches('var')) {
828
- if (!func.getArguments().hasChildren() || func.getArguments().getChild(0) === arg) {
829
- this.getVariableProposalsForCSSVarFunction(result);
830
- }
831
- }
832
- return result;
833
- }
834
- getCompletionsForFunctionDeclaration(decl, result) {
835
- const declarations = decl.getDeclarations();
836
- if (declarations && this.offset > declarations.offset && this.offset < declarations.end) {
837
- this.getTermProposals(undefined, null, result);
838
- }
839
- return result;
840
- }
841
- getCompletionsForMixinReference(ref, result) {
842
- const allMixins = this.getSymbolContext().findSymbolsAtOffset(this.offset, nodes.ReferenceType.Mixin);
843
- for (const mixinSymbol of allMixins) {
844
- if (mixinSymbol.node instanceof nodes.MixinDeclaration) {
845
- result.items.push(this.makeTermProposal(mixinSymbol, mixinSymbol.node.getParameters(), null));
846
- }
847
- }
848
- const identifierNode = ref.getIdentifier() || null;
849
- this.completionParticipants.forEach(participant => {
850
- if (participant.onCssMixinReference) {
851
- participant.onCssMixinReference({
852
- mixinName: this.currentWord,
853
- range: this.getCompletionRange(identifierNode)
854
- });
855
- }
856
- });
857
- return result;
858
- }
859
- getTermProposals(entry, existingNode, result) {
860
- const allFunctions = this.getSymbolContext().findSymbolsAtOffset(this.offset, nodes.ReferenceType.Function);
861
- for (const functionSymbol of allFunctions) {
862
- if (functionSymbol.node instanceof nodes.FunctionDeclaration) {
863
- result.items.push(this.makeTermProposal(functionSymbol, functionSymbol.node.getParameters(), existingNode));
864
- }
865
- }
866
- return result;
867
- }
868
- makeTermProposal(symbol, parameters, existingNode) {
869
- const decl = symbol.node;
870
- const params = parameters.getChildren().map((c) => {
871
- return (c instanceof nodes.FunctionParameter) ? c.getName() : c.getText();
872
- });
873
- const insertText = symbol.name + '(' + params.map((p, index) => '${' + (index + 1) + ':' + p + '}').join(', ') + ')';
874
- return {
875
- label: symbol.name,
876
- detail: symbol.name + '(' + params.join(', ') + ')',
877
- textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
878
- insertTextFormat: SnippetFormat,
879
- kind: cssLanguageTypes_1.CompletionItemKind.Function,
880
- sortText: SortTexts.Term
881
- };
882
- }
883
- getCompletionsForSupportsCondition(supportsCondition, result) {
884
- const child = supportsCondition.findFirstChildBeforeOffset(this.offset);
885
- if (child) {
886
- if (child instanceof nodes.Declaration) {
887
- if (!(0, objects_1.isDefined)(child.colonPosition) || this.offset <= child.colonPosition) {
888
- return this.getCompletionsForDeclarationProperty(child, result);
889
- }
890
- else {
891
- return this.getCompletionsForDeclarationValue(child, result);
892
- }
893
- }
894
- else if (child instanceof nodes.SupportsCondition) {
895
- return this.getCompletionsForSupportsCondition(child, result);
896
- }
897
- }
898
- if ((0, objects_1.isDefined)(supportsCondition.lParent) && this.offset > supportsCondition.lParent && (!(0, objects_1.isDefined)(supportsCondition.rParent) || this.offset <= supportsCondition.rParent)) {
899
- return this.getCompletionsForDeclarationProperty(null, result);
900
- }
901
- return result;
902
- }
903
- getCompletionsForSupports(supports, result) {
904
- const declarations = supports.getDeclarations();
905
- const inInCondition = !declarations || this.offset <= declarations.offset;
906
- if (inInCondition) {
907
- const child = supports.findFirstChildBeforeOffset(this.offset);
908
- if (child instanceof nodes.SupportsCondition) {
909
- return this.getCompletionsForSupportsCondition(child, result);
910
- }
911
- return result;
912
- }
913
- return this.getCompletionForTopLevel(result);
914
- }
915
- getCompletionsForExtendsReference(extendsRef, existingNode, result) {
916
- return result;
917
- }
918
- getCompletionForUriLiteralValue(uriLiteralNode, result) {
919
- let uriValue;
920
- let position;
921
- let range;
922
- // No children, empty value
923
- if (!uriLiteralNode.hasChildren()) {
924
- uriValue = '';
925
- position = this.position;
926
- const emptyURIValuePosition = this.textDocument.positionAt(uriLiteralNode.offset + 'url('.length);
927
- range = cssLanguageTypes_1.Range.create(emptyURIValuePosition, emptyURIValuePosition);
928
- }
929
- else {
930
- const uriValueNode = uriLiteralNode.getChild(0);
931
- uriValue = uriValueNode.getText();
932
- position = this.position;
933
- range = this.getCompletionRange(uriValueNode);
934
- }
935
- this.completionParticipants.forEach(participant => {
936
- if (participant.onCssURILiteralValue) {
937
- participant.onCssURILiteralValue({
938
- uriValue,
939
- position,
940
- range
941
- });
942
- }
943
- });
944
- return result;
945
- }
946
- getCompletionForImportPath(importPathNode, result) {
947
- this.completionParticipants.forEach(participant => {
948
- if (participant.onCssImportPath) {
949
- participant.onCssImportPath({
950
- pathValue: importPathNode.getText(),
951
- position: this.position,
952
- range: this.getCompletionRange(importPathNode)
953
- });
954
- }
955
- });
956
- return result;
957
- }
958
- hasCharacterAtPosition(offset, char) {
959
- const text = this.textDocument.getText();
960
- return (offset >= 0 && offset < text.length) && text.charAt(offset) === char;
961
- }
962
- doesSupportMarkdown() {
963
- if (!(0, objects_1.isDefined)(this.supportsMarkdown)) {
964
- if (!(0, objects_1.isDefined)(this.lsOptions.clientCapabilities)) {
965
- this.supportsMarkdown = true;
966
- return this.supportsMarkdown;
967
- }
968
- const documentationFormat = this.lsOptions.clientCapabilities.textDocument?.completion?.completionItem?.documentationFormat;
969
- this.supportsMarkdown = Array.isArray(documentationFormat) && documentationFormat.indexOf(cssLanguageTypes_1.MarkupKind.Markdown) !== -1;
970
- }
971
- return this.supportsMarkdown;
972
- }
973
- }
974
- exports.CSSCompletion = CSSCompletion;
975
- function isDeprecated(entry) {
976
- if (entry.status && (entry.status === 'nonstandard' || entry.status === 'obsolete')) {
977
- return true;
978
- }
979
- return false;
980
- }
981
- class Set {
982
- constructor() {
983
- this.entries = {};
984
- }
985
- add(entry) {
986
- this.entries[entry] = true;
987
- }
988
- remove(entry) {
989
- delete this.entries[entry];
990
- }
991
- getEntries() {
992
- return Object.keys(this.entries);
993
- }
994
- }
995
- function moveCursorInsideParenthesis(text) {
996
- return text.replace(/\(\)$/, "($1)");
997
- }
998
- function collectValues(styleSheet, declaration) {
999
- const fullPropertyName = declaration.getFullPropertyName();
1000
- const entries = new Set();
1001
- function visitValue(node) {
1002
- if (node instanceof nodes.Identifier || node instanceof nodes.NumericValue || node instanceof nodes.HexColorValue) {
1003
- entries.add(node.getText());
1004
- }
1005
- return true;
1006
- }
1007
- function matchesProperty(decl) {
1008
- const propertyName = decl.getFullPropertyName();
1009
- return fullPropertyName === propertyName;
1010
- }
1011
- function vistNode(node) {
1012
- if (node instanceof nodes.Declaration && node !== declaration) {
1013
- if (matchesProperty(node)) {
1014
- const value = node.getValue();
1015
- if (value) {
1016
- value.accept(visitValue);
1017
- }
1018
- }
1019
- }
1020
- return true;
1021
- }
1022
- styleSheet.accept(vistNode);
1023
- return entries;
1024
- }
1025
- class ColorValueCollector {
1026
- constructor(entries, currentOffset) {
1027
- this.entries = entries;
1028
- this.currentOffset = currentOffset;
1029
- // nothing to do
1030
- }
1031
- visitNode(node) {
1032
- if (node instanceof nodes.HexColorValue || (node instanceof nodes.Function && languageFacts.isColorConstructor(node))) {
1033
- if (this.currentOffset < node.offset || node.end < this.currentOffset) {
1034
- this.entries.add(node.getText());
1035
- }
1036
- }
1037
- return true;
1038
- }
1039
- }
1040
- class VariableCollector {
1041
- constructor(entries, currentOffset) {
1042
- this.entries = entries;
1043
- this.currentOffset = currentOffset;
1044
- // nothing to do
1045
- }
1046
- visitNode(node) {
1047
- if (node instanceof nodes.Identifier && node.isCustomProperty) {
1048
- if (this.currentOffset < node.offset || node.end < this.currentOffset) {
1049
- this.entries.add(node.getText());
1050
- }
1051
- }
1052
- return true;
1053
- }
1054
- }
1055
- function getCurrentWord(document, offset) {
1056
- let i = offset - 1;
1057
- const text = document.getText();
1058
- while (i >= 0 && ' \t\n\r":{[()]},*>+'.indexOf(text.charAt(i)) === -1) {
1059
- i--;
1060
- }
1061
- return text.substring(i + 1, offset);
1062
- }
1063
- function isColorString(s) {
1064
- // From https://stackoverflow.com/questions/8027423/how-to-check-if-a-string-is-a-valid-hex-color-representation/8027444
1065
- return (s.toLowerCase() in languageFacts.colors) || /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(s);
1066
- }
1067
- });
1
+ (function (factory) {
2
+ if (typeof module === "object" && typeof module.exports === "object") {
3
+ var v = factory(require, exports);
4
+ if (v !== undefined) module.exports = v;
5
+ }
6
+ else if (typeof define === "function" && define.amd) {
7
+ define(["require", "exports", "../parser/cssNodes", "../parser/cssSymbolScope", "../languageFacts/facts", "../utils/strings", "../cssLanguageTypes", "vscode-nls", "../utils/objects", "./pathCompletion"], factory);
8
+ }
9
+ })(function (require, exports) {
10
+ /*---------------------------------------------------------------------------------------------
11
+ * Copyright (c) Microsoft Corporation. All rights reserved.
12
+ * Licensed under the MIT License. See License.txt in the project root for license information.
13
+ *--------------------------------------------------------------------------------------------*/
14
+ 'use strict';
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.CSSCompletion = void 0;
17
+ const nodes = require("../parser/cssNodes");
18
+ const cssSymbolScope_1 = require("../parser/cssSymbolScope");
19
+ const languageFacts = require("../languageFacts/facts");
20
+ const strings = require("../utils/strings");
21
+ const cssLanguageTypes_1 = require("../cssLanguageTypes");
22
+ const nls = require("vscode-nls");
23
+ const objects_1 = require("../utils/objects");
24
+ const pathCompletion_1 = require("./pathCompletion");
25
+ const localize = nls.loadMessageBundle();
26
+ const SnippetFormat = cssLanguageTypes_1.InsertTextFormat.Snippet;
27
+ const retriggerCommand = {
28
+ title: 'Suggest',
29
+ command: 'editor.action.triggerSuggest'
30
+ };
31
+ var SortTexts;
32
+ (function (SortTexts) {
33
+ // char code 32, comes before everything
34
+ SortTexts["Enums"] = " ";
35
+ SortTexts["Normal"] = "d";
36
+ SortTexts["VendorPrefixed"] = "x";
37
+ SortTexts["Term"] = "y";
38
+ SortTexts["Variable"] = "z";
39
+ })(SortTexts || (SortTexts = {}));
40
+ class CSSCompletion {
41
+ constructor(variablePrefix = null, lsOptions, cssDataManager) {
42
+ this.variablePrefix = variablePrefix;
43
+ this.lsOptions = lsOptions;
44
+ this.cssDataManager = cssDataManager;
45
+ this.completionParticipants = [];
46
+ }
47
+ configure(settings) {
48
+ this.defaultSettings = settings;
49
+ }
50
+ getSymbolContext() {
51
+ if (!this.symbolContext) {
52
+ this.symbolContext = new cssSymbolScope_1.Symbols(this.styleSheet);
53
+ }
54
+ return this.symbolContext;
55
+ }
56
+ setCompletionParticipants(registeredCompletionParticipants) {
57
+ this.completionParticipants = registeredCompletionParticipants || [];
58
+ }
59
+ async doComplete2(document, position, styleSheet, documentContext, completionSettings = this.defaultSettings) {
60
+ if (!this.lsOptions.fileSystemProvider || !this.lsOptions.fileSystemProvider.readDirectory) {
61
+ return this.doComplete(document, position, styleSheet, completionSettings);
62
+ }
63
+ const participant = new pathCompletion_1.PathCompletionParticipant(this.lsOptions.fileSystemProvider.readDirectory);
64
+ const contributedParticipants = this.completionParticipants;
65
+ this.completionParticipants = [participant].concat(contributedParticipants);
66
+ const result = this.doComplete(document, position, styleSheet, completionSettings);
67
+ try {
68
+ const pathCompletionResult = await participant.computeCompletions(document, documentContext);
69
+ return {
70
+ isIncomplete: result.isIncomplete || pathCompletionResult.isIncomplete,
71
+ items: pathCompletionResult.items.concat(result.items)
72
+ };
73
+ }
74
+ finally {
75
+ this.completionParticipants = contributedParticipants;
76
+ }
77
+ }
78
+ doComplete(document, position, styleSheet, documentSettings) {
79
+ this.offset = document.offsetAt(position);
80
+ this.position = position;
81
+ this.currentWord = getCurrentWord(document, this.offset);
82
+ this.defaultReplaceRange = cssLanguageTypes_1.Range.create(cssLanguageTypes_1.Position.create(this.position.line, this.position.character - this.currentWord.length), this.position);
83
+ this.textDocument = document;
84
+ this.styleSheet = styleSheet;
85
+ this.documentSettings = documentSettings;
86
+ try {
87
+ const result = { isIncomplete: false, items: [] };
88
+ this.nodePath = nodes.getNodePath(this.styleSheet, this.offset);
89
+ for (let i = this.nodePath.length - 1; i >= 0; i--) {
90
+ const node = this.nodePath[i];
91
+ if (node instanceof nodes.Property) {
92
+ this.getCompletionsForDeclarationProperty(node.getParent(), result);
93
+ }
94
+ else if (node instanceof nodes.Expression) {
95
+ if (node.parent instanceof nodes.Interpolation) {
96
+ this.getVariableProposals(null, result);
97
+ }
98
+ else {
99
+ this.getCompletionsForExpression(node, result);
100
+ }
101
+ }
102
+ else if (node instanceof nodes.SimpleSelector) {
103
+ const parentRef = node.findAParent(nodes.NodeType.ExtendsReference, nodes.NodeType.Ruleset);
104
+ if (parentRef) {
105
+ if (parentRef.type === nodes.NodeType.ExtendsReference) {
106
+ this.getCompletionsForExtendsReference(parentRef, node, result);
107
+ }
108
+ else {
109
+ const parentRuleSet = parentRef;
110
+ this.getCompletionsForSelector(parentRuleSet, parentRuleSet && parentRuleSet.isNested(), result);
111
+ }
112
+ }
113
+ }
114
+ else if (node instanceof nodes.FunctionArgument) {
115
+ this.getCompletionsForFunctionArgument(node, node.getParent(), result);
116
+ }
117
+ else if (node instanceof nodes.Declarations) {
118
+ this.getCompletionsForDeclarations(node, result);
119
+ }
120
+ else if (node instanceof nodes.VariableDeclaration) {
121
+ this.getCompletionsForVariableDeclaration(node, result);
122
+ }
123
+ else if (node instanceof nodes.RuleSet) {
124
+ this.getCompletionsForRuleSet(node, result);
125
+ }
126
+ else if (node instanceof nodes.Interpolation) {
127
+ this.getCompletionsForInterpolation(node, result);
128
+ }
129
+ else if (node instanceof nodes.FunctionDeclaration) {
130
+ this.getCompletionsForFunctionDeclaration(node, result);
131
+ }
132
+ else if (node instanceof nodes.MixinReference) {
133
+ this.getCompletionsForMixinReference(node, result);
134
+ }
135
+ else if (node instanceof nodes.Function) {
136
+ this.getCompletionsForFunctionArgument(null, node, result);
137
+ }
138
+ else if (node instanceof nodes.Supports) {
139
+ this.getCompletionsForSupports(node, result);
140
+ }
141
+ else if (node instanceof nodes.SupportsCondition) {
142
+ this.getCompletionsForSupportsCondition(node, result);
143
+ }
144
+ else if (node instanceof nodes.ExtendsReference) {
145
+ this.getCompletionsForExtendsReference(node, null, result);
146
+ }
147
+ else if (node.type === nodes.NodeType.URILiteral) {
148
+ this.getCompletionForUriLiteralValue(node, result);
149
+ }
150
+ else if (node.parent === null) {
151
+ this.getCompletionForTopLevel(result);
152
+ }
153
+ else if (node.type === nodes.NodeType.StringLiteral && this.isImportPathParent(node.parent.type)) {
154
+ this.getCompletionForImportPath(node, result);
155
+ // } else if (node instanceof nodes.Variable) {
156
+ // this.getCompletionsForVariableDeclaration()
157
+ }
158
+ else {
159
+ continue;
160
+ }
161
+ if (result.items.length > 0 || this.offset > node.offset) {
162
+ return this.finalize(result);
163
+ }
164
+ }
165
+ this.getCompletionsForStylesheet(result);
166
+ if (result.items.length === 0) {
167
+ if (this.variablePrefix && this.currentWord.indexOf(this.variablePrefix) === 0) {
168
+ this.getVariableProposals(null, result);
169
+ }
170
+ }
171
+ return this.finalize(result);
172
+ }
173
+ finally {
174
+ // don't hold on any state, clear symbolContext
175
+ this.position = null;
176
+ this.currentWord = null;
177
+ this.textDocument = null;
178
+ this.styleSheet = null;
179
+ this.symbolContext = null;
180
+ this.defaultReplaceRange = null;
181
+ this.nodePath = null;
182
+ }
183
+ }
184
+ isImportPathParent(type) {
185
+ return type === nodes.NodeType.Import;
186
+ }
187
+ finalize(result) {
188
+ return result;
189
+ }
190
+ findInNodePath(...types) {
191
+ for (let i = this.nodePath.length - 1; i >= 0; i--) {
192
+ const node = this.nodePath[i];
193
+ if (types.indexOf(node.type) !== -1) {
194
+ return node;
195
+ }
196
+ }
197
+ return null;
198
+ }
199
+ getCompletionsForDeclarationProperty(declaration, result) {
200
+ return this.getPropertyProposals(declaration, result);
201
+ }
202
+ getPropertyProposals(declaration, result) {
203
+ const triggerPropertyValueCompletion = this.isTriggerPropertyValueCompletionEnabled;
204
+ const completePropertyWithSemicolon = this.isCompletePropertyWithSemicolonEnabled;
205
+ const properties = this.cssDataManager.getProperties();
206
+ properties.forEach(entry => {
207
+ let range;
208
+ let insertText;
209
+ let retrigger = false;
210
+ if (declaration) {
211
+ range = this.getCompletionRange(declaration.getProperty());
212
+ insertText = entry.name;
213
+ if (!(0, objects_1.isDefined)(declaration.colonPosition)) {
214
+ insertText += ': ';
215
+ retrigger = true;
216
+ }
217
+ }
218
+ else {
219
+ range = this.getCompletionRange(null);
220
+ insertText = entry.name + ': ';
221
+ retrigger = true;
222
+ }
223
+ // Empty .selector { | } case
224
+ if (!declaration && completePropertyWithSemicolon) {
225
+ insertText += '$0;';
226
+ }
227
+ // Cases such as .selector { p; } or .selector { p:; }
228
+ if (declaration && !declaration.semicolonPosition) {
229
+ if (completePropertyWithSemicolon && this.offset >= this.textDocument.offsetAt(range.end)) {
230
+ insertText += '$0;';
231
+ }
232
+ }
233
+ const item = {
234
+ label: entry.name,
235
+ documentation: languageFacts.getEntryDescription(entry, this.doesSupportMarkdown()),
236
+ tags: isDeprecated(entry) ? [cssLanguageTypes_1.CompletionItemTag.Deprecated] : [],
237
+ textEdit: cssLanguageTypes_1.TextEdit.replace(range, insertText),
238
+ insertTextFormat: cssLanguageTypes_1.InsertTextFormat.Snippet,
239
+ kind: cssLanguageTypes_1.CompletionItemKind.Property
240
+ };
241
+ if (!entry.restrictions) {
242
+ retrigger = false;
243
+ }
244
+ if (triggerPropertyValueCompletion && retrigger) {
245
+ item.command = retriggerCommand;
246
+ }
247
+ const relevance = typeof entry.relevance === 'number' ? Math.min(Math.max(entry.relevance, 0), 99) : 50;
248
+ const sortTextSuffix = (255 - relevance).toString(16);
249
+ const sortTextPrefix = strings.startsWith(entry.name, '-') ? SortTexts.VendorPrefixed : SortTexts.Normal;
250
+ item.sortText = sortTextPrefix + '_' + sortTextSuffix;
251
+ result.items.push(item);
252
+ });
253
+ this.completionParticipants.forEach(participant => {
254
+ if (participant.onCssProperty) {
255
+ participant.onCssProperty({
256
+ propertyName: this.currentWord,
257
+ range: this.defaultReplaceRange
258
+ });
259
+ }
260
+ });
261
+ return result;
262
+ }
263
+ get isTriggerPropertyValueCompletionEnabled() {
264
+ return this.documentSettings?.triggerPropertyValueCompletion ?? true;
265
+ }
266
+ get isCompletePropertyWithSemicolonEnabled() {
267
+ return this.documentSettings?.completePropertyWithSemicolon ?? true;
268
+ }
269
+ getCompletionsForDeclarationValue(node, result) {
270
+ const propertyName = node.getFullPropertyName();
271
+ const entry = this.cssDataManager.getProperty(propertyName);
272
+ let existingNode = node.getValue() || null;
273
+ while (existingNode && existingNode.hasChildren()) {
274
+ existingNode = existingNode.findChildAtOffset(this.offset, false);
275
+ }
276
+ this.completionParticipants.forEach(participant => {
277
+ if (participant.onCssPropertyValue) {
278
+ participant.onCssPropertyValue({
279
+ propertyName,
280
+ propertyValue: this.currentWord,
281
+ range: this.getCompletionRange(existingNode)
282
+ });
283
+ }
284
+ });
285
+ if (entry) {
286
+ if (entry.restrictions) {
287
+ for (const restriction of entry.restrictions) {
288
+ switch (restriction) {
289
+ case 'color':
290
+ this.getColorProposals(entry, existingNode, result);
291
+ break;
292
+ case 'position':
293
+ this.getPositionProposals(entry, existingNode, result);
294
+ break;
295
+ case 'repeat':
296
+ this.getRepeatStyleProposals(entry, existingNode, result);
297
+ break;
298
+ case 'line-style':
299
+ this.getLineStyleProposals(entry, existingNode, result);
300
+ break;
301
+ case 'line-width':
302
+ this.getLineWidthProposals(entry, existingNode, result);
303
+ break;
304
+ case 'geometry-box':
305
+ this.getGeometryBoxProposals(entry, existingNode, result);
306
+ break;
307
+ case 'box':
308
+ this.getBoxProposals(entry, existingNode, result);
309
+ break;
310
+ case 'image':
311
+ this.getImageProposals(entry, existingNode, result);
312
+ break;
313
+ case 'timing-function':
314
+ this.getTimingFunctionProposals(entry, existingNode, result);
315
+ break;
316
+ case 'shape':
317
+ this.getBasicShapeProposals(entry, existingNode, result);
318
+ break;
319
+ }
320
+ }
321
+ }
322
+ this.getValueEnumProposals(entry, existingNode, result);
323
+ this.getCSSWideKeywordProposals(entry, existingNode, result);
324
+ this.getUnitProposals(entry, existingNode, result);
325
+ }
326
+ else {
327
+ const existingValues = collectValues(this.styleSheet, node);
328
+ for (const existingValue of existingValues.getEntries()) {
329
+ result.items.push({
330
+ label: existingValue,
331
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), existingValue),
332
+ kind: cssLanguageTypes_1.CompletionItemKind.Value
333
+ });
334
+ }
335
+ }
336
+ this.getVariableProposals(existingNode, result);
337
+ this.getTermProposals(entry, existingNode, result);
338
+ return result;
339
+ }
340
+ getValueEnumProposals(entry, existingNode, result) {
341
+ if (entry.values) {
342
+ for (const value of entry.values) {
343
+ let insertString = value.name;
344
+ let insertTextFormat;
345
+ if (strings.endsWith(insertString, ')')) {
346
+ const from = insertString.lastIndexOf('(');
347
+ if (from !== -1) {
348
+ insertString = insertString.substring(0, from + 1) + '$1' + insertString.substring(from + 1);
349
+ insertTextFormat = SnippetFormat;
350
+ }
351
+ }
352
+ let sortText = SortTexts.Enums;
353
+ if (strings.startsWith(value.name, '-')) {
354
+ sortText += SortTexts.VendorPrefixed;
355
+ }
356
+ const item = {
357
+ label: value.name,
358
+ documentation: languageFacts.getEntryDescription(value, this.doesSupportMarkdown()),
359
+ tags: isDeprecated(entry) ? [cssLanguageTypes_1.CompletionItemTag.Deprecated] : [],
360
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertString),
361
+ sortText,
362
+ kind: cssLanguageTypes_1.CompletionItemKind.Value,
363
+ insertTextFormat
364
+ };
365
+ result.items.push(item);
366
+ }
367
+ }
368
+ return result;
369
+ }
370
+ getCSSWideKeywordProposals(entry, existingNode, result) {
371
+ for (const keywords in languageFacts.cssWideKeywords) {
372
+ result.items.push({
373
+ label: keywords,
374
+ documentation: languageFacts.cssWideKeywords[keywords],
375
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), keywords),
376
+ kind: cssLanguageTypes_1.CompletionItemKind.Value
377
+ });
378
+ }
379
+ for (const func in languageFacts.cssWideFunctions) {
380
+ const insertText = moveCursorInsideParenthesis(func);
381
+ result.items.push({
382
+ label: func,
383
+ documentation: languageFacts.cssWideFunctions[func],
384
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
385
+ kind: cssLanguageTypes_1.CompletionItemKind.Function,
386
+ insertTextFormat: SnippetFormat,
387
+ command: strings.startsWith(func, 'var') ? retriggerCommand : undefined
388
+ });
389
+ }
390
+ return result;
391
+ }
392
+ getCompletionsForInterpolation(node, result) {
393
+ if (this.offset >= node.offset + 2) {
394
+ this.getVariableProposals(null, result);
395
+ }
396
+ return result;
397
+ }
398
+ getVariableProposals(existingNode, result) {
399
+ const symbols = this.getSymbolContext().findSymbolsAtOffset(this.offset, nodes.ReferenceType.Variable);
400
+ for (const symbol of symbols) {
401
+ const insertText = strings.startsWith(symbol.name, '--') ? `var(${symbol.name})` : symbol.name;
402
+ const completionItem = {
403
+ label: symbol.name,
404
+ documentation: symbol.value ? strings.getLimitedString(symbol.value) : symbol.value,
405
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
406
+ kind: cssLanguageTypes_1.CompletionItemKind.Variable,
407
+ sortText: SortTexts.Variable
408
+ };
409
+ if (typeof completionItem.documentation === 'string' && isColorString(completionItem.documentation)) {
410
+ completionItem.kind = cssLanguageTypes_1.CompletionItemKind.Color;
411
+ }
412
+ if (symbol.node.type === nodes.NodeType.FunctionParameter) {
413
+ const mixinNode = (symbol.node.getParent());
414
+ if (mixinNode.type === nodes.NodeType.MixinDeclaration) {
415
+ completionItem.detail = localize('completion.argument', 'argument from \'{0}\'', mixinNode.getName());
416
+ }
417
+ }
418
+ result.items.push(completionItem);
419
+ }
420
+ return result;
421
+ }
422
+ getVariableProposalsForCSSVarFunction(result) {
423
+ const allReferencedVariables = new Set();
424
+ this.styleSheet.acceptVisitor(new VariableCollector(allReferencedVariables, this.offset));
425
+ let symbols = this.getSymbolContext().findSymbolsAtOffset(this.offset, nodes.ReferenceType.Variable);
426
+ for (const symbol of symbols) {
427
+ if (strings.startsWith(symbol.name, '--')) {
428
+ const completionItem = {
429
+ label: symbol.name,
430
+ documentation: symbol.value ? strings.getLimitedString(symbol.value) : symbol.value,
431
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(null), symbol.name),
432
+ kind: cssLanguageTypes_1.CompletionItemKind.Variable
433
+ };
434
+ if (typeof completionItem.documentation === 'string' && isColorString(completionItem.documentation)) {
435
+ completionItem.kind = cssLanguageTypes_1.CompletionItemKind.Color;
436
+ }
437
+ result.items.push(completionItem);
438
+ }
439
+ allReferencedVariables.remove(symbol.name);
440
+ }
441
+ for (const name of allReferencedVariables.getEntries()) {
442
+ if (strings.startsWith(name, '--')) {
443
+ const completionItem = {
444
+ label: name,
445
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(null), name),
446
+ kind: cssLanguageTypes_1.CompletionItemKind.Variable
447
+ };
448
+ result.items.push(completionItem);
449
+ }
450
+ }
451
+ return result;
452
+ }
453
+ getUnitProposals(entry, existingNode, result) {
454
+ let currentWord = '0';
455
+ if (this.currentWord.length > 0) {
456
+ const numMatch = this.currentWord.match(/^-?\d[\.\d+]*/);
457
+ if (numMatch) {
458
+ currentWord = numMatch[0];
459
+ result.isIncomplete = currentWord.length === this.currentWord.length;
460
+ }
461
+ }
462
+ else if (this.currentWord.length === 0) {
463
+ result.isIncomplete = true;
464
+ }
465
+ if (existingNode && existingNode.parent && existingNode.parent.type === nodes.NodeType.Term) {
466
+ existingNode = existingNode.getParent(); // include the unary operator
467
+ }
468
+ if (entry.restrictions) {
469
+ for (const restriction of entry.restrictions) {
470
+ const units = languageFacts.units[restriction];
471
+ if (units) {
472
+ for (const unit of units) {
473
+ const insertText = currentWord + unit;
474
+ result.items.push({
475
+ label: insertText,
476
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
477
+ kind: cssLanguageTypes_1.CompletionItemKind.Unit
478
+ });
479
+ }
480
+ }
481
+ }
482
+ }
483
+ return result;
484
+ }
485
+ getCompletionRange(existingNode) {
486
+ if (existingNode && existingNode.offset <= this.offset && this.offset <= existingNode.end) {
487
+ const end = existingNode.end !== -1 ? this.textDocument.positionAt(existingNode.end) : this.position;
488
+ const start = this.textDocument.positionAt(existingNode.offset);
489
+ if (start.line === end.line) {
490
+ return cssLanguageTypes_1.Range.create(start, end); // multi line edits are not allowed
491
+ }
492
+ }
493
+ return this.defaultReplaceRange;
494
+ }
495
+ getColorProposals(entry, existingNode, result) {
496
+ for (const color in languageFacts.colors) {
497
+ result.items.push({
498
+ label: color,
499
+ documentation: languageFacts.colors[color],
500
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), color),
501
+ kind: cssLanguageTypes_1.CompletionItemKind.Color
502
+ });
503
+ }
504
+ for (const color in languageFacts.colorKeywords) {
505
+ result.items.push({
506
+ label: color,
507
+ documentation: languageFacts.colorKeywords[color],
508
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), color),
509
+ kind: cssLanguageTypes_1.CompletionItemKind.Value
510
+ });
511
+ }
512
+ const colorValues = new Set();
513
+ this.styleSheet.acceptVisitor(new ColorValueCollector(colorValues, this.offset));
514
+ for (const color of colorValues.getEntries()) {
515
+ result.items.push({
516
+ label: color,
517
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), color),
518
+ kind: cssLanguageTypes_1.CompletionItemKind.Color
519
+ });
520
+ }
521
+ for (const p of languageFacts.colorFunctions) {
522
+ let tabStop = 1;
523
+ const replaceFunction = (_match, p1) => '${' + tabStop++ + ':' + p1 + '}';
524
+ const insertText = p.func.replace(/\[?\$(\w+)\]?/g, replaceFunction);
525
+ result.items.push({
526
+ label: p.func.substr(0, p.func.indexOf('(')),
527
+ detail: p.func,
528
+ documentation: p.desc,
529
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
530
+ insertTextFormat: SnippetFormat,
531
+ kind: cssLanguageTypes_1.CompletionItemKind.Function
532
+ });
533
+ }
534
+ return result;
535
+ }
536
+ getPositionProposals(entry, existingNode, result) {
537
+ for (const position in languageFacts.positionKeywords) {
538
+ result.items.push({
539
+ label: position,
540
+ documentation: languageFacts.positionKeywords[position],
541
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), position),
542
+ kind: cssLanguageTypes_1.CompletionItemKind.Value
543
+ });
544
+ }
545
+ return result;
546
+ }
547
+ getRepeatStyleProposals(entry, existingNode, result) {
548
+ for (const repeat in languageFacts.repeatStyleKeywords) {
549
+ result.items.push({
550
+ label: repeat,
551
+ documentation: languageFacts.repeatStyleKeywords[repeat],
552
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), repeat),
553
+ kind: cssLanguageTypes_1.CompletionItemKind.Value
554
+ });
555
+ }
556
+ return result;
557
+ }
558
+ getLineStyleProposals(entry, existingNode, result) {
559
+ for (const lineStyle in languageFacts.lineStyleKeywords) {
560
+ result.items.push({
561
+ label: lineStyle,
562
+ documentation: languageFacts.lineStyleKeywords[lineStyle],
563
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), lineStyle),
564
+ kind: cssLanguageTypes_1.CompletionItemKind.Value
565
+ });
566
+ }
567
+ return result;
568
+ }
569
+ getLineWidthProposals(entry, existingNode, result) {
570
+ for (const lineWidth of languageFacts.lineWidthKeywords) {
571
+ result.items.push({
572
+ label: lineWidth,
573
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), lineWidth),
574
+ kind: cssLanguageTypes_1.CompletionItemKind.Value
575
+ });
576
+ }
577
+ return result;
578
+ }
579
+ getGeometryBoxProposals(entry, existingNode, result) {
580
+ for (const box in languageFacts.geometryBoxKeywords) {
581
+ result.items.push({
582
+ label: box,
583
+ documentation: languageFacts.geometryBoxKeywords[box],
584
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), box),
585
+ kind: cssLanguageTypes_1.CompletionItemKind.Value
586
+ });
587
+ }
588
+ return result;
589
+ }
590
+ getBoxProposals(entry, existingNode, result) {
591
+ for (const box in languageFacts.boxKeywords) {
592
+ result.items.push({
593
+ label: box,
594
+ documentation: languageFacts.boxKeywords[box],
595
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), box),
596
+ kind: cssLanguageTypes_1.CompletionItemKind.Value
597
+ });
598
+ }
599
+ return result;
600
+ }
601
+ getImageProposals(entry, existingNode, result) {
602
+ for (const image in languageFacts.imageFunctions) {
603
+ const insertText = moveCursorInsideParenthesis(image);
604
+ result.items.push({
605
+ label: image,
606
+ documentation: languageFacts.imageFunctions[image],
607
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
608
+ kind: cssLanguageTypes_1.CompletionItemKind.Function,
609
+ insertTextFormat: image !== insertText ? SnippetFormat : void 0
610
+ });
611
+ }
612
+ return result;
613
+ }
614
+ getTimingFunctionProposals(entry, existingNode, result) {
615
+ for (const timing in languageFacts.transitionTimingFunctions) {
616
+ const insertText = moveCursorInsideParenthesis(timing);
617
+ result.items.push({
618
+ label: timing,
619
+ documentation: languageFacts.transitionTimingFunctions[timing],
620
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
621
+ kind: cssLanguageTypes_1.CompletionItemKind.Function,
622
+ insertTextFormat: timing !== insertText ? SnippetFormat : void 0
623
+ });
624
+ }
625
+ return result;
626
+ }
627
+ getBasicShapeProposals(entry, existingNode, result) {
628
+ for (const shape in languageFacts.basicShapeFunctions) {
629
+ const insertText = moveCursorInsideParenthesis(shape);
630
+ result.items.push({
631
+ label: shape,
632
+ documentation: languageFacts.basicShapeFunctions[shape],
633
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
634
+ kind: cssLanguageTypes_1.CompletionItemKind.Function,
635
+ insertTextFormat: shape !== insertText ? SnippetFormat : void 0
636
+ });
637
+ }
638
+ return result;
639
+ }
640
+ getCompletionsForStylesheet(result) {
641
+ const node = this.styleSheet.findFirstChildBeforeOffset(this.offset);
642
+ if (!node) {
643
+ return this.getCompletionForTopLevel(result);
644
+ }
645
+ if (node instanceof nodes.RuleSet) {
646
+ return this.getCompletionsForRuleSet(node, result);
647
+ }
648
+ if (node instanceof nodes.Supports) {
649
+ return this.getCompletionsForSupports(node, result);
650
+ }
651
+ return result;
652
+ }
653
+ getCompletionForTopLevel(result) {
654
+ this.cssDataManager.getAtDirectives().forEach(entry => {
655
+ result.items.push({
656
+ label: entry.name,
657
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(null), entry.name),
658
+ documentation: languageFacts.getEntryDescription(entry, this.doesSupportMarkdown()),
659
+ tags: isDeprecated(entry) ? [cssLanguageTypes_1.CompletionItemTag.Deprecated] : [],
660
+ kind: cssLanguageTypes_1.CompletionItemKind.Keyword
661
+ });
662
+ });
663
+ this.getCompletionsForSelector(null, false, result);
664
+ return result;
665
+ }
666
+ getCompletionsForRuleSet(ruleSet, result) {
667
+ const declarations = ruleSet.getDeclarations();
668
+ const isAfter = declarations && declarations.endsWith('}') && this.offset >= declarations.end;
669
+ if (isAfter) {
670
+ return this.getCompletionForTopLevel(result);
671
+ }
672
+ const isInSelectors = !declarations || this.offset <= declarations.offset;
673
+ if (isInSelectors) {
674
+ return this.getCompletionsForSelector(ruleSet, ruleSet.isNested(), result);
675
+ }
676
+ return this.getCompletionsForDeclarations(ruleSet.getDeclarations(), result);
677
+ }
678
+ getCompletionsForSelector(ruleSet, isNested, result) {
679
+ const existingNode = this.findInNodePath(nodes.NodeType.PseudoSelector, nodes.NodeType.IdentifierSelector, nodes.NodeType.ClassSelector, nodes.NodeType.ElementNameSelector);
680
+ if (!existingNode && this.hasCharacterAtPosition(this.offset - this.currentWord.length - 1, ':')) {
681
+ // after the ':' of a pseudo selector, no node generated for just ':'
682
+ this.currentWord = ':' + this.currentWord;
683
+ if (this.hasCharacterAtPosition(this.offset - this.currentWord.length - 1, ':')) {
684
+ this.currentWord = ':' + this.currentWord; // for '::'
685
+ }
686
+ this.defaultReplaceRange = cssLanguageTypes_1.Range.create(cssLanguageTypes_1.Position.create(this.position.line, this.position.character - this.currentWord.length), this.position);
687
+ }
688
+ const pseudoClasses = this.cssDataManager.getPseudoClasses();
689
+ pseudoClasses.forEach(entry => {
690
+ const insertText = moveCursorInsideParenthesis(entry.name);
691
+ const item = {
692
+ label: entry.name,
693
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
694
+ documentation: languageFacts.getEntryDescription(entry, this.doesSupportMarkdown()),
695
+ tags: isDeprecated(entry) ? [cssLanguageTypes_1.CompletionItemTag.Deprecated] : [],
696
+ kind: cssLanguageTypes_1.CompletionItemKind.Function,
697
+ insertTextFormat: entry.name !== insertText ? SnippetFormat : void 0
698
+ };
699
+ if (strings.startsWith(entry.name, ':-')) {
700
+ item.sortText = SortTexts.VendorPrefixed;
701
+ }
702
+ result.items.push(item);
703
+ });
704
+ const pseudoElements = this.cssDataManager.getPseudoElements();
705
+ pseudoElements.forEach(entry => {
706
+ const insertText = moveCursorInsideParenthesis(entry.name);
707
+ const item = {
708
+ label: entry.name,
709
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
710
+ documentation: languageFacts.getEntryDescription(entry, this.doesSupportMarkdown()),
711
+ tags: isDeprecated(entry) ? [cssLanguageTypes_1.CompletionItemTag.Deprecated] : [],
712
+ kind: cssLanguageTypes_1.CompletionItemKind.Function,
713
+ insertTextFormat: entry.name !== insertText ? SnippetFormat : void 0
714
+ };
715
+ if (strings.startsWith(entry.name, '::-')) {
716
+ item.sortText = SortTexts.VendorPrefixed;
717
+ }
718
+ result.items.push(item);
719
+ });
720
+ if (!isNested) { // show html tags only for top level
721
+ for (const entry of languageFacts.html5Tags) {
722
+ result.items.push({
723
+ label: entry,
724
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), entry),
725
+ kind: cssLanguageTypes_1.CompletionItemKind.Keyword
726
+ });
727
+ }
728
+ for (const entry of languageFacts.svgElements) {
729
+ result.items.push({
730
+ label: entry,
731
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), entry),
732
+ kind: cssLanguageTypes_1.CompletionItemKind.Keyword
733
+ });
734
+ }
735
+ }
736
+ const visited = {};
737
+ visited[this.currentWord] = true;
738
+ const docText = this.textDocument.getText();
739
+ this.styleSheet.accept(n => {
740
+ if (n.type === nodes.NodeType.SimpleSelector && n.length > 0) {
741
+ const selector = docText.substr(n.offset, n.length);
742
+ if (selector.charAt(0) === '.' && !visited[selector]) {
743
+ visited[selector] = true;
744
+ result.items.push({
745
+ label: selector,
746
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), selector),
747
+ kind: cssLanguageTypes_1.CompletionItemKind.Keyword
748
+ });
749
+ }
750
+ return false;
751
+ }
752
+ return true;
753
+ });
754
+ if (ruleSet && ruleSet.isNested()) {
755
+ const selector = ruleSet.getSelectors().findFirstChildBeforeOffset(this.offset);
756
+ if (selector && ruleSet.getSelectors().getChildren().indexOf(selector) === 0) {
757
+ this.getPropertyProposals(null, result);
758
+ }
759
+ }
760
+ return result;
761
+ }
762
+ getCompletionsForDeclarations(declarations, result) {
763
+ if (!declarations || this.offset === declarations.offset) { // incomplete nodes
764
+ return result;
765
+ }
766
+ const node = declarations.findFirstChildBeforeOffset(this.offset);
767
+ if (!node) {
768
+ return this.getCompletionsForDeclarationProperty(null, result);
769
+ }
770
+ if (node instanceof nodes.AbstractDeclaration) {
771
+ const declaration = node;
772
+ if (!(0, objects_1.isDefined)(declaration.colonPosition) || this.offset <= declaration.colonPosition) {
773
+ // complete property
774
+ return this.getCompletionsForDeclarationProperty(declaration, result);
775
+ }
776
+ else if (((0, objects_1.isDefined)(declaration.semicolonPosition) && declaration.semicolonPosition < this.offset)) {
777
+ if (this.offset === declaration.semicolonPosition + 1) {
778
+ return result; // don't show new properties right after semicolon (see Bug 15421:[intellisense] [css] Be less aggressive when manually typing CSS)
779
+ }
780
+ // complete next property
781
+ return this.getCompletionsForDeclarationProperty(null, result);
782
+ }
783
+ if (declaration instanceof nodes.Declaration) {
784
+ // complete value
785
+ return this.getCompletionsForDeclarationValue(declaration, result);
786
+ }
787
+ }
788
+ else if (node instanceof nodes.ExtendsReference) {
789
+ this.getCompletionsForExtendsReference(node, null, result);
790
+ }
791
+ else if (this.currentWord && this.currentWord[0] === '@') {
792
+ this.getCompletionsForDeclarationProperty(null, result);
793
+ }
794
+ else if (node instanceof nodes.RuleSet) {
795
+ this.getCompletionsForDeclarationProperty(null, result);
796
+ }
797
+ return result;
798
+ }
799
+ getCompletionsForVariableDeclaration(declaration, result) {
800
+ if (this.offset && (0, objects_1.isDefined)(declaration.colonPosition) && this.offset > declaration.colonPosition) {
801
+ this.getVariableProposals(declaration.getValue() || null, result);
802
+ }
803
+ return result;
804
+ }
805
+ getCompletionsForExpression(expression, result) {
806
+ const parent = expression.getParent();
807
+ if (parent instanceof nodes.FunctionArgument) {
808
+ this.getCompletionsForFunctionArgument(parent, parent.getParent(), result);
809
+ return result;
810
+ }
811
+ const declaration = expression.findParent(nodes.NodeType.Declaration);
812
+ if (!declaration) {
813
+ this.getTermProposals(undefined, null, result);
814
+ return result;
815
+ }
816
+ const node = expression.findChildAtOffset(this.offset, true);
817
+ if (!node) {
818
+ return this.getCompletionsForDeclarationValue(declaration, result);
819
+ }
820
+ if (node instanceof nodes.NumericValue || node instanceof nodes.Identifier) {
821
+ return this.getCompletionsForDeclarationValue(declaration, result);
822
+ }
823
+ return result;
824
+ }
825
+ getCompletionsForFunctionArgument(arg, func, result) {
826
+ const identifier = func.getIdentifier();
827
+ if (identifier && identifier.matches('var')) {
828
+ if (!func.getArguments().hasChildren() || func.getArguments().getChild(0) === arg) {
829
+ this.getVariableProposalsForCSSVarFunction(result);
830
+ }
831
+ }
832
+ return result;
833
+ }
834
+ getCompletionsForFunctionDeclaration(decl, result) {
835
+ const declarations = decl.getDeclarations();
836
+ if (declarations && this.offset > declarations.offset && this.offset < declarations.end) {
837
+ this.getTermProposals(undefined, null, result);
838
+ }
839
+ return result;
840
+ }
841
+ getCompletionsForMixinReference(ref, result) {
842
+ const allMixins = this.getSymbolContext().findSymbolsAtOffset(this.offset, nodes.ReferenceType.Mixin);
843
+ for (const mixinSymbol of allMixins) {
844
+ if (mixinSymbol.node instanceof nodes.MixinDeclaration) {
845
+ result.items.push(this.makeTermProposal(mixinSymbol, mixinSymbol.node.getParameters(), null));
846
+ }
847
+ }
848
+ const identifierNode = ref.getIdentifier() || null;
849
+ this.completionParticipants.forEach(participant => {
850
+ if (participant.onCssMixinReference) {
851
+ participant.onCssMixinReference({
852
+ mixinName: this.currentWord,
853
+ range: this.getCompletionRange(identifierNode)
854
+ });
855
+ }
856
+ });
857
+ return result;
858
+ }
859
+ getTermProposals(entry, existingNode, result) {
860
+ const allFunctions = this.getSymbolContext().findSymbolsAtOffset(this.offset, nodes.ReferenceType.Function);
861
+ for (const functionSymbol of allFunctions) {
862
+ if (functionSymbol.node instanceof nodes.FunctionDeclaration) {
863
+ result.items.push(this.makeTermProposal(functionSymbol, functionSymbol.node.getParameters(), existingNode));
864
+ }
865
+ }
866
+ return result;
867
+ }
868
+ makeTermProposal(symbol, parameters, existingNode) {
869
+ const decl = symbol.node;
870
+ const params = parameters.getChildren().map((c) => {
871
+ return (c instanceof nodes.FunctionParameter) ? c.getName() : c.getText();
872
+ });
873
+ const insertText = symbol.name + '(' + params.map((p, index) => '${' + (index + 1) + ':' + p + '}').join(', ') + ')';
874
+ return {
875
+ label: symbol.name,
876
+ detail: symbol.name + '(' + params.join(', ') + ')',
877
+ textEdit: cssLanguageTypes_1.TextEdit.replace(this.getCompletionRange(existingNode), insertText),
878
+ insertTextFormat: SnippetFormat,
879
+ kind: cssLanguageTypes_1.CompletionItemKind.Function,
880
+ sortText: SortTexts.Term
881
+ };
882
+ }
883
+ getCompletionsForSupportsCondition(supportsCondition, result) {
884
+ const child = supportsCondition.findFirstChildBeforeOffset(this.offset);
885
+ if (child) {
886
+ if (child instanceof nodes.Declaration) {
887
+ if (!(0, objects_1.isDefined)(child.colonPosition) || this.offset <= child.colonPosition) {
888
+ return this.getCompletionsForDeclarationProperty(child, result);
889
+ }
890
+ else {
891
+ return this.getCompletionsForDeclarationValue(child, result);
892
+ }
893
+ }
894
+ else if (child instanceof nodes.SupportsCondition) {
895
+ return this.getCompletionsForSupportsCondition(child, result);
896
+ }
897
+ }
898
+ if ((0, objects_1.isDefined)(supportsCondition.lParent) && this.offset > supportsCondition.lParent && (!(0, objects_1.isDefined)(supportsCondition.rParent) || this.offset <= supportsCondition.rParent)) {
899
+ return this.getCompletionsForDeclarationProperty(null, result);
900
+ }
901
+ return result;
902
+ }
903
+ getCompletionsForSupports(supports, result) {
904
+ const declarations = supports.getDeclarations();
905
+ const inInCondition = !declarations || this.offset <= declarations.offset;
906
+ if (inInCondition) {
907
+ const child = supports.findFirstChildBeforeOffset(this.offset);
908
+ if (child instanceof nodes.SupportsCondition) {
909
+ return this.getCompletionsForSupportsCondition(child, result);
910
+ }
911
+ return result;
912
+ }
913
+ return this.getCompletionForTopLevel(result);
914
+ }
915
+ getCompletionsForExtendsReference(extendsRef, existingNode, result) {
916
+ return result;
917
+ }
918
+ getCompletionForUriLiteralValue(uriLiteralNode, result) {
919
+ let uriValue;
920
+ let position;
921
+ let range;
922
+ // No children, empty value
923
+ if (!uriLiteralNode.hasChildren()) {
924
+ uriValue = '';
925
+ position = this.position;
926
+ const emptyURIValuePosition = this.textDocument.positionAt(uriLiteralNode.offset + 'url('.length);
927
+ range = cssLanguageTypes_1.Range.create(emptyURIValuePosition, emptyURIValuePosition);
928
+ }
929
+ else {
930
+ const uriValueNode = uriLiteralNode.getChild(0);
931
+ uriValue = uriValueNode.getText();
932
+ position = this.position;
933
+ range = this.getCompletionRange(uriValueNode);
934
+ }
935
+ this.completionParticipants.forEach(participant => {
936
+ if (participant.onCssURILiteralValue) {
937
+ participant.onCssURILiteralValue({
938
+ uriValue,
939
+ position,
940
+ range
941
+ });
942
+ }
943
+ });
944
+ return result;
945
+ }
946
+ getCompletionForImportPath(importPathNode, result) {
947
+ this.completionParticipants.forEach(participant => {
948
+ if (participant.onCssImportPath) {
949
+ participant.onCssImportPath({
950
+ pathValue: importPathNode.getText(),
951
+ position: this.position,
952
+ range: this.getCompletionRange(importPathNode)
953
+ });
954
+ }
955
+ });
956
+ return result;
957
+ }
958
+ hasCharacterAtPosition(offset, char) {
959
+ const text = this.textDocument.getText();
960
+ return (offset >= 0 && offset < text.length) && text.charAt(offset) === char;
961
+ }
962
+ doesSupportMarkdown() {
963
+ if (!(0, objects_1.isDefined)(this.supportsMarkdown)) {
964
+ if (!(0, objects_1.isDefined)(this.lsOptions.clientCapabilities)) {
965
+ this.supportsMarkdown = true;
966
+ return this.supportsMarkdown;
967
+ }
968
+ const documentationFormat = this.lsOptions.clientCapabilities.textDocument?.completion?.completionItem?.documentationFormat;
969
+ this.supportsMarkdown = Array.isArray(documentationFormat) && documentationFormat.indexOf(cssLanguageTypes_1.MarkupKind.Markdown) !== -1;
970
+ }
971
+ return this.supportsMarkdown;
972
+ }
973
+ }
974
+ exports.CSSCompletion = CSSCompletion;
975
+ function isDeprecated(entry) {
976
+ if (entry.status && (entry.status === 'nonstandard' || entry.status === 'obsolete')) {
977
+ return true;
978
+ }
979
+ return false;
980
+ }
981
+ class Set {
982
+ constructor() {
983
+ this.entries = {};
984
+ }
985
+ add(entry) {
986
+ this.entries[entry] = true;
987
+ }
988
+ remove(entry) {
989
+ delete this.entries[entry];
990
+ }
991
+ getEntries() {
992
+ return Object.keys(this.entries);
993
+ }
994
+ }
995
+ function moveCursorInsideParenthesis(text) {
996
+ return text.replace(/\(\)$/, "($1)");
997
+ }
998
+ function collectValues(styleSheet, declaration) {
999
+ const fullPropertyName = declaration.getFullPropertyName();
1000
+ const entries = new Set();
1001
+ function visitValue(node) {
1002
+ if (node instanceof nodes.Identifier || node instanceof nodes.NumericValue || node instanceof nodes.HexColorValue) {
1003
+ entries.add(node.getText());
1004
+ }
1005
+ return true;
1006
+ }
1007
+ function matchesProperty(decl) {
1008
+ const propertyName = decl.getFullPropertyName();
1009
+ return fullPropertyName === propertyName;
1010
+ }
1011
+ function vistNode(node) {
1012
+ if (node instanceof nodes.Declaration && node !== declaration) {
1013
+ if (matchesProperty(node)) {
1014
+ const value = node.getValue();
1015
+ if (value) {
1016
+ value.accept(visitValue);
1017
+ }
1018
+ }
1019
+ }
1020
+ return true;
1021
+ }
1022
+ styleSheet.accept(vistNode);
1023
+ return entries;
1024
+ }
1025
+ class ColorValueCollector {
1026
+ constructor(entries, currentOffset) {
1027
+ this.entries = entries;
1028
+ this.currentOffset = currentOffset;
1029
+ // nothing to do
1030
+ }
1031
+ visitNode(node) {
1032
+ if (node instanceof nodes.HexColorValue || (node instanceof nodes.Function && languageFacts.isColorConstructor(node))) {
1033
+ if (this.currentOffset < node.offset || node.end < this.currentOffset) {
1034
+ this.entries.add(node.getText());
1035
+ }
1036
+ }
1037
+ return true;
1038
+ }
1039
+ }
1040
+ class VariableCollector {
1041
+ constructor(entries, currentOffset) {
1042
+ this.entries = entries;
1043
+ this.currentOffset = currentOffset;
1044
+ // nothing to do
1045
+ }
1046
+ visitNode(node) {
1047
+ if (node instanceof nodes.Identifier && node.isCustomProperty) {
1048
+ if (this.currentOffset < node.offset || node.end < this.currentOffset) {
1049
+ this.entries.add(node.getText());
1050
+ }
1051
+ }
1052
+ return true;
1053
+ }
1054
+ }
1055
+ function getCurrentWord(document, offset) {
1056
+ let i = offset - 1;
1057
+ const text = document.getText();
1058
+ while (i >= 0 && ' \t\n\r":{[()]},*>+'.indexOf(text.charAt(i)) === -1) {
1059
+ i--;
1060
+ }
1061
+ return text.substring(i + 1, offset);
1062
+ }
1063
+ function isColorString(s) {
1064
+ // From https://stackoverflow.com/questions/8027423/how-to-check-if-a-string-is-a-valid-hex-color-representation/8027444
1065
+ return (s.toLowerCase() in languageFacts.colors) || /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(s);
1066
+ }
1067
+ });