client.lua (51712B)
1 local uv = vim.uv 2 local api = vim.api 3 local lsp = vim.lsp 4 local log = lsp.log 5 local changetracking = lsp._changetracking 6 local validate = vim.validate 7 8 --- Tracks all clients initialized. 9 ---@type table<integer,vim.lsp.Client> 10 local all_clients = {} 11 12 --- @alias vim.lsp.client.on_init_cb fun(client: vim.lsp.Client, init_result: lsp.InitializeResult) 13 --- @alias vim.lsp.client.on_attach_cb fun(client: vim.lsp.Client, bufnr: integer) 14 --- @alias vim.lsp.client.on_exit_cb fun(code: integer, signal: integer, client_id: integer) 15 --- @alias vim.lsp.client.before_init_cb fun(params: lsp.InitializeParams, config: vim.lsp.ClientConfig) 16 17 --- @class vim.lsp.Client.Flags 18 --- @inlinedoc 19 --- 20 --- Allow using incremental sync for buffer edits 21 --- (default: `true`) 22 --- @field allow_incremental_sync? boolean 23 --- 24 --- Debounce `didChange` notifications to the server by the given number in milliseconds. 25 --- (default: `150`) 26 --- @field debounce_text_changes? integer 27 28 --- @class vim.lsp.ClientConfig 29 --- 30 --- Callback which can modify parameters before they are sent to the server. Invoked before LSP 31 --- "initialize" phase (after `cmd` is invoked), where `params` is the parameters being sent to the 32 --- server and `config` is the config passed to |vim.lsp.start()|. 33 --- @field before_init? fun(params: lsp.InitializeParams, config: vim.lsp.ClientConfig) 34 --- 35 --- Map overriding the default capabilities defined by |vim.lsp.protocol.make_client_capabilities()|, 36 --- passed to the language server on initialization. Hint: use make_client_capabilities() and modify 37 --- its result. 38 --- - Note: To send an empty dictionary use |vim.empty_dict()|, else it will be encoded as an 39 --- array. 40 --- @field capabilities? lsp.ClientCapabilities 41 --- 42 --- Command `string[]` that launches the language server (treated as in |jobstart()|, must be 43 --- absolute or on `$PATH`, shell constructs like "~" are not expanded), or function that creates an 44 --- RPC client. Function receives a `dispatchers` table and the resolved `config`, and must return 45 --- a table with member functions `request`, `notify`, `is_closing` and `terminate`. 46 --- See |vim.lsp.rpc.request()|, |vim.lsp.rpc.notify()|. 47 --- For TCP there is a builtin RPC client factory: |vim.lsp.rpc.connect()| 48 --- @field cmd string[]|fun(dispatchers: vim.lsp.rpc.Dispatchers, config: vim.lsp.ClientConfig): vim.lsp.rpc.PublicClient 49 --- 50 --- Directory to launch the `cmd` process. Not related to `root_dir`. 51 --- (default: cwd) 52 --- @field cmd_cwd? string 53 --- 54 --- Environment variables passed to the LSP process on spawn. Non-string values are coerced to 55 --- string. 56 --- Example: 57 --- ```lua 58 --- { PORT = 8080; HOST = '0.0.0.0'; } 59 --- ``` 60 --- @field cmd_env? table 61 --- 62 --- Map of client-defined commands overriding the global |vim.lsp.commands|. 63 --- @field commands? table<string,fun(command: lsp.Command, ctx: table)> 64 --- 65 --- Daemonize the server process so that it runs in a separate process group from Nvim. 66 --- Nvim will shutdown the process on exit, but if Nvim fails to exit cleanly this could leave 67 --- behind orphaned server processes. 68 --- (default: `true`) 69 --- @field detached? boolean 70 --- 71 --- Milliseconds to wait for server to exit cleanly after sending the "shutdown" request before 72 --- sending kill -15. If set to false, waits indefinitely. If set to true, nvim will kill the 73 --- server immediately. 74 --- (default: `false`) 75 --- @field exit_timeout? integer|boolean 76 --- 77 --- Experimental client flags: 78 --- @field flags? vim.lsp.Client.Flags 79 --- 80 --- Language ID as string. Defaults to the buffer filetype. 81 --- @field get_language_id? fun(bufnr: integer, filetype: string): string 82 --- 83 --- Map of LSP method names to |lsp-handler|s. 84 --- @field handlers? table<string,function> 85 --- 86 --- Values to pass in the initialization request as `initializationOptions`. See `initialize` in 87 --- the LSP spec. 88 --- @field init_options? lsp.LSPObject 89 --- 90 --- Name in logs and user messages. 91 --- (default: client-id) 92 --- @field name? string 93 --- 94 --- Called "position encoding" in LSP spec. The encoding that the LSP server expects, used for 95 --- communication. Not validated. Can be modified in `on_init` before text is sent to the server. 96 --- @field offset_encoding? 'utf-8'|'utf-16'|'utf-32' 97 --- 98 --- Callback invoked when client attaches to a buffer. 99 --- @field on_attach? elem_or_list<fun(client: vim.lsp.Client, bufnr: integer)> 100 --- 101 --- Callback invoked when the client operation throws an error. `code` is a number describing the error. 102 --- Other arguments may be passed depending on the error kind. See `vim.lsp.rpc.client_errors` 103 --- for possible errors. Use `vim.lsp.rpc.client_errors[code]` to get human-friendly name. 104 --- @field on_error? fun(code: integer, err: string) 105 --- 106 --- Callback invoked on client exit. 107 --- - code: exit code of the process 108 --- - signal: number describing the signal used to terminate (if any) 109 --- - client_id: client handle 110 --- @field on_exit? elem_or_list<fun(code: integer, signal: integer, client_id: integer)> 111 --- 112 --- Callback invoked after LSP "initialize", where `result` is a table of `capabilities` and 113 --- anything else the server may send. For example, clangd sends `init_result.offsetEncoding` if 114 --- `capabilities.offsetEncoding` was sent to it. You can only modify the `client.offset_encoding` 115 --- here before any notifications are sent. 116 --- @field on_init? elem_or_list<fun(client: vim.lsp.Client, init_result: lsp.InitializeResult)> 117 --- 118 --- Directory where the LSP server will base its workspaceFolders, rootUri, and rootPath on initialization. 119 --- @field root_dir? string 120 --- 121 --- Map of language server-specific settings, decided by the client. Sent to the LS if requested via 122 --- `workspace/configuration`. Keys are case-sensitive. 123 --- @field settings? lsp.LSPObject 124 --- 125 --- Passed directly to the language server in the initialize request. Invalid/empty values will 126 --- (default: "off") 127 --- @field trace? 'off'|'messages'|'verbose' 128 --- 129 --- List of workspace folders passed to the language server. For backwards compatibility rootUri and 130 --- rootPath are derived from the first workspace folder in this list. Can be `null` if the client 131 --- supports workspace folders but none are configured. See `workspaceFolders` in LSP spec. 132 --- @field workspace_folders? lsp.WorkspaceFolder[] 133 --- 134 --- Server requires a workspace (no "single file" support). Note: Without 135 --- a workspace, cross-file features (navigation, hover) may or may not work depending on the 136 --- language server, even if the server doesn't require a workspace. 137 --- (default: `false`) 138 --- @field workspace_required? boolean 139 140 --- @class vim.lsp.Client.Progress: vim.Ringbuf<{token: integer|string, value: any}> 141 --- @field pending table<lsp.ProgressToken,lsp.LSPAny> 142 143 --- @class vim.lsp.Client 144 --- 145 --- @field attached_buffers table<integer,true> 146 --- 147 --- Capabilities provided by the client (editor or tool), at startup. 148 --- @field capabilities lsp.ClientCapabilities 149 --- 150 --- Client commands. See [vim.lsp.ClientConfig]. 151 --- @field commands table<string,fun(command: lsp.Command, ctx: table)> 152 --- 153 --- Copy of the config passed to |vim.lsp.start()|. 154 --- @field config vim.lsp.ClientConfig 155 --- 156 --- Capabilities provided at runtime (after startup). 157 --- @field dynamic_capabilities lsp.DynamicCapabilities 158 --- 159 --- Milliseconds to wait for server to exit cleanly after sending the "shutdown" request before 160 --- sending kill -15. If set to false, waits indefinitely. If set to true, nvim will kill the 161 --- server immediately. 162 --- (default: `false`) 163 --- @field exit_timeout integer|boolean 164 --- 165 --- Experimental client flags: 166 --- @field flags vim.lsp.Client.Flags 167 --- 168 --- See [vim.lsp.ClientConfig]. 169 --- @field get_language_id fun(bufnr: integer, filetype: string): string 170 --- 171 --- See [vim.lsp.ClientConfig]. 172 --- @field handlers table<string,lsp.Handler> 173 --- 174 --- The id allocated to the client. 175 --- @field id integer 176 --- 177 --- @field initialized true? 178 --- 179 --- See [vim.lsp.ClientConfig]. 180 --- @field name string 181 --- 182 --- See [vim.lsp.ClientConfig]. 183 --- @field offset_encoding 'utf-8'|'utf-16'|'utf-32' 184 --- 185 --- A ring buffer (|vim.ringbuf()|) containing progress messages 186 --- sent by the server. 187 --- @field progress vim.lsp.Client.Progress 188 --- 189 --- The current pending requests in flight to the server. Entries are key-value 190 --- pairs with the key being the request id while the value is a table with 191 --- `type`, `bufnr`, and `method` key-value pairs. `type` is either "pending" 192 --- for an active request, or "cancel" for a cancel request. It will be 193 --- "complete" ephemerally while executing |LspRequest| autocmds when replies 194 --- are received from the server. 195 --- @field requests table<integer,{ type: string, bufnr: integer, method: string}?> 196 --- 197 --- See [vim.lsp.ClientConfig]. 198 --- @field root_dir string? 199 --- 200 --- RPC client object, for low level interaction with the client. 201 --- See |vim.lsp.rpc.start()|. 202 --- @field rpc vim.lsp.rpc.PublicClient 203 --- 204 --- Response from the server sent on `initialize` describing the server's capabilities. 205 --- @field server_capabilities lsp.ServerCapabilities? 206 --- 207 --- Response from the server sent on `initialize` describing server information (e.g. version). 208 --- @field server_info lsp.ServerInfo? 209 --- 210 --- See [vim.lsp.ClientConfig]. 211 --- @field settings lsp.LSPObject 212 --- 213 --- See [vim.lsp.ClientConfig]. 214 --- @field workspace_folders lsp.WorkspaceFolder[]? 215 --- 216 --- @field _enabled_capabilities table<vim.lsp.capability.Name, boolean?> 217 --- 218 --- Whether on-type formatting is enabled for this client. 219 --- @field _otf_enabled boolean? 220 --- 221 --- Timer for stop() with timeout. 222 --- @field private _shutdown_timer uv.uv_timer_t? 223 --- 224 --- Track this so that we can escalate automatically if we've already tried a 225 --- graceful shutdown 226 --- @field private _graceful_shutdown_failed true? 227 --- 228 --- The initial trace setting. If omitted trace is disabled ("off"). 229 --- trace = "off" | "messages" | "verbose"; 230 --- @field private _trace 'off'|'messages'|'verbose' 231 --- 232 --- @field private registrations table<string,lsp.Registration[]> 233 --- @field private _log_prefix string 234 --- @field private _before_init_cb? vim.lsp.client.before_init_cb 235 --- @field private _on_attach_cbs vim.lsp.client.on_attach_cb[] 236 --- @field private _on_init_cbs vim.lsp.client.on_init_cb[] 237 --- @field private _on_exit_cbs vim.lsp.client.on_exit_cb[] 238 --- @field private _on_error_cb? fun(code: integer, err: string) 239 local Client = {} 240 Client.__index = Client 241 242 --- @param obj table<string,any> 243 --- @param cls table<string,function> 244 --- @param name string 245 local function method_wrapper(obj, cls, name) 246 local meth = assert(cls[name]) 247 obj[name] = function(...) 248 local arg = select(1, ...) 249 if arg and getmetatable(arg) == cls then 250 -- First argument is self, call meth directly 251 return meth(...) 252 end 253 vim.deprecate('client.' .. name, 'client:' .. name, '0.13') 254 -- First argument is not self, insert it 255 return meth(obj, ...) 256 end 257 end 258 259 local client_index = 0 260 261 --- Checks whether a given path is a directory. 262 --- @param filename (string) path to check 263 --- @return boolean # true if {filename} exists and is a directory, false otherwise 264 local function is_dir(filename) 265 validate('filename', filename, 'string') 266 local stat = uv.fs_stat(filename) 267 return stat and stat.type == 'directory' or false 268 end 269 270 local valid_encodings = { 271 ['utf-8'] = 'utf-8', 272 ['utf-16'] = 'utf-16', 273 ['utf-32'] = 'utf-32', 274 ['utf8'] = 'utf-8', 275 ['utf16'] = 'utf-16', 276 ['utf32'] = 'utf-32', 277 } 278 279 --- Normalizes {encoding} to valid LSP encoding names. 280 --- @param encoding string? Encoding to normalize 281 --- @return string # normalized encoding name 282 local function validate_encoding(encoding) 283 validate('encoding', encoding, 'string', true) 284 if not encoding then 285 return valid_encodings.utf16 286 end 287 return valid_encodings[encoding:lower()] 288 or error( 289 string.format( 290 "Invalid position encoding %q. Must be one of: 'utf-8', 'utf-16', 'utf-32'", 291 encoding 292 ) 293 ) 294 end 295 296 --- Augments a validator function with support for optional (nil) values. 297 --- @param fn (fun(v): boolean) The original validator function; should return a 298 --- bool. 299 --- @return fun(v): boolean # The augmented function. Also returns true if {v} is 300 --- `nil`. 301 local function optional_validator(fn) 302 return function(v) 303 return v == nil or fn(v) 304 end 305 end 306 307 --- By default, get_language_id just returns the exact filetype it is passed. 308 --- It is possible to pass in something that will calculate a different filetype, 309 --- to be sent by the client. 310 --- @param _bufnr integer 311 --- @param filetype string 312 local function default_get_language_id(_bufnr, filetype) 313 return filetype 314 end 315 316 --- Validates a client configuration as given to |vim.lsp.start()|. 317 --- @param config vim.lsp.ClientConfig 318 local function validate_config(config) 319 validate('config', config, 'table') 320 validate('handlers', config.handlers, 'table', true) 321 validate('capabilities', config.capabilities, 'table', true) 322 validate('cmd_cwd', config.cmd_cwd, optional_validator(is_dir), 'directory') 323 validate('cmd_env', config.cmd_env, 'table', true) 324 validate('detached', config.detached, 'boolean', true) 325 validate('exit_timeout', config.exit_timeout, { 'number', 'boolean' }, true) 326 validate('name', config.name, 'string', true) 327 validate('on_error', config.on_error, 'function', true) 328 validate('on_exit', config.on_exit, { 'function', 'table' }, true) 329 validate('on_init', config.on_init, { 'function', 'table' }, true) 330 validate('on_attach', config.on_attach, { 'function', 'table' }, true) 331 validate('settings', config.settings, 'table', true) 332 validate('commands', config.commands, 'table', true) 333 validate('before_init', config.before_init, { 'function', 'table' }, true) 334 validate('offset_encoding', config.offset_encoding, 'string', true) 335 validate('flags', config.flags, 'table', true) 336 validate('get_language_id', config.get_language_id, 'function', true) 337 338 assert( 339 ( 340 not config.flags 341 or not config.flags.debounce_text_changes 342 or type(config.flags.debounce_text_changes) == 'number' 343 ), 344 'flags.debounce_text_changes must be a number with the debounce time in milliseconds' 345 ) 346 end 347 348 --- @param trace string 349 --- @return 'off'|'messages'|'verbose' 350 local function get_trace(trace) 351 local valid_traces = { 352 off = 'off', 353 messages = 'messages', 354 verbose = 'verbose', 355 } 356 return trace and valid_traces[trace] or 'off' 357 end 358 359 --- @param id integer 360 --- @param config vim.lsp.ClientConfig 361 --- @return string 362 local function get_name(id, config) 363 local name = config.name 364 if name then 365 return name 366 end 367 368 if type(config.cmd) == 'table' and config.cmd[1] then 369 return assert(vim.fs.basename(config.cmd[1])) 370 end 371 372 return tostring(id) 373 end 374 375 --- @nodoc 376 --- @param config vim.lsp.ClientConfig 377 --- @return vim.lsp.Client? 378 function Client.create(config) 379 validate_config(config) 380 381 client_index = client_index + 1 382 local id = client_index 383 local name = get_name(id, config) 384 385 --- @class vim.lsp.Client 386 local self = { 387 id = id, 388 config = config, 389 handlers = config.handlers or {}, 390 offset_encoding = validate_encoding(config.offset_encoding), 391 name = name, 392 _log_prefix = string.format('LSP[%s]', name), 393 requests = {}, 394 attached_buffers = {}, 395 server_capabilities = {}, 396 registrations = {}, 397 commands = config.commands or {}, 398 settings = config.settings or {}, 399 flags = config.flags or {}, 400 exit_timeout = config.exit_timeout or false, 401 get_language_id = config.get_language_id or default_get_language_id, 402 capabilities = config.capabilities, 403 workspace_folders = lsp._get_workspace_folders(config.workspace_folders or config.root_dir), 404 root_dir = config.root_dir, 405 _is_stopping = false, 406 _before_init_cb = config.before_init, 407 _on_init_cbs = vim._ensure_list(config.on_init), 408 _on_exit_cbs = vim._ensure_list(config.on_exit), 409 _on_attach_cbs = vim._ensure_list(config.on_attach), 410 _on_error_cb = config.on_error, 411 _trace = get_trace(config.trace), 412 413 --- Contains $/progress report messages. 414 --- They have the format {token: integer|string, value: any} 415 --- For "work done progress", value will be one of: 416 --- - lsp.WorkDoneProgressBegin, 417 --- - lsp.WorkDoneProgressReport (extended with title from Begin) 418 --- - lsp.WorkDoneProgressEnd (extended with title from Begin) 419 progress = vim.ringbuf(50) --[[@as vim.lsp.Client.Progress]], 420 421 --- @deprecated use client.progress instead 422 messages = { name = name, messages = {}, progress = {}, status = {} }, 423 } 424 425 self.capabilities = 426 vim.tbl_deep_extend('force', lsp.protocol.make_client_capabilities(), self.capabilities or {}) 427 428 --- @class lsp.DynamicCapabilities 429 --- @nodoc 430 self.dynamic_capabilities = { 431 capabilities = self.registrations, 432 client_id = id, 433 register = function(_, registrations) 434 return self:_register_dynamic(registrations) 435 end, 436 unregister = function(_, unregistrations) 437 return self:_unregister_dynamic(unregistrations) 438 end, 439 get = function(_, method, opts) 440 return self:_get_registrations(method, opts and opts.bufnr) 441 end, 442 supports_registration = function(_, method) 443 return self:_supports_registration(method) 444 end, 445 supports = function(_, method, opts) 446 return self:_get_registrations(method, opts and opts.bufnr) ~= nil 447 end, 448 } 449 450 ---@type table <vim.lsp.capability.Name, boolean?> 451 self._enabled_capabilities = {} 452 453 --- @type table<string|integer, string> title of unfinished progress sequences by token 454 self.progress.pending = {} 455 456 --- @type vim.lsp.rpc.Dispatchers 457 local dispatchers = { 458 notification = function(...) 459 self:_notification(...) 460 end, 461 server_request = function(...) 462 return self:_server_request(...) 463 end, 464 on_error = function(...) 465 self:_on_error(...) 466 end, 467 on_exit = function(...) 468 self:_on_exit(...) 469 end, 470 } 471 472 -- Start the RPC client. 473 local config_cmd = config.cmd 474 if type(config_cmd) == 'function' then 475 self.rpc = config_cmd(dispatchers, config) 476 else 477 self.rpc = lsp.rpc.start(config_cmd, dispatchers, { 478 cwd = config.cmd_cwd, 479 env = config.cmd_env, 480 detached = config.detached, 481 }) 482 end 483 484 setmetatable(self, Client) 485 486 method_wrapper(self, Client, 'request') 487 method_wrapper(self, Client, 'request_sync') 488 method_wrapper(self, Client, 'notify') 489 method_wrapper(self, Client, 'cancel_request') 490 method_wrapper(self, Client, 'stop') 491 method_wrapper(self, Client, 'is_stopped') 492 method_wrapper(self, Client, 'on_attach') 493 method_wrapper(self, Client, 'supports_method') 494 495 return self 496 end 497 498 --- @private 499 --- @param cbs function[] 500 --- @param error_id integer 501 --- @param ... any 502 function Client:_run_callbacks(cbs, error_id, ...) 503 for _, cb in pairs(cbs) do 504 --- @type boolean, string? 505 local status, err = pcall(cb, ...) 506 if not status then 507 self:write_error(error_id, err) 508 end 509 end 510 end 511 512 --- @nodoc 513 function Client:initialize() 514 -- Register all initialized clients. 515 all_clients[self.id] = self 516 517 local config = self.config 518 519 local root_uri --- @type string? 520 local root_path --- @type string? 521 if self.workspace_folders then 522 root_uri = self.workspace_folders[1].uri 523 root_path = vim.uri_to_fname(root_uri) 524 end 525 526 -- HACK: Capability modules must be loaded 527 require('vim.lsp.semantic_tokens') 528 require('vim.lsp._folding_range') 529 require('vim.lsp.inline_completion') 530 531 local init_params = { 532 -- The process Id of the parent process that started the server. Is null if 533 -- the process has not been started by another process. If the parent 534 -- process is not alive then the server should exit (see exit notification) 535 -- its process. 536 processId = uv.os_getpid(), 537 -- Information about the client 538 -- since 3.15.0 539 clientInfo = { 540 name = 'Neovim', 541 version = tostring(vim.version()), 542 }, 543 -- The rootPath of the workspace. Is null if no folder is open. 544 -- 545 -- @deprecated in favour of rootUri. 546 rootPath = root_path or vim.NIL, 547 -- The rootUri of the workspace. Is null if no folder is open. If both 548 -- `rootPath` and `rootUri` are set `rootUri` wins. 549 rootUri = root_uri or vim.NIL, 550 workspaceFolders = self.workspace_folders or vim.NIL, 551 -- User provided initialization options. 552 initializationOptions = config.init_options, 553 capabilities = self.capabilities, 554 trace = self._trace, 555 workDoneToken = '1', 556 } 557 558 self:_run_callbacks( 559 { self._before_init_cb }, 560 lsp.client_errors.BEFORE_INIT_CALLBACK_ERROR, 561 init_params, 562 config 563 ) 564 565 log.trace(self._log_prefix, 'init_params', init_params) 566 567 local rpc = self.rpc 568 569 rpc.request('initialize', init_params, function(init_err, result) 570 assert(not init_err, tostring(init_err)) 571 assert(result, 'server sent empty result') 572 rpc.notify('initialized', vim.empty_dict()) 573 self.initialized = true 574 575 -- These are the cleaned up capabilities we use for dynamically deciding 576 -- when to send certain events to clients. 577 self.server_capabilities = 578 assert(result.capabilities, "initialize result doesn't contain capabilities") 579 self.server_capabilities = assert(lsp.protocol.resolve_capabilities(self.server_capabilities)) 580 581 self:_process_static_registrations() 582 583 if self.server_capabilities.positionEncoding then 584 self.offset_encoding = self.server_capabilities.positionEncoding 585 end 586 587 self.server_info = result.serverInfo 588 589 if next(self.settings) then 590 self:notify('workspace/didChangeConfiguration', { settings = self.settings }) 591 end 592 593 -- If server is being restarted, make sure to re-attach to any previously attached buffers. 594 -- Save which buffers before on_init in case new buffers are attached. 595 local reattach_bufs = vim.deepcopy(self.attached_buffers) 596 597 self:_run_callbacks(self._on_init_cbs, lsp.client_errors.ON_INIT_CALLBACK_ERROR, self, result) 598 599 for buf in pairs(reattach_bufs) do 600 -- The buffer may have been detached in the on_init callback. 601 if self.attached_buffers[buf] then 602 self:on_attach(buf) 603 end 604 end 605 606 log.info( 607 self._log_prefix, 608 'server_capabilities', 609 { server_capabilities = self.server_capabilities } 610 ) 611 end) 612 end 613 614 --- @private 615 function Client:_process_static_registrations() 616 local static_registrations = {} ---@type lsp.Registration[] 617 618 for method in pairs(lsp.protocol._method_supports_static_registration) do 619 local capability = lsp.protocol._request_name_to_server_capability[method] 620 if 621 vim.tbl_get(self.server_capabilities, capability[1], 'id') 622 and self:_supports_registration(method) 623 then 624 local cap = vim.tbl_get(self.server_capabilities, capability[1]) 625 static_registrations[#static_registrations + 1] = { 626 id = cap.id, 627 method = method, 628 registerOptions = cap or {}, 629 } 630 end 631 end 632 633 if next(static_registrations) then 634 self:_register_dynamic(static_registrations) 635 end 636 end 637 638 --- @private 639 --- Returns the handler associated with an LSP method. 640 --- Returns the default handler if the user hasn't set a custom one. 641 --- 642 --- @param method (vim.lsp.protocol.Method) LSP method name 643 --- @return lsp.Handler? handler for the given method, if defined, or the default from |vim.lsp.handlers| 644 function Client:_resolve_handler(method) 645 return self.handlers[method] or lsp.handlers[method] 646 end 647 648 --- @private 649 --- @param id integer 650 --- @param req_type 'pending'|'complete'|'cancel' 651 --- @param bufnr? integer (only required for req_type='pending') 652 --- @param method? vim.lsp.protocol.Method (only required for req_type='pending') 653 function Client:_process_request(id, req_type, bufnr, method) 654 local pending = req_type == 'pending' 655 656 validate('id', id, 'number') 657 if pending then 658 validate('bufnr', bufnr, 'number') 659 validate('method', method, 'string') 660 end 661 662 local cur_request = self.requests[id] 663 664 if pending and cur_request then 665 log.error( 666 self._log_prefix, 667 ('Cannot create request with id %d as one already exists'):format(id) 668 ) 669 return 670 elseif not pending and not cur_request then 671 log.error( 672 self._log_prefix, 673 ('Cannot find request with id %d whilst attempting to %s'):format(id, req_type) 674 ) 675 return 676 end 677 678 if cur_request then 679 bufnr = cur_request.bufnr 680 method = cur_request.method 681 end 682 683 assert(bufnr and method) 684 685 local request = { type = req_type, bufnr = bufnr, method = method } 686 687 -- Clear 'complete' requests 688 -- Note 'pending' and 'cancelled' requests are cleared when the server sends a response 689 -- which is processed via the notify_reply_callback argument to rpc.request. 690 self.requests[id] = req_type ~= 'complete' and request or nil 691 692 api.nvim_exec_autocmds('LspRequest', { 693 buffer = api.nvim_buf_is_valid(bufnr) and bufnr or nil, 694 modeline = false, 695 data = { client_id = self.id, request_id = id, request = request }, 696 }) 697 end 698 699 --- Sends a request to the server. 700 --- 701 --- This is a thin wrapper around {client.rpc.request} with some additional 702 --- checks for capabilities and handler availability. 703 --- 704 --- @param method vim.lsp.protocol.Method.ClientToServer.Request LSP method name. 705 --- @param params? table LSP request params. 706 --- @param handler? lsp.Handler Response |lsp-handler| for this method. 707 --- @param bufnr? integer (default: 0) Buffer handle, or 0 for current. 708 --- @return boolean status indicates whether the request was successful. 709 --- If it is `false`, then it will always be `false` (the client has shutdown). 710 --- @return integer? request_id Can be used with |Client:cancel_request()|. 711 --- `nil` is request failed. 712 --- to cancel the-request. 713 --- @see |vim.lsp.buf_request_all()| 714 function Client:request(method, params, handler, bufnr) 715 if not handler then 716 handler = assert( 717 self:_resolve_handler(method), 718 string.format('not found: %q request handler for client %q.', method, self.name) 719 ) 720 end 721 -- Ensure pending didChange notifications are sent so that the server doesn't operate on a stale state 722 changetracking.flush(self, bufnr) 723 bufnr = vim._resolve_bufnr(bufnr) 724 local version = lsp.util.buf_versions[bufnr] 725 log.debug(self._log_prefix, 'client.request', self.id, method, params, handler, bufnr) 726 727 -- Detect if request resolved synchronously (only possible with in-process servers). 728 local already_responded = false 729 local request_registered = false 730 731 -- NOTE: rpc.request might call an in-process (Lua) server, thus may be synchronous. 732 local success, request_id = self.rpc.request(method, params, function(err, result, request_id) 733 handler(err, result, { 734 method = method, 735 client_id = self.id, 736 request_id = request_id, 737 bufnr = bufnr, 738 params = params, 739 version = version, 740 }) 741 end, function(request_id) 742 -- Called when the server sends a response to the request (including cancelled acknowledgment). 743 if request_registered then 744 self:_process_request(request_id, 'complete') 745 end 746 already_responded = true 747 end) 748 749 if success and request_id and not already_responded then 750 self:_process_request(request_id, 'pending', bufnr, method) 751 request_registered = true 752 end 753 754 return success, request_id 755 end 756 757 -- TODO(lewis6991): duplicated from lsp.lua 758 local wait_result_reason = { [-1] = 'timeout', [-2] = 'interrupted', [-3] = 'error' } 759 760 --- Concatenates and writes a list of strings to the Vim error buffer. 761 --- 762 --- @param ... string List to write to the buffer 763 local function err_message(...) 764 local chunks = { { table.concat(vim.iter({ ... }):flatten():totable()) } } 765 if vim.in_fast_event() then 766 vim.schedule(function() 767 api.nvim_echo(chunks, true, { err = true }) 768 api.nvim_command('redraw') 769 end) 770 else 771 api.nvim_echo(chunks, true, { err = true }) 772 api.nvim_command('redraw') 773 end 774 end 775 776 --- Sends a request to the server and synchronously waits for the response. 777 --- 778 --- This is a wrapper around |Client:request()| 779 --- 780 --- @param method vim.lsp.protocol.Method.ClientToServer.Request LSP method name. 781 --- @param params table LSP request params. 782 --- @param timeout_ms integer? Maximum time in milliseconds to wait for 783 --- a result. Defaults to 1000 784 --- @param bufnr? integer (default: 0) Buffer handle, or 0 for current. 785 --- @return {err: lsp.ResponseError?, result:any}? `result` and `err` from the |lsp-handler|. 786 --- `nil` is the request was unsuccessful 787 --- @return string? err On timeout, cancel or error, where `err` is a 788 --- string describing the failure reason. 789 --- @see |vim.lsp.buf_request_sync()| 790 function Client:request_sync(method, params, timeout_ms, bufnr) 791 local request_result = nil 792 local function _sync_handler(err, result) 793 request_result = { err = err, result = result } 794 end 795 796 local success, request_id = self:request(method, params, _sync_handler, bufnr) 797 if not success then 798 return nil 799 end 800 801 local wait_result, reason = vim.wait(timeout_ms or 1000, function() 802 return request_result ~= nil 803 end, 10) 804 805 if not wait_result then 806 if request_id then 807 self:cancel_request(request_id) 808 end 809 return nil, wait_result_reason[reason] 810 end 811 return request_result 812 end 813 814 --- Sends a notification to an LSP server. 815 --- 816 --- @param method vim.lsp.protocol.Method.ClientToServer.Notification LSP method name. 817 --- @param params table? LSP request params. 818 --- @return boolean status indicating if the notification was successful. 819 --- If it is false, then the client has shutdown. 820 function Client:notify(method, params) 821 if method ~= 'textDocument/didChange' then 822 changetracking.flush(self) 823 end 824 825 local client_active = self.rpc.notify(method, params) 826 827 if client_active then 828 vim.schedule(function() 829 api.nvim_exec_autocmds('LspNotify', { 830 modeline = false, 831 data = { 832 client_id = self.id, 833 method = method, 834 params = params, 835 }, 836 }) 837 end) 838 end 839 840 return client_active 841 end 842 843 --- Cancels a request with a given request id. 844 --- 845 --- @param id integer id of request to cancel 846 --- @return boolean status indicating if the notification was successful. 847 --- @see |Client:notify()| 848 function Client:cancel_request(id) 849 self:_process_request(id, 'cancel') 850 return self.rpc.notify('$/cancelRequest', { id = id }) 851 end 852 853 --- Stops a client, optionally with force after a timeout. 854 --- 855 --- By default, it will request the server to shutdown, then force a shutdown 856 --- if the server has not exited after `self.exit_timeout` milliseconds. If 857 --- you request to stop a client which has previously been requested to 858 --- shutdown, it will automatically escalate and force shutdown immediately, 859 --- regardless of the value of `force` (or `self.exit_timeout` if `nil`). 860 --- 861 --- Note: Forcing shutdown while a server is busy writing out project or index 862 --- files can lead to file corruption. 863 --- 864 --- @param force? integer|boolean Time in milliseconds to wait before forcing 865 --- a shutdown. If false, only request the 866 --- server to shutdown, but don't force it. If 867 --- true, force a shutdown immediately. 868 --- (default: `self.exit_timeout`) 869 function Client:stop(force) 870 validate('force', force, { 'number', 'boolean' }, true) 871 872 if force == nil then 873 force = self.exit_timeout 874 end 875 876 local rpc = self.rpc 877 if rpc.is_closing() then 878 return 879 end 880 881 self._is_stopping = true 882 883 lsp._watchfiles.cancel(self.id) 884 885 if force == true or not self.initialized or self._graceful_shutdown_failed then 886 rpc.terminate() 887 return 888 end 889 890 if type(force) == 'number' then 891 self._shutdown_timer = vim.defer_fn(function() 892 self._shutdown_timer = nil 893 self:stop(true) 894 end, force) 895 end 896 897 -- Sending a signal after a process has exited is acceptable. 898 rpc.request('shutdown', nil, function(err, _, _) 899 if err == nil then 900 rpc.notify('exit') 901 else 902 -- If there was an error in the shutdown request, then terminate to be safe. 903 rpc.terminate() 904 self._graceful_shutdown_failed = true 905 end 906 end) 907 end 908 909 --- Stops a client, then starts a new client with the same config and attached 910 --- buffers. 911 --- 912 --- @param force? integer|boolean See [Client:stop()] for details. 913 --- (default: `self.exit_timeout`) 914 function Client:_restart(force) 915 validate('force', force, { 'number', 'boolean' }, true) 916 917 self._handle_restart = function() 918 --- @type integer[] 919 local attached_buffers = vim.tbl_keys(self.attached_buffers) 920 921 vim.schedule(function() 922 local new_client_id = lsp.start(self.config, { attach = false }) 923 if new_client_id then 924 for _, buffer in ipairs(attached_buffers) do 925 lsp.buf_attach_client(buffer, new_client_id) 926 end 927 end 928 end) 929 end 930 931 self:stop(force) 932 end 933 934 --- Get options for a method that is registered dynamically. 935 --- @param method vim.lsp.protocol.Method | vim.lsp.protocol.Method.Registration 936 function Client:_supports_registration(method) 937 if lsp.protocol._methods_with_no_registration_options[method] then 938 return true 939 end 940 local provider = self:_registration_provider(method) 941 local capability_path = lsp.protocol._provider_to_client_registration[provider] 942 local capability = vim.tbl_get(self.capabilities, unpack(capability_path)) 943 return type(capability) == 'table' and capability.dynamicRegistration 944 end 945 946 --- Get provider for a method to be registered dynamically. 947 --- @param method vim.lsp.protocol.Method | vim.lsp.protocol.Method.Registration 948 function Client:_registration_provider(method) 949 local capability_path = lsp.protocol._request_name_to_server_capability[method] 950 return capability_path and capability_path[1] 951 end 952 953 --- @private 954 --- @param registrations lsp.Registration[] 955 function Client:_register_dynamic(registrations) 956 -- remove duplicates 957 self:_unregister_dynamic(registrations) 958 for _, reg in ipairs(registrations) do 959 local provider = self:_registration_provider(reg.method) 960 if not self.registrations[provider] then 961 self.registrations[provider] = {} 962 end 963 table.insert(self.registrations[provider], reg) 964 end 965 end 966 967 --- @param registrations lsp.Registration[] 968 function Client:_register(registrations) 969 self:_register_dynamic(registrations) 970 971 local unsupported = {} --- @type string[] 972 973 for _, reg in ipairs(registrations) do 974 local method = reg.method 975 if method == 'workspace/didChangeWatchedFiles' then 976 lsp._watchfiles.register(reg, self.id) 977 elseif not self:_supports_registration(method) then 978 unsupported[#unsupported + 1] = method 979 end 980 end 981 982 if #unsupported > 0 then 983 local warning_tpl = 'The language server %s triggers a registerCapability ' 984 .. 'handler for %s despite dynamicRegistration set to false. ' 985 .. 'Report upstream, this warning is harmless' 986 log.warn(string.format(warning_tpl, self.name, table.concat(unsupported, ', '))) 987 end 988 end 989 990 --- @private 991 --- @param unregistrations lsp.Unregistration[] 992 function Client:_unregister_dynamic(unregistrations) 993 for _, unreg in ipairs(unregistrations) do 994 local provider = self:_registration_provider(unreg.method) 995 local sreg = self.registrations[provider] 996 -- Unegister dynamic capability 997 for i, reg in ipairs(sreg or {}) do 998 if reg.id == unreg.id then 999 table.remove(sreg, i) 1000 break 1001 end 1002 end 1003 end 1004 end 1005 1006 --- @param unregistrations lsp.Unregistration[] 1007 function Client:_unregister(unregistrations) 1008 self:_unregister_dynamic(unregistrations) 1009 for _, unreg in ipairs(unregistrations) do 1010 if unreg.method == 'workspace/didChangeWatchedFiles' then 1011 lsp._watchfiles.unregister(unreg, self.id) 1012 end 1013 end 1014 end 1015 1016 --- @private 1017 function Client:_get_language_id(bufnr) 1018 return self.get_language_id(bufnr, vim.bo[bufnr].filetype) 1019 end 1020 1021 --- @param provider string 1022 --- @param bufnr? integer 1023 --- @return lsp.Registration[]? 1024 function Client:_get_registrations(provider, bufnr) 1025 bufnr = vim._resolve_bufnr(bufnr) 1026 local matched_regs = {} --- @type lsp.Registration[] 1027 for _, reg in ipairs(self.registrations[provider] or {}) do 1028 local regoptions = reg.registerOptions --[[@as {documentSelector:lsp.DocumentSelector|lsp.null}]] 1029 if 1030 not regoptions 1031 or regoptions == vim.NIL 1032 or not regoptions.documentSelector 1033 or regoptions.documentSelector == vim.NIL 1034 then 1035 matched_regs[#matched_regs + 1] = reg 1036 else 1037 local language = self:_get_language_id(bufnr) 1038 local uri = vim.uri_from_bufnr(bufnr) 1039 local fname = vim.uri_to_fname(uri) 1040 for _, filter in ipairs(regoptions.documentSelector) do 1041 local flang, fscheme, fpat = filter.language, filter.scheme, filter.pattern 1042 if 1043 not (flang and language ~= flang) 1044 and not (fscheme and not vim.startswith(uri, fscheme .. ':')) 1045 and not (type(fpat) == 'string' and not vim.glob.to_lpeg(fpat):match(fname)) 1046 then 1047 matched_regs[#matched_regs + 1] = reg 1048 end 1049 end 1050 end 1051 end 1052 return #matched_regs > 0 and matched_regs or nil 1053 end 1054 1055 --- Checks whether a client is stopped. 1056 --- 1057 --- @return boolean # true if client is stopped or in the process of being 1058 --- stopped; false otherwise 1059 function Client:is_stopped() 1060 return self.rpc.is_closing() or self._is_stopping 1061 end 1062 1063 --- Execute a lsp command, either via client command function (if available) 1064 --- or via workspace/executeCommand (if supported by the server) 1065 --- 1066 --- @param command lsp.Command 1067 --- @param context? {bufnr?: integer} 1068 --- @param handler? lsp.Handler only called if a server command 1069 function Client:exec_cmd(command, context, handler) 1070 context = vim.deepcopy(context or {}, true) --[[@as lsp.HandlerContext]] 1071 context.bufnr = vim._resolve_bufnr(context.bufnr) 1072 context.client_id = self.id 1073 local cmdname = command.command 1074 local fn = self.commands[cmdname] or lsp.commands[cmdname] 1075 if fn then 1076 fn(command, context) 1077 return 1078 end 1079 1080 local command_provider = self.server_capabilities.executeCommandProvider 1081 local commands = type(command_provider) == 'table' and command_provider.commands or {} 1082 1083 if not vim.list_contains(commands, cmdname) then 1084 vim.notify_once( 1085 string.format( 1086 'Language server `%s` does not support command `%s`. This command may require a client extension.', 1087 self.name, 1088 cmdname 1089 ), 1090 vim.log.levels.WARN 1091 ) 1092 return 1093 end 1094 -- Not using command directly to exclude extra properties, 1095 -- see https://github.com/python-lsp/python-lsp-server/issues/146 1096 --- @type lsp.ExecuteCommandParams 1097 local params = { 1098 command = cmdname, 1099 arguments = command.arguments, 1100 } 1101 self:request('workspace/executeCommand', params, handler, context.bufnr) 1102 end 1103 1104 --- Default handler for the 'textDocument/didOpen' LSP notification. 1105 --- 1106 --- @param bufnr integer Number of the buffer, or 0 for current 1107 function Client:_text_document_did_open_handler(bufnr) 1108 changetracking.init(self, bufnr) 1109 if not self:supports_method('textDocument/didOpen') then 1110 return 1111 end 1112 if not api.nvim_buf_is_loaded(bufnr) then 1113 return 1114 end 1115 1116 self:notify('textDocument/didOpen', { 1117 textDocument = { 1118 version = lsp.util.buf_versions[bufnr], 1119 uri = vim.uri_from_bufnr(bufnr), 1120 languageId = self:_get_language_id(bufnr), 1121 text = lsp._buf_get_full_text(bufnr), 1122 }, 1123 }) 1124 1125 -- Next chance we get, we should re-do the diagnostics 1126 vim.schedule(function() 1127 -- Protect against a race where the buffer disappears 1128 -- between `did_open_handler` and the scheduled function firing. 1129 if api.nvim_buf_is_valid(bufnr) then 1130 local namespace = lsp.diagnostic.get_namespace(self.id) 1131 vim.diagnostic.show(namespace, bufnr) 1132 end 1133 end) 1134 end 1135 1136 --- Runs the on_attach function from the client's config if it was defined. 1137 --- Useful for buffer-local setup. 1138 --- @param bufnr integer Buffer number 1139 function Client:on_attach(bufnr) 1140 self:_text_document_did_open_handler(bufnr) 1141 1142 lsp._set_defaults(self, bufnr) 1143 -- `enable(true)` cannot be called from `_set_defaults` for features with dynamic registration, 1144 -- because it overrides the state every time `client/registerCapability` is received. 1145 -- To allow disabling it once in `LspAttach`, we enable it once here instead. 1146 lsp.document_color.enable(true, bufnr) 1147 1148 api.nvim_exec_autocmds('LspAttach', { 1149 buffer = bufnr, 1150 modeline = false, 1151 data = { client_id = self.id }, 1152 }) 1153 1154 self:_run_callbacks(self._on_attach_cbs, lsp.client_errors.ON_ATTACH_ERROR, self, bufnr) 1155 -- schedule the initialization of capabilities to give the above 1156 -- on_attach and LspAttach callbacks the ability to schedule wrap the 1157 -- opt-out (such as deleting the semanticTokensProvider from capabilities) 1158 vim.schedule(function() 1159 if not vim.api.nvim_buf_is_valid(bufnr) then 1160 return 1161 end 1162 for _, Capability in pairs(lsp._capability.all) do 1163 if 1164 self:supports_method(Capability.method) 1165 and lsp._capability.is_enabled(Capability.name, { 1166 bufnr = bufnr, 1167 client_id = self.id, 1168 }) 1169 then 1170 local capability = Capability.active[bufnr] or Capability:new(bufnr) 1171 capability:on_attach(self.id) 1172 end 1173 end 1174 end) 1175 1176 self.attached_buffers[bufnr] = true 1177 end 1178 1179 --- @private 1180 --- Logs the given error to the LSP log and to the error buffer. 1181 --- @param code integer Error code 1182 --- @param err any Error arguments 1183 function Client:write_error(code, err) 1184 local client_error = lsp.client_errors[code] --- @type string|integer 1185 log.error(self._log_prefix, 'on_error', { code = client_error, err = err }) 1186 err_message(self._log_prefix, ': Error ', client_error, ': ', vim.inspect(err)) 1187 end 1188 1189 --- Checks if a client supports a given method. 1190 --- Always returns true for unknown off-spec methods. 1191 --- 1192 --- Note: Some language server capabilities can be file specific. 1193 --- @param method vim.lsp.protocol.Method.ClientToServer | vim.lsp.protocol.Method.Registration 1194 --- @param bufnr? integer 1195 --- @return boolean 1196 function Client:supports_method(method, bufnr) 1197 -- Deprecated form 1198 if type(bufnr) == 'table' then 1199 --- @diagnostic disable-next-line:no-unknown 1200 bufnr = bufnr.bufnr 1201 end 1202 local required_capability = lsp.protocol._request_name_to_server_capability[method] 1203 if required_capability and vim.tbl_get(self.server_capabilities, unpack(required_capability)) then 1204 return true 1205 end 1206 1207 local provider = self:_registration_provider(method) 1208 local regs = self:_get_registrations(provider, bufnr) 1209 if lsp.protocol._method_supports_dynamic_registration[method] and not regs then 1210 return false 1211 end 1212 if regs then 1213 for _, reg in ipairs(regs or {}) do 1214 if required_capability and #required_capability > 1 then 1215 if vim.tbl_get(reg, 'registerOptions', unpack(required_capability, 2)) then 1216 return self:_supports_registration(reg.method) 1217 end 1218 if lsp.protocol._methods_with_no_registration_options[method] then 1219 return true 1220 end 1221 else 1222 return self:_supports_registration(reg.method) 1223 end 1224 end 1225 return false 1226 end 1227 1228 -- if we don't know about the method, assume that the client supports it. 1229 -- This needs to be at the end, so that dynamic_capabilities are checked first 1230 return required_capability == nil 1231 end 1232 1233 --- Retrieves all capability values for a given LSP method, handling both static and dynamic registrations. 1234 --- This function abstracts over differences between capabilities declared in `server_capabilities` 1235 --- and those registered dynamically at runtime, returning all matching capability values. 1236 --- It also handles cases where the registration method differs from the calling method by abstracting to the Provider. 1237 --- For example, `workspace/diagnostic` uses capabilities registered under `textDocument/diagnostic`. 1238 --- This is useful for features like diagnostics and formatting, where servers may register multiple providers 1239 --- with different options (such as specific filetypes or document selectors). 1240 --- @param method vim.lsp.protocol.Method.ClientToServer | vim.lsp.protocol.Method.Registration LSP method name 1241 --- @param ... any Additional keys to index into the capability 1242 --- @return lsp.LSPAny[] # The capability value if it exists, empty table if not found 1243 function Client:_provider_value_get(method, ...) 1244 local matched_regs = {} --- @type any[] 1245 local provider = self:_registration_provider(method) 1246 local dynamic_regs = self:_get_registrations(provider) 1247 if not provider then 1248 return matched_regs 1249 elseif not dynamic_regs then 1250 -- First check static capabilities 1251 local static_reg = vim.tbl_get(self.server_capabilities, provider) 1252 if static_reg then 1253 matched_regs[1] = vim.tbl_get(static_reg, ...) or vim.NIL 1254 end 1255 else 1256 local required_capability = lsp.protocol._request_name_to_server_capability[method] 1257 for _, reg in ipairs(dynamic_regs) do 1258 if vim.tbl_get(reg, 'registerOptions', unpack(required_capability, 2)) then 1259 matched_regs[#matched_regs + 1] = vim.tbl_get(reg, 'registerOptions', ...) or vim.NIL 1260 end 1261 end 1262 end 1263 1264 return matched_regs 1265 end 1266 1267 --- @private 1268 --- Handles a notification sent by an LSP server by invoking the 1269 --- corresponding handler. 1270 --- 1271 --- @param method vim.lsp.protocol.Method.ServerToClient.Notification LSP method name 1272 --- @param params table The parameters for that method. 1273 function Client:_notification(method, params) 1274 log.trace('notification', method, params) 1275 local handler = self:_resolve_handler(method) 1276 if handler then 1277 -- Method name is provided here for convenience. 1278 handler(nil, params, { method = method, client_id = self.id }) 1279 end 1280 end 1281 1282 --- @private 1283 --- Handles a request from an LSP server by invoking the corresponding handler. 1284 --- 1285 --- @param method (vim.lsp.protocol.Method.ServerToClient) LSP method name 1286 --- @param params (table) The parameters for that method 1287 --- @return any result 1288 --- @return lsp.ResponseError? error code and message set in case an exception happens during the request. 1289 function Client:_server_request(method, params) 1290 log.trace('server_request', method, params) 1291 local handler = self:_resolve_handler(method) 1292 if handler then 1293 log.trace('server_request: found handler for', method) 1294 return handler(nil, params, { method = method, client_id = self.id }) 1295 end 1296 log.warn('server_request: no handler found for', method) 1297 return nil, lsp.rpc_response_error(lsp.protocol.ErrorCodes.MethodNotFound) 1298 end 1299 1300 --- @private 1301 --- Invoked when the client operation throws an error. 1302 --- 1303 --- @param code integer Error code 1304 --- @param err any Other arguments may be passed depending on the error kind 1305 --- @see vim.lsp.rpc.client_errors for possible errors. Use 1306 --- `vim.lsp.rpc.client_errors[code]` to get a human-friendly name. 1307 function Client:_on_error(code, err) 1308 self:write_error(code, err) 1309 if self._on_error_cb then 1310 --- @type boolean, string 1311 local status, usererr = pcall(self._on_error_cb, code, err) 1312 if not status then 1313 log.error(self._log_prefix, 'user on_error failed', { err = usererr }) 1314 err_message(self._log_prefix, ' user on_error failed: ', tostring(usererr)) 1315 end 1316 end 1317 end 1318 1319 ---@param bufnr integer resolved buffer 1320 function Client:_on_detach(bufnr) 1321 if self.attached_buffers[bufnr] and api.nvim_buf_is_valid(bufnr) then 1322 api.nvim_exec_autocmds('LspDetach', { 1323 buffer = bufnr, 1324 modeline = false, 1325 data = { client_id = self.id }, 1326 }) 1327 end 1328 1329 for _, Capability in pairs(lsp._capability.all) do 1330 if 1331 self:supports_method(Capability.method) 1332 and lsp._capability.is_enabled(Capability.name, { 1333 bufnr = bufnr, 1334 client_id = self.id, 1335 }) 1336 then 1337 local capability = Capability.active[bufnr] 1338 if capability then 1339 capability:on_detach(self.id) 1340 if next(capability.client_state) == nil then 1341 capability:destroy() 1342 end 1343 end 1344 end 1345 end 1346 1347 changetracking.reset_buf(self, bufnr) 1348 1349 if self:supports_method('textDocument/didClose') then 1350 local uri = vim.uri_from_bufnr(bufnr) 1351 local params = { textDocument = { uri = uri } } 1352 self:notify('textDocument/didClose', params) 1353 end 1354 1355 self.attached_buffers[bufnr] = nil 1356 1357 local namespace = lsp.diagnostic.get_namespace(self.id) 1358 vim.diagnostic.reset(namespace, bufnr) 1359 end 1360 1361 --- Reset defaults set by `set_defaults`. 1362 --- Must only be called if the last client attached to a buffer exits. 1363 local function reset_defaults(bufnr) 1364 if vim.bo[bufnr].tagfunc == 'v:lua.vim.lsp.tagfunc' then 1365 vim.bo[bufnr].tagfunc = nil 1366 end 1367 if vim.bo[bufnr].omnifunc == 'v:lua.vim.lsp.omnifunc' then 1368 vim.bo[bufnr].omnifunc = nil 1369 end 1370 if vim.bo[bufnr].formatexpr == 'v:lua.vim.lsp.formatexpr()' then 1371 vim.bo[bufnr].formatexpr = nil 1372 end 1373 vim._with({ buf = bufnr }, function() 1374 local keymap = vim.fn.maparg('K', 'n', false, true) 1375 if keymap and keymap.callback == lsp.buf.hover and keymap.buffer == 1 then 1376 vim.keymap.del('n', 'K', { buffer = bufnr }) 1377 end 1378 end) 1379 end 1380 1381 --- @private 1382 --- Invoked on client exit. 1383 --- 1384 --- @param code integer) exit code of the process 1385 --- @param signal integer the signal used to terminate (if any) 1386 function Client:_on_exit(code, signal) 1387 if self._shutdown_timer and not self._shutdown_timer:is_closing() then 1388 self._shutdown_timer:close() 1389 self._shutdown_timer = nil 1390 end 1391 1392 vim.schedule(function() 1393 for bufnr in pairs(self.attached_buffers) do 1394 self:_on_detach(bufnr) 1395 if #lsp.get_clients({ bufnr = bufnr, _uninitialized = true }) == 0 then 1396 reset_defaults(bufnr) 1397 end 1398 end 1399 1400 -- Schedule the deletion of the client object 1401 -- so that it exists in the execution of autocommands 1402 vim.schedule(function() 1403 all_clients[self.id] = nil 1404 1405 -- Client can be absent if executable starts, but initialize fails 1406 -- init/attach won't have happened 1407 if self then 1408 changetracking.reset(self) 1409 end 1410 if code ~= 0 or (signal ~= 0 and signal ~= 15) then 1411 local msg = string.format( 1412 'Client %s quit with exit code %s and signal %s. Check log for errors: %s', 1413 self and self.name or 'unknown', 1414 code, 1415 signal, 1416 log.get_filename() 1417 ) 1418 vim.notify(msg, vim.log.levels.WARN) 1419 end 1420 end) 1421 end) 1422 1423 if self._handle_restart ~= nil then 1424 self._handle_restart() 1425 self._handle_restart = nil 1426 end 1427 1428 self:_run_callbacks( 1429 self._on_exit_cbs, 1430 lsp.client_errors.ON_EXIT_CALLBACK_ERROR, 1431 code, 1432 signal, 1433 self.id 1434 ) 1435 end 1436 1437 --- Add a directory to the workspace folders. 1438 --- @param dir string? 1439 function Client:_add_workspace_folder(dir) 1440 for _, folder in pairs(self.workspace_folders or {}) do 1441 if folder.name == dir then 1442 print(dir, 'is already part of this workspace') 1443 return 1444 end 1445 end 1446 1447 local wf = assert(lsp._get_workspace_folders(dir)) 1448 1449 self:notify('workspace/didChangeWorkspaceFolders', { 1450 event = { added = wf, removed = {} }, 1451 }) 1452 1453 if not self.workspace_folders then 1454 self.workspace_folders = {} 1455 end 1456 vim.list_extend(self.workspace_folders, wf) 1457 end 1458 1459 --- Remove a directory to the workspace folders. 1460 --- @param dir string? 1461 function Client:_remove_workspace_folder(dir) 1462 local wf = assert(lsp._get_workspace_folders(dir)) 1463 1464 self:notify('workspace/didChangeWorkspaceFolders', { 1465 event = { added = {}, removed = wf }, 1466 }) 1467 1468 for idx, folder in pairs(self.workspace_folders) do 1469 if folder.name == dir then 1470 table.remove(self.workspace_folders, idx) 1471 break 1472 end 1473 end 1474 end 1475 1476 -- Export for internal use only. 1477 Client._all = all_clients 1478 1479 return Client