aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErikson Kaszubowski <erikson84@yahoo.com.br>2025-11-16 20:50:43 -0300
committerGitHub <noreply@github.com>2025-11-16 15:50:43 -0800
commitdbf98c4d15a1a8d7f620d8a558e0699eacda7582 (patch)
treeda9b36a3b321049f48edf794ab5bd2fac639efb8
parentfix(lsp): improve ts_ls root detection for deno projects #4193 (diff)
downloadnvim-lspconfig-dbf98c4d15a1a8d7f620d8a558e0699eacda7582.tar
nvim-lspconfig-dbf98c4d15a1a8d7f620d8a558e0699eacda7582.tar.gz
nvim-lspconfig-dbf98c4d15a1a8d7f620d8a558e0699eacda7582.tar.bz2
nvim-lspconfig-dbf98c4d15a1a8d7f620d8a558e0699eacda7582.tar.lz
nvim-lspconfig-dbf98c4d15a1a8d7f620d8a558e0699eacda7582.tar.xz
nvim-lspconfig-dbf98c4d15a1a8d7f620d8a558e0699eacda7582.tar.zst
nvim-lspconfig-dbf98c4d15a1a8d7f620d8a558e0699eacda7582.zip
fix(angularls): improves node_modules path resolution #4190
Problem: Search for node_modules uses a costly call to fn.globpath; the final path resolution was not working on Linux. Solution: A custom function to resolve ngserver location from CMD wrappers on Windows; and the corrected final path. Co-authored-by: Erikson K. <erikson23@gmail.com>
-rw-r--r--lsp/angularls.lua54
1 files changed, 40 insertions, 14 deletions
diff --git a/lsp/angularls.lua b/lsp/angularls.lua
index ec81789f..af82b87a 100644
--- a/lsp/angularls.lua
+++ b/lsp/angularls.lua
@@ -16,6 +16,41 @@
-- in order to use your projects configured versions.
local fs, fn, uv = vim.fs, vim.fn, vim.uv
+--- Recursively solve for the original ngserver path on Windows
+-- For a given ngserver path:
+-- - If it is not a CMD wrapper, return the path;
+-- - Or else, extract the path from the CMD wrapper.
+--
+-- @param cmd_path (string) path for the ngserver executable or its CMD wrapper.
+-- @return (string) the original executable path for ngserver
+-- @usage
+-- -- Base case: cmd_path already points to ngserver (expected behavior on Linux)
+-- resolve_cmd_shim('/home/user/project/node_modules/@angular/language-server/bin/ngserver')
+-- => '/home/user/project/node_modules/@angular/language-server/bin/ngserver'
+--
+-- -- Recursive case: cmd_path points to a CMD wrapper (Windows)
+-- resolve_cmd_shim('C:/Users/user/project/node_modules/.bin/ngserver.cmd')
+-- => 'C:/Users/user/project/node_modules/@angular/language-server/bin/ngserver'
+local function resolve_cmd_shim(cmd_path)
+ if not cmd_path:lower():match('%ngserver.cmd$') then
+ return cmd_path
+ end
+
+ local ok, content = pcall(fn.readblob, cmd_path)
+ if not ok or not content then
+ return cmd_path
+ end
+
+ local target = content:match('%s%"%%dp0%%\\([^\r\n]-ngserver[^\r\n]-)%"')
+ if not target then
+ return cmd_path
+ end
+
+ local full = fs.normalize(fs.joinpath(fs.dirname(cmd_path), target))
+
+ return resolve_cmd_shim(full)
+end
+
local function collect_node_modules(root_dir)
local results = {}
@@ -27,16 +62,8 @@ local function collect_node_modules(root_dir)
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 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'))
+ realpath = resolve_cmd_shim(realpath)
+ local candidate = fs.normalize(fs.joinpath(fs.dirname(realpath), '../../..'))
if uv.fs_stat(candidate) then
table.insert(results, candidate)
end
@@ -51,13 +78,12 @@ local function get_angular_core_version(root_dir)
return ''
end
- local ok, f = pcall(io.open, package_json, 'r')
- if not ok or not f then
+ local ok, content = pcall(fn.readblob, package_json)
+ if not ok or not content then
return ''
end
- local json = vim.json.decode(f:read('*a')) or {}
- f:close()
+ local json = vim.json.decode(content) or {}
local version = (json.dependencies or {})['@angular/core'] or ''
return version:match('%d+%.%d+%.%d+') or ''