前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >开源Tabby 原理解析,看完后的你:然来咱也能自己做一个 GitHub Copilot

开源Tabby 原理解析,看完后的你:然来咱也能自己做一个 GitHub Copilot

原创
作者头像
老码小张
发布2025-01-25 15:14:28
发布2025-01-25 15:14:28
9400
代码可运行
举报
文章被收录于专栏:玩转全栈玩转全栈
运行总次数:0
代码可运行

最近,我一直在用 Tabby[1] 搭配 VSCode 写代码,尤其是它的内联补全功能,真是越用越上瘾。今天,我想跟大家聊聊 Tabby 在 VSCode 中是如何实现内联代码补全的,这背后有一些挺有意思的技术细节。

图片
图片

Tabby 的内核在哪?

内联补全的核心实现是在 InlineCompletionProvider[2] 这个类中。它实现了 VSCode 提供的 InlineCompletionItemProvider 接口,负责处理所有内联补全的逻辑。

简单来说,Tabby 的这个组件有几个关键任务:

  1. 1. 接收用户的输入(比如你打代码@的时候触发补全)。
  2. 2. 把这些信息包装成补全请求,发送给 Tabby Agent。
  3. 3. 拿到 Agent 的补全建议后,再转换成 VSCode 能识别的格式显示出来。

它的核心代码逻辑长这样:

代码语言:javascript
代码运行次数:0
复制
async provideInlineCompletionItems(
document: TextDocument,
position: Position,
context: InlineCompletionContext,
token: CancellationToken,
): Promise<InlineCompletionItem[] | null> {
try {
    // 记录编辑器状态
    this.client.fileTrack.addingChangeEditor(window.activeTextEditor);

    // 发起请求
    const request = this.client.languageClient.sendRequest(
      InlineCompletionRequest.method,
      params,
      token
    );
    this.ongoing = request;
    this.emit("didChangeLoading", true); // 开始加载状态

    const result = awaitthis.ongoing;
    this.ongoing = null;
    this.emit("didChangeLoading", false); // 加载完成

    if (!result || result.items.length === 0 || token.isCancellationRequested) {
      returnnull;
    }

    // 转换补全项为 VSCode 支持的格式
    return result.items.map((item, index) => {
      returnnewInlineCompletionItem(
        typeof item.insertText === "string"
          ? item.insertText
          : newSnippetString(item.insertText.value),
        item.range
          ? newRange(
              item.range.start.line,
              item.range.start.character,
              item.range.end.line,
              item.range.end.character,
            )
          : undefined,
        {
          title: "",
          command: "tabby.applyCallback",
          arguments: [
            () => {
              this.handleEvent("accept", result, index);
            },
          ],
        },
      );
    });
  } catch (error) {
    this.ongoing = null;
    this.emit("didChangeLoading", false); // 出错后恢复状态
    returnnull;
  }
}

补全的背后都发生了什么?

1. 怎么触发补全?

补全分两种触发方式:

  • • 自动触发:比如你正在写代码,输入了一部分后,Tabby 会自动弹出补全建议。这种方式在默认情况下是开启的。
  • • 手动触发:通过快捷键调用,比如按下 Ctrl+Space

触发的模式由 Tabby 的 triggerMode 配置项控制,你可以根据需要设置为 automatic 或 manual

2. Tabby Agent 的角色

Tabby 的 VSCode 扩展和 Tabby Agent 是通过 LSP(Language Server Protocol)通信的。Agent 在这里扮演了一个桥梁角色:

  1. 1. 上下文分析:Agent 会分析你当前代码的上下文,比如你当前光标在哪,周围的代码长什么样。
  2. 2. 请求处理:扩展会将你的输入发送到 Agent,Agent 会将它转发给 Tabby 的服务器。
  3. 3. 补全生成:服务器返回补全建议,Agent 再把这些数据返回给扩展。

可以简单画个流程图说明整个过程:

图片
图片

补全结果是怎么处理的?

从服务器返回的补全结果可能包含多个建议,Tabby 会把它们转换成 VSCode 支持的 InlineCompletionItem 格式。每个补全项包含以下内容:

  1. 1. 插入文本(insertText):这是补全的核心内容。
  2. 2. 替换范围(range):如果你的补全需要替换掉某部分已有代码,这里会指定具体范围。
  3. 3. 回调命令:补全被用户接受时触发的事件,比如统计你接受了哪个补全。

代码是这样处理的:

代码语言:javascript
代码运行次数:0
复制
return result.items.map((item, index) => {
returnnewInlineCompletionItem(
    typeof item.insertText === "string" ? item.insertText : newSnippetString(item.insertText.value),
    item.range
      ? newRange(
          item.range.start.line,
          item.range.start.character,
          item.range.end.line,
          item.range.end.character,
        )
      : undefined,
    {
      title: "",
      command: "tabby.applyCallback",
      arguments: [
        () => {
          this.handleEvent("accept", result, index);
        },
      ],
    },
  );
});

补全事件追踪

Tabby 的补全系统还内置了一个事件追踪功能。通过这些事件,Tabby 可以知道你是如何与补全交互的:

  • • show:补全被显示时触发。
  • • accept:你点击了补全建议时触发。
  • • dismiss:你关闭了补全框,没有选任何建议。
  • • accept_word:你接受了一个单词补全。
  • • accept_line:你接受了整行补全。

性能优化

  1. 1. 请求防抖 为了避免你快速输入代码时频繁发送请求,Tabby 使用了防抖机制。如果上一个请求还没完成,就会取消掉旧的请求。
  2. 2. 结果缓存 如果你的输入环境没有变化,Tabby 会直接返回缓存的补全结果,省去了重新请求的时间。

Tabby 和同类工具的对比

最后我们简单看看 Tabby 和其他类似工具的区别:

工具

内联补全

自动触发

支持多语言

性能优化

事件追踪

Tabby

Copilot

Codeium


一些思考

Tabby 的内联补全功能,不仅提升了编程效率,还在用户体验上下了不少功夫。从核心架构到事件追踪,再到性能优化,每个环节都设计得相当用心。对开发者来说,它确实是一款值得尝试的工具。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Tabby 的内核在哪?
  • 补全的背后都发生了什么?
    • 1. 怎么触发补全?
    • 2. Tabby Agent 的角色
  • 补全结果是怎么处理的?
  • 补全事件追踪
  • 性能优化
  • Tabby 和同类工具的对比
  • 一些思考
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档