LSP 实现细节 (LSP Implementation)

OpenCode 的 Language Server Protocol 客户端实现。


1. 概览

  • 路径: packages/opencode/src/lsp/
  • 定位: LSP 客户端,提供代码智能功能
  • 核心职责:
    • 管理语言服务器生命周期
    • 提供代码补全、跳转、诊断等功能
    • 将 LSP 能力暴露为工具

2. 支持的功能

功能说明工具名
Hover获取类型信息lsp_hover
Goto Definition跳转到定义lsp_goto_definition
Find References查找引用lsp_find_references
Diagnostics获取错误和警告lsp_diagnostics
Code Actions获取快速修复lsp_code_actions
Rename重命名符号lsp_rename

3. LSP 工具实现

// src/tool/lsp.ts
export const LspTool: Tool.Info = {
  id: "lsp",
  init: async (initCtx) => ({
    description: "LSP 代码智能功能",
    parameters: z.object({
      operation: z.enum(["hover", "goto_definition", "find_references"]),
      filePath: z.string(),
      line: z.number(),
      character: z.number()
    }),
    
    async execute(args, ctx) {
      const lspClient = await LSP.getClient(args.filePath)
      
      switch (args.operation) {
        case "hover":
          return await lspClient.hover({
            filePath: args.filePath,
            position: { line: args.line, character: args.character }
          })
        
        case "goto_definition":
          return await lspClient.gotoDefinition({
            filePath: args.filePath,
            position: { line: args.line, character: args.character }
          })
        
        case "find_references":
          return await lspClient.findReferences({
            filePath: args.filePath,
            position: { line: args.line, character: args.character }
          })
      }
    }
  })
}

4. LSP 客户端管理

// src/lsp/client.ts
export namespace LSP {
  // 每个文件类型对应一个 LSP Server
  const clients = new Map<string, LSPClient>()
  
  export async function getClient(filePath: string): Promise<LSPClient> {
    const fileType = getFileType(filePath)
    
    if (clients.has(fileType)) {
      return clients.get(fileType)!
    }
    
    // 启动新的 LSP Server
    const client = await startLSPServer(fileType)
    clients.set(fileType, client)
    
    return client
  }
  
  async function startLSPServer(fileType: string): Promise<LSPClient> {
    const config = LSP_SERVER_CONFIGS[fileType]
    
    const server = spawn(config.command, config.args)
    const client = new LSPClient(server)
    
    await client.initialize()
    
    return client
  }
}

5. 配置

const LSP_SERVER_CONFIGS = {
  typescript: {
    command: "typescript-language-server",
    args: ["--stdio"]
  },
  python: {
    command: "pylsp",
    args: []
  },
  rust: {
    command: "rust-analyzer",
    args: []
  }
}

6. 相关文档