获取 vscode registerCompletionItemProvider 以在带有 `word.` 触发器的 json 文件中工作

Get vscode registerCompletionItemProvider to work in a json file with a `word.` trigger

我正在使用此代码尝试在我的扩展中注册 CompletionProvider。它本质上是示例 completionProvider 示例 https://github.com/microsoft/vscode-extension-samples/blob/master/completions-sample/src/extension.ts.

中的代码

我希望它由 .如“发射”。最终在 keybindings.json 中的扩展命令中,但它在任何 json 文件中什么都不做。没有任何反应,没有错误。

function activate(context) {

  loadLaunchSettings(context);
  activeContext = context;

  const configCompletionProvider = vscode.languages.registerCompletionItemProvider (
    { language: 'json', scheme: 'file' },   // tried scheme: 'untitled' too
    {
      // eslint-disable-next-line no-unused-vars
      provideCompletionItems(document, position, token, context) {

        // get all text until the `position` and check if it reads `"launches."`

        const linePrefix = document.lineAt(position).text.substr(0, position.character);
        if (!linePrefix.endsWith('\"launches.\"')) {  // tried without the escapes too
          return undefined;
        }

        return [
          new vscode.CompletionItem('log', vscode.CompletionItemKind.Text),
          new vscode.CompletionItem('warn', vscode.CompletionItemKind.Text),
          new vscode.CompletionItem('error', vscode.CompletionItemKind.Text),
        ];
      }
    },
    '.' // trigger
  );

  context.subscriptions.push(configCompletionProvider);
}

在此代码中:

  {
    "key": "alt+f",
    "command": "launches."   <= provider completion options here
  },

我找不到任何有用的东西,我认为我密切关注示例,但没有关于键入 "launches." 或使用 Ctrl+ 的完成建议Space 触发智能感知。

我有这个设置:

  "editor.quickSuggestions": {
    "comments": true,
    "other": true,
    "strings": true   // <===
  },

并且我尝试了此处提供的各种替代方案来解决类似问题:


仍然感到困惑 - 在 javascript 文件中工作,但在 json 文件中不工作。我需要做一些特别的事情才能让 . 在 json 文件中被识别为触发字符(除了如下所示将其列在 vscode.languages.registerCompletionItemProvider 中)吗?

我已将其精简为:

function activate(context) {

  loadLaunchSettings(context);
  activeContext = context;

  let docFilter = { scheme: 'file', language: 'json' };

  const configCompletionProvider = vscode.languages.registerCompletionItemProvider (
    // { language: 'json', pattern: './**/test.json' }, // does not work
    // 'javascript',                                    //  works
    // 'json',                                          // does not work
    docFilter,                                          // does not work
    {
       // eslint-disable-next-line no-unused-vars
      provideCompletionItems(document, position, token, context) {

        return [
          new vscode.CompletionItem('howdy1', vscode.CompletionItemKind.Text),
          new vscode.CompletionItem('howdy2', vscode.CompletionItemKind.Text),
          new vscode.CompletionItem('howdy3', vscode.CompletionItemKind.Text),
        ];
      }
    },
    "." // trigger
  );

    context.subscriptions.push(configCompletionProvider);
};
    

根据 关于什么是 JSON 中的单词的回答,整个字符串被认为是一个包含 " 个字符的单词。

如果您调整完成项应替换的范围,而不是在该位置查找当前单词,它就会起作用。

  context.subscriptions.push(vscode.languages.registerCompletionItemProvider (
    { language: 'json', scheme: 'file' },
    // 'json',
    {
      // eslint-disable-next-line no-unused-vars
      provideCompletionItems(document, position, token, context) {

        // get all text until the `position` and check if it reads `"launches.`

        const linePrefix = document.lineAt(position).text.substring(0, position.character);
        if (!linePrefix.endsWith('"launches.')) {
          return undefined;
        }
        let myitem = (text) => {
          let item = new vscode.CompletionItem(text, vscode.CompletionItemKind.Text);
          item.range = new vscode.Range(position, position);
          return item;
        }
        return [
          myitem('log'),
          myitem('warn'),
          myitem('error'),
        ];
      }
    },
    '.' // trigger
  ));

编辑:

同样有效但不好看的是

return [
  new vscode.CompletionItem('"launches.log"', vscode.CompletionItemKind.Text),
  new vscode.CompletionItem('"launches.warn"', vscode.CompletionItemKind.Text),
  new vscode.CompletionItem('"launches.error"', vscode.CompletionItemKind.Text),
];

编辑:

只是为了提供任何 . 类型的补全,我刚刚删除了 ..

前面的测试 (endsWith)

为了查看是否调用了完成提供程序,我在 return 和 CompletionItem 上放置了一个 LogPoint 断点。

CompletionItem 的文档非常简洁。

来自 CompletionItem 的文档:

It is sufficient to create a completion item from just a label. In that case the completion item will replace the word until the cursor with the given label or insertText. Otherwise the given edit is used.

虽然他们在正文中讨论了 edit,但 textEdit 文档告诉您它已被弃用,您需要使用 insertTextrange。但是 additionalTextEdits 并未弃用 (??)

range 属性 不是 很清楚 insertingreplacing 范围是如何使用的以及你的影响可以通过一定的方式设置来实现。

When omitted, the range of the current word is used as replace-range and as insert-range the start of the current word to the current position is used.

然后部分问题是 " 是 JSON 文件的单词的一部分。正如 Gamma11 指出的那样,如果您出于某种奇怪的原因将这些 " 添加到它在某些情况下起作用的标签中。设置相同内容的insertText不起作用,可能是因为默认的range选择不正确。

如果您自己设置 range,您可以绕过奇怪的默认行为。

因为我们想在光标位置插入新内容,只需将 range 设置为光标位置的空范围即可。

  context.subscriptions.push(vscode.languages.registerCompletionItemProvider (
    // { language: 'json', scheme: 'file' },
    'json',
    {
      // eslint-disable-next-line no-unused-vars
      provideCompletionItems(document, position, token, context) {
        let myitem = (text) => {
          let item = new vscode.CompletionItem(text, vscode.CompletionItemKind.Text);
          item.range = new vscode.Range(position, position);
          return item;
        }
        return [
          myitem('howdy1'),
          myitem('howdy2'),
          myitem('howdy3'),
        ];
      }
    },
    '.' // trigger
  ));