Skip to content

编辑器与开发协议学习笔记

100 天认知提升计划 | Day 1


目录


第一部分:LSP 语言服务器协议

LSP 概述

什么是 LSP

LSP (Language Server Protocol) 是微软开发的通信协议,现已成为业界标准。它解决了编辑器对编程语言支持的重复开发问题。

核心价值:从 N×M 到 N+M

传统模式LSP 模式
N 个编辑器 × M 种语言 = N×M 个实现N 个编辑器 + M 个语言服务器 = N+M 个实现

提供的能力

功能说明
代码补全Autocomplete
跳转到定义Go to Definition
查找引用Find References
悬停提示Hover Information
代码诊断Diagnostics
重命名重构Rename Symbol
代码格式化Formatting

常见语言服务器

语言服务器
TypeScripttypescript-language-server
Gogopls
Rustrust-analyzer
Pythonpylsp、pyright

通信原理

架构图

┌─────────────┐      LSP (JSON-RPC)      ┌─────────────────┐
│   编辑器     │  ◄────────────────────►  │    语言服务器    │
│ (VS Code等) │   请求/响应/通知          │ (tsserver/gopls)│
│             │                          │                 │
│   • UI      │                          │   • 代码分析     │
│   • 文本编辑 │                          │   • 语法解析     │
│   • 渲染    │                          │   • 类型推断     │
└─────────────┘                          └─────────────────┘

解耦设计

  • 编辑器(客户端):只负责 UI 和文本编辑
  • 语言服务器(服务端):负责代码分析、智能提示等
  • 通信协议:JSON-RPC 2.0

JSON-RPC 消息格式

LSP/DAP 基于 JSON-RPC 2.0,有三种消息类型:

1. Request / Response(请求-响应)

请求示例:编辑器请求补全

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "textDocument/completion",
  "params": {
    "textDocument": { "uri": "file:///path/to/file.ts" },
    "position": { "line": 5, "character": 10 }
  }
}

响应示例:服务器返回补全列表

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "items": [
      { "label": "console", "kind": 3, "detail": "var console: Console" },
      { "label": "const", "kind": 14, "detail": "keyword" }
    ]
  }
}

2. Notification(通知,单向)

编辑器通知服务器文件已打开

json
{
  "jsonrpc": "2.0",
  "method": "textDocument/didOpen",
  "params": {
    "textDocument": {
      "uri": "file:///path/to/file.ts",
      "languageId": "typescript",
      "version": 1,
      "text": "const x = 1;"
    }
  }
}

服务器通知编辑器有错误

json
{
  "jsonrpc": "2.0",
  "method": "textDocument/publishDiagnostics",
  "params": {
    "uri": "file:///path/to/file.ts",
    "diagnostics": [
      {
        "range": { "start": {"line": 0, "character": 8}, "end": {"line": 0, "character": 9} },
        "severity": 1,
        "message": "Cannot find name 'x'"
      }
    ]
  }
}

消息类型对比

类型字段特征是否需要响应典型场景
Requestid✅ 是获取补全、跳转定义
Responseidresult-返回请求结果
Notificationid❌ 否文件变更、错误通知

开发 LSP 服务器

技术选型

语言推荐框架
TypeScriptvscode-languageserverlangium
Pythonpygls
Gogopls/langserver
Rusttower-lsp

最小实现示例(Python + pygls)

python
from pygls.server import LanguageServer
from pygls.lsp import CompletionItem, CompletionItemKind

# 创建服务器实例
server = LanguageServer()

# 注册补全处理器
@server.feature("textDocument/completion")
def completions(params):
    return [
        CompletionItem(label="hello", kind=CompletionItemKind.Text),
        CompletionItem(label="world", kind=CompletionItemKind.Text),
    ]

# 启动服务器
server.start_io()

开发流程

┌─────────────┐     ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│ 定义语言能力 │ ──► │ 实现处理器   │ ──► │  测试验证   │ ──► │  打包发布   │
│ (capabilities)│     │ (handlers)  │     │ (VS Code等) │     │ (npm/pip)   │
└─────────────┘     └─────────────┘     └─────────────┘     └─────────────┘

必须实现的基础能力

方法说明优先级
initialize返回服务器能力🔴 必须
initialized客户端初始化完成通知🔴 必须
shutdown关闭请求🔴 必须
textDocument/didOpen文档打开🟡 高
textDocument/didChange文档变更🟡 高
textDocument/completion代码补全🟡 高

