]> git.madduck.net Git - etc/vim.git/blob - lua/ale/lsp.lua

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Squashed '.vim/bundle/ale/' content from commit 22185c4c
[etc/vim.git] / lua / ale / lsp.lua
1 local module = {}
2
3 module.start = function(config)
4     -- Neovim's luaeval sometimes adds a Boolean key to table we need to remove.
5     if type(config.init_options) == "table"
6     and config.init_options[true] ~= nil
7     then
8         config.init_options[true] = nil
9     end
10
11     -- If configuring LSP via a socket connection, then generate the cmd
12     -- using vim.lsp.rpc.connect(), as defined in Neovim documentation.
13     if config.host then
14         local cmd_func = vim.lsp.rpc.connect(config.host, config.port)
15         config.host = nil
16         config.port = nil
17
18         -- Wrap the cmd function so we don't throw errors back to the user
19         -- if the connection to an address fails to start.
20         --
21         -- We will separately log in ALE that we failed to start a connection.
22         --
23         -- In older Neovim versions TCP connections do not function if supplied
24         -- a hostname instead of an address.
25         config.cmd = function(dispatch)
26             local success, result = pcall(cmd_func, dispatch)
27
28             if success then
29                 return result
30             end
31
32             return nil
33         end
34     end
35
36     config.handlers = {
37         -- Override Neovim's handling of diagnostics to run through ALE's
38         -- functions so all of the functionality in ALE works.
39         ["textDocument/publishDiagnostics"] = function(err, result, _, _)
40             if err == nil then
41                 vim.fn["ale#lsp_linter#HandleLSPDiagnostics"](
42                     config.name,
43                     result.uri,
44                     result.diagnostics
45                 )
46             end
47         end,
48         -- Handle pull model diagnostic data.
49         ["textDocument/diagnostic"] = function(err, result, request, _)
50             if err == nil then
51                 local diagnostics
52
53                 if result.kind == "unchanged" then
54                     diagnostics = "unchanged"
55                 else
56                     diagnostics = result.items
57                 end
58
59                 vim.fn["ale#lsp_linter#HandleLSPDiagnostics"](
60                     config.name,
61                     request.params.textDocument.uri,
62                     diagnostics
63                 )
64             end
65         end,
66         -- When the pull model is enabled we have to handle and return
67         -- some kind of data for a server diagnostic refresh request.
68         ["workspace/diagnostic/refresh"] = function()
69             return {}
70         end,
71     }
72
73     config.on_init = function(client, _)
74         -- Tell ALE about server capabilities as soon as we can.
75         -- This will inform ALE commands what can be done with each server,
76         -- such as "go to definition" support, etc.
77         vim.fn["ale#lsp#UpdateCapabilities"](
78             config.name,
79             client.server_capabilities
80         )
81
82         -- Neovim calls `on_init` before marking a client as active, meaning
83         -- we can't get a client via get_client_by_id until after `on_init` is
84         -- called. By deferring execution of calling the init callbacks we
85         -- can only call them after the client becomes available, which
86         -- will make notifications for configuration changes work, etc.
87         vim.defer_fn(function()
88             vim.fn["ale#lsp#CallInitCallbacks"](config.name)
89         end, 0)
90     end
91
92     config.get_language_id = function(bufnr, _)
93         return vim.fn["ale#lsp#GetLanguage"](config.name, bufnr)
94     end
95
96     local capabilities = vim.lsp.protocol.make_client_capabilities()
97
98     -- Language servers like Pyright do not enable the diagnostics pull model
99     -- unless dynamicRegistration is enabled for diagnostics.
100     if capabilities.textDocument.diagnostic ~= nil then
101         capabilities.textDocument.diagnostic.dynamicRegistration = true
102         config.capabilities = capabilities
103     end
104
105     ---@diagnostic disable-next-line: missing-fields
106     return vim.lsp.start(config, {
107         attach = false,
108         silent = true,
109     })
110 end
111
112 module.buf_attach = function(args)
113     return vim.lsp.buf_attach_client(args.bufnr, args.client_id)
114 end
115
116 module.buf_detach = function(args)
117     return vim.lsp.buf_detach_client(args.bufnr, args.client_id)
118 end
119
120 -- Send a message to an LSP server.
121 -- Notifications do not need to be handled.
122 --
123 -- Returns -1 when a message is sent, but no response is expected
124 --         0 when the message is not sent and
125 --         >= 1 with the message ID when a response is expected.
126 module.send_message = function(args)
127     local client = vim.lsp.get_client_by_id(args.client_id)
128
129     if client == nil then
130         return 0
131     end
132
133     if args.is_notification then
134         -- For notifications we send a request and expect no direct response.
135         local success = client.notify(args.method, args.params)
136
137         if success then
138             return -1
139         end
140
141         return 0
142     end
143
144     local success, request_id
145
146     -- For request we send a request and handle the response.
147     --
148     -- We set the bufnr to -1 to prevent Neovim from flushing anything, as ALE
149     -- already flushes changes to files before sending requests.
150     success, request_id = client.request(
151         args.method,
152         args.params,
153         ---@diagnostic disable-next-line: param-type-mismatch
154         function(_, result, _, _)
155             vim.fn["ale#lsp#HandleResponse"](client.name, {
156                 id = request_id,
157                 result = result,
158             })
159         end,
160         ---@diagnostic disable-next-line: param-type-mismatch
161         -1
162     )
163
164     if success then
165         return request_id
166     end
167
168     return 0
169 end
170
171 return module