Как эти полезные плагины VS Code повышают эффективность кодирования?

внешний интерфейс JavaScript
Как эти полезные плагины VS Code повышают эффективность кодирования?

существуетпредыдущий постУ нас уже есть предварительное представление и понимание плагина 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. Хотя его функция очень мощная, это как обоюдоострый меч, и он также занимает много ресурсов.Хотите знать, как его использовать? С нетерпением жду следующего выпуска.