@elice/material-exercise 1.220830.0 → 1.220919.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/components/material-exercise/MaterialExercise.styled.js +1 -1
- package/cjs/components/material-exercise/exercise-menu/ExerciseMenuDropdown.js +9 -1
- package/cjs/components/material-exercise/exercise-runner/ExerciseRunner.js +5 -1
- package/cjs/components/shared/monaco-editor/MonacoEditor.js +9 -9
- package/cjs/components/shared/monaco-editor/editor-hooks/useMonacoMarkers.js +3 -3
- package/cjs/components/shared/monaco-editor/editor-languages/css/index.d.ts +4 -0
- package/cjs/components/shared/monaco-editor/editor-languages/css/index.js +12 -0
- package/cjs/components/shared/monaco-editor/editor-languages/html/index.d.ts +4 -0
- package/cjs/components/shared/monaco-editor/editor-languages/html/index.js +10 -0
- package/cjs/components/shared/monaco-editor/editor-languages/index.js +2 -2
- package/cjs/components/shared/monaco-editor/editor-languages/typescript/index.d.ts +4 -0
- package/cjs/components/shared/monaco-editor/editor-languages/typescript/index.js +10 -0
- package/cjs/components/shared/monaco-editor/utils/emmet/emmet.d.ts +13 -0
- package/cjs/components/shared/monaco-editor/utils/emmet/emmet.js +31 -0
- package/cjs/components/shared/monaco-editor/utils/emmet/index.d.ts +1 -0
- package/cjs/components/shared/monaco-editor/utils/emmet/registerProvider.d.ts +5 -0
- package/cjs/components/shared/monaco-editor/utils/emmet/registerProvider.js +26 -0
- package/cjs/components/shared/monaco-editor/utils/grammar/index.js +2 -2
- package/cjs/components/shared/monaco-editor/utils/prettier/index.js +6 -2
- package/cjs/components/shared/monaco-editor/vendors/vscode-emmet-helper/configCompat.d.ts +15 -0
- package/cjs/components/shared/monaco-editor/vendors/vscode-emmet-helper/configCompat.js +15 -0
- package/cjs/components/shared/monaco-editor/vendors/vscode-emmet-helper/data.d.ts +6 -0
- package/cjs/components/shared/monaco-editor/vendors/vscode-emmet-helper/data.js +22 -0
- package/cjs/components/shared/monaco-editor/vendors/vscode-emmet-helper/emmetHelper.d.ts +96 -0
- package/cjs/components/shared/monaco-editor/vendors/vscode-emmet-helper/emmetHelper.js +900 -0
- package/cjs/components/shared/monaco-editor/vendors/vscode-emmet-helper/index.d.ts +2 -0
- package/cjs/components/shared/monaco-editor/vendors/vscode-emmet-helper/utils.d.ts +12 -0
- package/cjs/components/shared/monaco-editor/vendors/vscode-emmet-helper/utils.js +42 -0
- package/cjs/components/shared/web-browser/WebBrowser.js +16 -11
- package/cjs/components/shared/xterm/Xterm.js +10 -3
- package/es/components/material-exercise/MaterialExercise.styled.js +1 -1
- package/es/components/material-exercise/exercise-menu/ExerciseMenuDropdown.js +10 -2
- package/es/components/material-exercise/exercise-runner/ExerciseRunner.js +5 -1
- package/es/components/shared/monaco-editor/MonacoEditor.js +11 -11
- package/es/components/shared/monaco-editor/editor-hooks/useMonacoMarkers.js +3 -3
- package/es/components/shared/monaco-editor/editor-languages/css/index.d.ts +4 -0
- package/es/components/shared/monaco-editor/editor-languages/css/index.js +12 -1
- package/es/components/shared/monaco-editor/editor-languages/html/index.d.ts +4 -0
- package/es/components/shared/monaco-editor/editor-languages/html/index.js +10 -1
- package/es/components/shared/monaco-editor/editor-languages/index.js +2 -2
- package/es/components/shared/monaco-editor/editor-languages/typescript/index.d.ts +4 -0
- package/es/components/shared/monaco-editor/editor-languages/typescript/index.js +10 -1
- package/es/components/shared/monaco-editor/utils/emmet/emmet.d.ts +13 -0
- package/es/components/shared/monaco-editor/utils/emmet/emmet.js +25 -0
- package/es/components/shared/monaco-editor/utils/emmet/index.d.ts +1 -0
- package/es/components/shared/monaco-editor/utils/emmet/registerProvider.d.ts +5 -0
- package/es/components/shared/monaco-editor/utils/emmet/registerProvider.js +22 -0
- package/es/components/shared/monaco-editor/utils/grammar/index.js +2 -2
- package/es/components/shared/monaco-editor/utils/prettier/index.js +6 -2
- package/es/components/shared/monaco-editor/vendors/vscode-emmet-helper/configCompat.d.ts +15 -0
- package/es/components/shared/monaco-editor/vendors/vscode-emmet-helper/configCompat.js +11 -0
- package/es/components/shared/monaco-editor/vendors/vscode-emmet-helper/data.d.ts +6 -0
- package/es/components/shared/monaco-editor/vendors/vscode-emmet-helper/data.js +17 -0
- package/es/components/shared/monaco-editor/vendors/vscode-emmet-helper/emmetHelper.d.ts +96 -0
- package/es/components/shared/monaco-editor/vendors/vscode-emmet-helper/emmetHelper.js +883 -0
- package/es/components/shared/monaco-editor/vendors/vscode-emmet-helper/index.d.ts +2 -0
- package/es/components/shared/monaco-editor/vendors/vscode-emmet-helper/utils.d.ts +12 -0
- package/es/components/shared/monaco-editor/vendors/vscode-emmet-helper/utils.js +36 -0
- package/es/components/shared/web-browser/WebBrowser.js +16 -11
- package/es/components/shared/xterm/Xterm.js +10 -3
- package/package.json +7 -6
- /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/OnDisposed.d.ts +0 -0
- /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursor.d.ts +0 -0
- /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursor.js +0 -0
- /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursorManager.d.ts +0 -0
- /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursorManager.js +0 -0
- /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursorWidget.d.ts +0 -0
- /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursorWidget.js +0 -0
- /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteSelection.d.ts +0 -0
- /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteSelection.js +0 -0
- /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteSelectionManager.d.ts +0 -0
- /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteSelectionManager.js +0 -0
- /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/index.d.ts +0 -0
- /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/styles.d.ts +0 -0
- /package/cjs/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/styles.js +0 -0
- /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/OnDisposed.d.ts +0 -0
- /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursor.d.ts +0 -0
- /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursor.js +0 -0
- /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursorManager.d.ts +0 -0
- /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursorManager.js +0 -0
- /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursorWidget.d.ts +0 -0
- /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteCursorWidget.js +0 -0
- /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteSelection.d.ts +0 -0
- /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteSelection.js +0 -0
- /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteSelectionManager.d.ts +0 -0
- /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/RemoteSelectionManager.js +0 -0
- /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/index.d.ts +0 -0
- /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/styles.d.ts +0 -0
- /package/es/components/shared/monaco-editor/{utils/remoteMarker → vendors/monaco-collab-ext}/styles.js +0 -0
|
@@ -0,0 +1,883 @@
|
|
|
1
|
+
import expand, { resolveConfig, extract } from 'emmet';
|
|
2
|
+
import { cssData, htmlData } from './data.js';
|
|
3
|
+
import { syntaxes } from './configCompat.js';
|
|
4
|
+
|
|
5
|
+
/* ====================================================================================================
|
|
6
|
+
* These codes forked and modified from `microsoft/vscode-emmet-helper`
|
|
7
|
+
* under the terms of the MIT license.
|
|
8
|
+
* Make sure to check the original project if any issue exists.
|
|
9
|
+
* - project: https://github.com/microsoft/vscode-emmet-helper
|
|
10
|
+
* - codes: https://github.com/microsoft/vscode-emmet-helper/blob/e64481648451f0189216794979ce2ace82ee8148/src/emmetHelper.ts
|
|
11
|
+
* ==================================================================================================== */
|
|
12
|
+
// @emmetio/extract-abbreviation has a cjs that uses a default export
|
|
13
|
+
// */
|
|
14
|
+
// const extract = typeof _extractAbbreviation === 'function' ? _extractAbbreviation : _extractAbbreviation.default;
|
|
15
|
+
|
|
16
|
+
const snippetKeyCache = new Map();
|
|
17
|
+
let markupSnippetKeys;
|
|
18
|
+
const stylesheetCustomSnippetsKeyCache = new Map();
|
|
19
|
+
const htmlAbbreviationStartRegex = /^[a-z,A-Z,!,(,[,#,\.\{]/; // take off { for jsx because it interferes with the language
|
|
20
|
+
|
|
21
|
+
const jsxAbbreviationStartRegex = /^[a-z,A-Z,!,(,[,#,\.]/;
|
|
22
|
+
const cssAbbreviationRegex = /^-?[a-z,A-Z,!,@,#]/;
|
|
23
|
+
const htmlAbbreviationRegex = /[a-z,A-Z\.]/;
|
|
24
|
+
const commonlyUsedTags = [...htmlData.tags, 'lorem'];
|
|
25
|
+
const bemFilterSuffix = 'bem';
|
|
26
|
+
const filterDelimitor = '|';
|
|
27
|
+
const trimFilterSuffix = 't';
|
|
28
|
+
const commentFilterSuffix = 'c';
|
|
29
|
+
const maxFilters = 3;
|
|
30
|
+
/**
|
|
31
|
+
* Returns all applicable emmet expansions for abbreviation at given position in a CompletionList
|
|
32
|
+
* @param document TextDocument in which completions are requested
|
|
33
|
+
* @param position Position in the document at which completions are requested
|
|
34
|
+
* @param syntax Emmet supported language
|
|
35
|
+
* @param emmetConfig Emmet Configurations as derived from VS Code
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
function doComplete(monaco, model, position, syntax, emmetConfig) {
|
|
39
|
+
var _a, _b;
|
|
40
|
+
|
|
41
|
+
if (emmetConfig.showExpandedAbbreviation === 'never' || !getEmmetMode(syntax, emmetConfig.excludeLanguages)) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const isStyleSheetRes = isStyleSheet(syntax); // Fetch markupSnippets so that we can provide possible abbreviation completions
|
|
46
|
+
// For example, when text at position is `a`, completions should return `a:blank`, `a:link`, `acr` etc.
|
|
47
|
+
|
|
48
|
+
if (!isStyleSheetRes) {
|
|
49
|
+
if (!snippetKeyCache.has(syntax)) {
|
|
50
|
+
const registry = (_a = customSnippetsRegistry[syntax]) !== null && _a !== void 0 ? _a : getDefaultSnippets(syntax);
|
|
51
|
+
snippetKeyCache.set(syntax, Object.keys(registry));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
markupSnippetKeys = (_b = snippetKeyCache.get(syntax)) !== null && _b !== void 0 ? _b : [];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const extractOptions = {
|
|
58
|
+
lookAhead: !isStyleSheetRes,
|
|
59
|
+
type: isStyleSheetRes ? 'stylesheet' : 'markup'
|
|
60
|
+
};
|
|
61
|
+
const extractedValue = extractAbbreviation(monaco, model, position, extractOptions);
|
|
62
|
+
|
|
63
|
+
if (!extractedValue) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const {
|
|
68
|
+
abbreviationRange,
|
|
69
|
+
abbreviation,
|
|
70
|
+
filter
|
|
71
|
+
} = extractedValue;
|
|
72
|
+
const currentLineTillPosition = getCurrentLine(model, position).substr(0, position.column - 1);
|
|
73
|
+
const currentWord = getCurrentWord(currentLineTillPosition); // Don't attempt to expand open tags
|
|
74
|
+
|
|
75
|
+
if (currentWord === abbreviation && currentLineTillPosition.endsWith(`<${abbreviation}`) && syntaxes.markup.includes(syntax)) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const expandOptions = getExpandOptions(syntax, emmetConfig, filter);
|
|
80
|
+
let expandedText = "";
|
|
81
|
+
let expandedAbbr;
|
|
82
|
+
let completionItems = []; // Create completion item after expanding given abbreviation
|
|
83
|
+
// if abbreviation is valid and expanded value is not noise
|
|
84
|
+
|
|
85
|
+
const createExpandedAbbr = (syntax, abbr) => {
|
|
86
|
+
if (!isAbbreviationValid(syntax, abbreviation)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
expandedText = expand(abbr, expandOptions); // manually patch https://github.com/microsoft/vscode/issues/120245 for now
|
|
92
|
+
|
|
93
|
+
if (isStyleSheetRes && '!important'.startsWith(abbr)) {
|
|
94
|
+
expandedText = '!important';
|
|
95
|
+
}
|
|
96
|
+
} catch (e) {}
|
|
97
|
+
|
|
98
|
+
if (!expandedText || isExpandedTextNoise(syntax, abbr, expandedText, expandOptions.options)) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
expandedAbbr = {
|
|
103
|
+
kind: monaco.languages.CompletionItemKind.Property,
|
|
104
|
+
label: abbreviation + (filter ? '|' + filter.replace(',', '|') : ''),
|
|
105
|
+
documentation: replaceTabStopsWithCursors(expandedText),
|
|
106
|
+
detail: 'Emmet abbreviation',
|
|
107
|
+
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
108
|
+
range: abbreviationRange,
|
|
109
|
+
insertText: escapeNonTabStopDollar(addFinalTabStop(expandedText))
|
|
110
|
+
};
|
|
111
|
+
completionItems = [expandedAbbr];
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
if (isStyleSheet(syntax)) {
|
|
115
|
+
createExpandedAbbr(syntax, abbreviation); // When abbr is longer than usual emmet snippets and matches better with existing css property, then no emmet
|
|
116
|
+
|
|
117
|
+
if (abbreviation.length > 4 && cssData.properties.find(x => x.startsWith(abbreviation))) {
|
|
118
|
+
return {
|
|
119
|
+
suggestions: [],
|
|
120
|
+
incomplete: true
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (expandedAbbr && expandedText.length) {
|
|
125
|
+
expandedAbbr.range = abbreviationRange;
|
|
126
|
+
expandedAbbr.insertText = escapeNonTabStopDollar(addFinalTabStop(expandedText));
|
|
127
|
+
expandedAbbr.documentation = replaceTabStopsWithCursors(expandedText);
|
|
128
|
+
expandedAbbr.label = removeTabStops(expandedText);
|
|
129
|
+
expandedAbbr.filterText = abbreviation; // Custom snippets should show up in completions if abbreviation is a prefix
|
|
130
|
+
|
|
131
|
+
const stylesheetCustomSnippetsKeys = stylesheetCustomSnippetsKeyCache.has(syntax) ? stylesheetCustomSnippetsKeyCache.get(syntax) : stylesheetCustomSnippetsKeyCache.get('css');
|
|
132
|
+
completionItems = makeSnippetSuggestion(monaco, stylesheetCustomSnippetsKeys !== null && stylesheetCustomSnippetsKeys !== void 0 ? stylesheetCustomSnippetsKeys : [], abbreviation, abbreviation, abbreviationRange, expandOptions, 'Emmet Custom Snippet', false);
|
|
133
|
+
|
|
134
|
+
if (!completionItems.find(x => x.insertText === (expandedAbbr === null || expandedAbbr === void 0 ? void 0 : expandedAbbr.insertText))) {
|
|
135
|
+
// Fix for https://github.com/Microsoft/vscode/issues/28933#issuecomment-309236902
|
|
136
|
+
// When user types in propertyname, emmet uses it to match with snippet names, resulting in width -> widows or font-family -> font: family
|
|
137
|
+
// Filter out those cases here.
|
|
138
|
+
const abbrRegex = new RegExp('.*' + abbreviation.split('').map(x => x === '$' || x === '+' ? '\\' + x : x).join('.*') + '.*', 'i');
|
|
139
|
+
|
|
140
|
+
if (/\d/.test(abbreviation) || abbrRegex.test(expandedAbbr.label)) {
|
|
141
|
+
completionItems.push(expandedAbbr);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
createExpandedAbbr(syntax, abbreviation);
|
|
147
|
+
let tagToFindMoreSuggestionsFor = abbreviation;
|
|
148
|
+
const newTagMatches = /(>|\+)([\w:-]+)$/.exec(abbreviation);
|
|
149
|
+
|
|
150
|
+
if (newTagMatches && newTagMatches.length === 3) {
|
|
151
|
+
tagToFindMoreSuggestionsFor = newTagMatches[2];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (syntax !== 'xml') {
|
|
155
|
+
const commonlyUsedTagSuggestions = makeSnippetSuggestion(monaco, commonlyUsedTags, tagToFindMoreSuggestionsFor, abbreviation, abbreviationRange, expandOptions, 'Emmet Abbreviation');
|
|
156
|
+
completionItems = completionItems.concat(commonlyUsedTagSuggestions);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (emmetConfig.showAbbreviationSuggestions === true) {
|
|
160
|
+
const abbreviationSuggestions = makeSnippetSuggestion(monaco, markupSnippetKeys.filter(x => !commonlyUsedTags.includes(x)), tagToFindMoreSuggestionsFor, abbreviation, abbreviationRange, expandOptions, 'Emmet Abbreviation'); // Workaround for the main expanded abbr not appearing before the snippet suggestions
|
|
161
|
+
|
|
162
|
+
if (expandedAbbr && abbreviationSuggestions.length > 0 && tagToFindMoreSuggestionsFor !== abbreviation) {
|
|
163
|
+
expandedAbbr.sortText = '0' + expandedAbbr.label;
|
|
164
|
+
abbreviationSuggestions.forEach(item => {
|
|
165
|
+
// Workaround for snippet suggestions items getting filtered out as the complete abbr does not start with snippetKey
|
|
166
|
+
item.filterText = abbreviation; // Workaround for the main expanded abbr not appearing before the snippet suggestions
|
|
167
|
+
|
|
168
|
+
item.sortText = '9' + abbreviation;
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
completionItems = completionItems.concat(abbreviationSuggestions);
|
|
173
|
+
} // https://github.com/microsoft/vscode/issues/66680
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
if (syntax === 'html' && completionItems.length >= 2 && abbreviation.includes(":") && (expandedAbbr === null || expandedAbbr === void 0 ? void 0 : expandedAbbr.insertText) === `<${abbreviation}>\${0}</${abbreviation}>`) {
|
|
177
|
+
completionItems = completionItems.filter(item => item.label !== abbreviation);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (emmetConfig.showSuggestionsAsSnippets === true) {
|
|
182
|
+
completionItems.forEach(x => x.kind = monaco.languages.CompletionItemKind.Snippet);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return completionItems.length ? {
|
|
186
|
+
suggestions: completionItems,
|
|
187
|
+
incomplete: true
|
|
188
|
+
} : undefined;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Create & return snippets for snippet keys that start with given prefix
|
|
192
|
+
*/
|
|
193
|
+
|
|
194
|
+
function makeSnippetSuggestion(monaco, snippetKeys, prefix, abbreviation, abbreviationRange, expandOptions, snippetDetail, skipFullMatch = true) {
|
|
195
|
+
if (!prefix || !snippetKeys) {
|
|
196
|
+
return [];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const snippetCompletions = [];
|
|
200
|
+
snippetKeys.forEach(snippetKey => {
|
|
201
|
+
if (!snippetKey.startsWith(prefix.toLowerCase()) || skipFullMatch && snippetKey === prefix.toLowerCase()) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const currentAbbr = abbreviation + snippetKey.substr(prefix.length);
|
|
206
|
+
let expandedAbbr;
|
|
207
|
+
|
|
208
|
+
try {
|
|
209
|
+
expandedAbbr = expand(currentAbbr, expandOptions);
|
|
210
|
+
} catch (e) {}
|
|
211
|
+
|
|
212
|
+
if (!expandedAbbr) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const item = {
|
|
217
|
+
kind: monaco.languages.CompletionItemKind.Property,
|
|
218
|
+
label: prefix + snippetKey.substr(prefix.length),
|
|
219
|
+
documentation: replaceTabStopsWithCursors(expandedAbbr),
|
|
220
|
+
detail: snippetDetail,
|
|
221
|
+
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
222
|
+
range: abbreviationRange,
|
|
223
|
+
insertText: escapeNonTabStopDollar(addFinalTabStop(expandedAbbr))
|
|
224
|
+
};
|
|
225
|
+
snippetCompletions.push(item);
|
|
226
|
+
});
|
|
227
|
+
return snippetCompletions;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function getCurrentWord(currentLineTillPosition) {
|
|
231
|
+
if (currentLineTillPosition) {
|
|
232
|
+
const matches = /[\w,:,-,\.]*$/.exec(currentLineTillPosition);
|
|
233
|
+
|
|
234
|
+
if (matches) {
|
|
235
|
+
return matches[0];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function replaceTabStopsWithCursors(expandedWord) {
|
|
241
|
+
return expandedWord.replace(/([^\\])\$\{\d+\}/g, '$1|').replace(/\$\{\d+:([^\}]+)\}/g, '$1');
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function removeTabStops(expandedWord) {
|
|
245
|
+
return expandedWord.replace(/([^\\])\$\{\d+\}/g, '$1').replace(/\$\{\d+:([^\}]+)\}/g, '$1');
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function escapeNonTabStopDollar(text) {
|
|
249
|
+
return text ? text.replace(/([^\\])(\$)([^\{])/g, '$1\\$2$3') : text;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function addFinalTabStop(text) {
|
|
253
|
+
if (!text || !text.trim()) {
|
|
254
|
+
return text;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
let maxTabStop = -1;
|
|
258
|
+
let maxTabStopRanges = [];
|
|
259
|
+
let foundLastStop = false;
|
|
260
|
+
let replaceWithLastStop = false;
|
|
261
|
+
let i = 0;
|
|
262
|
+
const n = text.length;
|
|
263
|
+
|
|
264
|
+
try {
|
|
265
|
+
while (i < n && !foundLastStop) {
|
|
266
|
+
// Look for ${
|
|
267
|
+
if (text[i++] != '$' || text[i++] != '{') {
|
|
268
|
+
continue;
|
|
269
|
+
} // Find tabstop
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
let numberStart = -1;
|
|
273
|
+
let numberEnd = -1;
|
|
274
|
+
|
|
275
|
+
while (i < n && /\d/.test(text[i])) {
|
|
276
|
+
numberStart = numberStart < 0 ? i : numberStart;
|
|
277
|
+
numberEnd = i + 1;
|
|
278
|
+
i++;
|
|
279
|
+
} // If ${ was not followed by a number and either } or :, then its not a tabstop
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
if (numberStart === -1 || numberEnd === -1 || i >= n || text[i] != '}' && text[i] != ':') {
|
|
283
|
+
continue;
|
|
284
|
+
} // If ${0} was found, then break
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
const currentTabStop = text.substring(numberStart, numberEnd);
|
|
288
|
+
foundLastStop = currentTabStop === '0';
|
|
289
|
+
|
|
290
|
+
if (foundLastStop) {
|
|
291
|
+
break;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
let foundPlaceholder = false;
|
|
295
|
+
|
|
296
|
+
if (text[i++] == ':') {
|
|
297
|
+
// TODO: Nested placeholders may break here
|
|
298
|
+
while (i < n) {
|
|
299
|
+
if (text[i] == '}') {
|
|
300
|
+
foundPlaceholder = true;
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
i++;
|
|
305
|
+
}
|
|
306
|
+
} // Decide to replace currentTabStop with ${0} only if its the max among all tabstops and is not a placeholder
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
if (Number(currentTabStop) > Number(maxTabStop)) {
|
|
310
|
+
maxTabStop = Number(currentTabStop);
|
|
311
|
+
maxTabStopRanges = [{
|
|
312
|
+
numberStart,
|
|
313
|
+
numberEnd
|
|
314
|
+
}];
|
|
315
|
+
replaceWithLastStop = !foundPlaceholder;
|
|
316
|
+
} else if (Number(currentTabStop) === maxTabStop) {
|
|
317
|
+
maxTabStopRanges.push({
|
|
318
|
+
numberStart,
|
|
319
|
+
numberEnd
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
} catch (e) {}
|
|
324
|
+
|
|
325
|
+
if (replaceWithLastStop && !foundLastStop) {
|
|
326
|
+
for (let i = 0; i < maxTabStopRanges.length; i++) {
|
|
327
|
+
const rangeStart = maxTabStopRanges[i].numberStart;
|
|
328
|
+
const rangeEnd = maxTabStopRanges[i].numberEnd;
|
|
329
|
+
text = text.substr(0, rangeStart) + '0' + text.substr(rangeEnd);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return text;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function getCurrentLine(model, position) {
|
|
337
|
+
const currentLine = model.getLineContent(position.lineNumber);
|
|
338
|
+
return currentLine;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
let customSnippetsRegistry = {};
|
|
342
|
+
let variablesFromFile = {};
|
|
343
|
+
let profilesFromFile = {};
|
|
344
|
+
const emmetSnippetField = (index, placeholder) => `\${${index}${placeholder ? ':' + placeholder : ''}}`;
|
|
345
|
+
/** Returns whether or not syntax is a supported stylesheet syntax, like CSS */
|
|
346
|
+
|
|
347
|
+
function isStyleSheet(syntax) {
|
|
348
|
+
return syntaxes.stylesheet.includes(syntax);
|
|
349
|
+
}
|
|
350
|
+
/** Returns the syntax type, either markup (e.g. for HTML) or stylesheet (e.g. for CSS) */
|
|
351
|
+
|
|
352
|
+
function getSyntaxType(syntax) {
|
|
353
|
+
return isStyleSheet(syntax) ? 'stylesheet' : 'markup';
|
|
354
|
+
}
|
|
355
|
+
/** Returns the default syntax (html or css) to use for the snippets registry */
|
|
356
|
+
|
|
357
|
+
function getDefaultSyntax(syntax) {
|
|
358
|
+
return isStyleSheet(syntax) ? 'css' : 'html';
|
|
359
|
+
}
|
|
360
|
+
/** Returns the default snippets that Emmet suggests */
|
|
361
|
+
|
|
362
|
+
function getDefaultSnippets(syntax) {
|
|
363
|
+
const syntaxType = getSyntaxType(syntax);
|
|
364
|
+
const emptyUserConfig = {
|
|
365
|
+
type: syntaxType,
|
|
366
|
+
syntax
|
|
367
|
+
};
|
|
368
|
+
const resolvedConfig = resolveConfig(emptyUserConfig); // https://github.com/microsoft/vscode/issues/97632
|
|
369
|
+
// don't return markup (HTML) snippets for XML
|
|
370
|
+
|
|
371
|
+
return syntax === 'xml' ? {} : resolvedConfig.snippets;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function getFilters(text, pos) {
|
|
375
|
+
let filter;
|
|
376
|
+
|
|
377
|
+
for (let i = 0; i < maxFilters; i++) {
|
|
378
|
+
if (text.endsWith(`${filterDelimitor}${bemFilterSuffix}`, pos)) {
|
|
379
|
+
pos -= bemFilterSuffix.length + 1;
|
|
380
|
+
filter = filter ? bemFilterSuffix + ',' + filter : bemFilterSuffix;
|
|
381
|
+
} else if (text.endsWith(`${filterDelimitor}${commentFilterSuffix}`, pos)) {
|
|
382
|
+
pos -= commentFilterSuffix.length + 1;
|
|
383
|
+
filter = filter ? commentFilterSuffix + ',' + filter : commentFilterSuffix;
|
|
384
|
+
} else if (text.endsWith(`${filterDelimitor}${trimFilterSuffix}`, pos)) {
|
|
385
|
+
pos -= trimFilterSuffix.length + 1;
|
|
386
|
+
filter = filter ? trimFilterSuffix + ',' + filter : trimFilterSuffix;
|
|
387
|
+
} else {
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return {
|
|
393
|
+
pos: pos,
|
|
394
|
+
filter: filter
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Extracts abbreviation from the given position in the given document
|
|
399
|
+
*/
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
function extractAbbreviation(monaco, model, position, options) {
|
|
403
|
+
const currentLine = model.getLineContent(position.lineNumber);
|
|
404
|
+
const currentLineTillPosition = currentLine.substr(0, position.column - 1);
|
|
405
|
+
const {
|
|
406
|
+
pos,
|
|
407
|
+
filter
|
|
408
|
+
} = getFilters(currentLineTillPosition, position.column - 1);
|
|
409
|
+
const lengthOccupiedByFilter = filter ? filter.length + 1 : 0;
|
|
410
|
+
const result = extract(currentLine, pos, options);
|
|
411
|
+
|
|
412
|
+
if (!result) {
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const rangeToReplace = new monaco.Range(position.lineNumber, result.location + 1, position.lineNumber, result.location + result.abbreviation.length + lengthOccupiedByFilter + 1);
|
|
417
|
+
return {
|
|
418
|
+
abbreviationRange: rangeToReplace,
|
|
419
|
+
abbreviation: result.abbreviation,
|
|
420
|
+
filter
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Returns a boolean denoting validity of given abbreviation in the context of given syntax
|
|
425
|
+
* Not needed once https://github.com/emmetio/atom-plugin/issues/22 is fixed
|
|
426
|
+
* @param syntax string
|
|
427
|
+
* @param abbreviation string
|
|
428
|
+
*/
|
|
429
|
+
|
|
430
|
+
function isAbbreviationValid(syntax, abbreviation) {
|
|
431
|
+
if (!abbreviation) {
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (isStyleSheet(syntax)) {
|
|
436
|
+
if (abbreviation.includes('#')) {
|
|
437
|
+
if (abbreviation.startsWith('#')) {
|
|
438
|
+
const hexColorRegex = /^#[\d,a-f,A-F]{1,6}$/;
|
|
439
|
+
return hexColorRegex.test(abbreviation);
|
|
440
|
+
} else if (commonlyUsedTags.includes(abbreviation.substring(0, abbreviation.indexOf('#')))) {
|
|
441
|
+
return false;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return cssAbbreviationRegex.test(abbreviation);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
if (abbreviation.startsWith('!')) {
|
|
449
|
+
return !/[^!]/.test(abbreviation);
|
|
450
|
+
} // Its common for users to type (sometextinsidebrackets), this should not be treated as an abbreviation
|
|
451
|
+
// Grouping in abbreviation is valid only if it's inside a text node or preceeded/succeeded with one of the symbols for nesting, sibling, repeater or climb up
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
if ((/\(/.test(abbreviation) || /\)/.test(abbreviation)) && !/\{[^\}\{]*[\(\)]+[^\}\{]*\}(?:[>\+\*\^]|$)/.test(abbreviation) && !/\(.*\)[>\+\*\^]/.test(abbreviation) && !/[>\+\*\^]\(.*\)/.test(abbreviation)) {
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
if (syntax === 'jsx') {
|
|
459
|
+
return jsxAbbreviationStartRegex.test(abbreviation) && htmlAbbreviationRegex.test(abbreviation);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
return htmlAbbreviationStartRegex.test(abbreviation) && htmlAbbreviationRegex.test(abbreviation);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function isExpandedTextNoise(syntax, abbreviation, expandedText, options) {
|
|
466
|
+
var _a, _b; // Unresolved css abbreviations get expanded to a blank property value
|
|
467
|
+
// Eg: abc -> abc: ; or abc:d -> abc: d; which is noise if it gets suggested for every word typed
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
if (isStyleSheet(syntax) && options) {
|
|
471
|
+
const between = (_a = options['stylesheet.between']) !== null && _a !== void 0 ? _a : ': ';
|
|
472
|
+
const after = (_b = options['stylesheet.after']) !== null && _b !== void 0 ? _b : ';'; // Remove overlapping between `abbreviation` and `between`, if any
|
|
473
|
+
|
|
474
|
+
let endPrefixIndex = abbreviation.indexOf(between[0], Math.max(abbreviation.length - between.length, 0));
|
|
475
|
+
endPrefixIndex = endPrefixIndex >= 0 ? endPrefixIndex : abbreviation.length;
|
|
476
|
+
const abbr = abbreviation.substring(0, endPrefixIndex);
|
|
477
|
+
return expandedText === `${abbr}${between}\${0}${after}` || expandedText.replace(/\s/g, '') === abbreviation.replace(/\s/g, '') + after;
|
|
478
|
+
} // we don't want common html tags suggested for xml
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
if (syntax === 'xml' && commonlyUsedTags.some(tag => tag.startsWith(abbreviation.toLowerCase()))) {
|
|
482
|
+
return true;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (commonlyUsedTags.includes(abbreviation.toLowerCase()) || markupSnippetKeys.includes(abbreviation)) {
|
|
486
|
+
return false;
|
|
487
|
+
} // Custom tags can have - or :
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
if (/[-,:]/.test(abbreviation) && !/--|::/.test(abbreviation) && !abbreviation.endsWith(':')) {
|
|
491
|
+
return false;
|
|
492
|
+
} // Its common for users to type some text and end it with period, this should not be treated as an abbreviation
|
|
493
|
+
// Else it becomes noise.
|
|
494
|
+
// When user just types '.', return the expansion
|
|
495
|
+
// Otherwise emmet loses change to participate later
|
|
496
|
+
// For example in `.foo`. See https://github.com/Microsoft/vscode/issues/66013
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
if (abbreviation === '.') {
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const dotMatches = /^([a-z,A-Z,\d]*)\.$/.exec(abbreviation);
|
|
504
|
+
|
|
505
|
+
if (dotMatches) {
|
|
506
|
+
// Valid html tags such as `div.`
|
|
507
|
+
if (dotMatches[1] && htmlData.tags.includes(dotMatches[1])) {
|
|
508
|
+
return false;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
return true;
|
|
512
|
+
} // Fix for https://github.com/microsoft/vscode/issues/89746
|
|
513
|
+
// PascalCase tags are common in jsx code, which should not be treated as noise.
|
|
514
|
+
// Eg: MyAwesomComponent -> <MyAwesomComponent></MyAwesomComponent>
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
if (syntax === 'jsx' && /^([A-Z][A-Za-z0-9]*)+$/.test(abbreviation)) {
|
|
518
|
+
return false;
|
|
519
|
+
} // Unresolved html abbreviations get expanded as if it were a tag
|
|
520
|
+
// Eg: abc -> <abc></abc> which is noise if it gets suggested for every word typed
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
return expandedText.toLowerCase() === `<${abbreviation.toLowerCase()}>\${1}</${abbreviation.toLowerCase()}>`;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Returns options to be used by emmet
|
|
527
|
+
*/
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
function getExpandOptions(syntax, emmetConfig, filter) {
|
|
531
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
532
|
+
|
|
533
|
+
emmetConfig = emmetConfig !== null && emmetConfig !== void 0 ? emmetConfig : {};
|
|
534
|
+
emmetConfig['preferences'] = (_a = emmetConfig['preferences']) !== null && _a !== void 0 ? _a : {};
|
|
535
|
+
const preferences = emmetConfig['preferences'];
|
|
536
|
+
const stylesheetSyntax = isStyleSheet(syntax) ? syntax : 'css'; // Fetch Profile
|
|
537
|
+
|
|
538
|
+
const profile = getProfile(syntax, (_b = emmetConfig['syntaxProfiles']) !== null && _b !== void 0 ? _b : {});
|
|
539
|
+
const filtersFromProfile = profile && profile['filters'] ? profile['filters'].split(',') : [];
|
|
540
|
+
const trimmedFilters = filtersFromProfile.map(filterFromProfile => filterFromProfile.trim());
|
|
541
|
+
const bemEnabled = filter && filter.split(',').some(x => x.trim() === 'bem') || trimmedFilters.includes('bem');
|
|
542
|
+
const commentEnabled = filter && filter.split(',').some(x => x.trim() === 'c') || trimmedFilters.includes('c'); // Fetch formatters
|
|
543
|
+
|
|
544
|
+
const formatters = getFormatters(syntax, emmetConfig['preferences']);
|
|
545
|
+
const unitAliases = (formatters === null || formatters === void 0 ? void 0 : formatters.stylesheet) && formatters.stylesheet['unitAliases'] || {}; // These options are the default values provided by vscode for
|
|
546
|
+
// extension preferences
|
|
547
|
+
|
|
548
|
+
const defaultVSCodeOptions = {
|
|
549
|
+
// inlineElements: string[],
|
|
550
|
+
// 'output.indent': string,
|
|
551
|
+
// 'output.baseIndent': string,
|
|
552
|
+
// 'output.newline': string,
|
|
553
|
+
// 'output.tagCase': profile['tagCase'],
|
|
554
|
+
// 'output.attributeCase': profile['attributeCase'],
|
|
555
|
+
// 'output.attributeQuotes': profile['attributeQuotes'],
|
|
556
|
+
// 'output.format': profile['format'] ?? true,
|
|
557
|
+
// 'output.formatLeafNode': boolean,
|
|
558
|
+
'output.formatSkip': ['html'],
|
|
559
|
+
'output.formatForce': ['body'],
|
|
560
|
+
'output.inlineBreak': 0,
|
|
561
|
+
'output.compactBoolean': false,
|
|
562
|
+
// 'output.booleanAttributes': string[],
|
|
563
|
+
'output.reverseAttributes': false,
|
|
564
|
+
// 'output.selfClosingStyle': profile['selfClosingStyle'],
|
|
565
|
+
'output.field': emmetSnippetField,
|
|
566
|
+
// 'output.text': TextOutput,
|
|
567
|
+
'markup.href': true,
|
|
568
|
+
'comment.enabled': false,
|
|
569
|
+
'comment.trigger': ['id', 'class'],
|
|
570
|
+
'comment.before': '',
|
|
571
|
+
'comment.after': '\n<!-- /[#ID][.CLASS] -->',
|
|
572
|
+
'bem.enabled': false,
|
|
573
|
+
'bem.element': '__',
|
|
574
|
+
'bem.modifier': '_',
|
|
575
|
+
'jsx.enabled': syntax === 'jsx',
|
|
576
|
+
// 'stylesheet.keywords': string[],
|
|
577
|
+
// 'stylesheet.unitless': string[],
|
|
578
|
+
'stylesheet.shortHex': true,
|
|
579
|
+
'stylesheet.between': syntax === 'stylus' ? ' ' : ': ',
|
|
580
|
+
'stylesheet.after': syntax === 'sass' || syntax === 'stylus' ? '' : ';',
|
|
581
|
+
'stylesheet.intUnit': 'px',
|
|
582
|
+
'stylesheet.floatUnit': 'em',
|
|
583
|
+
'stylesheet.unitAliases': {
|
|
584
|
+
e: 'em',
|
|
585
|
+
p: '%',
|
|
586
|
+
x: 'ex',
|
|
587
|
+
r: 'rem'
|
|
588
|
+
},
|
|
589
|
+
// 'stylesheet.json': boolean,
|
|
590
|
+
// 'stylesheet.jsonDoubleQuotes': boolean,
|
|
591
|
+
'stylesheet.fuzzySearchMinScore': 0.3
|
|
592
|
+
}; // These options come from user prefs in the vscode repo
|
|
593
|
+
|
|
594
|
+
const userPreferenceOptions = {
|
|
595
|
+
// inlineElements: string[],
|
|
596
|
+
// 'output.indent': string,
|
|
597
|
+
// 'output.baseIndent': string,
|
|
598
|
+
// 'output.newline': string,
|
|
599
|
+
'output.tagCase': profile['tagCase'],
|
|
600
|
+
'output.attributeCase': profile['attributeCase'],
|
|
601
|
+
'output.attributeQuotes': profile['attributeQuotes'],
|
|
602
|
+
'output.format': (_c = profile['format']) !== null && _c !== void 0 ? _c : true,
|
|
603
|
+
// 'output.formatLeafNode': boolean,
|
|
604
|
+
'output.formatSkip': preferences['format.noIndentTags'],
|
|
605
|
+
'output.formatForce': preferences['format.forceIndentationForTags'],
|
|
606
|
+
'output.inlineBreak': (_d = profile['inlineBreak']) !== null && _d !== void 0 ? _d : preferences['output.inlineBreak'],
|
|
607
|
+
'output.compactBoolean': (_e = profile['compactBooleanAttributes']) !== null && _e !== void 0 ? _e : preferences['profile.allowCompactBoolean'],
|
|
608
|
+
// 'output.booleanAttributes': string[],
|
|
609
|
+
'output.reverseAttributes': preferences['output.reverseAttributes'],
|
|
610
|
+
'output.selfClosingStyle': (_g = (_f = profile['selfClosingStyle']) !== null && _f !== void 0 ? _f : preferences['output.selfClosingStyle']) !== null && _g !== void 0 ? _g : getClosingStyle(syntax),
|
|
611
|
+
'output.field': emmetSnippetField,
|
|
612
|
+
// 'output.text': TextOutput,
|
|
613
|
+
// 'markup.href': boolean,
|
|
614
|
+
'comment.enabled': commentEnabled,
|
|
615
|
+
'comment.trigger': preferences['filter.commentTrigger'],
|
|
616
|
+
'comment.before': preferences['filter.commentBefore'],
|
|
617
|
+
'comment.after': preferences['filter.commentAfter'],
|
|
618
|
+
'bem.enabled': bemEnabled,
|
|
619
|
+
'bem.element': (_h = preferences['bem.elementSeparator']) !== null && _h !== void 0 ? _h : '__',
|
|
620
|
+
'bem.modifier': (_j = preferences['bem.modifierSeparator']) !== null && _j !== void 0 ? _j : '_',
|
|
621
|
+
'jsx.enabled': syntax === 'jsx',
|
|
622
|
+
// 'stylesheet.keywords': string[],
|
|
623
|
+
// 'stylesheet.unitless': string[],
|
|
624
|
+
'stylesheet.shortHex': preferences['css.color.short'],
|
|
625
|
+
'stylesheet.between': preferences[`${stylesheetSyntax}.valueSeparator`],
|
|
626
|
+
'stylesheet.after': preferences[`${stylesheetSyntax}.propertyEnd`],
|
|
627
|
+
'stylesheet.intUnit': preferences['css.intUnit'],
|
|
628
|
+
'stylesheet.floatUnit': preferences['css.floatUnit'],
|
|
629
|
+
'stylesheet.unitAliases': unitAliases,
|
|
630
|
+
// 'stylesheet.json': boolean,
|
|
631
|
+
// 'stylesheet.jsonDoubleQuotes': boolean,
|
|
632
|
+
'stylesheet.fuzzySearchMinScore': preferences['css.fuzzySearchMinScore']
|
|
633
|
+
};
|
|
634
|
+
const combinedOptions = {};
|
|
635
|
+
[...Object.keys(defaultVSCodeOptions), ...Object.keys(userPreferenceOptions)].forEach(key => {
|
|
636
|
+
var _a;
|
|
637
|
+
|
|
638
|
+
const castKey = key;
|
|
639
|
+
combinedOptions[castKey] = (_a = userPreferenceOptions[castKey]) !== null && _a !== void 0 ? _a : defaultVSCodeOptions[castKey];
|
|
640
|
+
});
|
|
641
|
+
const mergedAliases = Object.assign(Object.assign({}, defaultVSCodeOptions['stylesheet.unitAliases']), userPreferenceOptions['stylesheet.unitAliases']);
|
|
642
|
+
combinedOptions['stylesheet.unitAliases'] = mergedAliases;
|
|
643
|
+
const type = getSyntaxType(syntax);
|
|
644
|
+
const variables = getVariables(emmetConfig['variables']);
|
|
645
|
+
const baseSyntax = getDefaultSyntax(syntax);
|
|
646
|
+
const snippets = type === 'stylesheet' ? (_k = customSnippetsRegistry[syntax]) !== null && _k !== void 0 ? _k : customSnippetsRegistry[baseSyntax] : customSnippetsRegistry[syntax];
|
|
647
|
+
return {
|
|
648
|
+
type,
|
|
649
|
+
options: combinedOptions,
|
|
650
|
+
variables,
|
|
651
|
+
snippets,
|
|
652
|
+
syntax,
|
|
653
|
+
// context: null,
|
|
654
|
+
text: undefined,
|
|
655
|
+
maxRepeat: 1000 // cache: null
|
|
656
|
+
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
function getClosingStyle(syntax) {
|
|
661
|
+
switch (syntax) {
|
|
662
|
+
case 'xhtml':
|
|
663
|
+
return 'xhtml';
|
|
664
|
+
|
|
665
|
+
case 'xml':
|
|
666
|
+
return 'xml';
|
|
667
|
+
|
|
668
|
+
case 'xsl':
|
|
669
|
+
return 'xml';
|
|
670
|
+
|
|
671
|
+
case 'jsx':
|
|
672
|
+
return 'xhtml';
|
|
673
|
+
|
|
674
|
+
default:
|
|
675
|
+
return 'html';
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* Maps and returns syntaxProfiles of previous format to ones compatible with new emmet modules
|
|
680
|
+
* @param syntax
|
|
681
|
+
*/
|
|
682
|
+
|
|
683
|
+
function getProfile(syntax, profilesFromSettings) {
|
|
684
|
+
if (!profilesFromSettings) {
|
|
685
|
+
profilesFromSettings = {};
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
const profilesConfig = Object.assign({}, profilesFromFile, profilesFromSettings);
|
|
689
|
+
const options = profilesConfig[syntax];
|
|
690
|
+
|
|
691
|
+
if (!options || typeof options === 'string') {
|
|
692
|
+
if (options === 'xhtml') {
|
|
693
|
+
return {
|
|
694
|
+
selfClosingStyle: 'xhtml'
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
return {};
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
const newOptions = {};
|
|
702
|
+
|
|
703
|
+
for (const key in options) {
|
|
704
|
+
switch (key) {
|
|
705
|
+
case 'tag_case':
|
|
706
|
+
newOptions['tagCase'] = options[key] === 'lower' || options[key] === 'upper' ? options[key] : '';
|
|
707
|
+
break;
|
|
708
|
+
|
|
709
|
+
case 'attr_case':
|
|
710
|
+
newOptions['attributeCase'] = options[key] === 'lower' || options[key] === 'upper' ? options[key] : '';
|
|
711
|
+
break;
|
|
712
|
+
|
|
713
|
+
case 'attr_quotes':
|
|
714
|
+
newOptions['attributeQuotes'] = options[key];
|
|
715
|
+
break;
|
|
716
|
+
|
|
717
|
+
case 'tag_nl':
|
|
718
|
+
newOptions['format'] = options[key] === true || options[key] === false ? options[key] : true;
|
|
719
|
+
break;
|
|
720
|
+
|
|
721
|
+
case 'inline_break':
|
|
722
|
+
newOptions['inlineBreak'] = options[key];
|
|
723
|
+
break;
|
|
724
|
+
|
|
725
|
+
case 'self_closing_tag':
|
|
726
|
+
if (options[key] === true) {
|
|
727
|
+
newOptions['selfClosingStyle'] = 'xml';
|
|
728
|
+
break;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
if (options[key] === false) {
|
|
732
|
+
newOptions['selfClosingStyle'] = 'html';
|
|
733
|
+
break;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
newOptions['selfClosingStyle'] = options[key];
|
|
737
|
+
break;
|
|
738
|
+
|
|
739
|
+
case 'compact_bool':
|
|
740
|
+
newOptions['compactBooleanAttributes'] = options[key];
|
|
741
|
+
break;
|
|
742
|
+
|
|
743
|
+
default:
|
|
744
|
+
newOptions[key] = options[key];
|
|
745
|
+
break;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
return newOptions;
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Returns variables to be used while expanding snippets
|
|
753
|
+
*/
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
function getVariables(variablesFromSettings) {
|
|
757
|
+
if (!variablesFromSettings) {
|
|
758
|
+
return variablesFromFile;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
return Object.assign({}, variablesFromFile, variablesFromSettings);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
function getFormatters(syntax, preferences) {
|
|
765
|
+
if (!preferences || typeof preferences !== 'object') {
|
|
766
|
+
return {};
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
if (!isStyleSheet(syntax)) {
|
|
770
|
+
const commentFormatter = {};
|
|
771
|
+
|
|
772
|
+
for (const key in preferences) {
|
|
773
|
+
switch (key) {
|
|
774
|
+
case 'filter.commentAfter':
|
|
775
|
+
commentFormatter['after'] = preferences[key];
|
|
776
|
+
break;
|
|
777
|
+
|
|
778
|
+
case 'filter.commentBefore':
|
|
779
|
+
commentFormatter['before'] = preferences[key];
|
|
780
|
+
break;
|
|
781
|
+
|
|
782
|
+
case 'filter.commentTrigger':
|
|
783
|
+
commentFormatter['trigger'] = preferences[key];
|
|
784
|
+
break;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
return {
|
|
789
|
+
comment: commentFormatter
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
let fuzzySearchMinScore = typeof (preferences === null || preferences === void 0 ? void 0 : preferences['css.fuzzySearchMinScore']) === 'number' ? preferences['css.fuzzySearchMinScore'] : 0.3;
|
|
794
|
+
|
|
795
|
+
if (fuzzySearchMinScore > 1) {
|
|
796
|
+
fuzzySearchMinScore = 1;
|
|
797
|
+
} else if (fuzzySearchMinScore < 0) {
|
|
798
|
+
fuzzySearchMinScore = 0;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
const stylesheetFormatter = {
|
|
802
|
+
'fuzzySearchMinScore': fuzzySearchMinScore
|
|
803
|
+
};
|
|
804
|
+
|
|
805
|
+
for (const key in preferences) {
|
|
806
|
+
switch (key) {
|
|
807
|
+
case 'css.floatUnit':
|
|
808
|
+
stylesheetFormatter['floatUnit'] = preferences[key];
|
|
809
|
+
break;
|
|
810
|
+
|
|
811
|
+
case 'css.intUnit':
|
|
812
|
+
stylesheetFormatter['intUnit'] = preferences[key];
|
|
813
|
+
break;
|
|
814
|
+
|
|
815
|
+
case 'css.unitAliases':
|
|
816
|
+
const unitAliases = {};
|
|
817
|
+
preferences[key].split(',').forEach(alias => {
|
|
818
|
+
if (!alias || !alias.trim() || !alias.includes(':')) {
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
const aliasName = alias.substr(0, alias.indexOf(':'));
|
|
823
|
+
const aliasValue = alias.substr(aliasName.length + 1);
|
|
824
|
+
|
|
825
|
+
if (!aliasName.trim() || !aliasValue) {
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
unitAliases[aliasName.trim()] = aliasValue;
|
|
830
|
+
});
|
|
831
|
+
stylesheetFormatter['unitAliases'] = unitAliases;
|
|
832
|
+
break;
|
|
833
|
+
|
|
834
|
+
case `${syntax}.valueSeparator`:
|
|
835
|
+
stylesheetFormatter['between'] = preferences[key];
|
|
836
|
+
break;
|
|
837
|
+
|
|
838
|
+
case `${syntax}.propertyEnd`:
|
|
839
|
+
stylesheetFormatter['after'] = preferences[key];
|
|
840
|
+
break;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
return {
|
|
845
|
+
stylesheet: stylesheetFormatter
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* Get the corresponding emmet mode for given vscode language mode
|
|
850
|
+
* Eg: jsx for typescriptreact/javascriptreact or pug for jade
|
|
851
|
+
* If the language is not supported by emmet or has been exlcuded via `exlcudeLanguages` setting,
|
|
852
|
+
* then nothing is returned
|
|
853
|
+
*
|
|
854
|
+
* @param language
|
|
855
|
+
* @param exlcudedLanguages Array of language ids that user has chosen to exlcude for emmet
|
|
856
|
+
*/
|
|
857
|
+
|
|
858
|
+
|
|
859
|
+
function getEmmetMode(language, excludedLanguages = []) {
|
|
860
|
+
if (!language || excludedLanguages.includes(language)) {
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
if (/\b(typescriptreact|javascriptreact|jsx-tags)\b/.test(language)) {
|
|
865
|
+
// treat tsx like jsx
|
|
866
|
+
return 'jsx';
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
if (language === 'sass-indented') {
|
|
870
|
+
// map sass-indented to sass
|
|
871
|
+
return 'sass';
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
if (language === 'jade') {
|
|
875
|
+
return 'pug';
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
if (syntaxes.markup.includes(language) || syntaxes.stylesheet.includes(language)) {
|
|
879
|
+
return language;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
export { doComplete, emmetSnippetField, extractAbbreviation, getDefaultSnippets, getDefaultSyntax, getEmmetMode, getExpandOptions, getSyntaxType, isAbbreviationValid, isStyleSheet };
|