From 93c7eae2caac683f1c5800448331d95b4a93118e Mon Sep 17 00:00:00 2001 From: rayx Date: Fri, 1 Oct 2021 18:53:52 +1000 Subject: [PATCH] Code action v2 (#81) * bugfix for #71 * Better lspinstall support * incoming_calls and outgoing_calls cause errors when results from LSP server have multiple lines #78 * remove logs * update README.md * defer format update * lazyload lua-dev #72 * timer of filetype detect to 500 * document update * update codeaction * action command * update code action details * add svelteserver --- README.md | 24 +++- lua/navigator.lua | 8 +- lua/navigator/codeAction.lua | 152 ++++++++++++++++++++-- lua/navigator/codelens.lua | 6 +- lua/navigator/diagnostics.lua | 1 + lua/navigator/formatting.lua | 28 +++-- lua/navigator/hierarchy.lua | 13 +- lua/navigator/lazyloader.lua | 67 ++++++---- lua/navigator/lspclient/clients.lua | 124 +++++++++++------- lua/navigator/lspclient/mapping.lua | 2 +- lua/navigator/lspwrapper.lua | 52 ++++++++ lua/navigator/protocal.txt | 189 ++++++++++++++++++++++++++-- lua/navigator/symbols.lua | 2 +- 13 files changed, 562 insertions(+), 106 deletions(-) diff --git a/README.md b/README.md index 6af74e0..7eb08b3 100644 --- a/README.md +++ b/README.md @@ -297,7 +297,8 @@ Other than above setup, additional none default setup are used for following lsp Please check [client setup](https://github.com/ray-x/navigator.lua/blob/26012cf9c172aa788a2e53018d94b32c5c75af75/lua/navigator/lspclient/clients.lua#L98-L234) The plugin can work with multiple LSP, e.g sqls+gopls+efm. But there are cases you may need to disable some of the -servers. (Prevent loading multiple LSP for same source code.) e.g. I saw strange behaviours when I use pyls+pyright+pyls_ms +servers. (Prevent loading multiple LSP for same source code.) e.g. I saw strange behaviours when I use +pylsp+pyright+jedi together. If you have multiple similar LSP installed and have trouble with the plugin, please enable only one at a time. ### Disable a lsp client loading from navigator @@ -306,7 +307,7 @@ To disable a specific LSP, set `filetypes` to {} e.g. ```lua require'navigator'.setup({ - pyls={filetype={}} + pylsd={filetype={}} }) ``` @@ -315,7 +316,7 @@ Or: ```lua require'navigator'.setup({ - disable_lsp = {'pyls', 'sqlls'}, + disable_lsp = {'pylsd', 'sqlls'}, }) ``` @@ -366,6 +367,8 @@ require'navigator'.setup({ | n | \ | open preview file in nvim with vsplit | | n | \ | open preview file in nvim with split | | n | \ | open preview file in nvim/Apply action | +| n | \ | close listview of floating window | +| i/n | \ | close listview of floating window | | i/n | \ | previous page in listview | | i/n | \ | next page in listview | | i/n | \ | save the modification to preview window to file | @@ -405,7 +408,20 @@ If you'd like to only use the lsp servers installed by lspinstall. Please set lspinstall = false ``` -In the config +In the config. + +If you need to use the setup from navigator instead of default setup in lspinstall. Please setup + +```lua +lspinstall = false + +require'navigator'.setup({ + lsp = { + tsserver = { cmd = {'your tsserver installed by lspinstall'} } + } +}) + +``` ## Usage diff --git a/lua/navigator.lua b/lua/navigator.lua index 7247511..6c57033 100644 --- a/lua/navigator.lua +++ b/lua/navigator.lua @@ -133,11 +133,13 @@ end M.setup = function(cfg) extend_config(cfg) + + vim.cmd([[autocmd FileType * lua require'navigator.lspclient.clients'.setup()]]) -- BufWinEnter BufNewFile,BufRead ? -- local log = require"navigator.util".log -- log(debug.traceback()) -- log(cfg, _NgConfigValues) -- print("loading navigator") - require('navigator.lazyloader') + require('navigator.lazyloader').init() require('navigator.lspclient.clients').setup(_NgConfigValues) -- require("navigator.lspclient.mapping").setup(_NgConfigValues) require("navigator.reference") @@ -149,14 +151,16 @@ M.setup = function(cfg) if _NgConfigValues.code_action_prompt.enable then vim.cmd [[autocmd CursorHold,CursorHoldI * lua require'navigator.codeAction'.code_action_prompt()]] end + -- vim.cmd("autocmd BufNewFile,BufRead *.go setlocal noexpandtab tabstop=4 shiftwidth=4") if not _NgConfigValues.loaded then - vim.cmd([[autocmd FileType * lua require'navigator.lspclient.clients'.setup()]]) -- BufWinEnter BufNewFile,BufRead ? _NgConfigValues.loaded = true end + if _NgConfigValues.ts_fold == true then require('navigator.foldts').on_attach() end + end return M diff --git a/lua/navigator/codeAction.lua b/lua/navigator/codeAction.lua index 34a17fe..3288dd9 100644 --- a/lua/navigator/codeAction.lua +++ b/lua/navigator/codeAction.lua @@ -5,9 +5,127 @@ local code_action = {} local gui = require "navigator.gui" local config = require("navigator").config_values() local api = vim.api +trace = log local sign_name = "NavigatorLightBulb" +--- `codeAction/resolve` +-- from neovim buf.lua, change vim.ui.select to gui +local function on_code_action_results(results, ctx) + local action_tuples = {} + for client_id, result in pairs(results) do + for _, action in pairs(result.result or {}) do + table.insert(action_tuples, {client_id, action}) + end + end + if #action_tuples == 0 then + vim.notify('No code actions available', vim.log.levels.INFO) + return + end + + trace(action_tuples, ctx) + local data = {"  Auto Fix Apply Exit"} + for i, act in pairs(action_tuples) do + local title = 'apply action' + local action = act[2] + trace(action) + if action.edit and action.edit.title then + local edit = action.edit + title = edit.title:gsub("\n", " ↳ ") + elseif action.title then + title = action.title:gsub("\n", " ↳ ") + elseif action.command and action.command.title then + title = action.command.title:gsub("\n", " ↳ ") + end + + local edit = action.edit or {} + -- trace(edit.documentChanges) + if edit.documentChanges or edit.changes then + local changes = edit.documentChanges or edit.changes + -- trace(action.edit.documentChanges) + for _, change in pairs(changes or {}) do + -- trace(change) + if change.edits then + title = title .. " [newText:]" + for _, ed in pairs(change.edits) do + -- trace(ed) + if ed.newText then + ed.newText = ed.newText:gsub("\n\t", " ↳ ") + ed.newText = ed.newText:gsub("\n", "↳") + title = title .. " (" .. ed.newText + if ed.range then + title = title .. " line: " .. tostring(ed.range.start.line) .. ")" + else + title = title .. ")" + end + end + end + elseif change.newText then + + change.newText = change.newText:gsub("\"\n\t\"", " ↳ ") + change.newText = change.newText:gsub("\n", "↳") + title = title .. " (newText: " .. change.newText + if change.range then + title = title .. " line: " .. tostring(change.range.start.line) .. ")" + else + title = title .. ")" + end + end + + end + end + + title = title:gsub("\n", "\\n") + title = string.format("[%d] %s", i, title) + table.insert(data, title) + action_tuples[i].display_title = title + end + + log(action_tuples) + local width = 42 + for _, str in ipairs(data) do + if #str > width then + width = #str + end + end + + local divider = string.rep('─', width + 2) + + table.insert(data, 2, divider) + + local listview = gui.new_list_view { + items = data, + width = width + 4, + loc = "top_center", + relative = "cursor", + rawdata = true, + data = data, + on_confirm = function(item) + trace(item) + local action_chosen = nil + for key, value in pairs(action_tuples) do + if value.display_title == item then + action_chosen = value + end + end + if action_chosen == nil then + log("no match for ", item, action_tuples) + return + end + require('navigator.lspwrapper').on_user_choice(action_chosen, ctx) + + end, + on_move = function(pos) + trace(pos) + return pos + end + } + + log("new buffer", listview.bufnr) + vim.api.nvim_buf_add_highlight(listview.bufnr, -1, 'Title', 0, 0, -1) + +end + local diagnostic = vim.diagnostic or vim.lsp.diagnostic code_action.code_action_handler = util.mk_handler(function(err, actions, ctx, cfg) if actions == nil or vim.tbl_isempty(actions) or err then @@ -87,7 +205,7 @@ local function _update_virtual_text(line, actions) pcall(api.nvim_buf_clear_namespace, 0, namespace, 0, -1) if line then - log(line, actions) + trace(line, actions) local icon_with_indent = " " .. config.icons.code_action_icon local title = actions[1].title @@ -135,7 +253,7 @@ function code_action:render_action_virtual_text(line, diagnostics) _update_sign(nil) end else - log(err, line, diagnostics, actions, context) + trace(err, line, diagnostics, actions, context) if config.code_action_prompt.sign then if need_check_diagnostic[vim.bo.filetype] then if next(diagnostics) == nil then @@ -165,7 +283,6 @@ function code_action:render_action_virtual_text(line, diagnostics) end local special_buffers = { - ["LspSagaCodecode_action"] = true, ["lspsagafinder"] = true, ["NvimTree"] = true, ["vista"] = true, @@ -191,13 +308,34 @@ local code_action_req = function(_call_back_fn, diagnostics) vim.lsp.buf_request(0, "textDocument/codeAction", params, callback) end --- code_action.code_action = function() --- local diagnostics = vim.lsp.diagnostic.get_line_diagnostics() --- code_action_req(action_call_back, diagnostics) --- end +local function code_action_request(params) + local bufnr = vim.api.nvim_get_current_buf() + local method = 'textDocument/codeAction' + vim.lsp.buf_request_all(bufnr, method, params, function(results) + on_code_action_results(results, {bufnr = bufnr, method = method, params = params}) + end) +end + +code_action.code_action = function() + local diagnostics = vim.lsp.diagnostic.get_line_diagnostics() + local context = {diagnostics = diagnostics} + local params = vim.lsp.util.make_range_params() + params.context = context + -- vim.lsp.buf_request(0, "textDocument/codeAction", params, code_action.code_action_handler) + code_action_request(params) +end + +code_action.range_code_action = function(startpos, endpos) + local context = {} + context.diagnostics = vim.lsp.diagnostic.get_line_diagnostics() + local params = util.make_given_range_params(startpos, endpos) + params.context = context + code_action_request(params) +end code_action.code_action_prompt = function() if special_buffers[vim.bo.filetype] then + log('skip buffer', vim.bo.filetype) return end diff --git a/lua/navigator/codelens.lua b/lua/navigator/codelens.lua index 8da777b..982442e 100644 --- a/lua/navigator/codelens.lua +++ b/lua/navigator/codelens.lua @@ -109,6 +109,7 @@ function M.run_action() local bufnr = api.nvim_get_current_buf() local lenses = codelens.get(bufnr) + log(lenses) if lenses == nil or #lenses == 0 then return end @@ -147,7 +148,7 @@ function M.run_action() local divider = string.rep('─', width + 2) table.insert(data, 2, divider) - if #data > 0 then + if #data > 2 then local lv = gui.new_list_view { items = data, width = width + 4, @@ -166,6 +167,9 @@ function M.run_action() } vim.api.nvim_buf_add_highlight(lv.bufnr, -1, 'Title', 0, 0, -1) + else + print('no codelense in current line') + end end diff --git a/lua/navigator/diagnostics.lua b/lua/navigator/diagnostics.lua index 24044ac..ed27a08 100644 --- a/lua/navigator/diagnostics.lua +++ b/lua/navigator/diagnostics.lua @@ -6,6 +6,7 @@ _NG_VT_DIAG_NS = vim.api.nvim_create_namespace("navigator_lua_diag") local util = require "navigator.util" local log = util.log local trace = require"guihua.log".trace +-- trace = log local error = util.error local path_sep = require"navigator.util".path_sep() local mk_handler = require"navigator.util".mk_handler diff --git a/lua/navigator/formatting.lua b/lua/navigator/formatting.lua index ade2af2..b9b354a 100644 --- a/lua/navigator/formatting.lua +++ b/lua/navigator/formatting.lua @@ -9,17 +9,23 @@ return { -- If the buffer hasn't been modified before the formatting has finished, -- update the buffer - if not vim.api.nvim_buf_get_option(ctx.bufnr, 'modified') then - local view = vim.fn.winsaveview() - vim.lsp.util.apply_text_edits(result, ctx.bufnr) - vim.fn.winrestview(view) - -- FIXME: commented out as a workaround - -- if bufnr == vim.api.nvim_get_current_buf() then - vim.api.nvim_command('noautocmd :update') + -- if not vim.api.nvim_buf_get_option(ctx.bufnr, 'modified') then + vim.defer_fn(function() - -- Trigger post-formatting autocommand which can be used to refresh gitgutter - -- vim.api.nvim_command('silent doautocmd User FormatterPost') - -- end - end + if ctx.bufnr == vim.api.nvim_get_current_buf() + or not vim.api.nvim_buf_get_option(ctx.bufnr, 'modified') then + + local view = vim.fn.winsaveview() + vim.lsp.util.apply_text_edits(result, ctx.bufnr) + vim.fn.winrestview(view) + -- FIXME: commented out as a workaround + -- if bufnr == vim.api.nvim_get_current_buf() then + vim.api.nvim_command('noautocmd :update') + + -- Trigger post-formatting autocommand which can be used to refresh gitgutter + vim.api.nvim_command('silent doautocmd User FormatterPost') + -- end + end + end, 20) end) } diff --git a/lua/navigator/hierarchy.lua b/lua/navigator/hierarchy.lua index 26ebdd9..fd31a8c 100644 --- a/lua/navigator/hierarchy.lua +++ b/lua/navigator/hierarchy.lua @@ -1,6 +1,7 @@ local gui = require "navigator.gui" local util = require "navigator.util" local log = util.log +local trace = util.trace local partial = util.partial local lsphelper = require "navigator.lspwrapper" @@ -10,7 +11,7 @@ local cwd = vim.loop.cwd() local M = {} local function call_hierarchy_handler(direction, err, result, ctx, cfg, error_message) - log('call_hierarchy') + trace('call_hierarchy', result) assert(#vim.lsp.buf_get_clients() > 0, "Must have a client running to use lsp_tags") if err ~= nil then log("dir", direction, "result", result, "err", err, ctx) @@ -29,11 +30,13 @@ local function call_hierarchy_handler(direction, err, result, ctx, cfg, error_me for _, range in pairs(call_hierarchy_call.fromRanges) do local filename = assert(vim.uri_to_fname(call_hierarchy_item.uri)) local display_filename = filename:gsub(cwd .. path_sep, path_cur, 1) + call_hierarchy_item.detail = call_hierarchy_item.detail:gsub("\n", " ↳ ") + table.insert(items, { uri = call_hierarchy_item.uri, filename = filename, - display_filename = call_hierarchy_item.detail or display_filename, - text = kind .. call_hierarchy_item.name, + display_filename = display_filename, + text = kind .. call_hierarchy_item.name .. ' ﰲ ' .. call_hierarchy_item.detail, range = range, lnum = range.start.line, col = range.start.character @@ -47,7 +50,7 @@ local call_hierarchy_handler_from = partial(call_hierarchy_handler, "from") local call_hierarchy_handler_to = partial(call_hierarchy_handler, "to") local function incoming_calls_handler(bang, err, result, ctx, cfg) - assert(#vim.lsp.buf_get_clients() > 0, "Must have a client running to use lsp_tags") + assert(#vim.lsp.buf_get_clients() > 0, "Must have a client running to use lsp hierarchy") local results = call_hierarchy_handler_from(err, result, ctx, cfg, "Incoming calls not found") local ft = vim.api.nvim_buf_get_option(ctx.bufnr, "ft") @@ -63,7 +66,7 @@ local function outgoing_calls_handler(bang, err, result, ctx, cfg) end function M.incoming_calls(bang, opts) - assert(#vim.lsp.buf_get_clients() > 0, "Must have a client running to use lsp_tags") + assert(#vim.lsp.buf_get_clients() > 0, "Must have a client running to use lsp hierarchy") if not lsphelper.check_capabilities("call_hierarchy") then return end diff --git a/lua/navigator/lazyloader.lua b/lua/navigator/lazyloader.lua index fe7fd34..b6b136b 100644 --- a/lua/navigator/lazyloader.lua +++ b/lua/navigator/lazyloader.lua @@ -1,31 +1,48 @@ -local log = require"navigator.util".log -_LoadedClients = {} -local loader = nil -local packer_plugins = packer_plugins or nil -- suppress warnings +return { + init = function() + local loader = nil + local packer_plugins = packer_plugins or nil -- suppress warnings + local log = require'navigator.util'.log + -- packer only + if packer_plugins ~= nil then -- packer install + local lazy_plugins = { + ["nvim-lspconfig"] = "neovim/nvim-lspconfig", + ["guihua.lua"] = "ray-x/guihua.lua", + ["lua-dev.nvim"] = "folke/lua-dev.nvim" + } --- packer only -if packer_plugins ~= nil then -- packer install - local lazy_plugins = { - ["nvim-lspconfig"] = "neovim/nvim-lspconfig", - ["guihua.lua"] = "ray-x/guihua.lua" - } - if _NgConfigValues.lspinstall == true then - lazy_plugins["nvim-lspinstall"] = "kabouzeid/nvim-lspinstall" - end + if _NgConfigValues.lspinstall == true then + lazy_plugins["nvim-lspinstall"] = "kabouzeid/nvim-lspinstall" + end + + -- packer installed + loader = require"packer".loader + for plugin, url in pairs(lazy_plugins) do + if not packer_plugins[url] or not packer_plugins[url].loaded then + -- log("loading ", plugin) + loader(plugin) + end + end - -- packer installed - loader = require"packer".loader - for plugin, url in pairs(lazy_plugins) do - if not packer_plugins[url] or not packer_plugins[url].loaded then - log("loading ", plugin) - loader(plugin) end - end - if _NgConfigValues.lspinstall == true then - local has_lspinst, lspinst = pcall(require, "lspinstall") - if has_lspinst then - lspinst.setup() + if _NgConfigValues.lspinstall == true then + local has_lspinst, lspinst = pcall(require, "lspinstall") + log('lspinstall', has_lspinst) + if has_lspinst then + lspinst.setup() + local configs = require "lspconfig/configs" + local servers = require'lspinstall'.installed_servers() + for _, server in pairs(servers) do + local cfg = require'navigator.lspclient.clients'.get_cfg(server) + local lsp_inst_cfg = configs[server] + if lsp_inst_cfg and lsp_inst_cfg.document_config.default_config then + lsp_inst_cfg = lsp_inst_cfg.document_config.default_config + lsp_inst_cfg = vim.tbl_deep_extend('keep', lsp_inst_cfg, cfg) + require'lspconfig'[server].setup(lsp_inst_cfg) + end + end + end end end -end +} diff --git a/lua/navigator/lspclient/clients.lua b/lua/navigator/lspclient/clients.lua index 5870dcd..7a407ce 100644 --- a/lua/navigator/lspclient/clients.lua +++ b/lua/navigator/lspclient/clients.lua @@ -2,9 +2,9 @@ local log = require"navigator.util".log local trace = require"navigator.util".trace local uv = vim.loop -_NG_Loading = false +_NG_Loaded = {} -_LoadedClients = {} +_LoadedFiletypes = {} local loader = nil packer_plugins = packer_plugins or nil -- suppress warnings @@ -31,6 +31,24 @@ local on_attach = require("navigator.lspclient.attach").on_attach -- lua setup local library = {} +local luadevcfg = { + library = { + vimruntime = true, -- runtime path + types = true, -- full signature, docs and completion of vim.api, vim.treesitter, vim.lsp and others + plugins = {"nvim-treesitter", "plenary.nvim"} + }, + lspconfig = { + -- cmd = {sumneko_binary}, + on_attach = on_attach + } +} + +local luadev = {} +local ok, l = pcall(require, "lua-dev") +if ok and l then + luadev = l.setup(luadevcfg) +end + local path = vim.split(package.path, ";") table.insert(path, "lua/?.lua") @@ -239,12 +257,14 @@ local setups = { } } +setups.sumneko_lua = vim.tbl_deep_extend('force', luadev, setups.sumneko_lua) + local servers = { "angularls", "gopls", "tsserver", "flow", "bashls", "dockerls", "julials", "pylsp", "pyright", "jedi_language_server", "jdtls", "sumneko_lua", "vimls", "html", "jsonls", "solargraph", "cssls", "yamlls", "clangd", "ccls", "sqls", "denols", "graphql", "dartls", "dotls", "kotlin_language_server", "nimls", "intelephense", "vuels", "phpactor", "omnisharp", - "r_language_server", "rust_analyzer", "terraformls" + "r_language_server", "rust_analyzer", "terraformls", "svelteserver" } if config.lspinstall == true then @@ -262,13 +282,19 @@ if config.lsp.disable_lsp == 'all' then config.lsp.disable_lsp = servers end -local default_cfg = { +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) + -- if _NG_LSPCfgSetup ~= true then + -- log(lspconfig_setup) + -- lspconfig_setup(cfg) + -- _NG_LSPCfgSetup = true + -- end + log(ft, client, loaded) if lspconfig[client] == nil then log("not supported by nvim", client) return @@ -307,16 +333,21 @@ local function load_cfg(ft, client, cfg, loaded) return end - log("load cfg", cfg) - lspconfig[client].setup(cfg) - -- dont know why but 1st lsp client setup may fail.. could be a upstream defect + trace("load cfg", cfg) + log('lspconfig setup') + -- log(lspconfig.available_servers()) + -- force reload with config lspconfig[client].setup(cfg) + vim.defer_fn(function() + + vim.cmd([[doautocmd FileType ]] .. ft) + end, 100) log(client, "loading for", ft) end -- need to verify the lsp server is up end -local function wait_lsp_startup(ft, retry, user_lsp_opts) +local function lsp_startup(ft, retry, user_lsp_opts) retry = retry or false local clients = vim.lsp.get_active_clients() or {} @@ -340,12 +371,18 @@ local function wait_lsp_startup(ft, retry, user_lsp_opts) end end for _, lspclient in ipairs(servers) do + -- check should load lsp if user_lsp_opts[lspclient] ~= nil and user_lsp_opts[lspclient].filetypes ~= nil then if not vim.tbl_contains(user_lsp_opts[lspclient].filetypes, ft) then trace("ft", ft, "disabled for", lspclient) goto continue end end + + if _NG_Loaded[lspclient] then + log('client loaded', lspclient) + end + if vim.tbl_contains(config.lsp.disable_lsp or {}, lspclient) then log("disable lsp", lspclient) goto continue @@ -356,6 +393,7 @@ local function wait_lsp_startup(ft, retry, user_lsp_opts) print("lspclient", lspclient, "no longer support by lspconfig, please submit an issue") goto continue end + if lspconfig[lspclient].document_config and lspconfig[lspclient].document_config.default_config then default_config = lspconfig[lspclient].document_config.default_config else @@ -363,9 +401,10 @@ local function wait_lsp_startup(ft, retry, user_lsp_opts) goto continue end - default_config = vim.tbl_deep_extend("force", default_config, default_cfg) + default_config = vim.tbl_deep_extend("force", default_config, ng_default_cfg) local cfg = setups[lspclient] or {} cfg = vim.tbl_deep_extend("keep", cfg, default_config) + -- filetype disabled if not vim.tbl_contains(cfg.filetypes or {}, ft) then trace("ft", ft, "disabled for", lspclient) goto continue @@ -424,39 +463,43 @@ local function wait_lsp_startup(ft, retry, user_lsp_opts) end end + log('loading', lspclient, 'name', lspconfig[lspclient].name) + -- start up lsp load_cfg(ft, lspclient, cfg, loaded) + + _NG_Loaded[lspclient] = true -- load_cfg(ft, lspclient, {}, loaded) ::continue:: end - local efm_cfg = user_lsp_opts['efm'] - if efm_cfg then - lspconfig.efm.setup(efm_cfg) + if not _NG_Loaded['efm'] then + local efm_cfg = user_lsp_opts['efm'] + if efm_cfg then + lspconfig.efm.setup(efm_cfg) + log('efm loading') + _NG_Loaded['efm'] = true + end end if not retry or ft == nil then return end - -- - local timer = vim.loop.new_timer() - local i = 0 - timer:start(1000, 200, function() - clients = vim.lsp.get_active_clients() or {} - i = i + 1 - if i > 5 or #clients > 0 then - timer:close() -- Always close handles to avoid leaks. - log("active", #clients, i) - _NG_Loading = false - return true - end - -- giveup - -- _NG_Loading = false - end) +end + +local function get_cfg(client) + local ng_cfg = ng_default_cfg + if setups[client] ~= nil then + local ng_setup = vim.deepcopy(setups[client]) + ng_setup.cmd = nil + return ng_setup + else + return ng_cfg + end end local function setup(user_opts) local ft = vim.bo.filetype - if _LoadedClients[ft] then - -- log("navigator is loaded for ft", ft) + if _LoadedFiletypes[ft] then + log("navigator was loaded for ft", ft) return end if user_opts ~= nil then @@ -465,15 +508,16 @@ local function setup(user_opts) trace(debug.traceback()) user_opts = user_opts or config -- incase setup was triggered from autocmd - if _NG_Loading == true then - return - end if ft == nil then ft = vim.api.nvim_buf_get_option(0, "filetype") end if ft == nil or ft == "" then - log("nil filetype") + vim.defer_fn(function() + setup(user_opts) + end, 500) + + log("nil filetype, callback") return end local retry = true @@ -482,7 +526,7 @@ local function setup(user_opts) "csv", "txt", "markdown", "defx" } for i = 1, #disable_ft do - if ft == disable_ft[i] or _LoadedClients[ft] then + if ft == disable_ft[i] or _LoadedFiletypes[ft] then trace("navigator disabled for ft or it is loaded", ft) return end @@ -502,8 +546,6 @@ local function setup(user_opts) highlight.add_highlight() local lsp_opts = user_opts.lsp - _NG_Loading = true - if vim.bo.filetype == 'lua' then local slua = lsp_opts.sumneko_lua if slua and not slua.cmd then @@ -517,17 +559,15 @@ local function setup(user_opts) end end - wait_lsp_startup(ft, retry, lsp_opts) + lsp_startup(ft, retry, lsp_opts) --- if code line enabled if _NgConfigValues.lsp.code_lens then require("navigator.codelens").setup() end - _LoadedClients[ft] = true - -- _LoadedClients[ft] = vim.tbl_extend("keep", _LoadedClients[ft] or {}, {ft}) - - _NG_Loading = false + _LoadedFiletypes[ft] = true + -- _LoadedFiletypes[ft] = vim.tbl_extend("keep", _LoadedFiletypes[ft] or {}, {ft}) end -return {setup = setup} +return {setup = setup, get_cfg = get_cfg} diff --git a/lua/navigator/lspclient/mapping.lua b/lua/navigator/lspclient/mapping.lua index 79fd209..9f3ffa8 100644 --- a/lua/navigator/lspclient/mapping.lua +++ b/lua/navigator/lspclient/mapping.lua @@ -23,7 +23,7 @@ local key_maps = { {key = "gT", func = "require('navigator.treesitter').buf_ts()"}, {key = "gT", func = "require('navigator.treesitter').bufs_ts()"}, {key = "K", func = "hover({ popup_opts = { border = single, max_width = 80 }})"}, - {key = "ca", mode = "n", func = "code_action()"}, + {key = "ca", mode = "n", func = "require('navigator.codeAction').code_action()"}, {key = "cA", mode = "v", func = "range_code_action()"}, {key = "re", func = "rename()"}, {key = "rn", func = "require('navigator.rename').rename()"}, diff --git a/lua/navigator/lspwrapper.lua b/lua/navigator/lspwrapper.lua index 32d70ea..96dc10b 100644 --- a/lua/navigator/lspwrapper.lua +++ b/lua/navigator/lspwrapper.lua @@ -434,6 +434,58 @@ function M.apply_action(action_chosen) end +local function apply_action(action, client, ctx) + log(action, client) + if action.edit then + require('vim.lsp.util').apply_workspace_edit(action.edit) + end + if action.command then + local command = type(action.command) == 'table' and action.command or action + local fn = vim.lsp.commands[command.command] + if fn then + local enriched_ctx = vim.deepcopy(ctx) + enriched_ctx.client_id = client.id + fn(command, ctx) + else + require('vim.lsp.buf').execute_command(command) + end + end +end + +function M.on_user_choice(action_tuple, ctx) + if not action_tuple then + return + end + log(action_tuple) + -- textDocument/codeAction can return either Command[] or CodeAction[] + -- + -- CodeAction + -- ... + -- edit?: WorkspaceEdit -- <- must be applied before command + -- command?: Command + -- + -- Command: + -- title: string + -- command: string + -- arguments?: any[] + -- + local client = vim.lsp.get_client_by_id(action_tuple[1]) + local action = action_tuple[2] + if not action.edit and client and type(client.resolved_capabilities.code_action) == 'table' + and client.resolved_capabilities.code_action.resolveProvider then + + client.request('codeAction/resolve', action, function(err, resolved_action) + if err then + vim.notify(err.code .. ': ' .. err.message, vim.log.levels.ERROR) + return + end + apply_action(resolved_action, client, ctx) + end) + else + apply_action(action, client, ctx) + end +end + function M.symbol_to_items(locations) if not locations or vim.tbl_isempty(locations) then print("list not avalible") diff --git a/lua/navigator/protocal.txt b/lua/navigator/protocal.txt index e952e94..df19ff4 100644 --- a/lua/navigator/protocal.txt +++ b/lua/navigator/protocal.txt @@ -1136,7 +1136,7 @@ definition.lua:9: { { cargoArgs = { "run", "--package", "hello", "--bin", "hello" }, cargoExtraArgs = {}, executableArgs = {}, - workspaceRoot = "/Users/ray.xu/lsp_test/rust" + workspaceRoot = "/Users/glsp_test/rust" }, kind = "cargo", label = "run hello", @@ -1161,7 +1161,7 @@ definition.lua:9: { { line = 45 } }, - targetUri = "file:///Users/ray.xu/lsp_test/rust/src/main.rs" + targetUri = "file:///Users/glsp_test/rust/src/main.rs" } } }, command = "rust-analyzer.runSingle", @@ -1184,7 +1184,7 @@ definition.lua:9: { { cargoArgs = { "run", "--package", "hello", "--bin", "hello" }, cargoExtraArgs = {}, executableArgs = {}, - workspaceRoot = "/Users/ray.xu/lsp_test/rust" + workspaceRoot = "/Users/glsp_test/rust" }, kind = "cargo", label = "run hello", @@ -1209,7 +1209,7 @@ definition.lua:9: { { line = 45 } }, - targetUri = "file:///Users/ray.xu/lsp_test/rust/src/main.rs" + targetUri = "file:///Users/glsp_test/rust/src/main.rs" } } }, command = "rust-analyzer.debugSingle", @@ -1233,7 +1233,7 @@ definition.lua:9: { { line = 2 }, textDocument = { - uri = "file:///Users/ray.xu/lsp_test/rust/src/main.rs" + uri = "file:///Users/glsp_test/rust/src/main.rs" } } }, @@ -1255,7 +1255,7 @@ definition.lua:9: { { line = 28 }, textDocument = { - uri = "file:///Users/ray.xu/lsp_test/rust/src/main.rs" + uri = "file:///Users/glsp_test/rust/src/main.rs" } } }, @@ -1277,7 +1277,7 @@ definition.lua:9: { { line = 31 }, textDocument = { - uri = "file:///Users/ray.xu/lsp_test/rust/src/main.rs" + uri = "file:///Users/glsp_test/rust/src/main.rs" } } }, @@ -1293,3 +1293,178 @@ definition.lua:9: { { } } } } } + + + + +type_definition = true, + workspace_folder_properties = { + changeNotifications = false, + supported = false + }, + workspace_symbol = true +} + + + +...ack/packer/opt/navigator.lua/lua/navigator/hierarchy.lua:13: call_hierarchy { { + fromRanges = { { + end = { + character = 68, + line = 53 + }, + start = { + character = 54, + line = 53 + } + } }, + to = { + detail = "pub fn unwrap_or_else(self, f: F) -> T\nwhere\n F: FnOnce<(), Output = T>,", + kind = 12, + name = "unwrap_or_else", + range = { + end = { + character = 5, + line = 764 + }, + start = { + character = 4, + line = 748 + } + }, + selectionRange = { + end = { + character = 25, + line = 759 + }, + start = { + character = 11, + line = 759 + } + }, + uri = "file:///Users/g.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs" + } + }, { + fromRanges = { { + end = { + character = 33, + line = 54 + }, + start = { + character = 27, + line = 54 + } + }, { + end = { + character = 28, + line = 55 + }, + start = { + character = 22, + line = 55 + } + } }, + to = { + detail = "pub const fn unwrap(self) -> T", + kind = 12, + name = "unwrap", + range = { + end = { + character = 5, + line = 723 + }, + start = { + character = 4, + line = 688 + } + }, + selectionRange = { + end = { + character = 23, + line = 718 + }, + start = { + character = 17, + line = 718 + } + }, + uri = "file:///Users/g.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/option.rs" + } + } } + + + call_hierarchy { { + from = { + detail = "fn test2()", + kind = 12, + name = "test2", + range = { + end = { + character = 20, + line = 43 + }, + start = { + character = 0, + line = 43 + } + }, + selectionRange = { + end = { + character = 8, + line = 43 + }, + start = { + character = 3, + line = 43 + } + }, + uri = "file:///Users/glsp_test/rust/src/main.rs" + }, + fromRanges = { { + end = { + character = 16, + line = 43 + }, + start = { + character = 12, + line = 43 + } + } } + }, { + from = { + detail = "fn test3()", + kind = 12, + name = "test3", + range = { + end = { + character = 29, + line = 44 + }, + start = { + character = 0, + line = 44 + } + }, + selectionRange = { + end = { + character = 8, + line = 44 + }, + start = { + character = 3, + line = 44 + } + }, + uri = "file:///Users/glsp_test/rust/src/main.rs" + }, + fromRanges = { { + end = { + character = 16, + line = 44 + }, + start = { + character = 12, + line = 44 + } + } } + } } diff --git a/lua/navigator/symbols.lua b/lua/navigator/symbols.lua index 6a3cf3b..e6cf453 100644 --- a/lua/navigator/symbols.lua +++ b/lua/navigator/symbols.lua @@ -50,7 +50,7 @@ function M.workspace_symbols(opts) local results_lsp = vim.lsp.buf_request_sync(0, "workspace/symbol", params, lspopts.timeout or 15000) if not results_lsp or vim.tbl_isempty(results_lsp) then - print(bufnr, "symbol not found for buf") + print("symbol not found for buf") return end -- result_lsp