существуетпредыдущий постУ нас уже есть предварительное представление и понимание плагина vscode, далее мы «раскроем», как полезные плагины vscode, представленные на рынке, помогают нам повысить эффективность нашей работы.
1. От «целого» к «частичному»
Прежде чем начать тему, давайте вспомним, часто ли мы используем VS Code и получаем ли мы удовольствие от кодирования, чтобы включить следующие пункты.
1.1, Фрагмент - фрагмент кода
Мы часто видим фрагменты кода в файлах с разными суффиксами и в разных местах файла. Введите несколько коротких символов соглашения, вы можете иметь большой или маленький сегмент кода, освободить руки, сэкономить время и увеличить количество ежедневного кода.
Следующие изображения взяты из плагина:vue-vscode-snippets
1.2. Подсказки по коду
Другим распространенным «противоядием» для спасения «ленивого рака» являются подсказки кода. Вы можете не заметить этого в обычное время, но эта функция идеально подходит для таких людей, как я, которые имеют посредственную память слов и не могут запомнить все значения перечисления!
Следующие изображения взяты из плагина:vue-helper
2. От «Видения» к «Практике»
Я считаю, что, прочитав приведенный выше пример, вы достаточно умны, чтобы это почувствовать. Тогда давайте сразу к теме - добиться вышеизложенногоФрагменты кода и подсказки по кодуФункция! Перед этим вернемся на официальный сайт VS Code и посмотримLanguage Extensions APIи что он может помочь нам достичь.
Во-первых, Visual Studio Code предоставляет интеллектуальные возможности редактирования для разных языков программирования с помощью языковых расширений. Хотя он не обеспечивает встроенной языковой поддержки, он предоставляет набор API-интерфейсов, поддерживающих расширенные языковые функции. В общем, API-интерфейсы, связанные с языком плагинов VS Code, делятся на две категории: одна — «функции языка объявлений», а другая — «функции языка программы». Первый в основном определяется в файле конфигурации, а второй активируется путем регистрации в коде.
2.1. Завершение сниппета
Давайте начнем с фрагмента кода для «Объявления функций языка», чтобы увидеть, как файл конфигурации может помочь нам работать более эффективно.
Во-первых, мы добавляем package.json внутриsnippetsподъезд, расположенный по адресуcontributesПодчиненные:
"contributes": {
"commands": [
{
"command": "test.helloGitHub",
"title": "Hello World"
},
{
"command": "test.button",
"title": "按钮",
"icon": {
"light": "./media/light/preview.svg",
"dark": "./media/dark/preview.svg"
}
}
],
"menus": {
"editor/title": [
{
"command": "test.button",
"group": "navigation",
"when": "resourceLangId == javascript"
}
],
"editor/context": [
{
"command": "test.button",
"group": "navigation",
"when": "resourceLangId == javascript"
}
]
},
// 就是这里了!!
"snippets": [
{
"language": "javascript",
"path": "./snippets/javascript.json"
}
]
},
Это место, вам нужно вручную создать новую папку и файл:
Дальше фокус, фокус, фокус. Как мы пишем файлы конфигурации для фрагментов кода? Если вам интересно, вы можете перейти кОфициальный сайтОзнакомьтесь с этим подробным руководством. Если вы хотите сначала посмотреть, как написать простую конфигурацию, следуйте этой статье, чтобы увидеть ее ~
Давайте сначала «увидеть, значит поверить», чтобы увидеть, какой замечательный эффект будет от следующей конфигурации. Начнем с кода конфигурации:
{
"forLoop": {
"prefix": "for",
"body": [
"for(let i = 0; i < ${1: array.length}); i++) {",
"\t$BLOCK_COMMENT_START HelloGitHub: 这里可以写你的代码 $BLOCK_COMMENT_END",
"}"
],
"description": "for 循环"
}
}
Давайте посмотрим на эффект подсказки после запуска плагина (обязательно посмотрите, какой именно из нашего плагина):
Наконец, мы уверенно нажимаем клавишу «Enter», и мы увидим, что кусок кода уже находится в нашемjsв файле
for(let i = 0; i < array.length); i++) {
/* HelloGitHub: 这里可以写你的代码 */
}
Затем давайте рассмотрим приведенный выше файл конфигурации и то, как сгенерировать этот код.
| поле | имея в виду |
|---|---|
| forLoop | это имя фрагмента. Если описание не предоставлено, отобразите с помощью IntelliSense. |
| prefix | Определите одно или несколько триггерных слов для отображения сводок в IntelliSense. |
| body | — это одна или несколько строк содержимого, которые будут объединены в несколько строк при вставке. Разрывы строк и встроенные вкладки будут отформатированы в соответствии с контекстом, в который вставлен фрагмент. |
| description | Описание фрагмента кода, отображаемый Intellisense (не требуется) |
Во-первых, эта конфигурация будет иметь имяforLoop, который может быть настроен пользователями. Мы видим, что он поддерживает прописные и строчные буквы, а также пробелы и горизонтальные полосы. Конечно, вы можете спросить, поддерживает ли он китайский язык, тогда я могу сказать вам: да. Но так писать не рекомендуется, потому что наш кругозор нужно расширять и выходить на международный уровень~
Во-вторых, если вы хотите сопоставить несколькоprefix, вы можете изменить свой код следующим образом:
{
"forLoop": {
"prefix": ["for", "for-const"],
"body": [
"for(let i = 0; i < ${1:array.length}); i++) {",
"\t$BLOCK_COMMENT_START HelloGitHub: 这里可以写你的代码 $BLOCK_COMMENT_END", // \t 表示缩进,$BLOCK_COMMENT_START 和 $BLOCK_COMMENT_END 表示注释的开始和结束。 // 和 /**/ 这两种都支持
"}"
],
"description": "for 循环"
}
}
Эффект следующий:
А сопоставление подстрок выполняется по префиксам, поэтому в данном случае fcможет соответствоватьfor-const:
Фрагмент отображаемого кода:
1. Вкладки
Управляет перемещением курсора редактора внутри кода. вы можете использовать$1,$2Укажите положение курсора, число указывает порядок доступа к клавише Tab, то же самое будет обновляться синхронно,$0Указывает последнюю позицию курсора.Когда курсор находится в указанной позиции, он выходит из этого режима.
Возможно, вы немного запутаетесь, просто прочитав текст, тогда мы напрямую изменим вышеизложенное.forцикл:
{
"For Loop": {
"prefix": ["for", "for-const"],
"body": ["for (const ${2:element} of ${1:array}) {", "\t$0", "}"],
"description": "A for loop."
}
}
Эффекты (переключение с помощью вкладки), порядок$1 > $2 > $0:
2. Заполнитель
На самом деле, из предыдущего примера вы должны знать, что заполнитель — это синтаксис со значением по умолчанию, например${1:foo}. Текст-заполнитель будет вставлен и выделен, чтобы пользователь мог легко его изменить. И заполнители также могут быть вложенными, например${1:another ${2:placeholder}}
3. Выберите
Конечно, для «нас», которым нравится быть ленивым, это может сэкономить немного времени, поэтому заполнитель также может позволить нам просто перемещать клавиши вверх и вниз, чтобы завершить ввод. Синтаксис представляет собой перечисление значений, разделенных запятыми, и после запуска фрагмента вставки и выбора заполнителя опция предложит пользователю выбрать одно из значений.
Измените наш код следующим образом:
{
"forLoop": {
"prefix": ["for", "for-const"],
"body": [
"for(let i = 0; i < ${1:array.length}); i++) {",
"\t$BLOCK_COMMENT_START HelloGitHub: 这里可以写你的代码 $BLOCK_COMMENT_END",
"\t\t${2|one,two,three|}",
"}"
],
"description": "for 循环"
},
}
Эффект:
4. Переменные
Я не знаю, заметил ли вы небольшой комментарий в коде выше:
{
...
"\t$BLOCK_COMMENT_START HelloGitHub: 这里可以写你的代码 $BLOCK_COMMENT_END", // \t 表示缩进,$BLOCK_COMMENT_START 和 $BLOCK_COMMENT_END 表示注释的开始和结束。 // 和 /**/ 这两种都支持
...
}
Внутри используется закомментированная переменная$BLOCK_COMMENT_STARTа также$BLOCK_COMMENT_END. Этот синтаксис позволяет нам использовать$nameили${name:default}Оба способа установить вставленное значение переменной. Если переменная не установлена, она будет вставленаПо умолчаниюили пустая строка. Когда переменная неизвестна (т. е. ее имя не определено), имя переменной вставляется и преобразуется в заполнитель. Все поддерживаемые переменные можно посмотреть на официальном сайте VS Code:
Например, мы модифицируем наш пример следующим образом:
{
"forLoop": {
"prefix": ["for", "for-const"],
"body": [
"for(let i = 0; i < ${1:array.length}); i++) {",
"\t$BLOCK_COMMENT_START HelloGitHub: 这里可以写你的代码 $BLOCK_COMMENT_END",
"\t\tconsole.log('choice', ${2|one,two,three|})",
"\t\tconsole.log('year', ${CURRENT_YEAR})",
"\t\treturn ${name:value}",
"}"
],
"description": "for 循环"
}
Эффект:
На этом примере вы обнаружите, что наши фрагменты кода становятся длиннее и богаче, то есть мы можем быть ленивыми и «все больше и больше», и можем ли мы непреднамеренно повысить эффективность разработки?
Возможно, мой пример слишком прост и вы этого не чувствуете, так что давайте посмотрим на это, оно должно быть знакомо многим:
Соответствующая конфигурация кода на самом деле представляет собой синтаксис, о котором мы упоминали выше:
{
"hellogithub": {
"prefix": "swiper",
"body": [
"<swiper $0 indicator-dots=\"{{${1:indicatorDots}}}\" autoplay=\"{{${2:autoplay}}}\" interval=\"{{${3:interval}}}\" duration=\"{{${4:duration}}}\">",
"\t<block wx:for=\"{{${5:imgUrls}}}\">",
"\t\t<swiper-item>",
"\t\t\t<image src=\"{{${6:item}}}\" class=\"slide-image\" />",
"\t\t</swiper-item>",
"\t</block>",
"</swiper>$7"
],
"description": "滑块视图容器"
}
}
Конечно, если вы заинтересованы в написании очень полезного фрагмента кода, вышеизложенное может вас не удовлетворить, вы можете изучить его.TextMateБолее продвинутая грамматика (на самом деле это базовая грамматика TextMate, подразумевается, что она используется чаще и выглядит очень простой и понятной). Краткое введение в TextMate, которыйMacОн может соответствовать структуре документа в соответствии с определенными языковыми правилами, а также может быстро генерировать фрагменты кода в соответствии с определенными правилами грамматики.
2.2. Поставщик завершения
1. Первый взгляд
Выше описана «функция декларативного языка», которую можно выполнить с помощью конфигурации, давайте посмотрим на другую «функция языка программирования» —registerCompletionItemProvider.
Давайте сначала посмотрим на картинку, не думаете ли вы, что это «ленивый» артефакт! Но задумывались ли вы когда-нибудь, откуда этот редактор знает, о чем мы собираемся написать? Почему он все еще может порекомендовать нам, что писать? Если вы думаете, что это кристаллизация мудрости компьютерного века, то я не могу сказать, что вы ошибаетесь. Итак, сегодня мы лично «раскроем» эту функцию, которую вы можете использоватьregisterCompletionItemProviderдобиться этого.
Далее мы введем реализацию кода, помнитепредыдущий постизextension.js? Мы добавляем этот фрагмент кода здесь:
const completion = vscode.languages.registerCompletionItemProvider(
'javascript',
{
provideCompletionItems(document, position) {
const linePrefix = document.lineAt(position).text.substr(0, position.character);
if (!linePrefix.endsWith('hello.')) {
return undefined;
}
return [
new vscode.CompletionItem('HelloGitHub', vscode.CompletionItemKind.Property),
new vscode.CompletionItem('HelloWorld', vscode.CompletionItemKind.Property),
new vscode.CompletionItem('HelloPeople', vscode.CompletionItemKind.Property),
];
}
},
'.' // triggered whenever a '.' is being typed
);
context.subscriptions.push(completion);
Тогда сначала посмотрите на эффект:
Могут быть некоторые друзья, которые попадают в «яму» — если вы обнаружите, что эффект не может быть получен в процессе реализации, вы можете судить и решить его в соответствии со следующими идеями:
-
1. Проверьте правильность суффикса текущего файла. Например, приведенный выше код предусматривает
javascript, Было бы в.jsДействует только в файлах с суффиксом -
2. Разумеется, команда регистрации также тесно связана с жизненным циклом плагина, если вы обнаружите, что предыдущий шаг верен, то вам следует перейти
package.jsonпосмотри в файлеactivationEventsЗапускается ли команда внутри. Если вы забыли, как запустить жизненный цикл активации плагина, вы можете изменить его следующим образом.
...
"activationEvents": [
"*"
],
...
- 3. Если два вышеуказанных варианта не помогли решить вашу проблему, возможно, ваш код ctrl+c ctrl+v неверен! Шучу, если у вас все еще не получается... тогда вы можете оставить комментарий, поставить лайк и сделать триптих~
Возвращаясь к теме, давайте проанализируем, как реализован приведенный выше код:
const completion = vscode.languages.registerCompletionItemProvider(
// 这里是注册这个 Provider 有效的相关文件,支持字符串类型或 DocumentFilter 对象。
// 如果你要对多个后缀的文件做操作的话可以用数组的形式,例如 ['javascript', 'plaintext']
// DocumentFilter 对象包含三个字段(均非必须),例如:{ language: 'json', scheme: 'untitled', pattern: '**/package.json' }
'javascript',
...
}
...
{
// 这是代表了一个 provider
provideCompletionItems(document, position) {
// 拿到当前 `position` 的 text 并且判断一下是否以 `hello.` 开头
const linePrefix = document.lineAt(position).text.substr(0, position.character);
// 没有匹配到则不予提示
if (!linePrefix.endsWith('hello.')) {
return undefined;
}
// 如果匹配成功就返回 CompletionItem 有:HelloGitHub、HelloWorld、HelloPeople
return [
new vscode.('HelloGitHub', vscode.CompletionItemKind.Property),
new vscode.CompletionItem('HelloWorld', vscode.CompletionItemKind.Property),
new vscode.CompletionItem('HelloPeople', vscode.CompletionItemKind.Property),
];
}
},
...
Вам может быть интересно,vscode.CompletionItemKind.PropertyЧто это такое? Проще говоря, на самом деле это конфигурация значка. Мы можем изменить несколько свойств, чтобы увидеть разницу:
...
return [
new vscode.CompletionItem('HelloGitHub', vscode.CompletionItemKind.Method),
new vscode.CompletionItem('HelloWorld', vscode.CompletionItemKind.Enum),
new vscode.CompletionItem('HelloPeople', vscode.CompletionItemKind.Property),
];
...
отindex.d.tsВы можете видеть, что он поддерживает очень много типов значков ниже. Вы можете выбрать нужный значок в соответствии с различными потребностями. Конечно, это не будет здесь сосредоточено. Если вам интересно, вы можете организовать эти значки самостоятельно ~
/**
* Completion item kinds.
*/
export enum CompletionItemKind {
Text = 0,
Method = 1,
Function = 2,
Constructor = 3,
Field = 4,
Variable = 5,
Class = 6,
Interface = 7,
Module = 8,
Property = 9,
Unit = 10,
Value = 11,
Enum = 12,
Keyword = 13,
Snippet = 14,
Color = 15,
Reference = 17,
File = 16,
Folder = 18,
EnumMember = 19,
Constant = 20,
Struct = 21,
Event = 22,
Operator = 23,
TypeParameter = 24,
User = 25,
Issue = 26,
}
Наконец, объясните условие триггера:
...
'.' // 当键盘打 . 的时候触发,支持多个触发
...
Мы можем столкнуться с разными сценариями, которые требуют разных условий срабатывания, в этом случае просто добавьте их позже, например, мы добавим несколько новых условий срабатывания для специальных символов (здесь сначала уберите логику сопоставления строк, чтобы лучше срабатывать) :
const completion = vscode.languages.registerCompletionItemProvider(
['javascript', 'xml'],
{
provideCompletionItems(document, position) {
// const linePrefix = document.lineAt(position).text.substr(0, position.character);
// if (!linePrefix.endsWith('hello')) {
// return undefined;
// }
return [
new vscode.CompletionItem('HelloGitHub', vscode.CompletionItemKind.Method),
new vscode.CompletionItem('HelloWorld', vscode.CompletionItemKind.Enum),
new vscode.CompletionItem('HelloPeople', vscode.CompletionItemKind.Property),
];
}
},
'.',
',',
' '
);
2. Расширенный
Но в нормальных условиях нам часто нужно анализировать различный контент, введенный пользователем, чтобы получить разные соответствующие элементы завершения. Так что дальше мы будемxmlФайл в качестве примера, чтобы написать «мощный» Completion Proviwder.
Давайте сначала проанализируемxmlСуществует примерно три общих поставщика завершения для такого типа файлов:
-
название ярлыка
-
Имя свойства
-
значение атрибута
Конечно, если что-то вродеvueвtemplateНаписание шаблона, собственно, там названия событий и так далее. Затем мы используем символ @ в качестве условия срабатывания для приглашения имени события,
// 引入两个 mock 文件
const testEventName = require("./mock/testEventName");
const testTagName = require("./mock/testTagName");
...
const completion = vscode.languages.registerCompletionItemProvider(
'xml',
{
provideCompletionItems(
document, // 命令被调用的文档
position, // 命令被调用的位置
token, // 取消令牌
context // 自动补全是怎么触发的
) {
// 如果校验命中了取消令牌,就不提示
if (token.isCancellationRequested) {
return Promise.resolve([])
}
let char = context.triggerCharacter
switch (char) {
case '<': // 标签名提示
// todo
case '@': // 绑定事件
// todo
default: // 属性名、属性值等
// todo
}
}
},
'@',
'\n',
' ',
'"',
"'",
'<'
)
Макет файла может иметь произвольную структуру. Ниже представлена макетная структура данных (два файла), используемая в примере в этой статье:
// ./mock/testEventName
module.exports = [
{
name: 'onTap',
id: 'ontap',
desc: '这是一个点击事件的描述'
},
{
name: 'for',
id: 'for',
desc: '这是一个循环事件的描述'
}
]
// ./mock/testTagName
module.exports = [
{
name: 'HelloGitHub',
id: 'hg',
description: '这是我们的名字'
},
{
name: 'Welcome',
id: 'wlc',
description: '欢迎关注和喜欢我们'
}
]
Давайте сначала реализуем Completion Provider для имени тега:
const completionArr = []
for (let i = 0; i < testTagName.length; i++) {
const commandCompletion = new vscode.CompletionItem(testTagName[i].name);
commandCompletion.kind = vscode.CompletionItemKind.Property;
commandCompletion.documentation = new vscode.MarkdownString(testTagName[i].description);
let snippet = `${testTagName[i].name}\n` +
' name="${1:HelloGitHub}"\n' +
' desc="${2:We are serious about open source}"\n' +
'>\n' +
`</${testTagName[i].name}>`;
commandCompletion.insertText = new vscode.SnippetString(snippet);
completionArr.push(commandCompletion)
}
return completionArr;
Мы видим, что это похоже на то, что было сказано выше, и также необходимоnewОдинCompletionItemобъект, но здесь объект более "обогащен" добавлением атрибутов к этому объектуCompletionItemДобавлены иконки -kind, проиллюстрировать--documentationи фрагменты —insertText.
Давайте посмотрим на эффект, если никакие инструкции не появляются автоматически, нажмите маленькую стрелку справа от завершения:
Точно так же давайте напишем Completion Provider события, который представляет собой просто ctrl+c и ctrl+v:
if (testEventName && testEventName.length > 0) {
const arr = []
for(let i = 0; i < testEventName.length; i++) {
const item = testEventName[i]
const commandCompletion = new vscode.CompletionItem(item.name);
commandCompletion.kind = vscode.CompletionItemKind.Property;
commandCompletion.documentation = new vscode.MarkdownString(item.desc || '暂无介绍');
let snippet = `${item.name}{}`;
commandCompletion.insertText = new vscode.SnippetString(snippet);
arr.push(commandCompletion)
}
return arr
}
return []
Эффект:
Далее нам нужно преодолеть последний пункт: значение атрибута и имя атрибута. Это включает в себя анализ структуры текущего текста.По умолчанию положение одинарных и двойных кавычек указывает на значение атрибута.Следующий за символом
Итак, первый шаг, мы пишем метод для анализа и получения структуры документа, которую мы хотим знать выше, мы записываем эту часть кода в новый файл, чтобы ссылаться на прошлое (getTagAtPosition.js):
function getTagAtPosition(doc, pos) {
let offset = doc.offsetAt(pos);
let text = doc.getText();
// 因为引号里可能会有任何字符,所以做一层替换处理
let attrFlagText = text.replace(/("[^"]*"|'[^']*')/g, replacer('%'));
// 标签起始位置 [start,length]
const range = getBracketRange(attrFlagText, offset);
if (!range) {
return null
}
const [start, end] = range;
offset = offset - start;
text = text.substr(start, end);
attrFlagText = attrFlagText.substr(start, end);
const tagNameMatcher = attrFlagText.match(/^<([\w-:.]+)/);
if (!tagNameMatcher) {
return null;
}
const name = tagNameMatcher[1]; // 标签名称
const isOnAttrValue = attrFlagText[offset] === '%';
const attrName = isOnAttrValue ? getAttrName(attrFlagText.substring(0, offset)) : '' // 当前输入对应的属性
const isOnTagName = offset <= name.length + 1;
const isOnAttrName = !isOnTagName && !isOnAttrValue
return {
name, // 标签名
attrName, // 属性名
isOnTagName, // 是否处于 tag 上
isOnAttrName, // 是否处于属性名上
isOnAttrValue, // 是否处于属性值上
}
}
// 字符替换的方法
const replacer = (char) => (raw) => char.repeat(raw.length);
// 获取 <> 标签的位置
function getBracketRange(text, pos) {
const textBeforePos = text.substr(0, pos)
const startBracket = textBeforePos.lastIndexOf('<')
if (startBracket < 0 || textBeforePos[startBracket + 1] === '!' || textBeforePos.lastIndexOf('>') > startBracket) {
// 前没有开始符<,
// 或者正在注释中: <!-- | -->
// 或者不在标签中: <view > | </view>
return null
}
// 从光标位置后面找 > 标签
let endBracket = text.indexOf('>', pos + 1)
if (endBracket < 0) {
// 未找到闭合 > 文件结束位置为结束
// 如 <image ... | EOF
endBracket = text.length
}
// 可能尚未输入闭合标签,取下一个标签的头<
// 此时找到的闭合标签是下一个标签
// <view xxx | ... <view ></view>
const nextStart = text.indexOf('<', pos + 1)
if (nextStart > 0 && nextStart < endBracket) {
endBracket = nextStart
}
return [startBracket, endBracket - startBracket]
}
вести перепискуextension.jsДобавим в него нашу только что написанную логику:
...
default: // 属性、标签等
// step1. 找最近的标签名
let tag = getTagAtPosition(document, position);
if (!tag) {
return null
}
// 属性值提示
if (tag.isOnAttrValue) {
return getAttrValueCompletionArr(tag.attrName || '', targetObj.children)
} else {
// 属性提示
return getAttrCompletionArr(targetObj.children)
}
...
Затем мы добавляем новые фиктивные данные, и структура представляет собой древовидную структуру, и каждый тег имеет список возможных имен атрибутов (children), и каждое имя атрибута имеет соответствующий список значений атрибута (children):
module.exports = [
{
name: 'HelloGitHub',
id: 'hg',
description: '这是我们的名字',
children: [
{
name: 'hgAttrName1',
children: [
{
name: 'hgAttrVal1'
},
{
name: 'hgAttrVal2'
}
]
},
{
name: 'hgAttrName2'
}
]
},
{
name: 'Welcome',
id: 'wlc',
description: '欢迎关注和喜欢我们'
}
]
смотреть вышеgetAttrCompletionArrЭтот метод на самом деле получает значение из данных и отображает его так просто:
function getAttrCompletionArr (completionArr) {
const arr = []
if (completionArr.length > 0) {
for(let j = 0; j < completionArr.length; j++) {
if (completionArr[j] && completionArr[j].name) {
const commandCompletion = new vscode.CompletionItem(completionArr[j].name);
commandCompletion.kind = vscode.CompletionItemKind.Property;
arr.push(commandCompletion)
}
}
}
return arr
}
module.exports = getAttrCompletionArr;
Для списка значений атрибута нам нужно знать, какое имя тега находится под именем атрибута:
function getAttrValueCompletionArr (attrName, completionArr) {
const enumValue = completionArr.find(item => item.name === attrName) || {};
if (enumValue.children && enumValue.children.length > 0) {
const arr = []
for(let i = 0; i < enumValue.children.length; i++) {
const commandCompletion = new vscode.CompletionItem(enumValue.children[i].name);
commandCompletion.kind = vscode.CompletionItemKind.Property;
arr.push(commandCompletion)
}
return arr
}
return []
}
Конечный эффект:
У некоторых друзей может быть много сомнений по поводу вышеописанного метода разбора документов.Хотя в коде и есть комментарии, но они могут все же не чувствовать тела.В это время рекомендуется попрактиковаться, потому что все методы предоставлены VS Code Extension, так что здесь я не буду слишком расширяться, в конце концов, это не тема этой статьи~
3. «Сводка» и «Предварительный просмотр»
Итак, сегодня я расскажу о двух способах «лениться» и помогу нам повысить эффективность кодирования:
-
Фрагмент
-
Автоматическое пополнение (Complete Provider)
Это также одна из самых распространенных функций во многих плагинах VS Code, на самом деле подобраться к ней несложно~
Сегодняшний контент может быть немного больше.Если вы читаете первую, вторая основана на первой.Я думаю, вы сможете не отставать. В следующей статье мы рассмотрим еще одну очень мощную функцию плагина VS Code — WebView. То есть он поддерживает открытие веб-страниц в плагинах, общение с веб-страницами и написание классных стилей CSS. Хотя его функция очень мощная, это как обоюдоострый меч, и он также занимает много ресурсов.Хотите знать, как его использовать? С нетерпением жду следующего выпуска.