From 6a32f32db8a4a5cb74161e7f8c36aa84e6006ff4 Mon Sep 17 00:00:00 2001 From: ray-x Date: Fri, 28 Mar 2025 23:10:39 +1100 Subject: [PATCH 01/17] changes for nvim 0.11 --- README.md | 71 +------ doc/navigator.txt | 15 -- lsp/ccls.lua | 10 + lsp/clangd.lua | 15 ++ lsp/gopls.lua | 40 ++++ lsp/jdtls.lua | 8 + lsp/lua_ls.lua | 64 ++++++ lsp/luals.lua | 64 ++++++ lsp/omnisharp.lua | 3 + lsp/pyright.lua | 24 +++ lsp/ruff.lua | 6 + lsp/rust_analyzer.lua | 16 ++ lua/navigator.lua | 49 +++-- lua/navigator/lspclient/attach.lua | 91 -------- lua/navigator/lspclient/clients.lua | 209 +++--------------- lua/navigator/lspclient/clients_default.lua | 221 -------------------- lua/navigator/lspclient/inlay.lua | 68 ------ lua/navigator/lspclient/lua_ls.lua | 68 ------ 18 files changed, 327 insertions(+), 715 deletions(-) create mode 100644 lsp/ccls.lua create mode 100644 lsp/clangd.lua create mode 100644 lsp/gopls.lua create mode 100644 lsp/jdtls.lua create mode 100644 lsp/lua_ls.lua create mode 100644 lsp/luals.lua create mode 100644 lsp/omnisharp.lua create mode 100644 lsp/pyright.lua create mode 100644 lsp/ruff.lua create mode 100644 lsp/rust_analyzer.lua delete mode 100644 lua/navigator/lspclient/clients_default.lua delete mode 100644 lua/navigator/lspclient/inlay.lua delete mode 100644 lua/navigator/lspclient/lua_ls.lua diff --git a/README.md b/README.md index a791722..e3d44a9 100644 --- a/README.md +++ b/README.md @@ -239,14 +239,8 @@ require'navigator'.setup({ preview_height = 0.35, -- max height of preview windows border = {"╭", "─", "╮", "│", "╯", "─", "╰", "│"}, -- border style, can be one of 'none', 'single', 'double', -- 'shadow', or a list of chars which defines the border - on_attach = function(client, bufnr) - -- your hook + on_attach = function(client, bufnr) -- no longer supported for nvim > 0.11 use your own LspAttach autocmd end, - -- put a on_attach of your own here, e.g - -- function(client, bufnr) - -- -- the on_attach will be called at end of navigator on_attach - -- end, - -- The attach code will apply to all LSP clients ts_fold = { enable = false, @@ -351,42 +345,23 @@ require'navigator'.setup({ diagnostic_update_in_insert = false, -- update diagnostic message in insert mode display_diagnostic_qf = true, -- always show quickfix if there are diagnostic errors, set to false if you want to ignore it -- set to 'trouble' to show diagnostcs in Trouble - ts_ls = { - filetypes = {'typescript'} -- disable javascript etc, - -- set to {} to disable the lspclient for all filetypes - }, ctags ={ cmd = 'ctags', tagfile = 'tags', options = '-R --exclude=.git --exclude=node_modules --exclude=test --exclude=vendor --excmd=number', }, - gopls = { -- gopls setting - on_attach = function(client, bufnr) -- on_attach for gopls - -- your special on attach here - -- e.g. disable gopls format because a known issue https://github.com/golang/go/issues/45732 - print("i am a hook, I will disable document format") - client.resolved_capabilities.document_formatting = false - end, - settings = { - gopls = {gofumpt = false} -- disable gofumpt etc, - } + -- lsp setup and config no longer supported for nvim 0.11 + -- refer to nvim 0.11 lsp setup doc and lspconfig for more info + ts_ls = { -- no longer supported for nvim 0.11 + }, + gopls = { -- no longer supported for nvim 0.11 }, -- the lsp setup can be a function, .e.g - gopls = function() - local go = pcall(require, "go") - if go then - local cfg = require("go.lsp").config() - cfg.on_attach = function(client) - client.server_capabilities.documentFormattingProvider = false -- efm/null-ls - end - return cfg - end + gopls = function() -- no longer supported for nvim 0.11 end, - lua_ls = { - sumneko_root_path = vim.fn.expand("$HOME") .. "/github/sumneko/lua-language-server", - sumneko_binary = vim.fn.expand("$HOME") .. "/github/sumneko/lua-language-server/bin/macOS/lua-language-server", - }, + lua_ls = { }, -- no longer supported + servers = {'cmake', 'ltex'}, -- by default empty, and it should load all LSP clients available based on filetype -- but if you want navigator load e.g. `cmake` and `ltex` for you , you -- can put them in the `servers` list and navigator will auto load them. @@ -645,32 +620,6 @@ Another way to setup mason is disable navigator lsp setup and using mason setup Alternatively, Navigator can be used to startup the server installed by mason. as it will override the navigator setup -To start LSP installed by mason, please use following setups - -```lua -require'navigator'.setup({ - -- mason = false -- default value is false - lsp = { - ts_ls = { cmd = {'your typescript-language-server installed by mason'} } - -- e.g. ts_ls = { cmd = {'/home/username/.local/share/nvim/mason/packages/typescript-language-server/node_modules/typescript/bin/typescript-language-server'} } - - } -}) -``` - -example cmd setup (mac) for pyright : - -```lua -require'navigator'.setup({ - -- mason = false -- default value is false - - lsp = { - pyright = { - cmd = { "/Users/username/.local/share/nvim/lsp_servers/python/node_modules/.bin/pyright-langserver", "--stdio" } - } - } -} -``` ### Integration with other lsp plugins (e.g. rust-tools, go.nvim, clangd extension) @@ -697,7 +646,7 @@ use {"ray-x/navigator.lua", } ``` -- Here is an example to setup rust with rust-tools +- Here is an example to setup rust with rust-tools (nvim < 0.11) ```lua require('rust-tools').setup({ diff --git a/doc/navigator.txt b/doc/navigator.txt index a8e8c95..280e212 100644 --- a/doc/navigator.txt +++ b/doc/navigator.txt @@ -331,21 +331,6 @@ Nondefault configuration example: tagfile = 'tags' options = '-R --exclude=.git --exclude=node_modules --exclude=test --exclude=vendor --excmd=number' } - gopls = { -- gopls setting - on_attach = function(client, bufnr) -- on_attach for gopls - -- your special on attach here - -- e.g. disable gopls format because a known issue https://github.com/golang/go/issues/45732 - print("i am a hook, I will disable document format") - client.resolved_capabilities.document_formatting = false - end, - settings = { - gopls = {gofumpt = false} -- disable gofumpt etc, - } - }, - lua_ls = { - sumneko_root_path = vim.fn.expand("$HOME") .. "/github/sumneko/lua-language-server", - sumneko_binary = vim.fn.expand("$HOME") .. "/github/sumneko/lua-language-server/bin/macOS/lua-language-server", - }, servers = {'cmake', 'ltex'}, -- by default empty, and it should load all LSP clients avalible based on filetype -- but if you whant navigator load e.g. `cmake` and `ltex` for you , you -- can put them in the `servers` list and navigator will auto load them. diff --git a/lsp/ccls.lua b/lsp/ccls.lua new file mode 100644 index 0000000..1616ccb --- /dev/null +++ b/lsp/ccls.lua @@ -0,0 +1,10 @@ +return { + init_options = { + compilationDatabaseDirectory = 'build', + root_dir = + [[ util.root_pattern("compile_commands.json", "compile_flags.txt", "CMakeLists.txt", "Makefile", ".git") or util.path.dirname ]], + index = { threads = 2 }, + clang = { excludeArgs = { '-frounding-math' } }, + }, + flags = { allow_incremental_sync = true }, +} diff --git a/lsp/clangd.lua b/lsp/clangd.lua new file mode 100644 index 0000000..7d69a97 --- /dev/null +++ b/lsp/clangd.lua @@ -0,0 +1,15 @@ +return { + flags = { allow_incremental_sync = true, debounce_text_changes = 500 }, + cmd = { + 'clangd', + '--background-index', + '--suggest-missing-includes', + '--clang-tidy', + '--header-insertion=iwyu', + '--enable-config', + '--offset-encoding=utf-16', + '--clang-tidy-checks=-*,llvm-*,clang-analyzer-*', + '--cross-file-rename', + }, + filetypes = { 'c', 'cpp', 'objc', 'objcpp' }, +} diff --git a/lsp/gopls.lua b/lsp/gopls.lua new file mode 100644 index 0000000..f15cabe --- /dev/null +++ b/lsp/gopls.lua @@ -0,0 +1,40 @@ +local util = require('lspconfig').util +return { + -- capabilities = cap, + filetypes = { 'go', 'gomod', 'gohtmltmpl', 'gotexttmpl' }, + message_level = vim.lsp.protocol.MessageType.Error, + cmd = { + 'gopls', -- share the gopls instance if there is one already + '-remote=auto', --[[ debug options ]] -- + -- "-logfile=auto", + -- "-debug=:0", + '-remote.debug=:0', + -- "-rpc.trace", + }, + + flags = { allow_incremental_sync = true, debounce_text_changes = 1000 }, + settings = { + gopls = { + -- more settings: https://github.com/golang/tools/blob/master/gopls/doc/settings.md + -- flags = {allow_incremental_sync = true, debounce_text_changes = 500}, + -- not supported + analyses = { unusedparams = true, unreachable = false }, + codelenses = { + generate = true, -- show the `go generate` lens. + gc_details = true, -- // Show a code lens toggling the display of gc's choices. + test = true, + tidy = true, + }, + usePlaceholders = true, + completeUnimported = true, + staticcheck = true, + matcher = 'fuzzy', + diagnosticsDelay = '500ms', + symbolMatcher = 'fuzzy', + gofumpt = false, -- true, -- turn on for new repos, gofmpt is good but also create code turmoils + buildFlags = { '-tags', 'integration' }, + -- buildFlags = {"-tags", "functional"} + semanticTokens = true, + }, + }, +} diff --git a/lsp/jdtls.lua b/lsp/jdtls.lua new file mode 100644 index 0000000..bd77d81 --- /dev/null +++ b/lsp/jdtls.lua @@ -0,0 +1,8 @@ +return { + settings = { + java = { + signatureHelp = { enabled = true }, + contentProvider = { preferred = 'fernflower' }, + }, + }, +} diff --git a/lsp/lua_ls.lua b/lsp/lua_ls.lua new file mode 100644 index 0000000..d7ea829 --- /dev/null +++ b/lsp/lua_ls.lua @@ -0,0 +1,64 @@ +local vfn = vim.fn + +local library = {} +local function add(lib) + for _, p in pairs(vfn.expand(lib, false, true)) do + local uv = vim.uv or vim.loop + p = uv.fs_realpath(p) + if p then + library[p] = true + end + end +end +-- add runtime +-- add plugins it may be very slow to add all in path +add('$VIMRUNTIME') +-- add your config +-- local home = vfn.expand("$HOME") +add(vfn.stdpath('config')) + +library[vfn.expand('$VIMRUNTIME/lua')] = true +library[vfn.expand('$VIMRUNTIME')] = true +library[vfn.expand('$VIMRUNTIME/lua/vim')] = true +library[vfn.expand('$VIMRUNTIME/lua/vim/lsp')] = true + +return { + cmd = { 'lua-language-server' }, + filetypes = { 'lua' }, + flags = { allow_incremental_sync = true, debounce_text_changes = 500 }, + settings = { + Lua = { + runtime = { + -- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim) + version = 'LuaJIT', + path = { + 'lua/?.lua', + 'lua/?/init.lua', + }, + }, + hint = { enable = true, typeCoverage = true }, + diagnostics = { + enable = true, + -- Get the language server to recognize the `vim` global + globals = { 'vim', 'describe', 'it', 'before_each', 'after_each', 'teardown', 'pending' }, + }, + completion = { callSnippet = 'Both' }, + workspace = { + -- Make the server aware of Neovim runtime files + library = library, + checkThirdParty = false, + maxPreload = 1000, + preloadFileSize = 40000, + }, + telemetry = { enable = false }, + }, + }, + on_new_config = function(cfg, root) + local libs = vim.schedule(function() + vim.tbl_deep_extend('force', {}, library) + end) + libs[root] = nil + cfg.settings.Lua.workspace.library = libs + return cfg + end, +} diff --git a/lsp/luals.lua b/lsp/luals.lua new file mode 100644 index 0000000..d7ea829 --- /dev/null +++ b/lsp/luals.lua @@ -0,0 +1,64 @@ +local vfn = vim.fn + +local library = {} +local function add(lib) + for _, p in pairs(vfn.expand(lib, false, true)) do + local uv = vim.uv or vim.loop + p = uv.fs_realpath(p) + if p then + library[p] = true + end + end +end +-- add runtime +-- add plugins it may be very slow to add all in path +add('$VIMRUNTIME') +-- add your config +-- local home = vfn.expand("$HOME") +add(vfn.stdpath('config')) + +library[vfn.expand('$VIMRUNTIME/lua')] = true +library[vfn.expand('$VIMRUNTIME')] = true +library[vfn.expand('$VIMRUNTIME/lua/vim')] = true +library[vfn.expand('$VIMRUNTIME/lua/vim/lsp')] = true + +return { + cmd = { 'lua-language-server' }, + filetypes = { 'lua' }, + flags = { allow_incremental_sync = true, debounce_text_changes = 500 }, + settings = { + Lua = { + runtime = { + -- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim) + version = 'LuaJIT', + path = { + 'lua/?.lua', + 'lua/?/init.lua', + }, + }, + hint = { enable = true, typeCoverage = true }, + diagnostics = { + enable = true, + -- Get the language server to recognize the `vim` global + globals = { 'vim', 'describe', 'it', 'before_each', 'after_each', 'teardown', 'pending' }, + }, + completion = { callSnippet = 'Both' }, + workspace = { + -- Make the server aware of Neovim runtime files + library = library, + checkThirdParty = false, + maxPreload = 1000, + preloadFileSize = 40000, + }, + telemetry = { enable = false }, + }, + }, + on_new_config = function(cfg, root) + local libs = vim.schedule(function() + vim.tbl_deep_extend('force', {}, library) + end) + libs[root] = nil + cfg.settings.Lua.workspace.library = libs + return cfg + end, +} diff --git a/lsp/omnisharp.lua b/lsp/omnisharp.lua new file mode 100644 index 0000000..5afd8cd --- /dev/null +++ b/lsp/omnisharp.lua @@ -0,0 +1,3 @@ +return { + cmd = { 'omnisharp', '--languageserver', '--hostPID', tostring(vim.fn.getpid()) }, +} diff --git a/lsp/pyright.lua b/lsp/pyright.lua new file mode 100644 index 0000000..7734b49 --- /dev/null +++ b/lsp/pyright.lua @@ -0,0 +1,24 @@ +return { + -- on_init = require('navigator.lspclient.python').on_init, + on_init = function(client) + require('navigator.lspclient.python').on_init(client) + end, + on_new_config = function(new_config, new_root_dir) + local python_path = require('navigator.lspclient.python').pyenv_path(new_root_dir) + new_config.settings.python.pythonPath = python_path + end, + cmd = { 'pyright-langserver', '--stdio' }, + filetypes = { 'python' }, + flags = { allow_incremental_sync = true, debounce_text_changes = 500 }, + settings = { + python = { + venvPath = '.', + formatting = { provider = 'black' }, + analysis = { + autoSearchPaths = true, + useLibraryCodeForTypes = true, + diagnosticMode = 'workspace', + }, + }, + }, +} diff --git a/lsp/ruff.lua b/lsp/ruff.lua new file mode 100644 index 0000000..1e2e071 --- /dev/null +++ b/lsp/ruff.lua @@ -0,0 +1,6 @@ +return { + filetypes = { 'python' }, + init_options = { + settings = { logLevel = 'info' }, + }, +} diff --git a/lsp/rust_analyzer.lua b/lsp/rust_analyzer.lua new file mode 100644 index 0000000..ad111e5 --- /dev/null +++ b/lsp/rust_analyzer.lua @@ -0,0 +1,16 @@ +local util = require('lspconfig').util +return { + root_dir = function(fname) + return util.root_pattern('Cargo.toml', 'rust-project.json', '.git')(fname) + or util.path.dirname(fname) + end, + filetypes = { 'rust' }, + message_level = vim.lsp.protocol.MessageType.error, + settings = { + ['rust-analyzer'] = { + cargo = { loadOutDirsFromCheck = true }, + procMacro = { enable = true }, + }, + }, + flags = { allow_incremental_sync = true, debounce_text_changes = 500 }, +} diff --git a/lua/navigator.lua b/lua/navigator.lua index a21ea32..9ff8f6b 100644 --- a/lua/navigator.lua +++ b/lua/navigator.lua @@ -27,9 +27,6 @@ _NgConfigValues = { prompt_mode = 'insert', -- 'normal' | 'insert' -- fuzzy finder prompt will be shown combined_attach = 'both', -- both: use both customized attach and navigator default attach, mine: only use my attach defined in vimrc - on_attach = function(client, bufnr) - -- your on_attach will be called at end of navigator on_attach - end, -- ts_fold = false, -- deprecated ts_fold = { enable = false, @@ -154,11 +151,6 @@ _NgConfigValues = { diagnostic_update_in_insert = false, -- update diagnostic message in insert mode diagnostic_scrollbar_sign = { '▃', '▆', '█' }, -- set to nil to disable, set to {'╍', 'ﮆ'} to enable diagnostic status in scroll bar area neodev = false, - lua_ls = { - -- sumneko_root_path = sumneko_root_path, - -- sumneko_binary = sumneko_binary, - -- cmd = {'lua-language-server'} - }, servers = {}, -- you can add additional lsp server so navigator will load the default for you }, mason = false, -- set to true if you would like use the lsp installed by williamboman/mason @@ -388,13 +380,46 @@ M.setup = function(cfg) require('navigator.foldts').on_attach() end + vim.api.nvim_create_autocmd('LspAttach', { + group = vim.api.nvim_create_augroup('nv_lspattach', {}), + callback = function(args) + local bufnr = args.buf + local client = assert(vim.lsp.get_client_by_id(args.data.client_id)) + + local kinds = {} + if + type(client.server_capabilities.codeActionProvider) == 'table' + and client.server_capabilities.codeActionProvider.codeActionKinds + then + for _, kind in ipairs(client.server_capabilities.codeActionProvider.codeActionKinds) do + if not vim.tbl_contains(_NgConfigValues.lsp.code_action.exclude, kind) then + table.insert(kinds, kind) + end + end + end + + require('navigator.lspclient.mapping').setup({ + client = client, + bufnr = bufnr, + }) + + require('navigator.lspclient.highlight').add_highlight() + require('navigator.lspclient.highlight').config_signs() + require('navigator.lspclient.lspkind').init() + api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI' }, { + group = api.nvim_create_augroup('NGCodeActGroup_' .. tostring(bufnr), {}), + buffer = bufnr, + callback = function(args) + require('navigator.codeAction').code_action_prompt(client, bufnr, kinds) + end, + }) + end, + }) + local _start_client = vim.lsp.start_client vim.lsp.start_client = function(lsp_config) -- add highlight for Lspxxx - require('navigator.lspclient.highlight').add_highlight() - require('navigator.lspclient.highlight').config_signs() - -- require('navigator.lspclient.mapping').setup() - require('navigator.lspclient.lspkind').init() + return _start_client(lsp_config) end end, 1) diff --git a/lua/navigator/lspclient/attach.lua b/lua/navigator/lspclient/attach.lua index d4fd2de..ecf8145 100644 --- a/lua/navigator/lspclient/attach.lua +++ b/lua/navigator/lspclient/attach.lua @@ -7,97 +7,6 @@ local trace = util.trace _NG_Attached = {} local M = {} -M.on_attach = function(client, bufnr) - bufnr = bufnr or 0 - - if bufnr == 0 then - vim.notify('no bufnr provided from LSP ' .. client.name, vim.log.levels.DEBUG) - end - local uri = vim.uri_from_bufnr(bufnr) - - if uri == 'file://' or uri == 'file:///' or #uri < 11 then - log('skip for float buffer', uri) - return { error = 'invalid file', result = nil } - end - - log('attaching: ', bufnr, client.name, uri) - - trace(client) - _NG_Attached[client.name] = true - - -- add highlight for Lspxxx - require('navigator.lspclient.highlight').add_highlight() - require('navigator.lspclient.highlight').config_signs() - api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc') - - require('navigator.lspclient.mapping').setup({ - client = client, - bufnr = bufnr, - }) - - if client.server_capabilities.documentHighlightProvider == true then - trace('attaching doc highlight: ', bufnr, client.name) - vim.defer_fn(function() - require('navigator.dochighlight').documentHighlight(bufnr) - end, 50) -- allow a bit time for it to settle down - else - log('skip doc highlight: ', bufnr, client.name) - end - - require('navigator.lspclient.lspkind').init() - - local config = require('navigator').config_values() - trace(client.name, 'navigator on attach') - if config.on_attach ~= nil then - log(client.name, 'customized attach for all clients') - config.on_attach(client, bufnr) - end - if config.lsp and config.lsp[client.name] then - if type(config.lsp[client.name]) == 'function' then - local attach = config.lsp[client.name]().on_attach - if attach then - attach(client, bufnr) - end - elseif config.lsp[client.name].on_attach ~= nil then - log(client.name, 'customized attach for this client') - log('lsp client specific attach for', client.name) - config.lsp[client.name].on_attach(client, bufnr) - end - end - - --- if code lens enabled - if _NgConfigValues.lsp.code_lens_action.enable then - if client.server_capabilities.codeLensProvider then - require('navigator.codelens').setup(bufnr) - end - end - - if _NgConfigValues.lsp.code_action.enable then - if client.server_capabilities.codeActionProvider and client.name ~= 'null-ls' then - local kinds = {} - if - type(client.server_capabilities.codeActionProvider) == 'table' - and client.server_capabilities.codeActionProvider.codeActionKinds - then - for _, kind in ipairs(client.server_capabilities.codeActionProvider.codeActionKinds) do - if not vim.tbl_contains(_NgConfigValues.lsp.code_action.exclude, kind) then - table.insert(kinds, kind) - end - end - end - - trace('code action enabled for client', client.server_capabilities.codeActionProvider) - api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI' }, { - group = api.nvim_create_augroup('NGCodeActGroup_' .. tostring(bufnr), {}), - buffer = bufnr, - callback = function() - require('navigator.codeAction').code_action_prompt(client, bufnr, kinds) - end, - }) - end - end -end - -- M.setup = function(cfg) -- return M -- end diff --git a/lua/navigator/lspclient/clients.lua b/lua/navigator/lspclient/clients.lua index 6c25811..80c7f53 100644 --- a/lua/navigator/lspclient/clients.lua +++ b/lua/navigator/lspclient/clients.lua @@ -48,7 +48,6 @@ local disabled_ft = { '', } -- local cap = vim.lsp.protocol.make_client_capabilities() -local on_attach = require('navigator.lspclient.attach').on_attach -- gopls["ui.completion.usePlaceholders"] = true @@ -57,22 +56,18 @@ if _NgConfigValues.mason then require('navigator.lazyloader').load('mason-lspconfig.nvim', 'williamboman/mason-lspconfig.nvim') end -local servers = require('navigator.lspclient.servers') +local servers = require('navigator.lspclient.servers') local lsp_mason_servers = {} -local has_lspinst = false local has_mason = false local ng_default_cfg = { - on_attach = on_attach, flags = { allow_incremental_sync = true, debounce_text_changes = 1000 }, } -- check and load based on file type local function load_cfg(ft, client, cfg, loaded, starting) - - local setups = require('navigator.lspclient.clients_default').defaults() log(ft, client, loaded, starting) trace(cfg) if lspconfig[client] == nil then @@ -81,7 +76,7 @@ local function load_cfg(ft, client, cfg, loaded, starting) end local lspft = lspconfig[client].document_config.default_config.filetypes - local additional_ft = setups[client] and setups[client].filetypes or {} + local additional_ft = lspconfig[client] and lspconfig[client].filetypes or {} local bufnr = vim.api.nvim_get_current_buf() local cmd = cfg.cmd trace(lspft, additional_ft, _NG_Loaded) @@ -118,12 +113,12 @@ local function load_cfg(ft, client, cfg, loaded, starting) end end - local clients = vim.lsp.get_clients({buffer = 0 }) + local clients = vim.lsp.get_clients({ buffer = 0 }) for _, c in pairs(clients or {}) do log("lsp start up in progress client", client, c.name) if c.name == client then _NG_Loaded[bufnr].cnt = 10 - table.insert(_NG_Loaded[bufnr].lsp, c.name ) + table.insert(_NG_Loaded[bufnr].lsp, c.name) _NG_Loaded[client] = true return end @@ -132,8 +127,8 @@ local function load_cfg(ft, client, cfg, loaded, starting) if starting and (starting.cnt or 0) > 0 then log("lsp start up in progress", starting) return vim.defer_fn(function() - load_cfg(ft, client, cfg, loaded, { cnt = starting.cnt - 1 }) - end, + load_cfg(ft, client, cfg, loaded, { cnt = starting.cnt - 1 }) + end, 100) end @@ -151,7 +146,8 @@ local function load_cfg(ft, client, cfg, loaded, starting) if not _NG_Loaded[client] then trace(client, 'loading for', ft, cfg) trace(lspconfig[client]) - lspconfig[client].setup(cfg) + -- lspconfig[client].setup(cfg) + vim.lsp.enable(client) _NG_Loaded[client] = true table.insert(_NG_Loaded[bufnr].lsp, client) vim.defer_fn(function() @@ -162,11 +158,11 @@ local function load_cfg(ft, client, cfg, loaded, starting) else log('send filetype event') if not _NG_Loaded[bufnr] or _NG_Loaded[bufnr].cnt < 4 then - log('doautocmd filetype') - vim.defer_fn(function() - vim.cmd('doautocmd FileType') - _NG_Loaded[bufnr].cnt = _NG_Loaded[bufnr].cnt + 1 - end, 100) + log('doautocmd filetype') + vim.defer_fn(function() + vim.cmd('doautocmd FileType') + _NG_Loaded[bufnr].cnt = _NG_Loaded[bufnr].cnt + 1 + end, 100) end end end @@ -174,14 +170,6 @@ local function load_cfg(ft, client, cfg, loaded, starting) end local function setup_fmt(client, enabled) - if not require('navigator.util').nvim_0_8() then - if enabled == false then - client.resolved_capabilities.document_formatting = enabled - else - client.resolved_capabilities.document_formatting = client.resolved_capabilities.document_formatting or enabled - end - end - if enabled == false then client.server_capabilities.documentFormattingProvider = false else @@ -222,7 +210,6 @@ end local loaded = {} local function lsp_startup(ft, retry, user_lsp_opts) - local setups = require('navigator.lspclient.clients_default').defaults() retry = retry or false local path_sep = require('navigator.util').path_sep() local capabilities = update_capabilities() @@ -284,7 +271,7 @@ local function lsp_startup(ft, retry, user_lsp_opts) end default_config = vim.tbl_deep_extend('force', default_config, ng_default_cfg) - local cfg = setups[lspclient] or {} + local cfg = vim.lsp.config[lspclient] or require('lspconfig')[lspclient] or {} cfg = vim.tbl_deep_extend('keep', cfg, default_config) -- filetype disabled @@ -312,52 +299,6 @@ local function lsp_startup(ft, retry, user_lsp_opts) -- if config.combined_attach == nil then -- setup_fmt(client, enable_fmt) -- end - if config.combined_attach == 'mine' then - if config.on_attach == nil then - error('on attach not provided') - end - cfg.on_attach = function(client, bufnr) - config.on_attach(client, bufnr) - - setup_fmt(client, enable_fmt) - require('navigator.lspclient.mapping').setup({ - client = client, - bufnr = bufnr, - cap = capabilities, - }) - end - end - if config.combined_attach == 'their' then - cfg.on_attach = function(client, bufnr) - on_attach(client, bufnr) - config.on_attach(client, bufnr) - setup_fmt(client, enable_fmt) - require('navigator.lspclient.mapping').setup({ - client = client, - bufnr = bufnr, - cap = capabilities, - }) - end - end - if config.combined_attach == 'both' then - cfg.on_attach = function(client, bufnr) - setup_fmt(client, enable_fmt) - - if config.on_attach and type(config.on_attach) == 'function' then - config.on_attach(client, bufnr) - end - if setups[lspclient] and setups[lspclient].on_attach then - setups[lspclient].on_attach(client, bufnr) - else - on_attach(client, bufnr) - end - require('navigator.lspclient.mapping').setup({ - client = client, - bufnr = bufnr, - cap = capabilities, - }) - end - end cfg.on_init = function(client) if client and client.config and client.config.settings then client.notify( @@ -369,66 +310,12 @@ local function lsp_startup(ft, retry, user_lsp_opts) end else cfg.on_attach = function(client, bufnr) - on_attach(client, bufnr) - setup_fmt(client, enable_fmt) end end - log('loading', lspclient, 'name', lspconfig[lspclient].name, 'has lspinst', has_lspinst) + log('loading', lspclient, 'name', lspconfig[lspclient].name) -- start up lsp - local function mason_disabled_for(client) - local mdisabled = _NgConfigValues.mason_disabled_for - if #mdisabled > 0 then - for _, disabled_client in ipairs(mdisabled) do - if disabled_client == client then return true end - end - end - return false - end - if _NgConfigValues.mason then - has_mason, _ = pcall(require, 'mason-lspconfig') - if has_mason then - local srvs=require'mason-lspconfig'.get_installed_servers() - if #srvs > 0 then - lsp_mason_servers = srvs - end - end - end - log("lsp mason:", lsp_mason_servers) - if has_mason and not mason_disabled_for(lspconfig[lspclient].name) then - local mason_servers = require'mason-lspconfig'.get_installed_servers() - if not vim.tbl_contains(mason_servers, lspconfig[lspclient].name) then - log('mason server not installed', lspconfig[lspclient].name) - -- return - end - local pkg_name = require "mason-lspconfig.mappings.server".lspconfig_to_package[lspconfig[lspclient].name] - local pkg - if pkg_name then - pkg = require "mason-registry".get_package(pkg_name) - else - log('failed to get name', lspconfig[lspclient].name, pkg_name) - end - - log('lsp mason server config ' .. lspconfig[lspclient].name, pkg) - if pkg then - local path = pkg:get_install_path() - if not path then - -- for some reason lspinstaller does not install the binary, check default PATH - log('lsp mason does not install the lsp in its path, fallback') - return load_cfg(ft, lspclient, cfg, loaded) - end - - local cmd - cmd = table.concat({vfn.stdpath('data'), 'mason', 'bin', pkg.name}, path_sep) - if vfn.executable(cmd) == 0 then - log('failed to find cmd', cmd, "fallback") - load_cfg(ft, lspclient, cfg, loaded) - goto continue - end - end - end - if vfn.executable(cfg.cmd[1]) == 0 then log('lsp server not installed in path ' .. lspclient .. vim.inspect(cfg.cmd), vim.log.levels.WARN) @@ -452,31 +339,8 @@ local function lsp_startup(ft, retry, user_lsp_opts) if nulls_cfg then local cfg = {} cfg = vim.tbl_deep_extend('keep', cfg, nulls_cfg) - vim.defer_fn(function() - lspconfig['null-ls'].setup(cfg) -- adjust null_ls startup timing - end, 1000) - log('null-ls loading') - _NG_Loaded['null-ls'] = true - setups['null-ls'] = cfg - end - end - - if not _NG_Loaded['efm'] then - local efm_cfg = user_lsp_opts['efm'] - if efm_cfg then - local cfg = {} - cfg = vim.tbl_deep_extend('keep', cfg, efm_cfg) - cfg.on_attach = function(client, bufnr) - if efm_cfg.on_attach then - efm_cfg.on_attach(client, bufnr) - end - on_attach(client, bufnr) - end - - lspconfig.efm.setup(cfg) - log('efm loading') - _NG_Loaded['efm'] = true - setups['efm'] = cfg + vim.lsp.config['null-ls']=cfg + vim.lsp.enable('null-ls') end end @@ -538,17 +402,17 @@ local function setup(user_opts) user_opts = user_opts or {} local bufnr = user_opts.bufnr or vim.api.nvim_get_current_buf() - local ft = vim.api.nvim_buf_get_option(bufnr, 'ft') + local ft = vim.api.nvim_get_option_value('filetype', { buf = bufnr }) if vim.fn.empty(ft) == 1 then local ext = vfn.expand('%:e') local lang = ft_map[ext] or ext or '' - log('nil filetype, callback',vim.fn.expand('%'), vim.fn.expand('%') ,lang) + log('nil filetype, callback', vim.fn.expand('%'), vim.fn.expand('%'), lang) if vim.fn.empty(lang) == 0 then log('set filetype', ft, ext) - vim.api.nvim_buf_set_option(bufnr, 'filetype', lang) - vim.api.nvim_buf_set_option(bufnr, 'syntax', 'on') - ft = vim.api.nvim_buf_get_option(bufnr, 'ft') + vim.api.nvim_set_option_value('filetype', lang, {buf = bufnr}) + vim.api.nvim_set_option_value( 'syntax', 'on', {buf = bufnr}) + ft = vim.api.nvim_get_option_value('ft', { buf = bufnr }) if vim.fn.empty(ft) == 1 then log('still failed to idnetify filetype, try again') vim.cmd(':e') @@ -556,7 +420,8 @@ local function setup(user_opts) end log('no filetype, no ext return') - ft = vim.api.nvim_buf_get_option(bufnr, 'ft') + + ft = vim.api.nvim_get_option_value('ft', { buf = bufnr }) log('get filetype', ft) end local uri = vim.uri_from_bufnr(bufnr) @@ -582,7 +447,7 @@ local function setup(user_opts) trace(debug.traceback()) - local clients = vim.lsp.get_clients({buffer = bufnr}) + local clients = vim.lsp.get_clients({ buffer = bufnr }) for key, client in pairs(clients) do if client.name ~= 'null_ls' and client.name ~= 'efm' then if vim.tbl_contains(client.filetypes or {}, vim.bo.ft) then @@ -601,22 +466,7 @@ local function setup(user_opts) highlight.add_highlight() local lsp_opts = user_opts.lsp or {} - if vim.bo.filetype == 'lua' then - local slua = lsp_opts.lua_ls - if slua and not slua.cmd then - if slua.sumneko_root_path and slua.sumneko_binary then - lsp_opts.lua_ls.cmd = { - slua.sumneko_binary, - '-E', - slua.sumneko_root_path .. '/main.lua', - } - else - lsp_opts.lua_ls.cmd = { 'lua-language-server' } - end - end - end lsp_startup(ft, retry, lsp_opts) - end local function on_filetype() @@ -631,14 +481,14 @@ local function on_filetype() trace('skip loading for ft ', ft, uri) return end - _NG_Loaded[bufnr] = _NG_Loaded[bufnr] or {cnt = 1, lsp = {}} + _NG_Loaded[bufnr] = _NG_Loaded[bufnr] or { cnt = 1, lsp = {} } - trace (_NG_Loaded) + trace(_NG_Loaded) local loaded if _NG_Loaded[bufnr].cnt > 1 then log('navigator was loaded for ft', ft, bufnr) -- check if lsp is loaded - local clients = vim.lsp.get_clients({buffer = bufnr}) + local clients = vim.lsp.get_clients({ buffer = bufnr }) for key, client in pairs(clients) do if client.name ~= 'null_ls' and client.name ~= 'efm' then loaded = _NG_Loaded[bufnr].lsp[client.name] @@ -646,13 +496,14 @@ local function on_filetype() end if not loaded then -- trigger filetype so that lsp can be loaded + -- fire the check in 200 ms vim.cmd('setlocal filetype=' .. ft) end return end -- on_filetype should only be trigger only once for each bufnr - _NG_Loaded[bufnr].cnt = _NG_Loaded[bufnr].cnt + 1 -- do not hook and trigger filetype event multiple times + _NG_Loaded[bufnr].cnt = _NG_Loaded[bufnr].cnt + 1 -- do not hook and trigger filetype event multiple times -- as setup will send filetype event as well log(uri) diff --git a/lua/navigator/lspclient/clients_default.lua b/lua/navigator/lspclient/clients_default.lua deleted file mode 100644 index a23e927..0000000 --- a/lua/navigator/lspclient/clients_default.lua +++ /dev/null @@ -1,221 +0,0 @@ -local M = {} -local vfn = vim.fn -M.defaults = function() - local has_lsp, lspconfig = pcall(require, 'lspconfig') - local highlight = require('navigator.lspclient.highlight') - if not has_lsp then - return { - setup = function() - vim.notify('loading lsp config failed LSP may not working correctly', vim.log.levels.WARN) - end, - } - end - local util = lspconfig.util - local on_attach = require('navigator.lspclient.attach').on_attach - - local setups = { - clojure_lsp = { - root_dir = function(fname) - return util.root_pattern( - 'deps.edn', - 'build.boot', - 'project.clj', - 'shadow-cljs.edn', - 'bb.edn', - '.git' - )(fname) or util.path.dirname(fname) - end, - on_attach = on_attach, - filetypes = { 'clojure', 'edn' }, - message_level = vim.lsp.protocol.MessageType.error, - cmd = { 'clojure-lsp' }, - }, - - elixirls = { - on_attach = on_attach, - filetypes = { 'elixir', 'eelixir' }, - cmd = { 'elixir-ls' }, - message_level = vim.lsp.protocol.MessageType.error, - settings = { - elixirLS = { - dialyzerEnabled = true, - fetchDeps = false, - }, - }, - root_dir = function(fname) - return util.root_pattern('mix.exs', '.git')(fname) or util.path.dirname(fname) - end, - }, - - gopls = { - -- capabilities = cap, - filetypes = { 'go', 'gomod', 'gohtmltmpl', 'gotexttmpl' }, - message_level = vim.lsp.protocol.MessageType.Error, - cmd = { - 'gopls', -- share the gopls instance if there is one already - '-remote=auto', --[[ debug options ]] -- - -- "-logfile=auto", - -- "-debug=:0", - '-remote.debug=:0', - -- "-rpc.trace", - }, - - flags = { allow_incremental_sync = true, debounce_text_changes = 1000 }, - settings = { - gopls = { - -- more settings: https://github.com/golang/tools/blob/master/gopls/doc/settings.md - -- flags = {allow_incremental_sync = true, debounce_text_changes = 500}, - -- not supported - analyses = { unusedparams = true, unreachable = false }, - codelenses = { - generate = true, -- show the `go generate` lens. - gc_details = true, -- // Show a code lens toggling the display of gc's choices. - test = true, - tidy = true, - }, - usePlaceholders = true, - completeUnimported = true, - staticcheck = true, - matcher = 'fuzzy', - diagnosticsDelay = '500ms', - symbolMatcher = 'fuzzy', - gofumpt = false, -- true, -- turn on for new repos, gofmpt is good but also create code turmoils - buildFlags = { '-tags', 'integration' }, - -- buildFlags = {"-tags", "functional"} - semanticTokens = true, - }, - }, - on_attach = function(client, bufnr) - on_attach(client, bufnr) - if - vim.fn.has('nvim-0.8.3') == 1 - and not client.server_capabilities.semanticTokensProvider - then - local semantic = client.config.capabilities.textDocument.semanticTokens - if semantic then - client.server_capabilities.semanticTokensProvider = { - full = true, - legend = { - tokenModifiers = semantic.tokenModifiers, - tokenTypes = semantic.tokenTypes, - }, - range = true, - } - end - end - end, - root_dir = function(fname) - return util.root_pattern('go.mod', '.git')(fname) or util.path.dirname(fname) - end, - }, - clangd = { - flags = { allow_incremental_sync = true, debounce_text_changes = 500 }, - cmd = { - 'clangd', - '--background-index', - '--suggest-missing-includes', - '--clang-tidy', - '--header-insertion=iwyu', - '--enable-config', - '--offset-encoding=utf-16', - '--clang-tidy-checks=-*,llvm-*,clang-analyzer-*', - '--cross-file-rename', - }, - filetypes = { 'c', 'cpp', 'objc', 'objcpp' }, - on_attach = function(client, bufnr) - client.server_capabilities.documentFormattingProvider = client.server_capabilities.documentFormattingProvider - or true - on_attach(client, bufnr) - end, - }, - rust_analyzer = { - root_dir = function(fname) - return util.root_pattern('Cargo.toml', 'rust-project.json', '.git')(fname) - or util.path.dirname(fname) - end, - filetypes = { 'rust' }, - message_level = vim.lsp.protocol.MessageType.error, - on_attach = on_attach, - settings = { - ['rust-analyzer'] = { - cargo = { loadOutDirsFromCheck = true }, - procMacro = { enable = true }, - }, - }, - flags = { allow_incremental_sync = true, debounce_text_changes = 500 }, - }, - sqlls = { - cmd = { 'sql-language-server', 'up', '--method', 'stdio' }, - filetypes = { 'sql', 'mysql' }, - root_dir = util.root_pattern('.sqllsrc.json'), - on_attach = on_attach, - flags = { allow_incremental_sync = true, debounce_text_changes = 500 }, - }, - - pyright = { - on_attach = on_attach, - -- on_init = require('navigator.lspclient.python').on_init, - on_init = function(client) - require('navigator.lspclient.python').on_init(client) - end, - on_new_config = function(new_config, new_root_dir) - local python_path = require('navigator.lspclient.python').pyenv_path(new_root_dir) - new_config.settings.python.pythonPath = python_path - end, - cmd = { 'pyright-langserver', '--stdio' }, - filetypes = { 'python' }, - flags = { allow_incremental_sync = true, debounce_text_changes = 500 }, - settings = { - python = { - venvPath = '.', - formatting = { provider = 'black' }, - analysis = { - autoSearchPaths = true, - useLibraryCodeForTypes = true, - diagnosticMode = 'workspace', - }, - }, - }, - }, - ccls = { - on_attach = on_attach, - init_options = { - compilationDatabaseDirectory = 'build', - root_dir = [[ util.root_pattern("compile_commands.json", "compile_flags.txt", "CMakeLists.txt", "Makefile", ".git") or util.path.dirname ]], - index = { threads = 2 }, - clang = { excludeArgs = { '-frounding-math' } }, - }, - flags = { allow_incremental_sync = true }, - }, - ruff = { - filetypes = { 'python' }, - init_options = { - settings = { logLevel = 'info' } - } - }, - jdtls = { - settings = { - java = { - signatureHelp = { enabled = true }, - contentProvider = { preferred = 'fernflower' }, - }, - }, - }, - omnisharp = { - cmd = { 'omnisharp', '--languageserver', '--hostPID', tostring(vfn.getpid()) }, - }, - terraformls = { - filetypes = { 'terraform', 'tf' }, - }, - - sourcekit = { - cmd = { 'sourcekit-lsp' }, - filetypes = { 'swift' }, -- This is recommended if you have separate settings for clangd. - }, - } - - setups.lua_ls = require('navigator.lspclient.lua_ls').lua_ls() - return setups -end - -return M diff --git a/lua/navigator/lspclient/inlay.lua b/lua/navigator/lspclient/inlay.lua deleted file mode 100644 index 21ab2fa..0000000 --- a/lua/navigator/lspclient/inlay.lua +++ /dev/null @@ -1,68 +0,0 @@ -local log = require('vim.lsp.log') -local util = require('vim.lsp.util') -local api = vim.api -local bufstates = {} -return { - on_inlayhint = function(err, result, ctx, _) - if err then - if log.error() then - log.error('inlayhint', err) - end - return - end - local bufnr = assert(ctx.bufnr) - if util.buf_versions[bufnr] ~= ctx.version then - return - end - local client_id = ctx.client_id - if not result then - return - end - local bufstate = bufstates[bufnr] - if not bufstate or not bufstate.enabled then - return - end - if not (bufstate.client_hint and bufstate.version) then - bufstate.client_hint = vim.defaulttable() - bufstate.version = ctx.version - end - local hints_by_client = bufstate.client_hint - local client = assert(vim.lsp.get_client_by_id(client_id)) - - local new_hints_by_lnum = vim.defaulttable() - local num_unprocessed = #result - if num_unprocessed == 0 then - hints_by_client[client_id] = {} - bufstate.version = ctx.version - api.nvim__buf_redraw_range(bufnr, 0, -1) - return - end - - local lines = api.nvim_buf_get_lines(bufnr, 0, -1, false) - ---@param position lsp.Position - ---@return integer - local function pos_to_byte(position) - local col = position.character - if col > 0 then - local line = lines[position.line + 1] or '' - local ok, convert_result - ok, convert_result = pcall(util._str_byteindex_enc, line, col, client.offset_encoding) - if ok then - return convert_result - end - return math.min(#line, col) - end - return col - end - - for _, hint in ipairs(result) do - local lnum = hint.position.line - hint.position.character = pos_to_byte(hint.position) - table.insert(new_hints_by_lnum[lnum], hint) - end - - hints_by_client[client_id] = new_hints_by_lnum - bufstate.version = ctx.version - api.nvim__buf_redraw_range(bufnr, 0, -1) - end, -} diff --git a/lua/navigator/lspclient/lua_ls.lua b/lua/navigator/lspclient/lua_ls.lua deleted file mode 100644 index 0bced8b..0000000 --- a/lua/navigator/lspclient/lua_ls.lua +++ /dev/null @@ -1,68 +0,0 @@ -local vfn = vim.fn - -local on_attach = require('navigator.lspclient.attach').on_attach - -local library = {} -local function add(lib) - for _, p in pairs(vfn.expand(lib, false, true)) do - local uv = vim.uv or vim.loop - p = uv.fs_realpath(p) - if p then - library[p] = true - end - end -end -local function lua_ls() - -- add runtime - -- add plugins it may be very slow to add all in path - add('$VIMRUNTIME') - -- add your config - -- local home = vfn.expand("$HOME") - add(vfn.stdpath('config')) - - library[vfn.expand('$VIMRUNTIME/lua')] = true - library[vfn.expand('$VIMRUNTIME/lua/vim')] = true - library[vfn.expand('$VIMRUNTIME/lua/vim/lsp')] = true - - return { - cmd = { 'lua-language-server' }, - filetypes = { 'lua' }, - on_attach = on_attach, - flags = { allow_incremental_sync = true, debounce_text_changes = 500 }, - settings = { - Lua = { - runtime = { - -- Tell the language server which version of Lua you're using (most likely LuaJIT in the case of Neovim) - version = 'LuaJIT', - }, - hint = { enable = true, typeCoverage = true }, - diagnostics = { - enable = true, - -- Get the language server to recognize the `vim` global - globals = { 'vim', 'describe', 'it', 'before_each', 'after_each', 'teardown', 'pending' }, - }, - completion = { callSnippet = 'Both' }, - workspace = { - -- Make the server aware of Neovim runtime files - library = library, - checkThirdParty = false, - maxPreload = 1000, - preloadFileSize = 40000, - }, - telemetry = { enable = false }, - }, - }, - on_new_config = function(cfg, root) - local libs = vim.schedule(function() - vim.tbl_deep_extend('force', {}, library) - end) - libs[root] = nil - cfg.settings.Lua.workspace.library = libs - return cfg - end, - } -end - -return { - lua_ls = lua_ls, -} From d7a9615435ffaa59ed192af857db0d93de2da868 Mon Sep 17 00:00:00 2001 From: ray-x Date: Sun, 30 Mar 2025 11:39:36 +1100 Subject: [PATCH 02/17] deprecate mason lspconfig setting, use LspAttach instead --- README.md | 80 +++-------------------------- lua/navigator/lspclient/clients.lua | 25 +++------ 2 files changed, 12 insertions(+), 93 deletions(-) diff --git a/README.md b/README.md index e3d44a9..182ba5d 100644 --- a/README.md +++ b/README.md @@ -278,7 +278,7 @@ require'navigator'.setup({ separator = '', -- e.g. shows  3 lines  }, }, - mason = false, -- set to true if you would like use the lsp installed by williamboman/mason + mason = false, -- Deprecated, mason no longger supported as setup lsp changed in nvim 0.11 lsp = { enable = true, -- skip lsp setup, and only use treesitter in navigator. -- Use this if you are not using LSP servers, and only want to enable treesitter support. @@ -544,83 +544,15 @@ Terminal nerdfont and emoji capacity. I am using Kitty with nerdfont (Victor Mon ## Integrate with williamboman/mason.nvim -If you are using mason and would like to use the lsp servers installed by mason. Please set +Note: mason lspconfig no longger support as of nvim 0.11 The only change you need in in LspAttach event add if you +prefer to use mason lspconfig ```lua -mason = true -- mason user +require("navigator.lspclient.mapping").setup({ client = client, bufnr = bufnr }) -- setup navigator keymaps here, +require("navigator.dochighlight").documentHighlight(bufnr) +require("navigator.codeAction").code_action_prompt(bufnr) ``` -In the config. Also please setup the lsp server from installer setup with `server:setup{opts}` - -for mason - -```lua - use("williamboman/mason.nvim") - use({ - "williamboman/mason-lspconfig.nvim", - config = function() - require("mason").setup() - require("mason-lspconfig").setup({}) - end, - }) - - use({ - "ray-x/navigator.lua", - requires = { - { "ray-x/guihua.lua", run = "cd lua/fzy && make" }, - { "neovim/nvim-lspconfig" }, - { "nvim-treesitter/nvim-treesitter" }, - }, - config = function() - require("navigator").setup({ - mason = true, - }) - end, - }) -``` - -Another way to setup mason is disable navigator lsp setup and using mason setup handlers, pylsp for example - -```lua - use("williamboman/mason.nvim") - use({ - "williamboman/mason-lspconfig.nvim", - config = function() - require("mason").setup() - require("mason-lspconfig").setup_handlers({ - ["pylsp"] = function() - require("lspconfig").pylsp.setup({ - on_attach = function(client, bufnr) - require("navigator.lspclient.mapping").setup({ client = client, bufnr = bufnr }) -- setup navigator keymaps here, - require("navigator.dochighlight").documentHighlight(bufnr) - require("navigator.codeAction").code_action_prompt(bufnr) - end, - }) - end, - }) - require("mason-lspconfig").setup({}) - end, - }) - - use({ - "navigator.lua", - requires = { - { "ray-x/guihua.lua", run = "cd lua/fzy && make" }, - { "nvim-lspconfig" }, - { "nvim-treesitter/nvim-treesitter" }, - }, - config = function() - require("navigator").setup({ - mason = true, - lsp = { disable_lsp = { "pylsp" } }, -- disable pylsp setup from navigator - }) - end, - }) -``` - -Alternatively, Navigator can be used to startup the server installed by mason. as it will override the navigator setup - - ### Integration with other lsp plugins (e.g. rust-tools, go.nvim, clangd extension) There are lots of plugins provides lsp support diff --git a/lua/navigator/lspclient/clients.lua b/lua/navigator/lspclient/clients.lua index 80c7f53..f85b018 100644 --- a/lua/navigator/lspclient/clients.lua +++ b/lua/navigator/lspclient/clients.lua @@ -14,15 +14,11 @@ _LoadedFiletypes = {} local highlight = require('navigator.lspclient.highlight') local has_lsp, lspconfig = pcall(require, 'lspconfig') -if not has_lsp then - return { - setup = function() - vim.notify('loading lsp config failed LSP may not working correctly', vim.log.levels.WARN) - end, - } +local has_nvim_011 = vfn.has('nvim-0.11') +if not has_lsp and not has_nvim_011 then + vim.notify('loading lsp config failed LSP may not working correctly', vim.log.levels.WARN) end -local util = lspconfig.util local config = require('navigator').config_values() local disabled_ft = { 'NvimTree', @@ -51,17 +47,8 @@ local disabled_ft = { -- gopls["ui.completion.usePlaceholders"] = true -if _NgConfigValues.mason then - require('navigator.lazyloader').load('mason.nvim', 'williamboman/mason.nvim') - require('navigator.lazyloader').load('mason-lspconfig.nvim', 'williamboman/mason-lspconfig.nvim') -end - local servers = require('navigator.lspclient.servers') -local lsp_mason_servers = {} -local has_mason = false - - local ng_default_cfg = { flags = { allow_incremental_sync = true, debounce_text_changes = 1000 }, } @@ -339,7 +326,7 @@ local function lsp_startup(ft, retry, user_lsp_opts) if nulls_cfg then local cfg = {} cfg = vim.tbl_deep_extend('keep', cfg, nulls_cfg) - vim.lsp.config['null-ls']=cfg + vim.lsp.config['null-ls'] = cfg vim.lsp.enable('null-ls') end end @@ -410,8 +397,8 @@ local function setup(user_opts) if vim.fn.empty(lang) == 0 then log('set filetype', ft, ext) - vim.api.nvim_set_option_value('filetype', lang, {buf = bufnr}) - vim.api.nvim_set_option_value( 'syntax', 'on', {buf = bufnr}) + vim.api.nvim_set_option_value('filetype', lang, { buf = bufnr }) + vim.api.nvim_set_option_value('syntax', 'on', { buf = bufnr }) ft = vim.api.nvim_get_option_value('ft', { buf = bufnr }) if vim.fn.empty(ft) == 1 then log('still failed to idnetify filetype, try again') From 9bc2cc7ad67116d50c743aac189c6e15019ce446 Mon Sep 17 00:00:00 2001 From: ray-x Date: Sun, 30 Mar 2025 11:56:05 +1100 Subject: [PATCH 03/17] github action updates --- .github/workflows/ci.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6e9c654..7a3fd2c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,26 +10,26 @@ jobs: fail-fast: false matrix: include: - - os: ubuntu-22.04 - url: https://github.com/neovim/neovim/releases/download/nightly/nvim-linux64.tar.gz + - os: ubuntu-latest + url: https://github.com/neovim/neovim/releases/download/nightly/nvim-linux-x86_64.tar.gz manager: sudo snap packages: go - os: ubuntu-22.04 - url: https://github.com/neovim/neovim/releases/download/v0.10.0/nvim-linux64.tar.gz + url: https://github.com/neovim/neovim/releases/download/stable/nvim-linux-x86_64.tar.gz manager: sudo snap packages: go - os: ubuntu-22.04 - url: https://github.com/neovim/neovim/releases/download/v0.9.5/nvim-linux64.tar.gz + url: https://github.com/neovim/neovim/releases/download/v0.10.4/nvim-linux-x86_64.tar.gz manager: sudo snap packages: go steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 with: - go-version: "^1.21.0" # The Go version to download (if necessary) and use. + go-version: "^1.24.0" # The Go version to download (if necessary) and use. - run: date +%F > todays-date - name: Restore cache for today's nightly. - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: _neovim key: ${{ runner.os }}-${{ matrix.url }}-${{ hashFiles('todays-date') }} From 3b9eac9add73140fcd3281eadfa097f09f663aeb Mon Sep 17 00:00:00 2001 From: ray-x Date: Sun, 30 Mar 2025 12:02:22 +1100 Subject: [PATCH 04/17] update treesitter spec --- tests/treesitter_spec.lua | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/treesitter_spec.lua b/tests/treesitter_spec.lua index f632497..6be43c0 100644 --- a/tests/treesitter_spec.lua +++ b/tests/treesitter_spec.lua @@ -187,6 +187,12 @@ describe('should run lsp reference', function() vim.cmd([[packadd nvim-lspconfig]]) vim.cmd([[packadd navigator.lua]]) vim.cmd([[packadd guihua.lua]]) + vim.cmd([[packadd nvim-treesitter]]) + require('nvim-treesitter.configs').setup({ + ensure_installed = { 'go' }, + sync_install = true, + highlight = { enable = true }, + }) local path = cur_dir .. '/tests/fixtures/interface_test.go' -- %:p:h ? %:p local cmd = " silent exe 'e " .. path .. "'" vim.cmd(cmd) From 41084e8ba855fb259371e50831acfee77e1a52ee Mon Sep 17 00:00:00 2001 From: ray-x Date: Sun, 30 Mar 2025 12:25:07 +1100 Subject: [PATCH 05/17] github action --- .github/workflows/ci.yml | 2 +- tests/minimal.vim | 8 +++++--- tests/treesitter_spec.lua | 4 ++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a3fd2c..813dfa2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: manager: sudo snap packages: go - os: ubuntu-22.04 - url: https://github.com/neovim/neovim/releases/download/v0.10.4/nvim-linux-x86_64.tar.gz + url: https://github.com/neovim/neovim/releases/download/v0.11.0/nvim-linux-x86_64.tar.gz manager: sudo snap packages: go steps: diff --git a/tests/minimal.vim b/tests/minimal.vim index 27d3f63..5306edc 100644 --- a/tests/minimal.vim +++ b/tests/minimal.vim @@ -27,10 +27,12 @@ _G.test_rename = true _G.test_close = true require("plenary/busted") require'nvim-treesitter.configs'.setup { - ensure_installed = {"go"}, -- one of "all", "maintained" (parsers with maintainers), or a list of languages + ensure_installed = { "go" }, + sync_install = true, + auto_install = true, highlight = { - enable = true, -- false will disable the whole extension - }, + enable = true, + } } -- for testing load gopls ahead diff --git a/tests/treesitter_spec.lua b/tests/treesitter_spec.lua index 6be43c0..fe1f0f2 100644 --- a/tests/treesitter_spec.lua +++ b/tests/treesitter_spec.lua @@ -216,7 +216,11 @@ describe('should run lsp reference', function() vim.fn.setpos('.', { bufn, 15, 4, 0 }) -- width vim.bo.filetype = 'go' + + vim.treesitter.stop() + vim.treesitter.start() local view, items, w = require('navigator.treesitter').buf_ts() + eq(items[1].node_text, golden_result[1].node_text) eq(items[2].node_text, golden_result[2].node_text) end) From 4e24d5b108e2bd8a9340dbd5c2ad149ca6f2fe85 Mon Sep 17 00:00:00 2001 From: ray-x Date: Sun, 30 Mar 2025 13:30:37 +1100 Subject: [PATCH 06/17] update minium.vim --- tests/minimal.vim | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/minimal.vim b/tests/minimal.vim index 5306edc..47ba994 100644 --- a/tests/minimal.vim +++ b/tests/minimal.vim @@ -28,8 +28,6 @@ _G.test_close = true require("plenary/busted") require'nvim-treesitter.configs'.setup { ensure_installed = { "go" }, - sync_install = true, - auto_install = true, highlight = { enable = true, } From b0a08144a438dbed44f34625a9a4b681d1b29ace Mon Sep 17 00:00:00 2001 From: ray-x Date: Sun, 30 Mar 2025 19:11:58 +1100 Subject: [PATCH 07/17] remove minimal_init --- Makefile | 25 ++++++++- lua/navigator/treesitter.lua | 106 +++++++++++++++++------------------ tests/minimal.vim | 1 - tests/treesitter_spec.lua | 24 ++++++-- 4 files changed, 95 insertions(+), 61 deletions(-) diff --git a/Makefile b/Makefile index 19494a6..3e680f2 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,25 @@ +PACKER_DIR = ~/.local/share/nvim/site/pack/vendor/start +localtestsetup: + @mkdir -p $(PACKER_DIR) + @mkdir -p ~/tmp + + @test -d $(PACKER_DIR)/plenary.nvim ||\ + git clone --depth 1 https://github.com/nvim-lua/plenary.nvim $(PACKER_DIR)/plenary.nvim + + @test -d $(PACKER_DIR)/nvim-lspconfig ||\ + git clone --depth 1 https://github.com/neovim/nvim-lspconfig $(PACKER_DIR)/nvim-lspconfig + + @test -d $(PACKER_DIR)/guihua.lua ||\ + git clone --depth 1 https://github.com/ray-x/guihua.lua $(PACKER_DIR)/guihua.lua + + @test -d $(PACKER_DIR)/nvim-treesitter ||\ + git clone --depth 1 https://github.com/nvim-treesitter/nvim-treesitter $(PACKER_DIR)/nvim-treesitter + + @test -d $(PACKER_DIR)/navigator.lua || ln -s ${shell pwd} $(PACKER_DIR) + + +localtestts: localtestsetup + nvim --headless --noplugin -u tests/minimal.vim -c "PlenaryBustedFile tests/treesitter_spec.lua" + test: - nvim --headless --noplugin -u tests/minimal.vim -c "PlenaryBustedDirectory tests/ {minimal_init = 'tests/minimal.vim'}" + nvim --headless --noplugin -u tests/minimal.vim -c "PlenaryBustedDirectory tests/ " diff --git a/lua/navigator/treesitter.lua b/lua/navigator/treesitter.lua index 41bac19..c4ef889 100644 --- a/lua/navigator/treesitter.lua +++ b/lua/navigator/treesitter.lua @@ -83,7 +83,7 @@ end -- use lsp range to find def function M.find_definition(range, bufnr) if not range or not range.start then - lerr('find_def incorrect range'..vim.inspect(range)) + lerr('find_def incorrect range' .. vim.inspect(range)) return end bufnr = bufnr or api.nvim_get_current_buf() @@ -94,7 +94,7 @@ function M.find_definition(range, bufnr) return end local node_at_point = - root:named_descendant_for_range(symbolpos[1], symbolpos[2], symbolpos[1], symbolpos[2]) + root:named_descendant_for_range(symbolpos[1], symbolpos[2], symbolpos[1], symbolpos[2]) if not node_at_point then return log('Err: no node at cursor', range) end @@ -112,9 +112,8 @@ function M.find_definition(range, bufnr) return { start = { line = r, character = c } } else if definition then - -- stylua: ignore start - trace( 'error: def not found in ', bufnr, definition:range(), definition:type()) + trace('error: def not found in ', bufnr, definition:range(), definition:type()) if definition:parent() then trace("def not found", definition:parent():type()) end @@ -228,7 +227,6 @@ function M.ref_context(opts) end --- Get definitions of bufnr (unique and sorted by order of appearance). ---- This function copy from treesitter/refactor/navigation.lua local function get_definitions(bufnr) local local_nodes = ts_locals.get_locals(bufnr) -- Make sure the nodes are unique. @@ -246,9 +244,9 @@ local function get_definitions(bufnr) trace(row, col, erow, offset, node:parent(), node:parent():start(), node:parent():type()) if - node - and node:parent() - and string.find(node:parent():type(), 'parameter_declaration') + node + and node:parent() + and string.find(node:parent():type(), 'parameter_declaration') then log('parameter_declaration skip') return @@ -273,7 +271,7 @@ local function get_definitions(bufnr) ts_locals.recurse_local_nodes(loc.interface, function(def, node, full_match, match) local k, l, start = node:start() -- stylua: ignore start - trace( k, l, start, def, node, full_match, + trace(k, l, start, def, node, full_match, match, node:parent(), node:parent():start(), node:parent():type()) -- stylua: ignore end if nodes_set[start] == nil then @@ -298,7 +296,8 @@ local function get_definitions(bufnr) p3t = p2:parent():type() end -- stylua: ignore start - trace( row, col, start, def, node, full_match, match, p1t, p1, node:parent():start(), node:parent():type(), p2, p2t, p3, p3t) + trace(row, col, start, def, node, full_match, match, p1t, p1, node:parent():start(), node:parent():type(), p2, + p2t, p3, p3t) -- stylua: ignore end if p1t == 'arrow_function' then row, col, start = p1:start() @@ -313,11 +312,11 @@ local function get_definitions(bufnr) end if nodes_set[start] == nil then if -- qualified_type : e.g. io.Reader inside interface - node:parent() - and node:parent():parent() - and node:type() == 'type_identifier' - and node:parent():type() == 'qualified_type' - and string.find(node:parent():parent():type(), 'interface') + node:parent() + and node:parent():parent() + and node:type() == 'type_identifier' + and node:parent():type() == 'qualified_type' + and string.find(node:parent():parent():type(), 'interface') then trace('add node', node) nodes_set[start] = { node = node, type = match or 'field' } @@ -384,9 +383,9 @@ local function get_scope(type, source) if type == 'var' and next ~= nil then if - next:type() == 'function' - or next:type() == 'arrow_function' - or next:type() == 'function_definition' + next:type() == 'function' + or next:type() == 'arrow_function' + or next:type() == 'function_definition' then trace(current:type(), current:range()) return next, true @@ -478,6 +477,7 @@ end function M.goto_next_usage(bufnr) return M.goto_adjacent_usage(bufnr, 1) end + function M.goto_previous_usage(bufnr) return M.goto_adjacent_usage(bufnr, -1) end @@ -517,7 +517,7 @@ local function get_all_nodes(bufnr, filter, summary) local ft = vim.api.nvim_buf_get_option(bufnr, 'filetype') if not parsers.has_parser() then if not require('navigator.lspclient.clients').ft_disabled(ft) then - -- vim.notify('ts not loaded ' .. ft, vim.log.levels.Debug) + vim.notify('ts not loaded ' .. ft, vim.log.levels.Debug) log('ts not loaded ' .. ft) end return {} @@ -529,17 +529,17 @@ local function get_all_nodes(bufnr, filter, summary) local all_nodes = {} local containers = filter - or { - ['function'] = true, - ['local_function'] = true, - ['arrow_function'] = true, - ['type'] = true, - ['class'] = true, - ['call_expression'] = true, - -- ['var'] = true, - ['struct'] = true, - ['method'] = true, - } + or { + ['function'] = true, + ['local_function'] = true, + ['arrow_function'] = true, + ['type'] = true, + ['class'] = true, + ['call_expression'] = true, + -- ['var'] = true, + ['struct'] = true, + ['method'] = true, + } -- check and load buff @@ -561,17 +561,17 @@ local function get_all_nodes(bufnr, filter, summary) -- trace(parent_def.type, parent_def.node:type(), vim.treesitter.get_node_text(parent_def.node, bufnr)) -- trace(def.node:type(), vim.treesitter.get_node_text(def.node, bufnr)) if - ts_utils.is_parent(parent_def.node, def.node) - or ( - containers[parent_def.type] - and ( - ts_utils.is_parent(parent_def.node:parent(), def.node) - or ( - parent_def.node:parent():type():find('dot_index') - and ts_utils.is_parent(parent_def.node:parent():parent(), def.node) + ts_utils.is_parent(parent_def.node, def.node) + or ( + containers[parent_def.type] + and ( + ts_utils.is_parent(parent_def.node:parent(), def.node) + or ( + parent_def.node:parent():type():find('dot_index') + and ts_utils.is_parent(parent_def.node:parent():parent(), def.node) + ) ) ) - ) then -- trace('is parent', i, index) break @@ -620,18 +620,18 @@ local function get_all_nodes(bufnr, filter, summary) local parent = tsdata:parent() if parent ~= nil and _NgConfigValues.debug == 'trace' then -- for github action failure -- stylua: ignore start - trace( parent:type(), vim.treesitter.get_node_text(parent, bufnr):sub(1, 30), item.node_text, item.type) + trace(parent:type(), vim.treesitter.get_node_text(parent, bufnr):sub(1, 30), item.node_text, item.type) -- stylua: ignore end end if - parent ~= nil - and ( - parent:type() == 'function_name' - -- or parent:type() == 'function' - -- or parent:type() == 'function_declaration' -- this bring in too much info - or parent:type() == 'method_name' - or parent:type() == 'function_name_field' - ) + parent ~= nil + and ( + parent:type() == 'function_name' + -- or parent:type() == 'function' + -- or parent:type() == 'function_declaration' -- this bring in too much info + or parent:type() == 'method_name' + or parent:type() == 'function_name_field' + ) then -- replace function name item.node_text = vim.treesitter.get_node_text(parent, bufnr) @@ -661,7 +661,7 @@ local function get_all_nodes(bufnr, filter, summary) if item.node_scope then -- stylua: ignore start - trace( item.type, tsdata:type(), item.node_text, item.kind, 'range', + trace(item.type, tsdata:type(), item.node_text, item.kind, 'range', item.node_scope.start.line, item.node_scope['end'].line) -- set to log if need to trace result -- stylua: ignore end end @@ -672,7 +672,7 @@ local function get_all_nodes(bufnr, filter, summary) local start_line_node, _, _ = tsdata:start() local line_text = api.nvim_buf_get_lines(bufnr, start_line_node, start_line_node + 1, false)[1] - or '' + or '' item.full_text = vim.trim(line_text) item.full_text = item.full_text:gsub('%s*[%[%(%{]*%s*$', '') @@ -710,13 +710,13 @@ local function get_all_nodes(bufnr, filter, summary) end item.text = - string.format(' %s %s%-10s\t %s', item.kind, indent, item.node_text, item.full_text) + string.format(' %s %s%-10s\t %s', item.kind, indent, item.node_text, item.full_text) if #item.text > length then length = #item.text end if - loaded_symbol[item.node_text .. item.kind] == nil - or not util.range_inside(loaded_symbol[item.node_text .. item.kind], item.node_scope) + loaded_symbol[item.node_text .. item.kind] == nil + or not util.range_inside(loaded_symbol[item.node_text .. item.kind], item.node_scope) then table.insert(all_nodes, item) loaded_symbol[item.node_text .. item.kind] = item.node_scope diff --git a/tests/minimal.vim b/tests/minimal.vim index 47ba994..df4eeff 100644 --- a/tests/minimal.vim +++ b/tests/minimal.vim @@ -3,7 +3,6 @@ set rtp +=../plenary.nvim/ set rtp +=../nvim-treesitter/ set rtp +=../nvim-lspconfig/ set rtp +=../guihua.lua/ -set rtp +=../navigator.lua/ runtime! plugin/plenary.vim runtime! plugin/nvim-treesitter.vim diff --git a/tests/treesitter_spec.lua b/tests/treesitter_spec.lua index fe1f0f2..7cb6a9d 100644 --- a/tests/treesitter_spec.lua +++ b/tests/treesitter_spec.lua @@ -183,22 +183,24 @@ describe('should run lsp reference', function() local status = require('plenary.reload').reload_module('navigator') local status = require('plenary.reload').reload_module('guihua') local status = require('plenary.reload').reload_module('lspconfig') - vim.cmd([[packadd nvim-lspconfig]]) vim.cmd([[packadd navigator.lua]]) vim.cmd([[packadd guihua.lua]]) vim.cmd([[packadd nvim-treesitter]]) - require('nvim-treesitter.configs').setup({ - ensure_installed = { 'go' }, - sync_install = true, - highlight = { enable = true }, - }) + require('plenary.reload').reload_module('nvim-treesitter/nvim-treesitter') + require('plenary.reload').reload_module('nvim-treesitter') local path = cur_dir .. '/tests/fixtures/interface_test.go' -- %:p:h ? %:p local cmd = " silent exe 'e " .. path .. "'" vim.cmd(cmd) vim.cmd([[cd %:p:h]]) local bufn = vim.fn.bufnr('') -- require'lspconfig'.gopls.setup {} + + require('nvim-treesitter.configs').setup({ + ensure_installed = { 'go' }, + sync_install = true, + highlight = { enable = true }, + }) require('navigator').setup({ debug = true, -- log output, set to true and log path: ~/.local/share/nvim/gh.log }) @@ -217,9 +219,19 @@ describe('should run lsp reference', function() vim.bo.filetype = 'go' + -- Give TreeSitter a moment to process the buffer + vim.wait(800, function() end) + vim.treesitter.stop() vim.treesitter.start() + + local view, items, w = require('navigator.treesitter').buf_ts() + if items == nil then + print('no items') + end + + print('ts result', vim.inspect(view), vim.inspect(items)) eq(items[1].node_text, golden_result[1].node_text) eq(items[2].node_text, golden_result[2].node_text) From 083602a99939fa932c5c7f1a6f4af67f9a4c33ad Mon Sep 17 00:00:00 2001 From: ray-x Date: Sun, 30 Mar 2025 20:55:15 +1100 Subject: [PATCH 08/17] force check nvim 0.11 --- lua/navigator.lua | 21 ++++++++++++++++----- lua/navigator/diagnostics.lua | 2 +- lua/navigator/health.lua | 14 +++++++------- lua/navigator/rename.lua | 6 ++---- lua/navigator/util.lua | 17 +++++++---------- 5 files changed, 33 insertions(+), 27 deletions(-) diff --git a/lua/navigator.lua b/lua/navigator.lua index 9ff8f6b..5d55f2c 100644 --- a/lua/navigator.lua +++ b/lua/navigator.lua @@ -229,10 +229,12 @@ M.deprecated = function(cfg) warn('ts_fold option changed, refer to README for more details') cfg.ts_fold = { enable = cfg.ts_fold } end - local has_nvim_010 = vim.fn.has('nvim-0.10') == 1 - if not has_nvim_010 then - vim.lsp.get_clients = vim.lsp.get_active_clients - vim.islist = vim.tbl_islist + local has_nvim_011 = vim.fn.has('nvim-0.11') == 1 + if not has_nvim_011 then + vim.notify( + 'navigator.nvim requires nvim 0.11 or higher, please update your neovim version', + vim.log.levels.WARN + ) end if cfg.lsp and cfg.lsp.hover and cfg.lsp.hover.keymaps then warn('lsp.hover.keymaps is deprecated, refer to README for more details') @@ -326,6 +328,12 @@ end local cmd_group M.setup = function(cfg) + local util = require('navigator.util') + local has_nvim_011 = util.nvim_0_11() + if not has_nvim_011 then + vim.notify('navigator.nvim requires nvim 0.11 or higher', vim.log.levels.WARN) + return + end cfg = cfg or {} extend_config(cfg) @@ -419,7 +427,10 @@ M.setup = function(cfg) local _start_client = vim.lsp.start_client vim.lsp.start_client = function(lsp_config) -- add highlight for Lspxxx - + require('navigator.lspclient.highlight').add_highlight() + require('navigator.lspclient.highlight').config_signs() + -- require('navigator.lspclient.mapping').setup() + require('navigator.lspclient.lspkind').init() return _start_client(lsp_config) end end, 1) diff --git a/lua/navigator/diagnostics.lua b/lua/navigator/diagnostics.lua index 15dd172..283f678 100644 --- a/lua/navigator/diagnostics.lua +++ b/lua/navigator/diagnostics.lua @@ -13,7 +13,7 @@ local empty = util.empty local api = vim.api _NG_VT_DIAG_NS = api.nvim_create_namespace('navigator_lua_diag') -util.nvim_0_8() +util.nvim_0_11() local diag_map = { Error = vim.diagnostic.severity.ERROR, diff --git a/lua/navigator/health.lua b/lua/navigator/health.lua index 8a06d92..b9b48f4 100644 --- a/lua/navigator/health.lua +++ b/lua/navigator/health.lua @@ -7,13 +7,13 @@ if not vim.health then health = require('health') end -local nvim_09 = vim.fn.has('nvim-0.9') == 1 +local nvim_011 = vim.fn.has('nvim-0.11') == 1 -local start = nvim_09 and health.start or health.report_start -local ok = nvim_09 and health.ok or health.report_ok -local error = nvim_09 and health.error or health.report_error -local warn = nvim_09 and health.warn or health.report_warn -local info = nvim_09 and health.info or health.report_info +local start = nvim_011 and health.start or health.report_start +local ok = nvim_011 and health.ok or health.report_ok +local error = nvim_011 and health.error or health.report_error +local warn = nvim_011 and health.warn or health.report_warn +local info = nvim_011 and health.info or health.report_info local vfn = vim.fn @@ -47,7 +47,7 @@ end function M.check() - if vim.fn.has('nvim-0.9') == 0 then + if vim.fn.has('nvim-0.11') == 0 then warn('Suggested neovim version 0.9 or higher') end plugin_check() diff --git a/lua/navigator/rename.lua b/lua/navigator/rename.lua index 7e92499..2c0e227 100644 --- a/lua/navigator/rename.lua +++ b/lua/navigator/rename.lua @@ -46,7 +46,7 @@ local function ts_symbol() local ft_to_lang = require('nvim-treesitter.parsers').ft_to_lang local lang = ft_to_lang(vim.bo[bufnr].filetype) - local query = (vim.fn.has('nvim-0.9') == 1) and vim.treesitter.query.get(lang, 'highlights') + local query = vim.treesitter.query.get(lang, 'highlights') or vim.treesitter.get_query(lang, 'highlights') local ts_utils = require('nvim-treesitter.ts_utils') @@ -362,9 +362,7 @@ M.rename_preview = function() log('cancel', new_name) end, } - if vim.fn.has('nvim-0.9.0') == 1 then - inputopts.title = 'symbol rename' - end + inputopts.title = 'symbol rename' ghinput.setup(inputopts) vim.ui.input = ghinput.input diff --git a/lua/navigator/util.lua b/lua/navigator/util.lua index dd4c870..fab044e 100644 --- a/lua/navigator/util.lua +++ b/lua/navigator/util.lua @@ -5,7 +5,7 @@ local M = { log_path = vim.lsp.get_log_path() } -- local is_windows = uv.os_uname().version:match("Windows") pcall(require, 'guihua') -- lazy load local guihua = require('guihua.util') -local nvim_0_8 +local nvim_0_11 local vfn = vim.fn local api = vim.api local uv = vim.uv or vim.loop @@ -404,16 +404,13 @@ function M.get_current_winid() return api.nvim_get_current_win() end -function M.nvim_0_8() - if nvim_0_8 ~= nil then - return nvim_0_8 - end - nvim_0_8 = vfn.has('nvim-0.8') == 1 - if nvim_0_8 == false then - M.log('Please use navigator 0.4 version for neovim version < 0.8') - vim.notify('Please use navigator 0.4 version for neovim version < 0.8', vim.log.levels.ERROR) +function M.nvim_0_11() + if vim.fn.has('nvim-0.11') == 1 then + nvim_0_11 = true + else + nvim_0_11 = false end - return nvim_0_8 + return nvim_0_11 end function M.mk_handler(fn) From e5d3d7e7dd3475bfebb9a27313b2309b448d8834 Mon Sep 17 00:00:00 2001 From: ray-x Date: Mon, 31 Mar 2025 14:09:24 +1100 Subject: [PATCH 09/17] updates for preview context --- lua/navigator.lua | 1 + lua/navigator/dochighlight.lua | 12 ++++++++++-- lua/navigator/gui.lua | 2 +- lua/navigator/lspwrapper.lua | 8 ++++---- lua/navigator/treesitter.lua | 24 +++++++++++++++++++++--- 5 files changed, 37 insertions(+), 10 deletions(-) diff --git a/lua/navigator.lua b/lua/navigator.lua index 5d55f2c..0a48f54 100644 --- a/lua/navigator.lua +++ b/lua/navigator.lua @@ -411,6 +411,7 @@ M.setup = function(cfg) bufnr = bufnr, }) + require('navigator.dochighlight').documentHighlight(bufnr) require('navigator.lspclient.highlight').add_highlight() require('navigator.lspclient.highlight').config_signs() require('navigator.lspclient.lspkind').init() diff --git a/lua/navigator/dochighlight.lua b/lua/navigator/dochighlight.lua index 0ff338c..ed85a3b 100644 --- a/lua/navigator/dochighlight.lua +++ b/lua/navigator/dochighlight.lua @@ -19,8 +19,14 @@ local function add_locs(bufnr, result) end local winid = vim.fn.bufwinid(0) - symbol = - string.format('%s_%i_%i_%i_%i', symbol, bufnr, result[1].range.start.line, result[1].range.start.character, winid) + symbol = string.format( + '%s_%i_%i_%i_%i', + symbol, + bufnr, + result[1].range.start.line, + result[1].range.start.character, + winid + ) if _NG_hi_list[symbol] == nil then _NG_hi_list[symbol] = { range = {} } end @@ -179,6 +185,7 @@ local function goto_adjent_reference(opt) local bufnr = vim.api.nvim_get_current_buf() local refs = references[bufnr] if not refs or #refs == 0 then + log('no refs') return nil end @@ -186,6 +193,7 @@ local function goto_adjent_reference(opt) local nexti = nil local crow, ccol = unpack(vim.api.nvim_win_get_cursor(0)) local crange = { start = { line = crow - 1, character = ccol } } + trace(refs) for i, ref in ipairs(refs) do local range = ref.range diff --git a/lua/navigator/gui.lua b/lua/navigator/gui.lua index 0b0d869..5b73972 100644 --- a/lua/navigator/gui.lua +++ b/lua/navigator/gui.lua @@ -52,7 +52,7 @@ function M.new_list_view(opts) opts.transparency = config.transparency if #items >= config.lines_show_prompt then opts.prompt = true - opts.prompt_mode = _NgConfigValues.prompt_mode + opts.prompt_mode = _NgConfigValues.prompt_mode end opts.external = config.external diff --git a/lua/navigator/lspwrapper.lua b/lua/navigator/lspwrapper.lua index f431a4c..2abb93b 100644 --- a/lua/navigator/lspwrapper.lua +++ b/lua/navigator/lspwrapper.lua @@ -379,20 +379,19 @@ function M.locations_to_items(locations, ctx) and table.getn(file_cnt) < _NgConfigValues.treesitter_analysis_max_fnum -- getn deprecated, but it is the best solution for getting dict size local unload, def local context = '' + local org_context if not proj_file then trace('not proj file', i, item.uri) end if TS_analysis_enabled and not ctx.no_show and proj_file then - local ts_context = nts.ref_context - local bufnr = vim.uri_to_bufnr(item.uri) if not api.nvim_buf_is_loaded(bufnr) then log('! load buf !', item.uri, bufnr) vim.fn.bufload(bufnr) unload = bufnr end - context = ts_context({ bufnr = bufnr, pos = item.range, encoding = enc }) or 'not found' - trace('ts ctx', i, context, uv.now() - looptimer) + context, org_context = nts.ref_context({ bufnr = bufnr, pos = item.range, encoding = enc }) + trace('ts ctx', i, context, org_context, uv.now() - looptimer) -- TODO: unload buffers if unload then @@ -446,6 +445,7 @@ function M.locations_to_items(locations, ctx) end item.display_filename = filename or item.filename item.call_by = context -- find_ts_func_by_range(funcs, item.range) + item.status_line = org_context item.rpath = util.get_relative_path(cwd, gutil.add_pec(item.filename)) if is_win then -- windows C: vs c: -- log(item.filename, filename, cwd .. path_sep, path_cur) diff --git a/lua/navigator/treesitter.lua b/lua/navigator/treesitter.lua index c4ef889..eaf01e2 100644 --- a/lua/navigator/treesitter.lua +++ b/lua/navigator/treesitter.lua @@ -173,6 +173,11 @@ local transform_line = function(line) return line end +local trim_line = function(line) + line = line:gsub('%s*[%[%(%{]*%s*$', '') + return line +end + function M.ref_context(opts) local options = opts or {} local bufnr = options.bufnr or api.nvim_get_current_buf() @@ -184,7 +189,7 @@ function M.ref_context(opts) local pos = options.pos if not pos then - pos = { start = vim.lsp.util.make_position_params(0, opts.encoding).position } + pos = { start = vim.lsp.util.make_position_params(0, opts.encoding or 'utf-8').position } end local indicator_size = options.indicator_size or 100 local type_patterns = options.type_patterns or { 'class', 'function', 'method' } @@ -198,14 +203,20 @@ function M.ref_context(opts) end local lines = {} + local org_lines = {} local expr = current_node while expr do local line = ts_utils._get_line_for_node(expr, type_patterns, transform_fn, bufnr) - trace('line', line) + local line_org = ts_utils._get_line_for_node(expr, type_patterns, trim_line, bufnr) + trace('line', line, line_org) + if line ~= '' and not vim.tbl_contains(lines, line) then table.insert(lines, 1, line) end + if line_org ~= '' and not vim.tbl_contains(org_lines, line_org) then + table.insert(org_lines, 1, line_org) + end expr = expr:parent() if #line > _NgConfigValues.treesitter_analysis_depth then break @@ -215,15 +226,19 @@ function M.ref_context(opts) log('no lines found') return '' end + trace(lines, org_lines or 'org lines not found') local text = table.concat(lines, separator) + local org_text = _NgConfigValues.icons.treesitter_defult .. + ' ' .. separator .. ' ' .. table.concat(org_lines, separator) + trace(text, org_text) local text_len = #text if text_len > indicator_size then local str = text:sub(1, text_len) -- copy string return util.sub_match(str) end - return text + return text, org_text end --- Get definitions of bufnr (unique and sorted by order of appearance). @@ -450,17 +465,20 @@ function M.goto_adjacent_usage(bufnr, delta) en = vim.tbl_contains(en, vim.o.ft) end if en == false then + log("fallback lsp") return lsp_reference(opt) end bufnr = bufnr or api.nvim_get_current_buf() local node_at_point = ts_utils.get_node_at_cursor() if not node_at_point then + log("no node fallback lsp") lsp_reference(opt) return end local def_node, scope = ts_locals.find_definition(node_at_point, bufnr) + trace(def_node, scope) local usages = ts_locals.find_usages(def_node, scope, bufnr) trace(usages) From bb7afea4afa047cdb4c6ceaa644c28f8aa9cc4e3 Mon Sep 17 00:00:00 2001 From: ray-x Date: Wed, 2 Apr 2025 10:42:41 +1100 Subject: [PATCH 10/17] use lsp.Methods --- lua/navigator/codelens.lua | 5 +++-- lua/navigator/hierarchy.lua | 2 +- lua/navigator/lspwrapper.lua | 6 +++--- lua/navigator/reference.lua | 2 +- lua/navigator/rename.lua | 6 ++++-- lua/navigator/symbols.lua | 3 ++- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/lua/navigator/codelens.lua b/lua/navigator/codelens.lua index 024b341..ac4d60c 100644 --- a/lua/navigator/codelens.lua +++ b/lua/navigator/codelens.lua @@ -145,8 +145,9 @@ M.inline = function() -- do we want to support multiple clients? local parameter = vim.lsp.util.make_position_params(0, clients[1].offset_encoding) - local ids = clients[1].request( - 'textDocument/codeLens', + local ms = require('vim.lsp.protocol').Methods + local ids = clients[1]:request( + ms.textDocument_codeLens, parameter, function(err, response, ctx, _) if err then diff --git a/lua/navigator/hierarchy.lua b/lua/navigator/hierarchy.lua index d6df4c0..8486e45 100644 --- a/lua/navigator/hierarchy.lua +++ b/lua/navigator/hierarchy.lua @@ -273,7 +273,7 @@ call_hierarchy = function(method, opts) local client = vim.lsp.get_client_by_id(ctx.client_id) if client then trace('result', result, 'items', call_hierarchy_item, method, ctx, client.name) - client.request(method, { + client:request(method, { item = call_hierarchy_item, args = { method = method, diff --git a/lua/navigator/lspwrapper.lua b/lua/navigator/lspwrapper.lua index 2abb93b..4e125c6 100644 --- a/lua/navigator/lspwrapper.lua +++ b/lua/navigator/lspwrapper.lua @@ -168,11 +168,11 @@ function M.call_async(method, params, handler, bufnr) -- get clients for the buffer local clients = lsp.get_clients({ buffer = bufnr }) for _, client in pairs(clients) do - if client.supports_method(method) then + if client:supports_method(method, bufnr) then if type(params) == 'function' then params = params(client) end - return client.request(method, params, callback, bufnr) + return client:request(method, params, callback, bufnr) end end @@ -522,7 +522,7 @@ function M.request(method, hdlr) -- e.g textDocument/reference local bufnr = vim.api.nvim_get_current_buf() util.for_each_buffer_client(bufnr, function(client, _, _) local ref_params = vim.lsp.util.make_position_params(0, client.offset_encoding) - client.request(method, ref_params, hdlr, bufnr) + client:request(method, ref_params, hdlr, bufnr) end) end diff --git a/lua/navigator/reference.lua b/lua/navigator/reference.lua index 68e9638..8c4a3b8 100644 --- a/lua/navigator/reference.lua +++ b/lua/navigator/reference.lua @@ -245,7 +245,7 @@ local function fetch_lsp_references(bufnr, params, callback) params.context = params.context or { includeDeclaration = true } -- return id, closer - return clients[1].request('textDocument/references', params, function(err, result, ctx, cfg) + return clients[1]:request('textDocument/references', params, function(err, result, ctx, cfg) if err then log('Error while finding references: ' .. err.message, bufnr, params, ctx, cfg) return diff --git a/lua/navigator/rename.lua b/lua/navigator/rename.lua index 38661d7..2225fb3 100644 --- a/lua/navigator/rename.lua +++ b/lua/navigator/rename.lua @@ -7,6 +7,7 @@ local util = require('navigator.util') local log = util.log local api = vim.api local vfn = vim.fn +local ms = require('vim.lsp.protocol').Methods local M = { hl_group = 'Substitute', @@ -241,6 +242,7 @@ end local function perform_lsp_rename(opts) local new_name = opts.args + opts.bufnr = opts.bufnr or api.nvim_get_current_buf() local clients = vim.lsp.get_clients({ method = 'textDocument/rename', bufnr = opts.bufnr, @@ -251,7 +253,7 @@ local function perform_lsp_rename(opts) local params = opts.params or state.lsp_params - clients[1].request('textDocument/rename', params, function(err, result, ctx, _) + clients[1]:request(ms.textDocument_rename, params, function(err, result, ctx, _) if err and err.message then vim.notify('[nav-rename] Error while renaming: ' .. err.message, vim.log.levels.ERROR) return @@ -289,7 +291,7 @@ local function perform_lsp_rename(opts) if M.config and M.config.post_hook then M.config.post_hook(result) end - end, 0) + end, opts.bufnr) end local function inc_rename_execute(opts) diff --git a/lua/navigator/symbols.lua b/lua/navigator/symbols.lua index 177680f..f78b8cf 100644 --- a/lua/navigator/symbols.lua +++ b/lua/navigator/symbols.lua @@ -6,6 +6,7 @@ local trace = util.trace local lsphelper = require('navigator.lspwrapper') local symbol_kind = require('navigator.lspclient.lspkind').symbol_kind local symbols_to_items = lsphelper.symbols_to_items +local ms = require('vim.lsp.protocol').Methods function M.workspace_symbols(query) query = query or pcall(vim.fn.input, 'Query: ') @@ -13,7 +14,7 @@ function M.workspace_symbols(query) local params = { query = query } util.for_each_buffer_client(bufnr, function(client, _, _bufnr) if client.server_capabilities.workspaceSymbolProvider then - client.request('workspace/symbol', params, M.workspace_symbol_handler, _bufnr) + client:request(ms.workspace_symbol, params, M.workspace_symbol_handler, _bufnr) end end) end From 9784326120b29e1a7e5cdfd9756a56dde14facda Mon Sep 17 00:00:00 2001 From: ray-x Date: Wed, 2 Apr 2025 10:59:27 +1100 Subject: [PATCH 11/17] change 'client.request to client:request' for nvim 0.11 --- lua/navigator/codeAction.lua | 6 +++--- lua/navigator/definition.lua | 12 +++++++----- lua/navigator/dochighlight.lua | 2 +- lua/navigator/foldlsp.lua | 7 ++++--- lua/navigator/reference.lua | 5 +++-- lua/navigator/rename.lua | 4 ++-- lua/navigator/symbols.lua | 13 +++++++------ 7 files changed, 27 insertions(+), 22 deletions(-) diff --git a/lua/navigator/codeAction.lua b/lua/navigator/codeAction.lua index ead3e66..2c70edd 100644 --- a/lua/navigator/codeAction.lua +++ b/lua/navigator/codeAction.lua @@ -5,6 +5,7 @@ local code_action = {} -- local gui = require('navigator.gui') local config = require('navigator').config_values() local api = vim.api +local ms = require('vim.lsp.protocol').Methods local sign_name = 'NavigatorLightBulb' @@ -145,11 +146,10 @@ end local code_action_req = function(_call_back_fn, client, context) local params = vim.lsp.util.make_range_params(0, client.offset_encoding) - params.context = context + params.context = vim.tbl_deep_extend( 'force', params.context or {}, context) local line = params.range.start.line local callback = _call_back_fn(line, context.diagnostics) - client.request('textDocument/codeAction', params, callback, bufnr) - + client:request(ms.textDocument_codeAction, params, callback, vim.api.nvim_get_current_buf()) end local function sort_select(action_tuples, opts, on_user_choice) diff --git a/lua/navigator/definition.lua b/lua/navigator/definition.lua index d65ba96..c48b535 100644 --- a/lua/navigator/definition.lua +++ b/lua/navigator/definition.lua @@ -5,6 +5,7 @@ local gui = require('navigator.gui') local log = util.log local trace = util.trace local TextView = require('guihua.textview') +local ms = require('vim.lsp.protocol').Methods -- callback for lsp definition, implementation and declaration handler local definition_hdlr = function(err, locations, ctx, _) if err ~= nil then @@ -150,14 +151,14 @@ local function def_preview(timeout_ms, method) end local width = 40 - local maxwidth = math.floor(vim.api.nvim_get_option('columns') * 0.8) + local maxwidth = math.floor(vim.api.nvim_get_option_value('columns', {scope = 'global'}) * 0.8) for _, value in pairs(definition) do -- log(key, value, width) width = math.max(width, #value + 4) width = math.min(maxwidth, width) end definition = vim.list_extend({ '  [' .. get_symbol() .. '] Definition: ' }, definition) - local filetype = vim.api.nvim_buf_get_option(bufnr, 'filetype') + local filetype = vim.api.nvim_get_option_value('filetype', {buf = bufnr}) -- TODO multiple resuts? local opts = { @@ -179,7 +180,7 @@ local function def_preview(timeout_ms, method) par.textDocument.uri = data[1].uri or data[1].targetUri log(par, clients[1].name) local bufnr_org = vim.uri_to_bufnr(data[1].uri or data[1].targetUri) - return clients[1].request('textDocument/hover', par, function(err, res, ctx, _) + return clients[1]:request(ms.textDocument_hover, par, function(err, res, ctx, _) if err ~= nil then log('error on hover', err) return @@ -190,7 +191,7 @@ local function def_preview(timeout_ms, method) end log(res) local contents = vim.lsp.util.convert_input_to_markdown_lines(res.contents) - local ft = vim.api.nvim_buf_get_option(view.buf, 'filetype') + local ft = vim.api.nvim_get_option_value('filetype', { buf = view.buf }) local hover_opts = { relative = 'cursor', style = 'minimal', @@ -227,6 +228,7 @@ end local function type_preview(timeout_ms) return def_preview(timeout_ms, 'textDocument/typeDefinition') end +local ms = require('vim.lsp.protocol').Methods local def = function() local bufnr = vim.api.nvim_get_current_buf() @@ -234,7 +236,7 @@ local def = function() util.for_each_buffer_client(bufnr, function(client, _, _bufnr) if client.server_capabilities.definitionProvider then local ref_params = vim.lsp.util.make_position_params(0, client.offset_encoding) - client.request('textDocument/definition', ref_params, definition_hdlr, _bufnr) + client:request(ms.textDocument_documentHighlight, ref_params, definition_hdlr, _bufnr or bufnr) return end end) diff --git a/lua/navigator/dochighlight.lua b/lua/navigator/dochighlight.lua index ed85a3b..7c85321 100644 --- a/lua/navigator/dochighlight.lua +++ b/lua/navigator/dochighlight.lua @@ -234,7 +234,7 @@ local nav_doc_hl = function(bufnr) if client.server_capabilities.documentHighlightProvider == true then trace('sending doc highlight', client.name, bufnr) local ref_params = vim.lsp.util.make_position_params(0, client.offset_encoding) - client.request('textDocument/documentHighlight', ref_params, handle_document_highlight, bufnr) + client:request(require('vim.lsp.protocol').Methods.textDocument_documentHighlight, ref_params, handle_document_highlight, bufnr) end end) end diff --git a/lua/navigator/foldlsp.lua b/lua/navigator/foldlsp.lua index 5215144..de641a8 100644 --- a/lua/navigator/foldlsp.lua +++ b/lua/navigator/foldlsp.lua @@ -2,6 +2,7 @@ local log = require('navigator.util').log local lsp = vim.lsp local api = vim.api +local ms = require('vim.lsp.protocol').Methods local M = {} @@ -55,10 +56,10 @@ end function M.update_folds() local current_window = api.nvim_get_current_win() - local in_diff_mode = api.nvim_win_get_option(current_window, 'diff') + local in_diff_mode = api.nvim_get_option_value('diff', {win = current_window}) if in_diff_mode then -- In diff mode, use diff folding. - api.nvim_win_set_option(current_window, 'foldmethod', 'diff') + api.nvim_set_option_value(current_window, 'foldmethod', 'diff', {win = current_window}) else local clients = lsp.get_clients({buffer = 0}) for client_id, client in pairs(clients) do @@ -67,7 +68,7 @@ function M.update_folds() -- client.config.callbacks['textDocument/foldingRange'] = M.fold_handler local current_bufnr = api.nvim_get_current_buf() local params = { uri = vim.uri_from_bufnr(current_bufnr) } - client.request('textDocument/foldingRange', { textDocument = params }, M.fold_handler, current_bufnr) + client:request(ms.textDocument_foldingRange, { textDocument = params }, M.fold_handler, current_bufnr) end end end diff --git a/lua/navigator/reference.lua b/lua/navigator/reference.lua index 8c4a3b8..625a7e6 100644 --- a/lua/navigator/reference.lua +++ b/lua/navigator/reference.lua @@ -4,6 +4,7 @@ local lsphelper = require('navigator.lspwrapper') local gui = require('navigator.gui') local lsp = require('navigator.lspwrapper') local trace = require('navigator.util').trace +local ms = require('vim.lsp.protocol').Methods -- local partial = util.partial -- local cwd = vim.loop.cwd() local uv = vim.uv or vim.loop @@ -286,7 +287,7 @@ local ref = function() local ref_params = util.make_position_params() util.for_each_buffer_client(bufnr, function(client, _, _) if client.server_capabilities.referencesProvider then - client.request('textDocument/references', ref_params, ref_hdlr, bufnr) + client:request(ms.textDocument_references, ref_params, ref_hdlr, bufnr) end end) end @@ -299,7 +300,7 @@ local function side_panel() scope = 'range', header = '  ' .. currentWord .. ' ref ', render = function(bufnr) - local ft = vim.api.nvim_buf_get_option(bufnr, 'buftype') + local ft = vim.api.nvim_get_option_value('buftype', { buf = bufnr }) if ft == 'nofile' or ft == 'guihua' or ft == 'prompt' then return end diff --git a/lua/navigator/rename.lua b/lua/navigator/rename.lua index 2225fb3..9760cf3 100644 --- a/lua/navigator/rename.lua +++ b/lua/navigator/rename.lua @@ -438,7 +438,7 @@ function M.rename_inplace(new_name, options) params.newName = name local handler = client.handlers['textDocument/rename'] or vim.lsp.handlers['textDocument/rename'] - client.request('textDocument/rename', params, function(...) + client:request(ms.textDocument_rename, params, function(...) handler(...) try_use_client(next(clients, idx)) end, bufnr) @@ -446,7 +446,7 @@ function M.rename_inplace(new_name, options) if client.supports_method('textDocument/prepareRename') then -- log(params) - client.request('textDocument/prepareRename', params, function(err, result) + client:request(ms.textDocument_prepareRename, params, function(err, result) if err or result == nil then if next(clients, idx) then try_use_client(next(clients, idx)) diff --git a/lua/navigator/symbols.lua b/lua/navigator/symbols.lua index 76c00a9..a430b9b 100644 --- a/lua/navigator/symbols.lua +++ b/lua/navigator/symbols.lua @@ -39,9 +39,10 @@ function M.document_symbols(opts) return end local params = vim.lsp.util.make_position_params(0, clients[1].offset_encoding) - params.context = { includeDeclaration = true } + params.context = params.context or {} + params.context.includeDeclaration = false params.query = opts.prompt or '' - clients[1].request('textDocument/documentSymbol', params, M.document_symbol_handler, bufnr) + clients[1]:request(ms.textDocument_documentSymbol, params, M.document_symbol_handler, bufnr) end M.document_symbol_handler = function(err, result, ctx) @@ -126,7 +127,7 @@ M.document_symbol_handler = function(err, result, ctx) return locations end - local ft = vim.api.nvim_buf_get_option(bufnr, 'ft') + local ft = vim.api.nvim_get_option_value('ft', { buf = bufnr }) gui.new_list_view({ items = locations, prompt = true, @@ -160,7 +161,7 @@ M.workspace_symbol_handler = function(err, result, ctx, cfg) local items = symbols_to_items(result) log(items[1]) - local ft = vim.api.nvim_buf_get_option(ctx.bufnr, 'ft') + local ft = vim.api.nvim_buf_get_option_value('ft', { buf = ctx.bufnr }) gui.new_list_view({ items = items, prompt = true, @@ -177,7 +178,7 @@ function M.side_panel() local p = Panel:new({ scope = 'range', render = function(bufnr) - local ft = vim.api.nvim_buf_get_option(bufnr, 'buftype') + local ft = vim.api.nvim_get_option_value('buftype', { buf = bufnr }) if ft == 'nofile' or ft == 'guihua' or ft == 'prompt' then return end @@ -192,7 +193,7 @@ function M.side_panel() end, }) p:open(true) - -- redraw the pannel if current buffer modified and saved + -- redraw the panel if current buffer modified and saved local group = vim.api.nvim_create_augroup('guihua_side_panel', { clear = false }) vim.api.nvim_create_autocmd({ 'BufWritePost', From 251f11dc00f820c6af0a1fb7cbb91de7e18ae65c Mon Sep 17 00:00:00 2001 From: rayx Date: Wed, 2 Apr 2025 11:03:27 +1100 Subject: [PATCH 12/17] Update README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 182ba5d..a478c01 100644 --- a/README.md +++ b/README.md @@ -278,7 +278,7 @@ require'navigator'.setup({ separator = '', -- e.g. shows  3 lines  }, }, - mason = false, -- Deprecated, mason no longger supported as setup lsp changed in nvim 0.11 + mason = false, -- Deprecated, mason no longer supported as setup lsp changed in nvim 0.11 lsp = { enable = true, -- skip lsp setup, and only use treesitter in navigator. -- Use this if you are not using LSP servers, and only want to enable treesitter support. From 9a2ec4540d6beefb2c38fc17f63804b751f48dce Mon Sep 17 00:00:00 2001 From: ray-x Date: Wed, 2 Apr 2025 12:37:34 +1100 Subject: [PATCH 13/17] bugfix for typos --- lua/navigator/definition.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/navigator/definition.lua b/lua/navigator/definition.lua index c48b535..010cef6 100644 --- a/lua/navigator/definition.lua +++ b/lua/navigator/definition.lua @@ -236,7 +236,7 @@ local def = function() util.for_each_buffer_client(bufnr, function(client, _, _bufnr) if client.server_capabilities.definitionProvider then local ref_params = vim.lsp.util.make_position_params(0, client.offset_encoding) - client:request(ms.textDocument_documentHighlight, ref_params, definition_hdlr, _bufnr or bufnr) + client:request(ms.textDocument_definition, ref_params, definition_hdlr, _bufnr or bufnr) return end end) From 283342c7196ea51030856a5f714ac3defcf4543c Mon Sep 17 00:00:00 2001 From: ray-x Date: Fri, 4 Apr 2025 12:47:17 +1100 Subject: [PATCH 14/17] gopls updates --- lsp/gopls.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lsp/gopls.lua b/lsp/gopls.lua index f15cabe..6109caa 100644 --- a/lsp/gopls.lua +++ b/lsp/gopls.lua @@ -1,4 +1,8 @@ local util = require('lspconfig').util +local hasgo = pcall(require 'go') +if hasgo then + return require('go.lsp').config() +end return { -- capabilities = cap, filetypes = { 'go', 'gomod', 'gohtmltmpl', 'gotexttmpl' }, @@ -33,8 +37,6 @@ return { symbolMatcher = 'fuzzy', gofumpt = false, -- true, -- turn on for new repos, gofmpt is good but also create code turmoils buildFlags = { '-tags', 'integration' }, - -- buildFlags = {"-tags", "functional"} - semanticTokens = true, }, }, } From 20ac4c6f26c128098d2fd4bee3421fef5da09d98 Mon Sep 17 00:00:00 2001 From: ray-x Date: Mon, 7 Apr 2025 12:26:14 +1000 Subject: [PATCH 15/17] warning msg updates --- lua/navigator.lua | 4 ++-- lua/navigator/lspclient/mapping.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/navigator.lua b/lua/navigator.lua index f44509a..cfc1564 100644 --- a/lua/navigator.lua +++ b/lua/navigator.lua @@ -2,7 +2,7 @@ local M = {} local api = vim.api local function warn(msg) - api.nvim_echo({ { 'WRN: ' .. msg, 'WarningMsg' } }, true, {}) + api.nvim_echo({ { 'WRN: ' .. msg, 'WarningMsg' } }, true, { err = true }) end local function info(msg) @@ -331,7 +331,7 @@ M.setup = function(cfg) local util = require('navigator.util') local has_nvim_011 = util.nvim_0_11() if not has_nvim_011 then - vim.notify('navigator.nvim requires nvim 0.11 or higher', vim.log.levels.WARN) + vim.notify('navigator.nvim requires nvim 0.11 or higher use nvim_0.10 branch if you are using old version of nvim', vim.log.levels.WARN) return end cfg = cfg or {} diff --git a/lua/navigator/lspclient/mapping.lua b/lua/navigator/lspclient/mapping.lua index c12e09d..8f4fb93 100644 --- a/lua/navigator/lspclient/mapping.lua +++ b/lua/navigator/lspclient/mapping.lua @@ -34,7 +34,7 @@ local key_maps = { { key = 'gr', func = require('navigator.reference').reference, desc = 'reference' }, -- reference deprecated { key = '', func = vim.lsp.buf.signature_help, desc = 'signature_help', mode = 'i' }, { key = '', func = vim.lsp.buf.signature_help, desc = 'signature_help' }, - { key = 'g0', func = require('navigator.symbols').document_symbols, desc = 'document_symbols' }, + { key = 'gO', func = require('navigator.symbols').document_symbols, desc = 'document_symbols' }, { key = 'gW', func = require('navigator.workspace').workspace_symbol_live, desc = 'workspace_symbol_live' }, { key = '', func = require('navigator.definition').definition, desc = 'definition' }, { key = 'gd', func = remap(require('navigator.definition').definition, 'gd'), desc = 'definition' }, From 03d476b28a3f329c89ed5813bd30dcf59bb48625 Mon Sep 17 00:00:00 2001 From: ray-x Date: Mon, 7 Apr 2025 12:38:22 +1000 Subject: [PATCH 16/17] warn func revert --- lsp/gopls.lua | 2 ++ lua/navigator.lua | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lsp/gopls.lua b/lsp/gopls.lua index 6109caa..35f1042 100644 --- a/lsp/gopls.lua +++ b/lsp/gopls.lua @@ -37,6 +37,8 @@ return { symbolMatcher = 'fuzzy', gofumpt = false, -- true, -- turn on for new repos, gofmpt is good but also create code turmoils buildFlags = { '-tags', 'integration' }, + -- buildFlags = {"-tags", "functional"} + semanticTokens = false, }, }, } diff --git a/lua/navigator.lua b/lua/navigator.lua index cfc1564..9a747f9 100644 --- a/lua/navigator.lua +++ b/lua/navigator.lua @@ -2,7 +2,7 @@ local M = {} local api = vim.api local function warn(msg) - api.nvim_echo({ { 'WRN: ' .. msg, 'WarningMsg' } }, true, { err = true }) + api.nvim_echo({ { 'WRN: ' .. msg, 'WarningMsg' } }, true, {}) end local function info(msg) From fc5a696dcd740d277af0f92599b67f80e968c998 Mon Sep 17 00:00:00 2001 From: ray-x Date: Mon, 21 Apr 2025 12:38:34 +1000 Subject: [PATCH 17/17] key mapping updates --- lua/navigator.lua | 15 +-- lua/navigator/definition.lua | 66 +++++++++--- lua/navigator/hierarchy.lua | 36 +++++-- lua/navigator/hover.lua | 161 ++++++++++++++++++++-------- lua/navigator/implementation.lua | 10 +- lua/navigator/lspclient/mapping.lua | 103 ++++++++++-------- lua/navigator/lspwrapper.lua | 2 +- 7 files changed, 263 insertions(+), 130 deletions(-) diff --git a/lua/navigator.lua b/lua/navigator.lua index 9a747f9..f4c36fd 100644 --- a/lua/navigator.lua +++ b/lua/navigator.lua @@ -331,7 +331,10 @@ M.setup = function(cfg) local util = require('navigator.util') local has_nvim_011 = util.nvim_0_11() if not has_nvim_011 then - vim.notify('navigator.nvim requires nvim 0.11 or higher use nvim_0.10 branch if you are using old version of nvim', vim.log.levels.WARN) + vim.notify( + 'navigator.nvim requires nvim 0.11 or higher use nvim_0.10 branch if you are using old version of nvim', + vim.log.levels.WARN + ) return end cfg = cfg or {} @@ -424,16 +427,6 @@ M.setup = function(cfg) }) end, }) - - local _start_client = vim.lsp.start_client - vim.lsp.start_client = function(lsp_config) - -- add highlight for Lspxxx - require('navigator.lspclient.highlight').add_highlight() - require('navigator.lspclient.highlight').config_signs() - -- require('navigator.lspclient.mapping').setup() - require('navigator.lspclient.lspkind').init() - return _start_client(lsp_config) - end end, 1) end diff --git a/lua/navigator/definition.lua b/lua/navigator/definition.lua index e3ab0d2..94bcddc 100644 --- a/lua/navigator/definition.lua +++ b/lua/navigator/definition.lua @@ -3,6 +3,7 @@ local lsphelper = require('navigator.lspwrapper') local locations_to_items = lsphelper.locations_to_items local gui = require('navigator.gui') local log = util.log +local ms = require('vim.lsp.protocol').Methods local trace = util.trace local TextView = require('guihua.textview') local ms = require('vim.lsp.protocol').Methods @@ -59,19 +60,33 @@ local function get_symbol() return currentWord end -local function def_preview(timeout_ms, method) - method = method or 'textDocument/definition' - local clients = vim.lsp.get_clients({ - bufnr = vim.api.nvim_get_current_buf(), - method = method, - }) +local function def_preview(timeout_ms, method, client, bufnr) + local ms_def = ms.textDocument_definition + method = method or ms_def - if not clients or #clients == 0 then - vim.notify('no definition clients found for bufnr') - return + bufnr = bufnr or vim.api.nvim_get_current_buf() + if not client then + local clients = vim.lsp.get_clients({ + bufnr = bufnr, + method = method, + }) + + if not clients or #clients == 0 then + vim.notify('no definition clients found for bufnr') + return + end + -- find first client support definition + -- for _, c in pairs(clients) do + -- if c:supports_method(ms_def, bufnr) then + -- client = c + -- break + -- end + -- end + client = clients[1] end - local params = vim.lsp.util.make_position_params(0, clients[1].offset_encoding) - local result = vim.lsp.buf_request_sync(0, method, params, timeout_ms or 1000) + local params = vim.lsp.util.make_position_params(0, client.offset_encoding) + -- local result = vim.lsp.buf_request_sync(0, method, params, timeout_ms or 1000) + local result = client:request_sync(method, params, timeout_ms or 1000, bufnr) if result == nil or vim.tbl_isempty(result) then vim.notify('No result found: ' .. method, vim.log.levels.WARN) @@ -146,14 +161,14 @@ local function def_preview(timeout_ms, method) end local width = 40 - local maxwidth = math.floor(vim.api.nvim_get_option_value('columns', {scope = 'global'}) * 0.8) + local maxwidth = math.floor(vim.api.nvim_get_option_value('columns', { scope = 'global' }) * 0.8) for _, value in pairs(definition) do -- log(key, value, width) width = math.max(width, #value + 4) width = math.min(maxwidth, width) end definition = vim.list_extend({ '  [' .. get_symbol() .. '] Definition: ' }, definition) - local filetype = vim.api.nvim_get_option_value('filetype', {buf = bufnr}) + local filetype = vim.api.nvim_get_option_value('filetype', { buf = bufnr }) -- TODO multiple resuts? local opts = { @@ -169,13 +184,13 @@ local function def_preview(timeout_ms, method) local view = TextView:new(opts) log(view.buf) vim.keymap.set('n', 'K', function() - local par = vim.lsp.util.make_position_params(0, clients[1].offset_encoding) + local par = vim.lsp.util.make_position_params(0, client.offset_encoding) log(row, par, data[1]) par.position.line = par.position.line + row - 1 -- header 1 par.textDocument.uri = data[1].uri or data[1].targetUri - log(par, clients[1].name) + log(par, client.name) local bufnr_org = vim.uri_to_bufnr(data[1].uri or data[1].targetUri) - return clients[1]:request(ms.textDocument_hover, par, function(err, res, ctx, _) + return client:request(ms.textDocument_hover, par, function(err, res, ctx, _) if err ~= nil then log('error on hover', err) return @@ -220,10 +235,24 @@ local function def_preview(timeout_ms, method) -- TODO: -- https://github.com/oblitum/goyo.vim/blob/master/autoload/goyo.vim#L108-L135 end + +local def_preview_wrapper = function(client, bufnr) + return function() + local ms_def = require('vim.lsp.protocol').Methods.textDocument_definition + def_preview(1000, ms_def, client, bufnr) + end +end + local function type_preview(timeout_ms) return def_preview(timeout_ms, 'textDocument/typeDefinition') end -local ms = require('vim.lsp.protocol').Methods +local type_preview_wrapper = function(client, bufnr) + return function(ts) + ts = ts or 1000 + return def_preview(1000, 'textDocument/typeDefinition', client, bufnr) + end +end + local def = function() local bufnr = vim.api.nvim_get_current_buf() @@ -240,7 +269,10 @@ end return { definition = def, definition_handler = definition_hdlr, + definition_preview_wrapper = def_preview_wrapper, + definition_wrapper = def_preview_wrapper, definition_preview = def_preview, + type_definition_preview_wrapper = type_preview_wrapper, type_definition_preview = type_preview, declaration_handler = definition_hdlr, type_definition_handler = definition_hdlr, diff --git a/lua/navigator/hierarchy.lua b/lua/navigator/hierarchy.lua index 8486e45..75002d4 100644 --- a/lua/navigator/hierarchy.lua +++ b/lua/navigator/hierarchy.lua @@ -251,17 +251,30 @@ local request = vim.lsp.buf_request -- call_hierarchy with floating window call_hierarchy = function(method, opts) + local client = opts.client + local bufnr = opts.bufnr or vim.api.nvim_get_current_buf() + + log(method, opts, client, bufnr) + if not client then + local clients = vim.lsp.get_clients({ + bufnr = bufnr, + method = method, + }) + if not clients or #clients == 0 then + vim.notify('no call hierarchy clients found for bufnr') + return + end + client = clients[1] + end trace(method, opts) opts = opts or {} local params = opts.params or util.make_position_params() - local bufnr = opts.bufnr local handler = function(err, result, ctx, cfg) ctx.opts = opts return opts.handler(err, result, ctx, cfg) end -- log(opts, params) - return request( - bufnr, + return client:request( 'textDocument/prepareCallHierarchy', params, util.lsp_with(function(err, result, ctx) @@ -269,8 +282,13 @@ call_hierarchy = function(method, opts) vim.notify(err.message, vim.log.levels.WARN) return end - local call_hierarchy_item = pick_call_hierarchy_item(result) local client = vim.lsp.get_client_by_id(ctx.client_id) + -- check if the client supports call hierarchy + if not client.supports_method(method, ctx.bufnr) then + vim.notify('Client ' .. client.name .. ' does not support ' .. method, vim.log.levels.INFO) + return + end + local call_hierarchy_item = pick_call_hierarchy_item(result) if client then trace('result', result, 'items', call_hierarchy_item, method, ctx, client.name) client:request(method, { @@ -282,17 +300,18 @@ call_hierarchy = function(method, opts) else vim.notify(string.format('Client with id=%d stopped', ctx.client_id), vim.log.levels.WARN) end - end, { direction = method, depth = opts.depth }) + end, { direction = method, depth = opts.depth }), + bufnr ) end function M.incoming_calls(opts) - opts = opts or {handler = incoming_calls_handler} + opts = opts or { handler = incoming_calls_handler } call_hierarchy(in_method, opts) end function M.outgoing_calls(opts) - opts = opts or {handler = outgoing_calls_handler} + opts = opts or { handler = outgoing_calls_handler } call_hierarchy(out_method, opts) end @@ -306,8 +325,6 @@ function M.outgoing_calls_panel(opts) call_hierarchy(out_method, opts) end -M.incoming_calls_handler = incoming_calls_handler -M.outgoing_calls_handler = outgoing_calls_handler -- for testing M._call_hierarchy = call_hierarchy @@ -317,4 +334,5 @@ function M.calltree(args) end M.incoming_calls_panel() end + return M diff --git a/lua/navigator/hover.lua b/lua/navigator/hover.lua index f6e9776..570e84c 100644 --- a/lua/navigator/hover.lua +++ b/lua/navigator/hover.lua @@ -5,51 +5,128 @@ local api = vim.api local log = nutils.log local M = {} -function M.handler(err, result, ctx, config) +local hover_ns = api.nvim_create_namespace('nvim.lsp.hover_range') +local ms = lsp.protocol.Methods + + +--- @class vim.lsp.buf.hover.Opts : vim.lsp.util.open_floating_preview.Opts +--- @field silent? boolean + +--- Displays hover information about the symbol under the cursor in a floating +--- window. The window will be dismissed on cursor move. +--- Calling the function twice will jump into the floating window +--- (thus by default, "KK" will open the hover window and focus it). +--- In the floating window, all commands and mappings are available as usual, +--- except that "q" dismisses the window. +--- You can scroll the contents the same as you would any other buffer. +--- +--- Note: to disable hover highlights, add the following to your config: +--- +--- ```lua +--- vim.api.nvim_create_autocmd('ColorScheme', { +--- callback = function() +--- vim.api.nvim_set_hl(0, 'LspReferenceTarget', {}) +--- end, +--- }) +--- ``` +--- @param config? vim.lsp.buf.hover.Opts +function M.hover(config) config = config or {} - config.focus_id = ctx.method - if api.nvim_get_current_buf() ~= ctx.bufnr then - -- Ignore result since buffer changed. This happens for slow language servers. - return - end - local failed = false - if err then - vim.notify('no hover info ' .. vim.inspect(err)) - failed = true - end - if not result or not result.contents then - if config.silent ~= true then - vim.notify('No hover information available') + config.focus_id = ms.textDocument_hover + + lsp.buf_request_all(0, ms.textDocument_hover, client_positional_params(), function(results, ctx) + local bufnr = assert(ctx.bufnr) + if api.nvim_get_current_buf() ~= bufnr then + -- Ignore result since buffer changed. This happens for slow language servers. + return end - failed = true - end - local bufnr = ctx.bufnr - -- get filetype for bufnr - local ft = api.nvim_buf_get_option(bufnr, 'filetype') - if failed then - if _NgConfigValues.lsp.hover.ft then - local fallback_fn = _NgConfigValues.hover.ft or '' - if type(fallback_fn) == 'function' then - fallback_fn(ctx, config) + + -- Filter errors from results + local results1 = {} --- @type table + + for client_id, resp in pairs(results) do + local err, result = resp.err, resp.result + if err then + lsp.log.error(err.code, err.message) + elseif result then + results1[client_id] = result end end - return -- return early as no valid hover info lets fallback to other sources - end - local format = 'markdown' - local contents ---@type string[] - if type(result.contents) == 'table' and result.contents.kind == 'plaintext' then - format = 'plaintext' - contents = vim.split(result.contents.value or '', '\n', { trimempty = true }) - else - contents = util.convert_input_to_markdown_lines(result.contents) - end - if vim.tbl_isempty(contents) then - if config.silent ~= true then - vim.notify('No information available') + + if vim.tbl_isempty(results1) then + if config.silent ~= true then + vim.notify('No information available') + end + return end - return - end - return util.open_floating_preview(contents, format, config) -end -return M + local contents = {} --- @type string[] + + local nresults = #vim.tbl_keys(results1) + + local format = 'markdown' + + for client_id, result in pairs(results1) do + local client = assert(lsp.get_client_by_id(client_id)) + if nresults > 1 then + -- Show client name if there are multiple clients + contents[#contents + 1] = string.format('# %s', client.name) + end + if type(result.contents) == 'table' and result.contents.kind == 'plaintext' then + if #results1 == 1 then + format = 'plaintext' + contents = vim.split(result.contents.value or '', '\n', { trimempty = true }) + else + -- Surround plaintext with ``` to get correct formatting + contents[#contents + 1] = '```' + vim.list_extend( + contents, + vim.split(result.contents.value or '', '\n', { trimempty = true }) + ) + contents[#contents + 1] = '```' + end + else + vim.list_extend(contents, util.convert_input_to_markdown_lines(result.contents)) + end + local range = result.range + if range then + local start = range.start + local end_ = range['end'] + local start_idx = util._get_line_byte_from_position(bufnr, start, client.offset_encoding) + local end_idx = util._get_line_byte_from_position(bufnr, end_, client.offset_encoding) + + vim.hl.range( + bufnr, + hover_ns, + 'LspReferenceTarget', + { start.line, start_idx }, + { end_.line, end_idx }, + { priority = vim.hl.priorities.user } + ) + end + contents[#contents + 1] = '---' + end + + -- Remove last linebreak ('---') + contents[#contents] = nil + + if vim.tbl_isempty(contents) then + if config.silent ~= true then + vim.notify('No information available') + end + return + end + + local _, winid = lsp.util.open_floating_preview(contents, format, config) + + api.nvim_create_autocmd('WinClosed', { + pattern = tostring(winid), + once = true, + callback = function() + api.nvim_buf_clear_namespace(bufnr, hover_ns, 0, -1) + return true + end, + }) + -- + end) +end diff --git a/lua/navigator/implementation.lua b/lua/navigator/implementation.lua index 3e45dee..6026842 100644 --- a/lua/navigator/implementation.lua +++ b/lua/navigator/implementation.lua @@ -15,9 +15,9 @@ local function location_handler(err, locations, ctx, _, msg) return locations_to_items(locations, ctx) end -local function implementation_handler(_, err, result, ctx, cfg) +local function implementation_handler(err, result, ctx, cfg) local results = location_handler(err, result, ctx, cfg, 'Implementation not found') - local ft = vim.api.nvim_buf_get_option(ctx.bufnr or 0, 'ft') + local ft = vim.api.nvim_get_option_value('ft', { buf = ctx.bufnr }) gui.new_list_view({ items = results, ft = ft, api = 'Implementation', title = 'Implementation' }) end @@ -33,12 +33,10 @@ function M.implementation(bang, opts) 'textDocument/implementation', params, opts, - partial(implementation_handler, bang) + implementation_handler ) end -M.implementation_call = partial(M.implementation, 0) - -M.implementation_handler = partial(implementation_handler, 0) +M.implementation_handler = implementation_handler return M diff --git a/lua/navigator/lspclient/mapping.lua b/lua/navigator/lspclient/mapping.lua index baec1e4..34aca08 100644 --- a/lua/navigator/lspclient/mapping.lua +++ b/lua/navigator/lspclient/mapping.lua @@ -2,6 +2,7 @@ local util = require('navigator.util') local log = util.log local trace = util.trace local api = vim.api +local ms = require('vim.lsp.protocol').Methods if vim.lsp.buf.format == nil then vim.lsp.buf.format = vim.lsp.buf.formatting @@ -30,50 +31,58 @@ local single = { '╭', '─', '╮', '│', '╯', '─', '╰', '│' } local remap = util.binding_remap -- stylua: ignore start local key_maps = { - { key = 'gr', func = require('navigator.reference').async_ref, desc = 'async_ref' }, - { key = 'gr', func = require('navigator.reference').reference, desc = 'reference' }, -- reference deprecated - { key = '', func = vim.lsp.buf.signature_help, desc = 'signature_help', mode = 'i' }, - { key = '', func = vim.lsp.buf.signature_help, desc = 'signature_help' }, - { key = 'gO', func = require('navigator.symbols').document_symbols, desc = 'document_symbols' }, - { key = 'gW', func = require('navigator.workspace').workspace_symbol_live, desc = 'workspace_symbol_live' }, - { key = '', func = require('navigator.definition').definition, desc = 'definition' }, - { key = 'gd', func = remap(require('navigator.definition').definition, 'gd'), desc = 'definition' }, - { key = 'gD', func = vim.lsp.buf.declaration, desc = 'declaration', fallback = fallback_fn('gD') }, -- fallback used + { key = 'grr', func = require('navigator.reference').async_ref, desc = 'async_ref' }, + { key = 'gr', func = require('navigator.reference').reference, desc = 'reference' }, -- reference deprecated + { key = '', func = vim.lsp.buf.signature_help, desc = 'signature_help', mode = 'i' }, + { key = '', func = vim.lsp.buf.signature_help, desc = 'signature_help' }, + { key = 'gO', func = require('navigator.symbols').document_symbols, desc = 'document_symbols' }, + { key = 'gW', func = require('navigator.workspace').workspace_symbol_live, desc = 'workspace_symbol_live' }, + { key = '', func = require('navigator.definition').definition, desc = 'definition' }, + { key = 'gd', func = require('navigator.definition').definition, desc = 'definition', remap = 'gd' }, + { key = 'gD', func = vim.lsp.buf.declaration, desc = 'declaration', fallback = fallback_fn('gD') }, -- fallback used -- for lsp handler - { key = 'gp', func = remap(require('navigator.definition').definition_preview, 'gp'), desc = 'definition_preview' }, -- paste - { key = 'gP', func = remap(require('navigator.definition').type_definition_preview, 'gP'), desc = 'type_definition_preview' }, -- paste - { key = 'gt', func = require('navigator.treesitter').buf_ts, desc = 'buf_ts' }, - { key = 'gT', func = require('navigator.treesitter').bufs_ts, desc = 'bufs_ts' }, - { key = 'ct', func = require('navigator.ctags').ctags, desc = 'ctags' }, - { key = 'ca', func = require('navigator.codeAction').code_action, desc = 'code_action', mode = { 'n', 'v' } }, + { key = 'gp', func = require('navigator.definition').definition_preview, desc = 'definition_preview', remap = 'gp' }, + { key = 'gP', func = require('navigator.definition').type_definition_preview, desc = 'type_definition_preview', remap = 'gP' }, + { key = 'gt', func = require('navigator.treesitter').buf_ts, desc = 'buf_ts' }, + { key = 'gT', func = require('navigator.treesitter').bufs_ts, desc = 'bufs_ts' }, + { key = 'ct', func = require('navigator.ctags').ctags, desc = 'ctags' }, + { key = 'ca', func = require('navigator.codeAction').code_action, desc = 'code_action', mode = { 'n', 'v' } }, -- { key = 're', func = 'rename()' }, - { key = 'rn', func = require('navigator.rename').rename, desc = 'rename' }, - { key = 'gi', func = require('navigator.hierarchy').incoming_calls, desc = 'incoming_calls' }, - { key = 'go', func = require('navigator.hierarchy').outgoing_calls, desc = 'outgoing_calls' }, - { key = 'gi', func = require('navigator.implementation').implementation_call, desc = 'implementation', fallback = fallback_fn('gi') }, -- insert - { key = 'D', func = vim.lsp.buf.type_definition, desc = 'type_definition' }, - { key = 'gL', func = require('navigator.diagnostics').show_diagnostics, desc = 'show_diagnostics' }, - { key = 'gG', func = require('navigator.diagnostics').show_buf_diagnostics, desc = 'show_buf_diagnostics' }, - { key = 'dt', func = require('navigator.diagnostics').toggle_diagnostics, desc = 'toggle_diagnostics' }, - { key = ']d', func = require('navigator.diagnostics').goto_next, desc = 'next diagnostics error or fallback' }, - { key = '[d', func = require('navigator.diagnostics').goto_prev, desc = 'prev diagnostics error or fallback' }, - { key = ']O', func = vim.diagnostic.set_loclist, desc = 'diagnostics set loclist' }, - { key = ']r', func = require('navigator.treesitter').goto_next_usage, desc = 'goto_next_usage' }, - { key = '[r', func = require('navigator.treesitter').goto_previous_usage, desc = 'goto_previous_usage' }, - { key = '', func = vim.lsp.buf.definition, desc = 'definition', fallback = fallback_fn('') }, - { key = 'g', func = vim.lsp.buf.implementation, desc = 'implementation' }, - { key = 'k', func = require('navigator.dochighlight').hi_symbol, desc = 'hi_symbol' }, - { key = 'wa', func = require('navigator.workspace').add_workspace_folder, desc = 'add_workspace_folder' }, - { key = 'wr', func = require('navigator.workspace').remove_workspace_folder, desc = 'remove_workspace_folder' }, - { key = 'ff', func = vim.lsp.buf.format, desc = 'format', mode = { 'n', 'v', 'x' } }, - { key = 'gm', func = require('navigator.formatting').range_format, mode = 'n', desc = 'range format operator e.g gmip' }, - { key = 'wl', func = require('navigator.workspace').list_workspace_folders, desc = 'list_workspace_folders' }, - { key = 'la', func = require('navigator.codelens').run_action, desc = 'run code lens action', mode = 'n' } + { key = 'grn', func = require('navigator.rename').rename, desc = 'rename' }, + { key = 'gi', func = require('navigator.hierarchy').incoming_calls, desc = 'incoming_calls' }, + { key = 'go', func = require('navigator.hierarchy').outgoing_calls, desc = 'outgoing_calls' }, + { key = 'gri', func = require('navigator.implementation').implementation, desc = 'implementation', }, -- insert + { key = 'D', func = vim.lsp.buf.type_definition, desc = 'type_definition' }, + { key = 'gL', func = require('navigator.diagnostics').show_diagnostics, desc = 'show_diagnostics' }, + { key = 'gG', func = require('navigator.diagnostics').show_buf_diagnostics, desc = 'show_buf_diagnostics' }, + { key = 'dt', func = require('navigator.diagnostics').toggle_diagnostics, desc = 'toggle_diagnostics' }, + { key = ']d', func = require('navigator.diagnostics').goto_next, desc = 'next diagnostics error or fallback' }, + { key = '[d', func = require('navigator.diagnostics').goto_prev, desc = 'prev diagnostics error or fallback' }, + { key = ']O', func = vim.diagnostic.set_loclist, desc = 'diagnostics set loclist' }, + { key = ']r', func = require('navigator.treesitter').goto_next_usage, desc = 'goto_next_usage' }, + { key = '[r', func = require('navigator.treesitter').goto_previous_usage, desc = 'goto_previous_usage' }, + { key = '', func = vim.lsp.buf.definition, desc = 'definition', fallback = fallback_fn('') }, + { key = 'g', func = vim.lsp.buf.implementation, desc = 'implementation' }, + { key = 'k', func = require('navigator.dochighlight').hi_symbol, desc = 'hi_symbol' }, + { key = 'wa', func = require('navigator.workspace').add_workspace_folder, desc = 'add_workspace_folder' }, + { key = 'wr', func = require('navigator.workspace').remove_workspace_folder, desc = 'remove_workspace_folder' }, + { key = 'ff', func = vim.lsp.buf.format, desc = 'format', mode = { 'n', 'v', 'x' } }, + { key = 'gm', func = require('navigator.formatting').range_format, mode = 'n', desc = 'range format operator e.g gmip' }, + { key = 'wl', func = require('navigator.workspace').list_workspace_folders, desc = 'list_workspace_folders' }, + { key = 'la', func = require('navigator.codelens').run_action, desc = 'run code lens action', mode = 'n' } -- stylua: ignore end } if _NgConfigValues.lsp.hover then - table.insert(key_maps, { key = 'K', func = vim.lsp.buf.hover, desc = 'hover' }) + table.insert(key_maps, { + key = 'K', + func = function() + return vim.lsp.buf.hover({ + border = _NgConfigValues.border, + }) + end, + desc = 'hover' + }) end local key_maps_help = {} @@ -219,7 +228,17 @@ local function set_mapping(lsp_attach_info) opts[k] = v end end - vim.keymap.set(value.mode or 'n', value.key, value.func, opts) + local f = value.func + if type(value.func) == 'function' then + if value.remap then + f = remap(f, value.remap) + end + if value.fallback then + f = util.mk_handler_remap(f, value.fallback) + end + end + + vim.keymap.set(value.mode or 'n', value.key, f, opts) if string.find(value.desc, 'range format') and value.mode == 'v' then rfmtkey = value.key if string.find(value.desc, 'range format') and value.mode == 'n' then @@ -337,6 +356,7 @@ M.toggle_lspformat = function(on) end end +---@attach_opts table {client = lspclient, bufnr = 0} function M.setup(attach_opts) if not attach_opts or not attach_opts.client then vim.notify( @@ -453,11 +473,6 @@ function M.setup(attach_opts) if _NgConfigValues.border == 'double' then border_style = double end - if _NgConfigValues.lsp.hover.enable then - vim.lsp.handlers['textDocument/hover'] = util.lsp_with(require('navigator.hover').handler, { - border = border_style, - }) - end if cap.documentFormattingProvider then log('formatting enabled setup hdl') vim.lsp.handlers['textDocument/formatting'] = require('navigator.formatting').format_hdl diff --git a/lua/navigator/lspwrapper.lua b/lua/navigator/lspwrapper.lua index 4e125c6..47ec3d7 100644 --- a/lua/navigator/lspwrapper.lua +++ b/lua/navigator/lspwrapper.lua @@ -166,7 +166,7 @@ function M.call_async(method, params, handler, bufnr) -- note: neovim vim.lsp.buf_request seems no longer exposed, in future, use lsp.Client:request -- return lsp.buf_request(bufnr, method, params, callback) -- get clients for the buffer - local clients = lsp.get_clients({ buffer = bufnr }) + local clients = lsp.get_clients({ buffer = bufnr, method = method }) for _, client in pairs(clients) do if client:supports_method(method, bufnr) then if type(params) == 'function' then