1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { groupBy, isFalsyOrEmpty } from 'vs/base/common/arrays';
import { compare } from 'vs/base/common/strings';
import { getCodeEditor } from 'vs/editor/browser/editorBrowser';
import { ILanguageService } from 'vs/editor/common/languages/language';
import { SnippetController2 } from 'vs/editor/contrib/snippet/browser/snippetController2';
import { localize } from 'vs/nls';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
import { SnippetsAction } from 'vs/workbench/contrib/snippets/browser/commands/abstractSnippetsActions';
import { ISnippetsService } from 'vs/workbench/contrib/snippets/browser/snippets';
import { Snippet } from 'vs/workbench/contrib/snippets/browser/snippetsFile';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
export class SelectSnippetForEmptyFile extends SnippetsAction {
static readonly Id = 'workbench.action.populateFromSnippet';
constructor() {
super({
id: SelectSnippetForEmptyFile.Id,
title: {
value: localize('label', 'Populate from Snippet'),
original: 'Populate from Snippet'
},
f1: true,
});
}
async run(accessor: ServicesAccessor): Promise<void> {
const snippetService = accessor.get(ISnippetsService);
const quickInputService = accessor.get(IQuickInputService);
const editorService = accessor.get(IEditorService);
const langService = accessor.get(ILanguageService);
const editor = getCodeEditor(editorService.activeTextEditorControl);
if (!editor || !editor.hasModel()) {
return;
}
const snippets = await snippetService.getSnippets(undefined, { topLevelSnippets: true, noRecencySort: true, includeNoPrefixSnippets: true });
if (snippets.length === 0) {
return;
}
const selection = await this._pick(quickInputService, langService, snippets);
if (!selection) {
return;
}
if (editor.hasModel()) {
// apply snippet edit -> replaces everything
SnippetController2.get(editor)?.apply([{
range: editor.getModel().getFullModelRange(),
template: selection.snippet.body
}]);
// set language if possible
if (langService.isRegisteredLanguageId(selection.langId)) {
editor.getModel().setMode(selection.langId);
}
}
}
private async _pick(quickInputService: IQuickInputService, langService: ILanguageService, snippets: Snippet[]) {
// spread snippet onto each language it supports
type SnippetAndLanguage = { langId: string; snippet: Snippet };
const all: SnippetAndLanguage[] = [];
for (const snippet of snippets) {
if (isFalsyOrEmpty(snippet.scopes)) {
all.push({ langId: '', snippet });
} else {
for (const langId of snippet.scopes) {
all.push({ langId, snippet });
}
}
}
type SnippetAndLanguagePick = IQuickPickItem & { snippet: SnippetAndLanguage };
const picks: (SnippetAndLanguagePick | IQuickPickSeparator)[] = [];
const groups = groupBy(all, (a, b) => compare(a.langId, b.langId));
for (const group of groups) {
let first = true;
for (const item of group) {
if (first) {
picks.push({
type: 'separator',
label: langService.getLanguageName(item.langId) ?? item.langId
});
first = false;
}
picks.push({
snippet: item,
label: item.snippet.prefix || item.snippet.name,
detail: item.snippet.description
});
}
}
const pick = await quickInputService.pick(picks, {
placeHolder: localize('placeholder', 'Select a snippet'),
matchOnDetail: true,
});
return pick?.snippet;
}
}
|