1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
func initLSPClient(ctx context.Context, svr io.ReadWriteCloser, dir DocumentURI, verbose bool) (*LSPClient, error) {
// 创建 LSP 请求处理器(自定义的 handler,用于接收和处理 LSP 服务端发来的消息)
h := newLSPHandler()
// 将 LSP 服务端的连接封装成 JSON-RPC2 流,指定 VSCode 兼容的对象编解码器
stream := jsonrpc2.NewBufferedStream(svr, jsonrpc2.VSCodeObjectCodec{})
// 创建 JSON-RPC2 连接对象,绑定上下文、数据流和消息处理器
conn := jsonrpc2.NewConn(ctx, stream, h)
// 封装为自定义的 LSPClient 结构体(包含连接和消息处理器)
cli := &LSPClient{Conn: conn, lspHandler: h}
// 根据 verbose 参数决定 trace 日志等级
trace := "off"
if verbose {
trace = "verbose"
}
// 客户端声明支持的能力(Capabilities)
// 这里显式开启 documentSymbol 的分层符号支持(hierarchicalDocumentSymbolSupport)
cs := map[string]interface{}{
"documentSymbol": map[string]interface{}{
"hierarchicalDocumentSymbolSupport": true,
},
}
// 构造 LSP 初始化请求参数
initParams := initializeParams{
ProcessID: os.Getpid(), // 当前客户端进程 ID
RootURI: lsp.DocumentURI(dir), // 项目的根目录 URI
Capabilities: cs, // 客户端支持的功能
Trace: lsp.Trace(trace), // Trace 日志等级
ClientInfo: lsp.ClientInfo{Name: "vscode"}, // 模拟 VSCode 客户端
}
// 保存初始化结果
var initResult initializeResult
// 发送 "initialize" 请求给 LSP 服务端,并等待响应
if err := conn.Call(ctx, "initialize", initParams, &initResult); err != nil {
return nil, err
}
// 解析服务端返回的 capabilities(能力声明)
vs, ok := initResult.Capabilities.(map[string]interface{})
if !ok || vs == nil {
return nil, fmt.Errorf("invalid server capabilities: %v", initResult.Capabilities)
}
// 检查服务端是否支持 definitionProvider(跳转到定义)
definitionProvider, ok := vs["definitionProvider"].(bool)
if !ok || !definitionProvider {
return nil, fmt.Errorf("server did not provide Definition")
}
// 检查是否支持 typeDefinitionProvider(跳转到类型定义)
typeDefinitionProvider, ok := vs["typeDefinitionProvider"].(bool)
if !ok || !typeDefinitionProvider {
return nil, fmt.Errorf("server did not provide TypeDefinition")
}
// 检查是否支持 documentSymbolProvider(文档符号)
documentSymbolProvider, ok := vs["documentSymbolProvider"].(bool)
if !ok || !documentSymbolProvider {
return nil, fmt.Errorf("server did not provide DocumentSymbol")
}
// 检查是否支持 referencesProvider(查找引用)
referencesProvider, ok := vs["referencesProvider"].(bool)
if !ok || !referencesProvider {
return nil, fmt.Errorf("server did not provide References")
}
// 检查是否支持 semanticTokensProvider(语义高亮)
semanticTokensProvider, ok := vs["semanticTokensProvider"].(map[string]interface{})
if !ok || semanticTokensProvider == nil {
return nil, fmt.Errorf("server did not provide SemanticTokensProvider")
}
// 检查是否支持按范围返回语义 token(range 模式)
semanticTokensRange, ok := semanticTokensProvider["range"].(bool)
cli.hasSemanticTokensRange = ok && semanticTokensRange
// 获取 semanticTokensProvider 的 legend(语义 token 类型和修饰符)
legend, ok := semanticTokensProvider["legend"].(map[string]interface{})
if !ok || legend == nil {
return nil, fmt.Errorf("server did not provide SemanticTokensProvider.legend")
}
// 获取 tokenTypes(token 类型列表)
tokenTypes, ok := legend["tokenTypes"].([]interface{})
if !ok || tokenTypes == nil {
return nil, fmt.Errorf("server did not provide SemanticTokensProvider.legend.tokenTypes")
}
// 获取 tokenModifiers(token 修饰符列表)
tokenModifiers, ok := legend["tokenModifiers"].([]interface{})
if !ok || tokenModifiers == nil {
return nil, fmt.Errorf("server did not provide SemanticTokensProvider.legend.tokenModifiers")
}
// 将 tokenTypes 保存到客户端
for _, t := range tokenTypes {
cli.tokenTypes = append(cli.tokenTypes, t.(string))
}
// 将 tokenModifiers 保存到客户端
for _, m := range tokenModifiers {
cli.tokenModifiers = append(cli.tokenModifiers, m.(string))
}
// 向服务端发送 "initialized" 通知,表明客户端初始化完成
if err := conn.Notify(ctx, "initialized", lsp.InitializeParams{}); err != nil {
return nil, err
}
return cli, nil
}
|