You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VSCode扩展开发:如何获取用户选中的CompletionItem信息?

解决VSCode扩展中监听补全项选中事件的问题

我明白你遇到的痛点了——resolveCompletionItem的触发时机确实容易让人误解,它是在补全列表渲染前就被调用,用来提前完善补全项的信息(比如添加上下文相关的文档),而不是等用户真正选中某一项时才触发。要精准捕获用户选中并插入补全项的动作,这里有两种可靠的实现方案:

方案一:利用CompletionItem的command属性(推荐)

这是VSCode官方设计的、最直接的补全项选中回调方式。我们可以给每个补全项绑定一个自定义命令,当用户选中该补全项时,会自动执行这个命令,同时把对应的CompletionItem作为参数传递进去。

import * as vscode from 'vscode';

class FuncCompletionProvider implements vscode.CompletionItemProvider {
    provideCompletionItems(
        document: vscode.TextDocument,
        position: vscode.Position,
        token: vscode.CancellationToken,
        context: vscode.CompletionContext
    ): vscode.ProviderResult<vscode.CompletionItem[] | vscode.CompletionList<vscode.CompletionItem>> {
        const completionItems: vscode.CompletionItem[] = [];

        // 创建示例补全项
        const funcItem = new vscode.CompletionItem('customFunc', vscode.CompletionItemKind.Function);
        funcItem.insertText = 'customFunc(${1:param})';
        funcItem.detail = '自定义工具函数';
        
        // 绑定选中后执行的命令,把当前补全项作为参数传递
        funcItem.command = {
            command: 'extension.onCompletionSelected',
            title: '处理补全项选中事件',
            arguments: [funcItem]
        };

        completionItems.push(funcItem);
        return completionItems;
    }

    // 保留resolveCompletionItem用于预处理(比如添加文档),但它不是选中触发
    resolveCompletionItem(
        item: vscode.CompletionItem,
        token: vscode.CancellationToken
    ): vscode.ProviderResult<vscode.CompletionItem> {
        item.documentation = '这是一个用于XXX场景的自定义函数';
        return item;
    }
}

export function activate(context: vscode.ExtensionContext) {
    // 注册补全提供者
    const providerDisposable = vscode.languages.registerCompletionItemProvider(
        { scheme: 'file', language: 'typescript' }, // 替换为你的目标语言/选择器
        new FuncCompletionProvider(),
        '.'
    );

    // 注册处理选中事件的自定义命令
    const commandDisposable = vscode.commands.registerCommand(
        'extension.onCompletionSelected',
        (selectedItem: vscode.CompletionItem) => {
            // 这里就是用户选中补全项后的回调逻辑
            console.log('选中的补全项信息:', selectedItem);
            console.log('补全项标签:', selectedItem.label);
            console.log('插入文本:', selectedItem.insertText);
            // 在这里可以执行任何你需要的操作,比如统计用户使用习惯、触发后续逻辑等
        }
    );

    context.subscriptions.push(providerDisposable, commandDisposable);
}

方案二:监听文本编辑器选择变化(备选)

如果因为某些原因无法使用command属性,也可以通过监听编辑器的选择变化事件,结合补全项的缓存来匹配用户选中的内容。这种方法需要处理更多边界情况,但适合特殊场景:

import * as vscode from 'vscode';

class FuncCompletionProvider implements vscode.CompletionItemProvider {
    // 缓存最近一次提供的补全项列表,用于后续匹配
    public lastProvidedItems: vscode.CompletionItem[] | undefined;

    provideCompletionItems(
        document: vscode.TextDocument,
        position: vscode.Position,
        token: vscode.CancellationToken,
        context: vscode.CompletionContext
    ): vscode.ProviderResult<vscode.CompletionItem[] | vscode.CompletionList<vscode.CompletionItem>> {
        const items: vscode.CompletionItem[] = [];
        // 创建补全项逻辑...
        const item = new vscode.CompletionItem('anotherFunc', vscode.CompletionItemKind.Function);
        item.insertText = 'anotherFunc()';
        items.push(item);

        // 缓存补全项
        this.lastProvidedItems = items;
        return items;
    }
}

export function activate(context: vscode.ExtensionContext) {
    const provider = new FuncCompletionProvider();
    const providerDisposable = vscode.languages.registerCompletionItemProvider(
        { scheme: 'file', language: 'typescript' },
        provider,
        '.'
    );

    // 监听编辑器选择变化事件
    const selectionDisposable = vscode.window.onDidChangeTextEditorSelection(async (event) => {
        // 过滤掉非命令触发的选择变化(比如用户手动选中文本)
        if (event.kind === vscode.TextEditorSelectionChangeKind.Command) {
            const editor = event.textEditor;
            const position = editor.selection.active;
            const doc = editor.document;
            
            // 获取光标位置的单词,匹配缓存的补全项
            const wordRange = doc.getWordRangeAtPosition(position);
            if (wordRange && provider.lastProvidedItems) {
                const insertedText = doc.getText(wordRange);
                const matchedItem = provider.lastProvidedItems.find(
                    item => item.insertText === insertedText
                );
                
                if (matchedItem) {
                    console.log('选中的补全项(通过选择变化):', matchedItem);
                }
            }
        }
    });

    context.subscriptions.push(providerDisposable, selectionDisposable);
}

总结

  • 方案一(command属性)是官方推荐的方式,逻辑清晰、可靠性高,适合大多数场景。
  • 方案二适合无法使用命令的特殊场景,但需要处理文本匹配、缓存失效等边界问题。

内容的提问来源于stack exchange,提问作者Godon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 14:42:34