Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/emmet/src/emmetCommon.ts
4772 views
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
6
import * as vscode from 'vscode';
7
import { DefaultCompletionItemProvider } from './defaultCompletionProvider';
8
import { expandEmmetAbbreviation, wrapWithAbbreviation } from './abbreviationActions';
9
import { removeTag } from './removeTag';
10
import { updateTag } from './updateTag';
11
import { matchTag } from './matchTag';
12
import { balanceOut, balanceIn } from './balance';
13
import { splitJoinTag } from './splitJoinTag';
14
import { mergeLines } from './mergeLines';
15
import { toggleComment } from './toggleComment';
16
import { fetchEditPoint } from './editPoint';
17
import { fetchSelectItem } from './selectItem';
18
import { evaluateMathExpression } from './evaluateMathExpression';
19
import { incrementDecrement } from './incrementDecrement';
20
import { LANGUAGE_MODES, getMappingForIncludedLanguages, updateEmmetExtensionsPath, migrateEmmetExtensionsPath, getPathBaseName, getSyntaxes, getEmmetMode } from './util';
21
import { reflectCssValue } from './reflectCssValue';
22
import { addFileToParseCache, clearParseCache, removeFileFromParseCache } from './parseDocument';
23
24
export function activateEmmetExtension(context: vscode.ExtensionContext) {
25
migrateEmmetExtensionsPath();
26
refreshCompletionProviders(context);
27
updateEmmetExtensionsPath();
28
29
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.wrapWithAbbreviation', (args) => {
30
wrapWithAbbreviation(args);
31
}));
32
33
context.subscriptions.push(vscode.commands.registerCommand('emmet.expandAbbreviation', (args) => {
34
expandEmmetAbbreviation(args);
35
}));
36
37
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.removeTag', () => {
38
return removeTag();
39
}));
40
41
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.updateTag', (inputTag) => {
42
if (inputTag && typeof inputTag === 'string') {
43
return updateTag(inputTag);
44
}
45
return updateTag(undefined);
46
}));
47
48
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.matchTag', () => {
49
matchTag();
50
}));
51
52
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.balanceOut', () => {
53
balanceOut();
54
}));
55
56
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.balanceIn', () => {
57
balanceIn();
58
}));
59
60
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.splitJoinTag', () => {
61
return splitJoinTag();
62
}));
63
64
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.mergeLines', () => {
65
mergeLines();
66
}));
67
68
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.toggleComment', () => {
69
toggleComment();
70
}));
71
72
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.nextEditPoint', () => {
73
fetchEditPoint('next');
74
}));
75
76
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.prevEditPoint', () => {
77
fetchEditPoint('prev');
78
}));
79
80
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.selectNextItem', () => {
81
fetchSelectItem('next');
82
}));
83
84
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.selectPrevItem', () => {
85
fetchSelectItem('prev');
86
}));
87
88
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.evaluateMathExpression', () => {
89
evaluateMathExpression();
90
}));
91
92
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.incrementNumberByOneTenth', () => {
93
return incrementDecrement(0.1);
94
}));
95
96
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.incrementNumberByOne', () => {
97
return incrementDecrement(1);
98
}));
99
100
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.incrementNumberByTen', () => {
101
return incrementDecrement(10);
102
}));
103
104
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.decrementNumberByOneTenth', () => {
105
return incrementDecrement(-0.1);
106
}));
107
108
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.decrementNumberByOne', () => {
109
return incrementDecrement(-1);
110
}));
111
112
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.decrementNumberByTen', () => {
113
return incrementDecrement(-10);
114
}));
115
116
context.subscriptions.push(vscode.commands.registerCommand('editor.emmet.action.reflectCSSValue', () => {
117
return reflectCssValue();
118
}));
119
120
context.subscriptions.push(vscode.commands.registerCommand('workbench.action.showEmmetCommands', () => {
121
vscode.commands.executeCommand('workbench.action.quickOpen', '>Emmet: ');
122
}));
123
124
context.subscriptions.push(vscode.workspace.onDidChangeConfiguration((e) => {
125
if (e.affectsConfiguration('emmet.includeLanguages') || e.affectsConfiguration('emmet.useInlineCompletions')) {
126
refreshCompletionProviders(context);
127
}
128
if (e.affectsConfiguration('emmet.extensionsPath')) {
129
updateEmmetExtensionsPath();
130
}
131
}));
132
133
context.subscriptions.push(vscode.workspace.onDidSaveTextDocument((e) => {
134
const basefileName: string = getPathBaseName(e.fileName);
135
if (basefileName.startsWith('snippets') && basefileName.endsWith('.json')) {
136
updateEmmetExtensionsPath(true);
137
}
138
}));
139
140
context.subscriptions.push(vscode.workspace.onDidOpenTextDocument((e) => {
141
const emmetMode = getEmmetMode(e.languageId, {}, []) ?? '';
142
const syntaxes = getSyntaxes();
143
if (syntaxes.markup.includes(emmetMode) || syntaxes.stylesheet.includes(emmetMode)) {
144
addFileToParseCache(e);
145
}
146
}));
147
148
context.subscriptions.push(vscode.workspace.onDidCloseTextDocument((e) => {
149
const emmetMode = getEmmetMode(e.languageId, {}, []) ?? '';
150
const syntaxes = getSyntaxes();
151
if (syntaxes.markup.includes(emmetMode) || syntaxes.stylesheet.includes(emmetMode)) {
152
removeFileFromParseCache(e);
153
}
154
}));
155
}
156
157
/**
158
* Holds any registered completion providers by their language strings
159
*/
160
const languageMappingForCompletionProviders: Map<string, string> = new Map<string, string>();
161
const completionProviderDisposables: vscode.Disposable[] = [];
162
163
function refreshCompletionProviders(_: vscode.ExtensionContext) {
164
clearCompletionProviderInfo();
165
166
const completionProvider = new DefaultCompletionItemProvider();
167
const inlineCompletionProvider: vscode.InlineCompletionItemProvider = {
168
async provideInlineCompletionItems(document: vscode.TextDocument, position: vscode.Position, _: vscode.InlineCompletionContext, token: vscode.CancellationToken) {
169
const items = await completionProvider.provideCompletionItems(document, position, token, { triggerCharacter: undefined, triggerKind: vscode.CompletionTriggerKind.Invoke });
170
if (!items) {
171
return undefined;
172
}
173
const item = items.items[0];
174
if (!item || !item.insertText) {
175
return undefined;
176
}
177
const range = item.range as vscode.Range;
178
179
if (document.getText(range) !== item.label) {
180
// We only want to show an inline completion if we are really sure the user meant emmet.
181
// If the user types `d`, we don't want to suggest `<div></div>`.
182
return undefined;
183
}
184
185
return [
186
{
187
insertText: item.insertText,
188
filterText: item.label,
189
range
190
}
191
];
192
}
193
};
194
195
const useInlineCompletionProvider = vscode.workspace.getConfiguration('emmet').get<boolean>('useInlineCompletions');
196
const includedLanguages = getMappingForIncludedLanguages();
197
Object.keys(includedLanguages).forEach(language => {
198
if (languageMappingForCompletionProviders.has(language) && languageMappingForCompletionProviders.get(language) === includedLanguages[language]) {
199
return;
200
}
201
202
if (useInlineCompletionProvider) {
203
const inlineCompletionsProvider = vscode.languages.registerInlineCompletionItemProvider({ language, scheme: '*' }, inlineCompletionProvider);
204
completionProviderDisposables.push(inlineCompletionsProvider);
205
}
206
207
const explicitProvider = vscode.languages.registerCompletionItemProvider({ language, scheme: '*' }, completionProvider, ...LANGUAGE_MODES[includedLanguages[language]]);
208
completionProviderDisposables.push(explicitProvider);
209
210
languageMappingForCompletionProviders.set(language, includedLanguages[language]);
211
});
212
213
Object.keys(LANGUAGE_MODES).forEach(language => {
214
if (!languageMappingForCompletionProviders.has(language)) {
215
if (useInlineCompletionProvider) {
216
const inlineCompletionsProvider = vscode.languages.registerInlineCompletionItemProvider({ language, scheme: '*' }, inlineCompletionProvider);
217
completionProviderDisposables.push(inlineCompletionsProvider);
218
}
219
220
const explicitProvider = vscode.languages.registerCompletionItemProvider({ language, scheme: '*' }, completionProvider, ...LANGUAGE_MODES[language]);
221
completionProviderDisposables.push(explicitProvider);
222
223
languageMappingForCompletionProviders.set(language, language);
224
}
225
});
226
}
227
228
function clearCompletionProviderInfo() {
229
languageMappingForCompletionProviders.clear();
230
let disposable: vscode.Disposable | undefined;
231
while (disposable = completionProviderDisposables.pop()) {
232
disposable.dispose();
233
}
234
}
235
236
export function deactivate() {
237
clearCompletionProviderInfo();
238
clearParseCache();
239
}
240
241