Skip to content

Commit

Permalink
nvim: fix horrible performance on windows
Browse files Browse the repository at this point in the history
All lsp servers were being registered w/ lspconfig on CmdEnter or
FileType. On windows, some were taking hundreds of ms, adding up to
nearly 5 seconds.

Fixed by making lsp registration / installation happen on FileType
event.
  • Loading branch information
chris468 committed Jun 22, 2024
2 parents 50e2fe2 + 74d8494 commit af90271
Show file tree
Hide file tree
Showing 13 changed files with 478 additions and 343 deletions.
71 changes: 71 additions & 0 deletions dotfiles/private_dot_config/nvim/lua/chris468/config/lang/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
local util = require("chris468.util")
local config = require("chris468.config")

--- @class chris468.config.lang.Tools
--- @field lint string[]?
--- @field format string[]?

--- @class (exact) chris468.config.lang.Lsp
--- @field config? (table | fun():table?)
--- @field register_server? table | fun():table?
--- @field package_name? string

--- @class (exact) chris468.config.lang.Config
--- @field lsp { [string]: false | chris468.config.lang.Lsp }
--- @field tools chris468.config.lang.Tools
local M = {}

M.lsp = {
angularls = {},
ansiblels = {},
autotools_ls = {},
bashls = {},
clangd = {},
cmake = {},
cssls = {},
docker_compose_language_service = {},
dockerls = {},
elixirls = {},
erlangls = {},
gopls = {},
helm_ls = {},
html = {},
java_language_server = {},
jsonls = {},
lemminx = {}, -- xml
lua_ls = {},
mesonlsp = {},
nil_ls = {}, -- nix
omnisharp = require("chris468.config.lang.omnisharp"),
powershell_es = {},
pyright = require("chris468.config.lang.pyright"),
roslyn_lsp = require("chris468.config.lang.roslyn"),
rust_analyzer = {},
ruff = {}, -- python
spectral = {}, -- OpenAPI
taplo = {}, -- toml
terraformls = {},
tflint = {},
tsserver = {},
vimls = {},
yamlls = {},
codeqlls = {},
}

--- @type { [string]: chris468.config.lang.Tools }
M.tools = {
markdown = {
lint = { "markdownlint" },
},
lua = {
format = { "stylua" },
},
python = {
format = { "black" },
},
javascript = {
format = { "prettierd", "prettier" },
},
}

return M
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
local util = require("chris468.util")
local config = require("chris468.config")

if not util.contains(config.csharp_lsp, "omnnisharp") then
return false
end

local function between(current, range)
return range.start.row == range["end"].row
and current.row == range.start.row
Expand Down Expand Up @@ -30,20 +37,23 @@ local function configure_omnisharp_commands()
end
end

