aboutsummaryrefslogtreecommitdiffstats
path: root/lsp/gopls.lua
diff options
context:
space:
mode:
authorBenjamin Alpert <benjamin.alpert@t-systems.com>2025-07-09 03:22:20 +0200
committerGitHub <noreply@github.com>2025-07-08 18:22:20 -0700
commit592916db3f4ecdf062962b3aa83583aebe3c4a14 (patch)
tree7f2845c8720b55c0521f6e27119fe59983c3a829 /lsp/gopls.lua
parentfeat(ts_ls): implement codelens support #3938 (diff)
downloadnvim-lspconfig-592916db3f4ecdf062962b3aa83583aebe3c4a14.tar
nvim-lspconfig-592916db3f4ecdf062962b3aa83583aebe3c4a14.tar.gz
nvim-lspconfig-592916db3f4ecdf062962b3aa83583aebe3c4a14.tar.bz2
nvim-lspconfig-592916db3f4ecdf062962b3aa83583aebe3c4a14.tar.lz
nvim-lspconfig-592916db3f4ecdf062962b3aa83583aebe3c4a14.tar.xz
nvim-lspconfig-592916db3f4ecdf062962b3aa83583aebe3c4a14.tar.zst
nvim-lspconfig-592916db3f4ecdf062962b3aa83583aebe3c4a14.zip
feat(gopls): refactor root_dir identification #3942
Refactor the logic on how to identify the root_dir for gopls. This will provide a viable solution to the issue where multiple gopls lsp client instances are started, causing adverse effects in certain areas like diagnostics, lsp functionality (such as `go to definition`, workspace-enabled projects). The identification for required directories are based on golang-specific environment variables which are set by default.
Diffstat (limited to 'lsp/gopls.lua')
-rw-r--r--lsp/gopls.lua91
1 files changed, 72 insertions, 19 deletions
diff --git a/lsp/gopls.lua b/lsp/gopls.lua
index fd22ff0d..0b4c59f6 100644
--- a/lsp/gopls.lua
+++ b/lsp/gopls.lua
@@ -4,13 +4,80 @@
---
--- Google's lsp server for golang.
+--- @class go_dir_custom_args
+---
+--- @field envvar_id string
+---
+--- @field custom_subdir string?
+
local mod_cache = nil
+local std_lib = nil
+
+---@param custom_args go_dir_custom_args
+---@param on_complete fun(dir: string | nil)
+local function identify_go_dir(custom_args, on_complete)
+ local cmd = { 'go', 'env', custom_args.envvar_id }
+ vim.system(cmd, { text = true }, function(output)
+ local res = vim.trim(output.stdout or '')
+ if output.code == 0 and res ~= '' then
+ if custom_args.custom_subdir and custom_args.custom_subdir ~= '' then
+ res = res .. custom_args.custom_subdir
+ end
+ on_complete(res)
+ else
+ vim.schedule(function()
+ vim.notify(
+ ('[gopls] identify ' .. custom_args.envvar_id .. ' dir cmd failed with code %d: %s\n%s'):format(
+ output.code,
+ vim.inspect(cmd),
+ output.stderr
+ )
+ )
+ end)
+ on_complete(nil)
+ end
+ end)
+end
+
+---@return string?
+local function get_std_lib_dir()
+ if std_lib and std_lib ~= '' then
+ return std_lib
+ end
+
+ identify_go_dir({ envvar_id = 'GOROOT', custom_subdir = '/src' }, function(dir)
+ if dir then
+ std_lib = dir
+ end
+ end)
+ return std_lib
+end
+
+---@return string?
+local function get_mod_cache_dir()
+ if mod_cache and mod_cache ~= '' then
+ return mod_cache
+ end
+
+ identify_go_dir({ envvar_id = 'GOMODCACHE' }, function(dir)
+ if dir then
+ mod_cache = dir
+ end
+ end)
+ return mod_cache
+end
---@param fname string
---@return string?
-local function get_root(fname)
+local function get_root_dir(fname)
if mod_cache and fname:sub(1, #mod_cache) == mod_cache then
- local clients = vim.lsp.get_clients { name = 'gopls' }
+ local clients = vim.lsp.get_clients({ name = 'gopls' })
+ if #clients > 0 then
+ return clients[#clients].config.root_dir
+ end
+ end
+ if std_lib and fname:sub(1, #std_lib) == std_lib then
+ local clients = vim.lsp.get_clients({ name = 'gopls' })
if #clients > 0 then
return clients[#clients].config.root_dir
end
@@ -23,23 +90,9 @@ return {
filetypes = { 'go', 'gomod', 'gowork', 'gotmpl' },
root_dir = function(bufnr, on_dir)
local fname = vim.api.nvim_buf_get_name(bufnr)
+ get_mod_cache_dir()
+ get_std_lib_dir()
-- see: https://github.com/neovim/nvim-lspconfig/issues/804
- if mod_cache then
- on_dir(get_root(fname))
- return
- end
- local cmd = { 'go', 'env', 'GOMODCACHE' }
- vim.system(cmd, { text = true }, function(output)
- if output.code == 0 then
- if output.stdout then
- mod_cache = vim.trim(output.stdout)
- end
- on_dir(get_root(fname))
- else
- vim.schedule(function()
- vim.notify(('[gopls] cmd failed with code %d: %s\n%s'):format(output.code, cmd, output.stderr))
- end)
- end
- end)
+ on_dir(get_root_dir(fname))
end,
}