vscode-css-languageservice 5.4.1 → 6.0.1

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