diff --git a/lsp/angularls.lua b/lsp/angularls.lua index 80b9d11dd1..a5a94c6ec1 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' }, }