aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorToby Vincent <tobyv@tobyvin.dev>2024-04-04 20:36:16 -0500
committerToby Vincent <tobyv@tobyvin.dev>2024-04-04 20:36:16 -0500
commit79650be92e3f89cc5a46032978bb77d783526ed4 (patch)
tree394d5eacbe389e4a6a638046d4fb83dd84a67b8b
parent17db1d2757db37d99c748bb00f5a1634c79dbf7c (diff)
feat(nvim,wip): add initial utils for lsp timeout
-rw-r--r--nvim/.config/nvim/lua/plugins/ferris.lua4
-rw-r--r--nvim/.config/nvim/lua/plugins/lspconfig.lua13
-rw-r--r--nvim/.config/nvim/lua/tobyvin/utils.lua25
-rw-r--r--nvim/.config/nvim/lua/tobyvin/utils/lsp.lua108
4 files changed, 119 insertions, 31 deletions
diff --git a/nvim/.config/nvim/lua/plugins/ferris.lua b/nvim/.config/nvim/lua/plugins/ferris.lua
index 5d3b685..8a800c1 100644
--- a/nvim/.config/nvim/lua/plugins/ferris.lua
+++ b/nvim/.config/nvim/lua/plugins/ferris.lua
@@ -8,9 +8,9 @@ local M = {
}
function M:init()
- U.on_attach(function()
+ U.lsp.on_attach("rust_analyzer", function()
vim.keymap.set("n", "gx", require("ferris.methods.open_documentation"), { desc = "open external docs" })
- end, { name = "rust_analyzer" })
+ end, { desc = "setup ferris keymaps" })
end
return M
diff --git a/nvim/.config/nvim/lua/plugins/lspconfig.lua b/nvim/.config/nvim/lua/plugins/lspconfig.lua
index df7450e..70652ef 100644
--- a/nvim/.config/nvim/lua/plugins/lspconfig.lua
+++ b/nvim/.config/nvim/lua/plugins/lspconfig.lua
@@ -11,16 +11,19 @@ local M = {
function M:config()
require("neoconf")
- require("lspconfig.util").default_config.capabilities =
+ require("lspconfig").util.default_config.capabilities =
require("cmp_nvim_lsp").default_capabilities(vim.lsp.protocol.make_client_capabilities())
require("lspconfig.ui.windows").default_options.border = "single"
- local available = require("lspconfig.util").available_servers()
- for name, config in pairs(require("tobyvin.lsp.configs")) do
- if not vim.tbl_contains(available, name) then
+ local avail = require("lspconfig").util.available_servers()
+
+ vim.iter(require("tobyvin.lsp.configs")):each(function(name, config)
+ if not vim.tbl_contains(avail, name) then
require("lspconfig")[name].setup(config)
end
- end
+
+ require("tobyvin.lsp.configs")[name] = require("lspconfig")[name].manager.config
+ end)
end
return M
diff --git a/nvim/.config/nvim/lua/tobyvin/utils.lua b/nvim/.config/nvim/lua/tobyvin/utils.lua
index c107d17..1cb6329 100644
--- a/nvim/.config/nvim/lua/tobyvin/utils.lua
+++ b/nvim/.config/nvim/lua/tobyvin/utils.lua
@@ -4,6 +4,7 @@ local M = {
dashboard = require("tobyvin.utils.dashboard"),
session = require("tobyvin.utils.session"),
dap = require("tobyvin.utils.dap"),
+ lsp = require("tobyvin.utils.lsp"),
}
function M.inspect(v)
@@ -74,30 +75,6 @@ function M.system(...)
return s
end
----Register callback to run when a lsp server matching a filter attaches to a buffer
----@param on_attach fun(client: lsp.Client, buffer: integer): boolean|nil
----@param filter vim.lsp.get_clients.filter|nil
-function M.on_attach(on_attach, filter)
- vim.api.nvim_create_autocmd("LspAttach", {
- desc = "on client attach",
- callback = function(args)
- local bufnr = args.buf ---@type number
- local client = vim.lsp.get_client_by_id(args.data.client_id)
- filter = filter or {}
-
- if
- client
- and (filter.id == nil or client.id == filter.id)
- and (filter.name == nil or client.name == filter.name)
- and (filter.bufnr == nil or bufnr == filter.bufnr)
- and (filter.method == nil or client.supports_method(filter.method, { bufnr = bufnr }))
- then
- on_attach(client, bufnr)
- end
- end,
- })
-end
-
---Merges two or more highlights groups into a new highlight group.
---
---**Note**: This will overwrite any existing group named <name>. If you would like to both merge
diff --git a/nvim/.config/nvim/lua/tobyvin/utils/lsp.lua b/nvim/.config/nvim/lua/tobyvin/utils/lsp.lua
new file mode 100644
index 0000000..e0fc17b
--- /dev/null
+++ b/nvim/.config/nvim/lua/tobyvin/utils/lsp.lua
@@ -0,0 +1,108 @@
+local M = {
+ lsp_timeout_ms = 600000,
+ lsp_restart_delay_ms = 1000,
+}
+
+---Register callback to run when a lsp server matching a filter attaches to a buffer
+---@param filter string|string[]|vim.lsp.get_clients.Filter|vim.lsp.get_clients.Filter[]|nil
+---@param on_attach fun(client: vim.lsp.Client, bufnr: integer): boolean|nil
+---@param opts vim.api.keyset.create_autocmd?
+function M.on_attach(filter, on_attach, opts)
+ opts = opts or {}
+ opts.callback = function(args)
+ local bufnr = args.buf ---@type number
+ local client = vim.lsp.get_client_by_id(args.data.client_id)
+
+ if
+ client
+ and vim.iter({ filter }):all(function(f)
+ return (type(f) == "string" and f == client.name)
+ or (f.id == nil or client.id == f.id)
+ and (f.name == nil or client.name == f.name)
+ and (f.bufnr == nil or bufnr == f.bufnr)
+ and (f.method == nil or client.supports_method(f.method, { bufnr = bufnr }))
+ end)
+ then
+ on_attach(client, bufnr)
+ end
+ end
+
+ vim.api.nvim_create_autocmd("LspAttach", opts)
+end
+
+---@param client vim.lsp.Client
+---@param bufnr integer
+function M.initiate_timeout(client, bufnr)
+ if vim.b[bufnr].timed_out then
+ return
+ end
+
+ if vim.b[bufnr].restarting then
+ vim.b[bufnr].restarting:stop()
+ end
+
+ vim.b[bufnr].lsp_timeout = vim.defer_fn(function()
+ vim.b[bufnr].timed_out = true
+
+ local timed_out = vim.iter(client.attached_buffers):all(function(buf)
+ return vim.b[buf].timed_out
+ end)
+
+ if timed_out then
+ client.stop()
+ client.rpc.terminate()
+ end
+ end, M.lsp_timeout)
+end
+
+---@param client vim.lsp.Client
+---@param bufnr integer
+function M.initiate_restart(client, bufnr)
+ if not vim.b[bufnr].timed_out then
+ return
+ end
+
+ vim.b[bufnr].restarting = vim.defer_fn(function()
+ vim.b[bufnr].lsp_timeout:stop()
+ require("lspconfig.configs")[client.name].launch(bufnr)
+
+ vim.b[bufnr].restarting:close()
+ vim.b[bufnr].restarting = nil
+ vim.b[bufnr].timed_out = nil
+ end, M.lsp_restart_delay_ms)
+end
+
+---@param client vim.lsp.Client
+---@param bufnr integer
+function M.setup_timeout(client, bufnr)
+ vim.api.nvim_create_autocmd("BufLeave", {
+ buffer = bufnr,
+ callback = function()
+ M.initiate_timeout(client, bufnr)
+ end,
+ })
+
+ vim.api.nvim_create_autocmd("BufEnter", {
+ buffer = bufnr,
+ callback = function()
+ M.initiate_restart(client, bufnr)
+ end,
+ })
+end
+
+---Sends a notification.
+---@param kind string Accepted values are:
+---{ "lsp_has_started", "lsp_has_stopped" }
+function M.notify(kind)
+ if kind == "lsp_has_started" then
+ vim.notify("Focus recovered. Starting LSP clients.", vim.log.levels.INFO, { title = "garbage-day.nvim" })
+ elseif kind == "lsp_has_stopped" then
+ vim.notify(
+ "Inactive LSP clients have been stopped to save resources.",
+ vim.log.levels.INFO,
+ { title = "garbage-day.nvim" }
+ )
+ end
+end
+
+return M