aboutsummaryrefslogtreecommitdiffstats
path: root/lsp
diff options
context:
space:
mode:
authorErikson Kaszubowski <erikson84@yahoo.com.br>2025-10-31 00:08:07 -0300
committerGitHub <noreply@github.com>2025-10-30 20:08:07 -0700
commit7580edb811bf48619943aba6abef3bbfa2319bf9 (patch)
treea981d58f68710c7a3170a3731f6b8a7e51d5602e /lsp
parentdocs: update configs.md (diff)
downloadnvim-lspconfig-7580edb811bf48619943aba6abef3bbfa2319bf9.tar
nvim-lspconfig-7580edb811bf48619943aba6abef3bbfa2319bf9.tar.gz
nvim-lspconfig-7580edb811bf48619943aba6abef3bbfa2319bf9.tar.bz2
nvim-lspconfig-7580edb811bf48619943aba6abef3bbfa2319bf9.tar.lz
nvim-lspconfig-7580edb811bf48619943aba6abef3bbfa2319bf9.tar.xz
nvim-lspconfig-7580edb811bf48619943aba6abef3bbfa2319bf9.tar.zst
nvim-lspconfig-7580edb811bf48619943aba6abef3bbfa2319bf9.zip
fix(angularls): improve root path resolution #4083
Problem: The current config for Angular LS make strong assumptions when trying to find the root dir, which can lead to unexpected LSP crashes. Solution: By defining the 'cmd' field as a function, the config employs Neovim's LSP root resolution to identify the correct path and find the relevant node_modules folder. Co-authored-by: Erikson Kaszubowski <erikson.kaszubowski@serpro.gov.br>
Diffstat (limited to 'lsp')
-rw-r--r--lsp/angularls.lua114
1 files changed, 63 insertions, 51 deletions
diff --git a/lsp/angularls.lua b/lsp/angularls.lua
index 80b9d11d..a5a94c6e 100644
--- a/lsp/angularls.lua
+++ b/lsp/angularls.lua
@@ -14,72 +14,84 @@
-- Angular requires a node_modules directory to probe for @angular/language-service and typescript
-- in order to use your projects configured versions.
-local root_dir = vim.fn.getcwd()
-local node_modules_dir = vim.fs.find('node_modules', { path = root_dir, upward = true })[1]
-local project_root = node_modules_dir and vim.fs.dirname(node_modules_dir) or '?'
+local fs, fn, uv = vim.fs, vim.fn, vim.uv
-local function get_probe_dir()
- return project_root and (project_root .. '/node_modules') or ''
-end
+local function collect_node_modules(root_dir)
+ local results = {}
-local function get_angular_core_version()
- if not project_root then
- return ''
+ local project_node = fs.joinpath(root_dir, 'node_modules')
+ if uv.fs_stat(project_node) then
+ table.insert(results, project_node)
end
- local package_json = project_root .. '/package.json'
- if not vim.uv.fs_stat(package_json) then
- return ''
+ local ngserver_exe = fn.exepath('ngserver')
+ if ngserver_exe and #ngserver_exe > 0 then
+ local realpath = uv.fs_realpath(ngserver_exe) or ngserver_exe
+ local candidate = fs.normalize(fs.joinpath(fs.dirname(realpath), '../../node_modules'))
+ if uv.fs_stat(candidate) then
+ table.insert(results, candidate)
+ end
end
- local contents = io.open(package_json):read '*a'
- local json = vim.json.decode(contents)
- if not json.dependencies then
- return ''
+ local internal_servers = fn.globpath(fn.stdpath('data'), '**/node_modules/.bin/ngserver', true, true)
+ for _, exe in ipairs(internal_servers) do
+ local realpath = uv.fs_realpath(exe) or exe
+ local candidate = fs.normalize(fs.joinpath(fs.dirname(realpath), '../../node_modules'))
+ if uv.fs_stat(candidate) then
+ table.insert(results, candidate)
+ end
end
- local angular_core_version = json.dependencies['@angular/core']
-
- angular_core_version = angular_core_version and angular_core_version:match('%d+%.%d+%.%d+')
-
- return angular_core_version
+ return results
end
-local default_probe_dir = get_probe_dir()
-local default_angular_core_version = get_angular_core_version()
+local function get_angular_core_version(root_dir)
+ local package_json = fs.joinpath(root_dir, 'package.json')
+ if not uv.fs_stat(package_json) then
+ return ''
+ end
+
+ local ok, f = pcall(io.open, package_json, 'r')
+ if not ok or not f then
+ return ''
+ end
--- structure should be like
--- - $EXTENSION_PATH
--- - @angular
--- - language-server
--- - bin
--- - ngserver
--- - typescript
-local ngserver_exe = vim.fn.exepath('ngserver')
-local ngserver_path = #(ngserver_exe or '') > 0 and vim.fs.dirname(vim.uv.fs_realpath(ngserver_exe)) or '?'
-local extension_path = vim.fs.normalize(vim.fs.joinpath(ngserver_path, '../../../'))
+ local json = vim.json.decode(f:read('*a')) or {}
+ f:close()
--- angularls will get module by `require.resolve(PROBE_PATH, MODULE_NAME)` of nodejs
-local ts_probe_dirs = vim.iter({ extension_path, default_probe_dir }):join(',')
-local ng_probe_dirs = vim
- .iter({ extension_path, default_probe_dir })
- :map(function(p)
- return vim.fs.joinpath(p, '/@angular/language-server/node_modules')
- end)
- :join(',')
+ local version = (json.dependencies or {})['@angular/core'] or ''
+ return version:match('%d+%.%d+%.%d+') or ''
+end
---@type vim.lsp.Config
return {
- cmd = {
- 'ngserver',
- '--stdio',
- '--tsProbeLocations',
- ts_probe_dirs,
- '--ngProbeLocations',
- ng_probe_dirs,
- '--angularCoreVersion',
- default_angular_core_version,
- },
+ cmd = function(dispatchers, config)
+ local root_dir = config.root or fn.getcwd()
+ local node_paths = collect_node_modules(root_dir)
+
+ local ts_probe = table.concat(node_paths, ',')
+ local ng_probe = table.concat(
+ vim
+ .iter(node_paths)
+ :map(function(p)
+ return fs.joinpath(p, '@angular/language-server/node_modules')
+ end)
+ :totable(),
+ ','
+ )
+ local cmd = {
+ 'ngserver',
+ '--stdio',
+ '--tsProbeLocations',
+ ts_probe,
+ '--ngProbeLocations',
+ ng_probe,
+ '--angularCoreVersion',
+ get_angular_core_version(root_dir),
+ }
+ return vim.lsp.rpc.start(cmd, dispatchers)
+ end,
+
filetypes = { 'typescript', 'html', 'typescriptreact', 'typescript.tsx', 'htmlangular' },
root_markers = { 'angular.json', 'nx.json' },
}