--- @type chris468.config.lang.Lsp
return {
cmd = { "omnisharp", "--languageserver", "--hostpid", tostring(vim.fn.getpid()) },
on_attach = function(_, _)
-- Ideally this would just set up the command in the comands table, but in lspconfig
-- that currently sets up autocmds. see neovim/nvim-lspconfig/issues/2632.
configure_omnisharp_commands()
end,
settings = {
FormattingOptions = {
OrganizeImports = true,
},
RoslynExtensionsOptions = {
EnableAnalyzersSupport = true,
EnableImportCompletion = true,
config = {
cmd = { "omnisharp", "--languageserver", "--hostpid", tostring(vim.fn.getpid()) },
on_attach = function(_, _)
-- Ideally this would just set up the command in the comands table, but in lspconfig
-- that currently sets up autocmds. see neovim/nvim-lspconfig/issues/2632.
configure_omnisharp_commands()
end,
settings = {
FormattingOptions = {
OrganizeImports = true,
},
RoslynExtensionsOptions = {
EnableAnalyzersSupport = true,
EnableImportCompletion = true,
},
},
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
local function detect_venv(root_dir)
local Job = require("plenary.job")
local python = vim.loop.os_uname().sysname == "Windows_NT" and "python.exe" or "python"
local dot_venv_python = root_dir .. "/.venv/bin/" .. python
if vim.fn.filereadable(dot_venv_python) == 1 then
return dot_venv_python
end

local pyproject = root_dir .. "/pyproject.toml"
if vim.fn.executable("poetry") == 1 and vim.fn.filereadable(pyproject) == 1 then
local ok, venv = pcall(function()
return Job:new({
command = "poetry",
cwd = root_dir,
args = { "env", "info", "-p" },
})
:sync()[1]
end)
if ok then
return venv .. "/bin/" .. python
end
end

return false
end

return {
config = {
on_new_config = function(new_config, new_root_dir)
local defaults = require("lspconfig.server_configurations.pyright")
if defaults.on_new_config then
defaults.on_new_config(new_config, new_root_dir)
end

local venv_python = detect_venv(new_root_dir)
if venv_python then
new_config.settings.python.pythonPath = venv_python
end
end,
},
}
104 changes: 104 additions & 0 deletions dotfiles/private_dot_config/nvim/lua/chris468/config/lang/roslyn.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
local util = require("chris468.util")
local config = require("chris468.config")

if not util.contains(config.csharp_lsp, "roslyn") then
return false
end

local function configure_client_commands()
vim.lsp.commands["roslyn.client.peekReferences"] = function(command, context)
local window = vim.fn.bufwinid(context.bufnr)
local pos = { command.arguments[2].line + 1, command.arguments[2].character }

vim.api.nvim_win_set_cursor(window, pos)

require("telescope.builtin").lsp_references()
end
end

local function open_solution(client, sln)
vim.notify("Opening " .. sln .. "...")
client.notify("solution/open", { solution = vim.uri_from_fname(sln) })
end

local function get_solutions(client)
local root = client.config.root_dir
local slns = vim.fn.glob(root .. "/*.sln", nil, true)
return slns
end

local function find_and_open_solution(client)
local slns = get_solutions(client)
vim.notify(tostring(#slns) .. " solution found.")
if #slns == 0 then
return
end
open_solution(client, slns[1])
end

local function prompt_for_solution(client)
local slns = get_solutions(client)
vim.ui.select(slns, { prompt = "Choose solution" }, function(selected)
if selected then
open_solution(client, selected)
end
end)
end

local function register_user_commands(client, bufnr)
vim.api.nvim_buf_set_keymap(bufnr, "n", "gos", "", {
callback = function()
prompt_for_solution(client)
end,
desc = "Open solution",
})
end

--- @type chris468.config.lang.Lsp
return {
config = {},
register_server = function()
local root_pattern = require("lspconfig.util").root_pattern

return {
default_config = {
cmd = {
"roslyn_lsp",
"--logLevel",
"Information",
"--extensionLogDirectory",
vim.fn.stdpath("state"),
},
filetypes = { "cs" },
handlers = {
["workspace/projectInitializationComplete"] = function()
vim.notify("Project initialization complete.")
end,
},
on_attach = function(client, bufnr)
register_user_commands(client, bufnr)
end,
on_init = function(client)
find_and_open_solution(client)

-- Ideally this would just set up the command in the comands table, but in lspconfig
-- that currently sets up autocmds. see neovim/nvim-lspconfig/issues/2632.
configure_client_commands()
end,
on_new_config = function(new_config, _)
if vim.g.debug_roslyn_lsp == 1 then
new_config.cmd = {
"lsp-devtools",
"agent",
"--",
unpack(new_config.cmd),
}
end
end,
root_dir = root_pattern({ "*.sln", "*.csproj" }),
settings = {},
},
}
end,
package_name = "chris468_roslyn_lsp",
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ local function format()
conform.format({ lsp_fallback = true, timeout_ms = 1500 })
end

--- @type { [string]: chris468.util.mason.Tool}
local formatters_by_ft = {
lua = { "stylua" },
python = { "black" },
Expand Down
Loading

0 comments on commit af90271

Please sign in to comment.