-
-
Notifications
You must be signed in to change notification settings - Fork 36
/
Copy pathlsp.lua
181 lines (160 loc) · 5.16 KB
/
lsp.lua
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
local actions = require("crates.actions")
local util = require("crates.util")
local state = require("crates.state")
local completion = require("crates.completion.common")
local popup = require("crates.popup")
local M = {
id = nil,
}
---@class ServerOpts
---@field capabilities table
---@field handlers table<string,fun(method: string, params: any, callback: function)>
---@field on_request fun(method: string, params: any)?
---@field on_notify fun(method: string, params: any)?
---@class CodeAction
---@field title string
---@field kind string
---@field action function
---@class Command
---@field title string
---@field command string
---@field arguments function[]
---@param opts ServerOpts
---@return function
function M.server(opts)
opts = opts or {}
local capabilities = opts.capabilities or {}
local on_request = opts.on_request or function(_, _) end
local on_notify = opts.on_notify or function(_, _) end
local handlers = opts.handlers or {}
return function(dispatchers)
local closing = false
local srv = {}
local request_id = 0
---@param method string
---@param params any
---@param callback fun(method: string?, params: any)
---@return boolean
---@return integer
function srv.request(method, params, callback)
pcall(on_request, method, params)
local handler = handlers[method]
if handler then
handler(method, params, callback)
elseif method == "initialize" then
callback(nil, {
capabilities = capabilities,
})
elseif method == "shutdown" then
callback(nil, nil)
end
request_id = request_id + 1
return true, request_id
end
---@param method string
---@param params any
function srv.notify(method, params)
pcall(on_notify, method, params)
if method == "exit" then
dispatchers.on_exit(0, 15)
end
end
---@return boolean
function srv.is_closing()
return closing
end
function srv.terminate()
closing = true
end
return srv
end
end
-- The default Neovim reuse_client function checks root_dir,
-- which is not used or needed by our LSP client.
--
-- So just check the client name.
--
--- @param client vim.lsp.Client
--- @param config vim.lsp.ClientConfig
--- @return boolean
local function reuse_client(client, config)
return client.name == config.name
end
function M.start_server()
local CRATES_COMMAND = "crates_command"
local commands = {
---@param cmd Command
---@param ctx table<string,any>
[CRATES_COMMAND] = function(cmd, ctx)
local action = cmd.arguments[1]
if action then
vim.api.nvim_buf_call(ctx.bufnr, action)
else
util.notify(vim.log.levels.INFO, "Action not available")
end
end,
}
local server = M.server({
capabilities = {
codeActionProvider = state.cfg.lsp.actions,
completionProvider = state.cfg.lsp.completion and {
triggerCharacters = completion.trigger_characters(),
},
hoverProvider = state.cfg.lsp.hover,
},
handlers = {
---@param _method string
---@param _params any
---@param callback fun(err: nil, actions: lsp.CodeAction[])
["textDocument/codeAction"] = function(_method, _params, callback)
local code_actions = {}
for _, action in ipairs(actions.get_actions()) do
table.insert(code_actions, {
title = action.name,
kind = "refactor.rewrite",
command = {
title = action.name,
command = CRATES_COMMAND,
arguments = { action.action },
},
})
end
callback(nil, code_actions)
end,
---@param _method string
---@param _params any
---@param callback fun(err: nil, items: CompletionList?)
["textDocument/completion"] = function(_method, _params, callback)
completion.complete(function(items)
callback(nil, items)
end)
end,
["textDocument/hover"] = popup.show,
},
on_exit = function(_code, _signal, client_id)
if M.id == client_id then
vim.lsp.stop_client(client_id)
end
end,
})
local buf = util.current_buf()
local client_id = vim.lsp.start({
name = state.cfg.lsp.name,
cmd = server,
commands = commands,
}, {
bufnr = buf,
reuse_client = reuse_client,
})
if client_id then
M.id = client_id
else
return
end
local client = vim.lsp.get_client_by_id(client_id)
if not client then
return
end
state.cfg.lsp.on_attach(client, buf)
end
return M