Skip to content

Commit 171bb38

Browse files
committed
new article: LSP
1 parent 5f256bb commit 171bb38

File tree

3 files changed

+70
-0
lines changed

3 files changed

+70
-0
lines changed

2022/08/lsp.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# [LSP](/2022/08/lsp.md)
2+
3+
## transport
4+
5+
通信方式一般是父子进程管道(较少情况用 socket),IDE 作为父进程启动 lsp server 通过管道进行父子进程双向通信
6+
7+
通信消息类似 HTTP 先传 header 后传 body(json), 通过 header 的 content-length 来分割消息/确定消息边界
8+
9+
所以在 rust-lang/rls 源码 rls/src/server/io.rs 的 `fn read_message`
10+
11+
会先 BufReader::lines 逐个读出 header 并找到 header 跟 body 之间的空行分割,
12+
13+
最后通过从 header 中获取到的 json 消息长度调用 read_exact 一次读完 body(json)
14+
15+
通过 content-length 进行消息分割读 json 显然比 serde_json::de::from_reader 通过花括号去匹配分割消息性能上会好很多
16+
17+
## LSP json 消息分类
18+
19+
LSP 消息 json 的详细结构及序列化可以看微软或者 rust-analyzer 源码 lsp-server 模块的 `struct Message` 定义
20+
21+
- Request: 大部分是客户端请求,少部分是服务端向客户端请求(例如 CodeLensRefresh)
22+
- Response: 一发一回一个 req 就一定有一个 rsp
23+
- Notification: 例如客户端编辑了某个文件给服务端通知下
24+
25+
## LSP 消息核心概念
26+
27+
### RequestId
28+
29+
由于客户端服务端只有一个 Stdio/pipe 作为信道,如果客户端一次发多条 Request 消息,
30+
31+
通过 RequestId 机制才能知道当前服务端返回的 json 是哪个请求 Id 对应的 Response
32+
33+
这样服务端因不同请求处理时间对多条请求返回的顺序是乱序时,客户端也能清楚知道那个响应消息对应了哪个请求消息
34+
35+
因此类似 TCP 的 ack 双方必须保证每个请求的 RequestId 都不一样
36+
37+
### ProgressToken
38+
39+
一些耗时很长的查询操作例如 find all reference 可以选择流式传输【一发多回】
40+
41+
这时候可以在请求参数加上 progress_token 让服务端找到一个 reference 就返回一个
42+
43+
### request cancel
44+
45+
LSP 的每个请求都能被 cancel, 由于 Rust 的 async cancel 基本很难用
46+
47+
加上 LSP 本身吃 CPU 不吃 IO 所以 rust-analyzer 和 rust-lang/rls 都没有用异步操作
48+
49+
---
50+
51+
## LSP 建立连接的时序图
52+
53+
跟 TCP 建立连接的三次握手过程类似
54+
55+
1. client->server: InitializeRequest
56+
2. server->client: InitializeResponse
57+
3. client->server: InitializedNotification
58+
59+
## LSP 关闭连接的时序图
60+
61+
跟 TCP 关闭连接的四次挥手过程相似
62+
63+
server/client 收到 Shutdown 后就会拒绝后续的任何请求了
64+
65+
1. client->server: ShutdownRequest
66+
2. server->client: ShutdownResponse (rust-analyzer server 不会发这条消息)
67+
3. client->server: ExitNotification

2022/08/vscode_go_tools.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
<https://github.com/golang/vscode-go/wiki/tools#goplay>
66

7+
archlinux 有个 go-tools 的包有另一些官方工具,本文介绍的工具则是 vscode Go 插件建议安装的工具
8+
79
```
810
go: /usr/bin/go: go version go1.19 linux/amd64
911

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
- [文章列表 - 吴翱翔的博客](/)
22
- **2022-08**
3+
- [LSP](/2022/08/lsp.md)
34
- [go tools](/2022/08/vscode_go_tools.md)
45
- [Stream::try_clone](/2022/08/stream_try_clone.md)
56
- [牙髓血运重建术](/2022/08/revascularization_procedure.md)

0 commit comments

Comments
 (0)