Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/emmet/browser/emmetActions.ts
3296 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 { EditorAction, ServicesAccessor, IActionOptions } from '../../../../editor/browser/editorExtensions.js';
7
import { grammarsExtPoint, ITMSyntaxExtensionPoint } from '../../../services/textMate/common/TMGrammars.js';
8
import { IExtensionService, ExtensionPointContribution } from '../../../services/extensions/common/extensions.js';
9
import { ICommandService } from '../../../../platform/commands/common/commands.js';
10
import { ICodeEditor } from '../../../../editor/browser/editorBrowser.js';
11
12
interface ModeScopeMap {
13
[key: string]: string;
14
}
15
16
export interface IGrammarContributions {
17
getGrammar(mode: string): string;
18
}
19
20
class GrammarContributions implements IGrammarContributions {
21
22
private static _grammars: ModeScopeMap = {};
23
24
constructor(contributions: ExtensionPointContribution<ITMSyntaxExtensionPoint[]>[]) {
25
if (!Object.keys(GrammarContributions._grammars).length) {
26
this.fillModeScopeMap(contributions);
27
}
28
}
29
30
private fillModeScopeMap(contributions: ExtensionPointContribution<ITMSyntaxExtensionPoint[]>[]) {
31
contributions.forEach((contribution) => {
32
contribution.value.forEach((grammar) => {
33
if (grammar.language && grammar.scopeName) {
34
GrammarContributions._grammars[grammar.language] = grammar.scopeName;
35
}
36
});
37
});
38
}
39
40
public getGrammar(mode: string): string {
41
return GrammarContributions._grammars[mode];
42
}
43
}
44
45
type IEmmetActionOptions = IActionOptions & {
46
actionName: string;
47
};
48
49
export abstract class EmmetEditorAction extends EditorAction {
50
51
protected emmetActionName: string;
52
53
constructor(opts: IEmmetActionOptions) {
54
super(opts);
55
this.emmetActionName = opts.actionName;
56
}
57
58
private static readonly emmetSupportedModes = ['html', 'css', 'xml', 'xsl', 'haml', 'jade', 'jsx', 'slim', 'scss', 'sass', 'less', 'stylus', 'styl', 'svg'];
59
60
private _lastGrammarContributions: Promise<GrammarContributions> | null = null;
61
private _lastExtensionService: IExtensionService | null = null;
62
private _withGrammarContributions(extensionService: IExtensionService): Promise<GrammarContributions | null> {
63
if (this._lastExtensionService !== extensionService) {
64
this._lastExtensionService = extensionService;
65
this._lastGrammarContributions = extensionService.readExtensionPointContributions(grammarsExtPoint).then((contributions) => {
66
return new GrammarContributions(contributions);
67
});
68
}
69
return this._lastGrammarContributions || Promise.resolve(null);
70
}
71
72
public run(accessor: ServicesAccessor, editor: ICodeEditor): Promise<void> {
73
const extensionService = accessor.get(IExtensionService);
74
const commandService = accessor.get(ICommandService);
75
76
return this._withGrammarContributions(extensionService).then((grammarContributions) => {
77
78
if (this.id === 'editor.emmet.action.expandAbbreviation' && grammarContributions) {
79
return commandService.executeCommand<void>('emmet.expandAbbreviation', EmmetEditorAction.getLanguage(editor, grammarContributions));
80
}
81
82
return undefined;
83
});
84
85
}
86
87
public static getLanguage(editor: ICodeEditor, grammars: IGrammarContributions) {
88
const model = editor.getModel();
89
const selection = editor.getSelection();
90
91
if (!model || !selection) {
92
return null;
93
}
94
95
const position = selection.getStartPosition();
96
model.tokenization.tokenizeIfCheap(position.lineNumber);
97
const languageId = model.getLanguageIdAtPosition(position.lineNumber, position.column);
98
const syntax = languageId.split('.').pop();
99
100
if (!syntax) {
101
return null;
102
}
103
104
const checkParentMode = (): string => {
105
const languageGrammar = grammars.getGrammar(syntax);
106
if (!languageGrammar) {
107
return syntax;
108
}
109
const languages = languageGrammar.split('.');
110
if (languages.length < 2) {
111
return syntax;
112
}
113
for (let i = 1; i < languages.length; i++) {
114
const language = languages[languages.length - i];
115
if (this.emmetSupportedModes.indexOf(language) !== -1) {
116
return language;
117
}
118
}
119
return syntax;
120
};
121
122
return {
123
language: syntax,
124
parentMode: checkParentMode()
125
};
126
}
127
128
129
}
130
131