第二部分:DAP 调试适配器协议

DAP 概述

什么是 DAP

DAP (Debug Adapter Protocol) 与 LSP 师出同门,解决编辑器对调试器支持的重复开发问题。

常见 Debug Adapter

语言/环境Debug Adapter
Godelve
Pythondebugpy
Node.jsnode-debug2
C++cpptools (gdb/lldb)
Rustlldb-dap / codelldb

与 LSP 的关系

类比关系

LSPDAP
代码编辑支持调试支持
Language ServerDebug Adapter
补全、跳转、诊断断点、单步、变量查看

DAP 工作原理

┌─────────────┐      DAP (JSON-RPC)      ┌─────────────────┐
│   编辑器     │  ◄────────────────────►  │   Debug Adapter  │
│ (VS Code等) │   请求/响应/事件          │ (gdb/lldb/dlv)   │
│             │                          │                 │
│   • 断点 UI │                          │   • 控制执行     │
│   • 变量面板 │                          │   • 读取内存     │
│   • 调用栈  │                          │   • 单步执行     │
└─────────────┘                          └────────┬────────┘


                                          ┌─────────────────┐
                                          │    被调试程序     │
                                          │  (目标进程)      │
                                          └─────────────────┘

调试流程

核心功能

功能说明
断点管理设置/删除断点,支持条件断点
步进控制Step Over、Step Into、Step Out
堆栈追踪查看调用栈,在栈帧间切换
变量查看局部变量、监视表达式、求值
异常处理捕获异常时暂停

调试流程图

     启动阶段
┌─────────────────────────────────────────────────┐
│ launch/attach → initialize → setBreakpoints      │
│           ↓                                      │
│    configurationDone                             │
└─────────────────────────────────────────────────┘


              调试循环
┌─────────────────────────────────────────────────┐
│ continue → stopped事件 → 查看状态 → step/continue │
│     ↑                                    ↓      │
│     └──────────────── 循环 ←──────────────┘      │
└─────────────────────────────────────────────────┘

远程调试

架构示意

本地开发环境                    远程服务器
    │                              │
    │  DAP over TCP/SSH           │
    ├─────────────────────────────►│
    │                          ┌───┴───┐
    │                          │  DAP   │
    │                          │ Server │
    │                          └───┬───┘
    │                          ┌───┴────┐
    │                          │ Target │
    │                          │  程序   │
    │                          └────────┘

两种模式

模式说明使用场景
attach连接到已运行的远程进程程序已在服务器运行
remote launch启动远程程序并调试从本地启动远程程序

VS Code 配置示例

json
{
  "type": "python",
  "request": "attach",
  "name": "Remote Attach",
  "connect": { "host": "remote-server.com", "port": 5678 },
  "pathMappings": [
    { "localRoot": "${workspaceFolder}", "remoteRoot": "/app" }
  ]
}

关键配置项

配置作用
connect.host远程服务器地址
connect.portDAP Server 监听端口
pathMappings本地路径 ↔ 远程路径映射
reverseListen反向连接(远程主动连接本地)

远程调试三步走

Step 1: 远程启动 DAP Server
└─▪ debugpy --listen 0.0.0.0:5678 --wait-for-client

Step 2: 本地 SSH 隧道转发(可选)
└─▪ ssh -L 5678:localhost:5678 user@remote

Step 3: 编辑器连接
└─▪ attach 到 localhost:5678

第三部分:实践与思考

实践记录

LSP 配置

  • [ ] 安装 Neovim 0.10+
  • [ ] 配置主要语言的 LSP(Go/Python/TypeScript)
  • [ ] 测试代码补全、跳转定义、悬停提示

DAP 配置

  • [ ] 安装 nvim-dap
  • [ ] 安装对应语言的 Debug Adapter
  • [ ] 测试断点、单步执行、变量查看

疑问与思考

已解答

  1. ✅ LSP 使用 JSON-RPC 通信,具体的消息格式是怎样的?
  2. ✅ 如何为一种新语言开发 LSP 服务器?
  3. ✅ LSP 和 DAP 的关系是什么?
  4. ✅ DAP 如何处理远程调试场景?

待探索

  1. ❓ 如何为自定义调试器开发 DAP Adapter?
  2. ❓ DAP 与 CRIU (Checkpoint/Restore) 结合可以实现进程快照调试吗?

更新日期:2026-02-10

用 ❤️ 和 AI 辅助学习