From 298c4659dadf2b813dd6990b5e1150d425a5b805 Mon Sep 17 00:00:00 2001 From: ray-x Date: Thu, 24 Jun 2021 00:09:33 +1000 Subject: [PATCH] ccls call hierarchy --- lua/navigator/cclshierarchy.lua | 101 ++++++++++++++++++++++++++++ lua/navigator/diagnostics.lua | 12 ++-- lua/navigator/gui.lua | 23 +------ lua/navigator/hierarchy.lua | 10 +-- lua/navigator/lspclient/attach.lua | 4 +- lua/navigator/lspclient/clients.lua | 4 +- lua/navigator/lspclient/mapping.lua | 27 ++++++-- lua/navigator/util.lua | 4 +- 8 files changed, 146 insertions(+), 39 deletions(-) create mode 100644 lua/navigator/cclshierarchy.lua diff --git a/lua/navigator/cclshierarchy.lua b/lua/navigator/cclshierarchy.lua new file mode 100644 index 0000000..62e3e4f --- /dev/null +++ b/lua/navigator/cclshierarchy.lua @@ -0,0 +1,101 @@ +local gui = require "navigator.gui" +local util = require "navigator.util" +local log = util.log +local partial = util.partial +local lsphelper = require "navigator.lspwrapper" +local cwd = vim.fn.getcwd(0) +local M = {} + +local function call_hierarchy_handler(direction, err, api, result, _, _, error_message) + log('call_hierarchy') + log('call_hierarchy', direction, err, result) + + assert(#vim.lsp.buf_get_clients() > 0, "Must have a client running to use lsp_tags") + if err ~= nil then + log(api, "dir", direction, "result", result, "err", err) + print("ERROR: " .. error_message) + return + end + -- local funcs = vim.lsp.util.locations_to_items(result) + -- log(funcs) + local items = {} + for _, call_hierarchy in pairs(result) do + local kind = ' ' + range = call_hierarchy.range + local filename = assert(vim.uri_to_fname(call_hierarchy.uri)) + local display_filename = filename:gsub(cwd .. "/", "./", 1) + + local bufnr = vim.uri_to_bufnr(call_hierarchy.uri) + local row = range.start.line + local line = (vim.api.nvim_buf_get_lines(bufnr, row, row + 1, false) or {""})[1] + fn = "" + if line ~= nil then + fn = line:sub(range.start.character, range['end'].character + 1) + end + table.insert(items, { + uri = call_hierarchy.uri, + filename = filename, + -- display_filename = filename:gsub(cwd .. "/", "./", 1), + display_filename = display_filename, + text = kind .. fn, + range = range, + lnum = range.start.line + 1, + col = range.start.character + }) + end + return items +end + +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, method, result, client_id, bufnr) + assert(#vim.lsp.buf_get_clients() > 0, "Must have a client running to use lsp_tags") + local results = call_hierarchy_handler_from(err, method, result, client_id, bufnr, + "Incoming calls not found") + + local ft = vim.api.nvim_buf_get_option(bufnr, "ft") + gui.new_list_view({items = results, ft = ft, api = ' '}) +end + +local function outgoing_calls_handler(bang, err, method, result, client_id, bufnr) + local results = call_hierarchy_handler_to(err, method, result, client_id, bufnr, + "Outgoing calls not found") + + local ft = vim.api.nvim_buf_get_option(bufnr, "ft") + gui.new_list_view({items = results, ft = ft, api = ' '}) + -- fzf_locations(bang, "", "Outgoing Calls", results, false) +end + +function M.incoming_calls(bang, opts) + assert(#vim.lsp.buf_get_clients() > 0, "Must have a client running to use lsp_tags") + -- if not lsphelper.check_capabilities("call_hierarchy") then + -- return + -- end + + local params = vim.lsp.util.make_position_params() + -- params['hierarchy'] = true + params['levels'] = 2 + params['callee'] = false + -- params['callee'] = true + log(params) + log(opts) + lsphelper.call_sync("$ccls/call", params, opts, partial(incoming_calls_handler, bang)) +end + +function M.outgoing_calls(bang, opts) + assert(#vim.lsp.buf_get_clients() > 0, "Must have a client running to use lsp_tags") + local params = vim.lsp.util.make_position_params() + params['levels'] = 2 + params['callee'] = true + log(params) + lsphelper.call_sync("$ccls/call", params, opts, partial(outgoing_calls_handler, bang)) +end + +M.incoming_calls_call = partial(M.incoming_calls, 0) +M.outgoing_calls_call = partial(M.outgoing_calls, 0) + +M.incoming_calls_handler = partial(incoming_calls_handler, 0) +M.outgoing_calls_handler = partial(outgoing_calls_handler, 0) + +return M diff --git a/lua/navigator/diagnostics.lua b/lua/navigator/diagnostics.lua index ed5eb88..9fc6808 100644 --- a/lua/navigator/diagnostics.lua +++ b/lua/navigator/diagnostics.lua @@ -42,7 +42,9 @@ local diag_hdlr = function(err, method, result, client_id, br, config) head = _NgConfigValues.icons.diagnostic_head_severity_3 end local bufnr = vim.uri_to_bufnr(uri) - vim.fn.bufload(bufnr) + if not vim.api.nvim_buf_is_loaded(bufnr) then + vim.fn.bufload(bufnr) + end local pos = v.range.start local row = pos.line local line = (vim.api.nvim_buf_get_lines(bufnr, row, row + 1, false) or {""})[1] @@ -64,10 +66,7 @@ M.diagnostic_handler = vim.lsp.with(diag_hdlr, { -- Enable underline, use default values underline = true, -- Enable virtual text, override spacing to 0 - virtual_text = { - spacing = 0, - prefix = _NgConfigValues.icons.diagnostic_virtual_text - }, + virtual_text = {spacing = 0, prefix = _NgConfigValues.icons.diagnostic_virtual_text}, -- Use a function to dynamically turn signs off -- and on, using buffer local variables signs = true, @@ -101,7 +100,8 @@ M.show_diagnostic = function() if #display_items > 0 then gui.new_list_view({ items = display_items, - api = _NgConfigValues.icons.diagnostic_file .. _NgConfigValues.icons.diagnostic_head .. " Diagnostic ", + api = _NgConfigValues.icons.diagnostic_file .. _NgConfigValues.icons.diagnostic_head + .. " Diagnostic ", enable_preview_edit = true }) end diff --git a/lua/navigator/gui.lua b/lua/navigator/gui.lua index db91c30..5377cbc 100644 --- a/lua/navigator/gui.lua +++ b/lua/navigator/gui.lua @@ -153,29 +153,8 @@ function M.new_list_view(opts) if prompt then offset_y = offset_y + 1 -- need to check this out end + local idx = require"guihua.util".fzy_idx - local function idx(data_list, pos) - -- first check if fzy is set - local fzy_on = false - for _, value in ipairs(data_list) do - if value.fzy ~= nil then - fzy_on = true - break - end - end - if fzy_on == true then - local i = 1 - for _, value in ipairs(data_list) do - if value.fzy ~= nil then - if i == pos then - return value - end - i = i + 1 - end - end - end - return data[pos] - end return ListView:new({ loc = loc, prompt = prompt, diff --git a/lua/navigator/hierarchy.lua b/lua/navigator/hierarchy.lua index dcc4a49..09a61a9 100644 --- a/lua/navigator/hierarchy.lua +++ b/lua/navigator/hierarchy.lua @@ -7,8 +7,7 @@ local cwd = vim.fn.getcwd(0) local M = {} local function call_hierarchy_handler(direction, err, _, result, _, _, error_message) - -- log('call_hierarchy') - + log('call_hierarchy') 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) @@ -17,6 +16,7 @@ local function call_hierarchy_handler(direction, err, _, result, _, _, error_mes end local items = {} + for _, call_hierarchy_call in pairs(result) do local call_hierarchy_item = call_hierarchy_call[direction] local kind = ' ' @@ -69,7 +69,8 @@ function M.incoming_calls(bang, opts) end local params = vim.lsp.util.make_position_params() - util.call_sync("callHierarchy/incomingCalls", params, opts, partial(incoming_calls_handler, bang)) + lsphelper.call_sync("callHierarchy/incomingCalls", params, opts, + partial(incoming_calls_handler, bang)) end function M.outgoing_calls(bang, opts) @@ -79,7 +80,8 @@ function M.outgoing_calls(bang, opts) end local params = vim.lsp.util.make_position_params() - util.call_sync("callHierarchy/outgoingCalls", params, opts, partial(outgoing_calls_handler, bang)) + lsphelper.call_sync("callHierarchy/outgoingCalls", params, opts, + partial(outgoing_calls_handler, bang)) end M.incoming_calls_call = partial(M.incoming_calls, 0) diff --git a/lua/navigator/lspclient/attach.lua b/lua/navigator/lspclient/attach.lua index 04f3e85..4ed81ff 100644 --- a/lua/navigator/lspclient/attach.lua +++ b/lua/navigator/lspclient/attach.lua @@ -13,7 +13,7 @@ end local M = {} M.on_attach = function(client, bufnr) - + log("on_attach") local uri = vim.uri_from_bufnr(bufnr) if uri == "file://" or uri == "file:///" or #uri < 11 then log("skip for float buffer", uri) @@ -51,6 +51,8 @@ M.on_attach = function(client, bufnr) config.lsp[client.name].on_attach(client, bufnr) end + require("navigator.lspclient.mapping").setup(_NgConfigValues) + end -- M.setup = function(cfg) diff --git a/lua/navigator/lspclient/clients.lua b/lua/navigator/lspclient/clients.lua index c13bbf7..64a368c 100644 --- a/lua/navigator/lspclient/clients.lua +++ b/lua/navigator/lspclient/clients.lua @@ -210,6 +210,7 @@ local setups = { end }, pyright = { + on_attach = on_attach, cmd = {"pyright-langserver", "--stdio"}, filetypes = {"python"}, flags = {allow_incremental_sync = true, debounce_text_changes = 500}, @@ -224,6 +225,7 @@ local setups = { } }, 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 ]], @@ -326,7 +328,7 @@ local function wait_lsp_startup(ft, retry, lsp_opts) return true end _Loading = false - end, 200) + end, 300) end end diff --git a/lua/navigator/lspclient/mapping.lua b/lua/navigator/lspclient/mapping.lua index c4c89a2..f7ca530 100644 --- a/lua/navigator/lspclient/mapping.lua +++ b/lua/navigator/lspclient/mapping.lua @@ -46,6 +46,11 @@ local key_maps = { {key = "k", func = "require('navigator.dochighlight').hi_symbol()"} } +local ccls_mappings = { + {key = "gi", func = "require('navigator.cclshierarchy').incoming_calls()"}, + {key = "go", func = "require('navigator.cclshierarchy').outgoing_calls()"} +} + local function set_mapping(user_opts) local opts = {noremap = true, silent = true} user_opts = user_opts or {} @@ -57,10 +62,6 @@ local function set_mapping(user_opts) vim.api.nvim_buf_set_keymap(bufnr, ...) end - local function set_keymap(...) - vim.api.nvim_set_keymap(...) - end - -- local function buf_set_option(...) -- vim.api.nvim_buf_set_option(bufnr, ...) -- end @@ -94,6 +95,8 @@ local function set_mapping(user_opts) local range_fmt = false local doc_fmt = false + local ccls = false + log(vim.lsp.buf_get_clients(0)) for _, value in pairs(vim.lsp.buf_get_clients(0)) do if value == nil or value.resolved_capabilities == nil then return @@ -104,8 +107,24 @@ local function set_mapping(user_opts) if value.resolved_capabilities.document_range_formatting then range_fmt = true end + + log("override ccls", value.config) + if value.config.name == "ccls" then + + ccls = true + end end + if ccls then + log("override ccls", ccls_mappings) + for _, value in pairs(ccls_mappings) do + f = "lua " .. value.func .. "" + local k = value.key + local m = value.mode or "n" + log(f, k, m) + set_keymap(m, k, f, opts) + end + end -- if user_opts.cap.document_formatting then if doc_fmt then buf_set_keymap("n", "ff", "lua vim.lsp.buf.formatting()", opts) diff --git a/lua/navigator/util.lua b/lua/navigator/util.lua index e364190..a628baf 100644 --- a/lua/navigator/util.lua +++ b/lua/navigator/util.lua @@ -13,7 +13,9 @@ function M.get_data_from_file(filename, startLine) end local uri = "file:///" .. filename local bufnr = vim.uri_to_bufnr(uri) - vim.fn.bufload(bufnr) + if not vim.api.nvim_buf_is_loaded(bufnr) then + vim.fn.bufload(bufnr) + end local data = vim.api.nvim_buf_get_lines(bufnr, startLine, startLine + 8, false) if data == nil or vim.tbl_isempty(data) then startLine = nil