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

在VS Code中并行运行SCIP自定义补全与TS语言服务的方案问询

解决方案:利用VS Code的isIncomplete属性实现并行补全展示

要实现先展示SCIP的快速补全,再合并TS语言服务的结果,核心是利用VS Code的CompletionList.isIncomplete属性,结合异步更新补全列表的机制。以下是具体实现思路和代码示例:

核心原理

VS Code允许补全提供者返回标记为isIncomplete: true的CompletionList,此时编辑器会先展示当前返回的补全项,同时保持补全菜单处于"加载中"状态,等待后续的补全更新。你可以利用这一点:

  1. 先快速返回SCIP的补全结果,标记为isIncomplete: true
  2. 在后台异步获取TS的补全结果
  3. 合并两者结果后,更新补全列表并标记为isIncomplete: false

具体实现步骤

1. 注册SCIP补全提供者

确保提供者的触发字符与TS语言服务一致(如., :等),保证能同时触发两者的补全逻辑。

2. 异步返回并更新补全列表

在provideCompletionItems方法中,先返回SCIP的结果,再异步获取TS结果并合并更新。

import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
  const scipCompletionProvider = vscode.languages.registerCompletionItemProvider(
    ['typescript', 'typescriptreact'],
    {
      async provideCompletionItems(doc: vscode.TextDocument, pos: vscode.Position) {
        // 1. 快速查询SCIP索引,获取补全项
        const scipItems = await fetchSCIPCompletions(doc, pos);
        
        // 2. 返回标记为未完成的补全列表,让VS Code先展示SCIP结果
        const initialList = new vscode.CompletionList(scipItems, true);
        
        // 3. 异步获取TS语言服务的补全结果,不阻塞初始返回
        process.nextTick(async () => {
          try {
            // 获取TS的补全结果(模拟TS服务的触发条件)
            const triggerChar = getTriggerCharacter(doc, pos);
            const tsItems = await vscode.languages.getCompletionItems(doc, pos, { triggerCharacter: triggerChar });
            
            // 4. 合并补全项,去重(SCIP项优先级高于TS)
            const mergedItems = mergeCompletions(scipItems, tsItems);
            
            // 5. 更新补全列表,标记为已完成
            vscode.languages.setTextDocumentCompletionItems(doc, new vscode.CompletionList(mergedItems, false));
          } catch (err) {
            // 处理TS服务异常,保持SCIP结果并标记为完成
            vscode.languages.setTextDocumentCompletionItems(doc, new vscode.CompletionList(scipItems, false));
          }
        });
        
        return initialList;
      }
    },
    '.', ':' // 与TS一致的触发字符
  );

  context.subscriptions.push(scipCompletionProvider);
}

// 模拟SCIP索引查询逻辑
async function fetchSCIPCompletions(doc: vscode.TextDocument, pos: vscode.Position): Promise<vscode.CompletionItem[]> {
  // 替换为你的SCIP索引查询代码
  return [
    new vscode.CompletionItem('SCIPGeneratedFunction', vscode.CompletionItemKind.Function),
    new vscode.CompletionItem('SCIPGeneratedClass', vscode.CompletionItemKind.Class)
  ];
}

// 获取触发补全的字符(用于匹配TS服务的触发条件)
function getTriggerCharacter(doc: vscode.TextDocument, pos: vscode.Position): string | undefined {
  const prevRange = new vscode.Range(pos.translate(0, -1), pos);
  const prevChar = doc.getText(prevRange);
  return ['/', '.', ':'].includes(prevChar) ? prevChar : undefined;
}

// 合并补全项,去重逻辑可自定义
function mergeCompletions(scipItems: vscode.CompletionItem[], tsItems: vscode.CompletionItem[]): vscode.CompletionItem[] {
  const itemMap = new Map<string, vscode.CompletionItem>();
  
  // 先添加SCIP项,确保优先级
  scipItems.forEach(item => itemMap.set(item.label.toString(), item));
  
  // 添加TS项,不覆盖已有的SCIP项
  tsItems.forEach(item => {
    const key = item.label.toString();
    if (!itemMap.has(key)) itemMap.set(key, item);
  });
  
  return Array.from(itemMap.values());
}

为什么之前的方案无效?

  • 直接使用CompletionItemProvider合并:如果你的实现是同步等待TS结果后再返回,自然会被TS的慢响应阻塞,无法先展示SCIP结果。
  • TS语言服务插件:插件运行在TS语言服务的内部流程中,必须等待TS自身的补全逻辑完成后才能返回结果,无法实现真正的并行。

类似实践案例

  • GitHub Copilot:先返回AI生成的补全结果,后台异步获取本地语言服务的补全,合并后更新补全菜单,用户会先看到AI建议,后续本地补全逐步加载。
  • Tabnine:同样基于isIncomplete机制,先展示AI补全,再合并本地语言服务的结果,实现快结果优先的体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 11:13:15