From 6a15e6838d0f84989592c5584c4b03f744e243b7 Mon Sep 17 00:00:00 2001 From: ray-x Date: Sat, 29 May 2021 21:08:30 +1000 Subject: [PATCH] add multiple symbol highlight --- README.md | 5 + lua/navigator/dochighlight.lua | 145 ++++++++++++++++++++++++-- lua/navigator/gui.lua | 29 +++++- lua/navigator/lspclient/clients.lua | 21 +++- lua/navigator/lspclient/highlight.lua | 29 +++++- lua/navigator/lspclient/mapping.lua | 13 ++- lua/navigator/render.lua | 4 +- lua/navigator/symbols.lua | 16 ++- 8 files changed, 240 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 253bd87..deb88aa 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,8 @@ implementation. - FZY search with Lua-JIT +- LSP multiple symbol highlight and jump between reference + - Better navigation for diagnostic errors, Navigate through all files/buffers that contain errors/warnings - Grouping references/implementation/incoming/outgoing based on file names. @@ -258,6 +260,9 @@ Pls check the first part of README ![workspace symbol](https://github.com/ray-x/files/blob/master/img/navigator/workspace_symbol.gif?raw=true) +### highlight document symbol and jump between reference +![multiple_symbol_hi3](https://user-images.githubusercontent.com/1681295/120067627-f9f80680-c0bf-11eb-9216-18e5c8547f59.gif) + # Current symbol highlight and jump backward/forward between symbols Document highlight provided by LSP. diff --git a/lua/navigator/dochighlight.lua b/lua/navigator/dochighlight.lua index f9f8e5b..a272e98 100644 --- a/lua/navigator/dochighlight.lua +++ b/lua/navigator/dochighlight.lua @@ -1,7 +1,127 @@ local util = require "navigator.util" local log = util.log +local trace = util.trace local api = vim.api local references = {} +_NG_hi_list = {} +_NG_current_symbol = "" +_NG_ref_hi_idx = 1 + +-- extract symbol from cursor +local function get_symbol() + local currentWord = vim.fn.expand('') + return currentWord +end + +local function add_locs(bufnr, result) + local symbol = get_symbol() + if #result < 1 then + return + end + symbol = string.format("%s_%i_%i_%i", symbol, bufnr, result[1].range.start.line, + result[1].range.start.character) + if _NG_hi_list[symbol] == nil then + _NG_hi_list[symbol] = {range = {}} + end + if _NG_hi_list[symbol] ~= nil then + log("already added", symbol) + _NG_hi_list[symbol].range = {} + -- vim.fn.matchdelete(hid) + end + trace("add ", symbol) + _NG_hi_list[symbol].range = result + _NG_current_symbol = symbol +end + +local function nohl() + for key, value in pairs(_NG_hi_list) do + if value.hi_ids ~= nil then + for _, v in ipairs(value.hi_ids) do + log("delete", v) + vim.fn.matchdelete(v) + end + _NG_hi_list[key].hi_ids = nil + end + end +end + +local function hi_symbol() + local symbol_wd = get_symbol() + local symbol = _NG_current_symbol + if string.find(symbol, symbol_wd) == nil then + vim.lsp.buf.document_highlight() + symbol = _NG_current_symbol + end + if symbol == nil or symbol == "" then + log("nil symbol") + return + end + + _NG_ref_hi_idx = _NG_ref_hi_idx + 1 + if _NG_ref_hi_idx > 6 then -- 6 magic number for colors + _NG_ref_hi_idx = 1 + end + + local range = _NG_hi_list[symbol].range or {} + if _NG_hi_list[symbol].hi_ids ~= nil then + for _, value in ipairs(_NG_hi_list[symbol].hi_ids) do + log("delete", value) + vim.fn.matchdelete(value) + end + _NG_hi_list[symbol].hi_ids = nil + return + end + local cur_pos = vim.fn.getpos('.') + _NG_hi_list[symbol].hi_ids = {} + local totalref = #range + local cmd = string.format("%s/\\<%s\\>//gn", "%s", symbol_wd) + local total_match = 0 + local match_result = vim.api.nvim_exec(cmd, true) + local p = match_result:find(" match") + vim.cmd("nohl") + vim.fn.setpos('.', cur_pos) + if p ~= nil then + p = match_result:sub(1, p) + total_match = tonumber(p) + end + if total_match == totalref then -- same number as matchpos + log(total_match, "use matchadd()") + local k = range[1].kind + local hi_name = string.format("NGHiReference_%i_%i", _NG_ref_hi_idx, k) + local m = string.format("\\<%s\\>", symbol_wd) + local r = vim.fn.matchadd(hi_name, m, 20) + trace("hi id", m, hi_name, r) + table.insert(_NG_hi_list[symbol].hi_ids, r) + -- + -- vim.fn.matchdelete(r) + else + for _, value in ipairs(range) do + local k = value.kind + local l = value.range.start.line + 1 + local el = value.range['end'].line + 1 + + local cs = value.range.start.character + 1 + local ecs = value.range['end'].character + 1 + if el ~= l and cs == 1 and ecs > 1 then + l = el + end + local w = value.range['end'].character - value.range.start.character + local hi_name = string.format("NGHiReference_%i_%i", _NG_ref_hi_idx, k) + log(hi_name, {l, cs, w}) + local m = vim.fn.matchaddpos(hi_name, {{l, cs, w}}, 10) + table.insert(_NG_hi_list[symbol].hi_ids, m) + end + end + + -- clean the _NG_hi_list + for key, value in pairs(_NG_hi_list) do + if value.hi_ids == nil then + _NG_hi_list[key] = nil + end + end + + -- log(_NG_hi_list) +end -- returns r1 < r2 based on start of range local function before(r1, r2) @@ -71,10 +191,14 @@ local function goto_adjent_reference(opt) vim.api.nvim_win_set_cursor(0, {next.start.line + 1, next.start.character}) return next end --- autocmd ColorScheme * --- \ hi default LspReferenceRead cterm=bold gui=Bold ctermbg=yellow guifg=yellow guibg=purple4 | --- \ hi default LspReferenceText cterm=bold gui=Bold ctermbg=red guifg=SlateBlue guibg=MidnightBlue | --- \ hi default LspReferenceWrite cterm=bold gui=Bold,Italic ctermbg=red guifg=DarkSlateBlue guibg=MistyRose + +local function cmd_nohl() + local cl = vim.trim(vim.fn.getcmdline()) + if #cl > 3 and ('nohlsearch'):match(cl) then + vim.schedule(nohl) + end +end + local function documentHighlight() api.nvim_exec([[ autocmd ColorScheme * | @@ -89,10 +213,15 @@ local function documentHighlight() augroup END ]], false) vim.lsp.handlers["textDocument/documentHighlight"] = - function(_, _, result, _, bufnr) + function(err, _, result, _, bufnr) + if err then + print(err) + return + end if not result then return end + trace("dochl", result) bufnr = api.nvim_get_current_buf() vim.lsp.util.buf_clear_references(bufnr) vim.lsp.util.buf_highlight_references(bufnr, result) @@ -105,11 +234,15 @@ local function documentHighlight() return before(a.range, b.range) end) references[bufnr] = result + add_locs(bufnr, result) end end return { documentHighlight = documentHighlight, goto_adjent_reference = goto_adjent_reference, - handle_document_highlight = handle_document_highlight + handle_document_highlight = handle_document_highlight, + hi_symbol = hi_symbol, + nohl = nohl, + cmd_nohl = cmd_nohl } diff --git a/lua/navigator/gui.lua b/lua/navigator/gui.lua index 9bccbe7..70a5fcc 100644 --- a/lua/navigator/gui.lua +++ b/lua/navigator/gui.lua @@ -151,6 +151,28 @@ function M.new_list_view(opts) offset_y = offset_y + 1 -- need to check this out end + 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, @@ -166,7 +188,8 @@ function M.new_list_view(opts) if pos == 0 then pos = 1 end - local l = data[pos] + local l = idx(data, pos) -- bug it not work with fzy filter + log(data) if l.filename ~= nil then trace("openfile ", l.filename, l.lnum, l.col) util.open_file_at(l.filename, l.lnum, l.col) @@ -176,7 +199,9 @@ function M.new_list_view(opts) if pos == 0 then pos = 1 end - local l = data[pos] + + local l = idx(data, pos) -- bug it not work with fzy filter + log(data) trace("on move", pos, l) trace("on move", pos, l.text or l, l.uri, l.filename) -- todo fix diff --git a/lua/navigator/lspclient/clients.lua b/lua/navigator/lspclient/clients.lua index ea42463..3c9e3ad 100644 --- a/lua/navigator/lspclient/clients.lua +++ b/lua/navigator/lspclient/clients.lua @@ -1,7 +1,7 @@ -- todo allow config passed in local log = require"navigator.util".log local trace = require"navigator.util".trace - +local uv = vim.loop _Loading = false _LoadedClients = {} @@ -68,6 +68,23 @@ library[vim.fn.expand("$VIMRUNTIME/lua/vim")] = true library[vim.fn.expand("$VIMRUNTIME/lua/vim/lsp")] = true -- [vim.fn.expand("~/repos/nvim/lua")] = true +-- TODO remove onece PR #944 merged to lspconfig +local is_windows = uv.os_uname().version:match("Windows") +local path_sep = is_windows and "\\" or "/" +local strip_dir_pat = path_sep .. "([^" .. path_sep .. "]+)$" +local strip_sep_pat = path_sep .. "$" +local dirname = function(path) + if not path or #path == 0 then + return + end + local result = path:gsub(strip_sep_pat, ""):gsub(strip_dir_pat, "") + if #result == 0 then + return "/" + end + return result +end +-- TODO end + local setups = { gopls = { on_attach = on_attach, @@ -101,7 +118,7 @@ local setups = { } }, root_dir = function(fname) - return util.root_pattern("go.mod", ".git")(fname) or util.path.dirname(fname) + return util.root_pattern("go.mod", ".git")(fname) or dirname(fname) -- util.path.dirname(fname) end }, clangd = { diff --git a/lua/navigator/lspclient/highlight.lua b/lua/navigator/lspclient/highlight.lua index ad96553..b3add54 100644 --- a/lua/navigator/lspclient/highlight.lua +++ b/lua/navigator/lspclient/highlight.lua @@ -3,10 +3,18 @@ local api = vim.api -- lsp sign          ﮻         ﯭ        ﳀ   function M.diagnositc_config_sign() - vim.fn.sign_define('LspDiagnosticsSignError', {text='', texthl='LspDiagnosticsSignError',linehl='', numhl=''}) - vim.fn.sign_define('LspDiagnosticsSignWarning', {text='', texthl='LspDiagnosticsSignWarning', linehl='', numhl=''}) - vim.fn.sign_define('LspDiagnosticsSignInformation', {text='', texthl='LspDiagnosticsSignInformation', linehl='', numhl=''}) - vim.fn.sign_define('LspDiagnosticsSignHint', {text='💡', texthl='LspDiagnosticsSignHint', linehl='', numhl=''}) + vim.fn.sign_define('LspDiagnosticsSignError', + {text = '', texthl = 'LspDiagnosticsSignError', linehl = '', numhl = ''}) + vim.fn.sign_define('LspDiagnosticsSignWarning', + {text = '', texthl = 'LspDiagnosticsSignWarning', linehl = '', numhl = ''}) + vim.fn.sign_define('LspDiagnosticsSignInformation', { + text = '', + texthl = 'LspDiagnosticsSignInformation', + linehl = '', + numhl = '' + }) + vim.fn.sign_define('LspDiagnosticsSignHint', + {text = '💡', texthl = 'LspDiagnosticsSignHint', linehl = '', numhl = ''}) end function M.add_highlight() @@ -18,6 +26,19 @@ function M.add_highlight() api.nvim_command("hi! link LspDiagnosticsUnderlineHint SpellRare") api.nvim_command("hi def link DefinitionPreviewTitle Title") + local colors = { + {'#aefe00', '#aede00', '#aebe00', '#4e7efe'}, {'#ff00e0', '#df00e0', '#af00e0', '#fedefe'}, + {'#1000ef', '#2000df', '#2000cf', '#f0f040'}, {'#d8a8a3', '#c8a8a3', '#b8a8a3', '#4e2c33'}, + {'#ffa724', '#efa024', '#dfa724', '#0040ff'}, {'#afdc2b', '#09dc4b', '#08d04b', '#ef4f8f'} + } + + for i = 1, #colors do + for j = 1, 3 do + local cmd = string.format("hi! default NGHiReference_%i_%i guibg=%s guifg=%s ", i, j, + colors[i][j], colors[i][4]) + vim.cmd(cmd) + end + end end return M diff --git a/lua/navigator/lspclient/mapping.lua b/lua/navigator/lspclient/mapping.lua index 5991b89..dd18771 100644 --- a/lua/navigator/lspclient/mapping.lua +++ b/lua/navigator/lspclient/mapping.lua @@ -27,7 +27,8 @@ local key_maps = { {key = "]d", func = "diagnostic.goto_next()"}, {key = "[d", func = "diagnostic.goto_prev()"}, {key = "]r", func = "require('navigator.treesitter').goto_next_usage()"}, {key = "[r", func = "require('navigator.treesitter').goto_previous_usage()"}, - {key = "", func = "definition()"}, {key = "g", func = "implementation()"} + {key = "", func = "definition()"}, {key = "g", func = "implementation()"}, + {key = "k", func = "require('navigator.dochighlight').hi_symbol()"} } local function set_mapping(user_opts) @@ -99,6 +100,15 @@ local function set_mapping(user_opts) end end +local function autocmd(user_opts) + vim.api.nvim_exec([[ + aug NavigatorAu + au! + au CmdlineLeave : lua require('navigator.dochighlight').cmd_nohl() + aug END + ]], false) +end + local function set_event_handler(user_opts) user_opts = user_opts or {} local file_types = @@ -129,6 +139,7 @@ function M.setup(user_opts) set_mapping(user_opts) end + autocmd(user_opts) set_event_handler(user_opts) local cap = user_opts.cap or vim.lsp.protocol.make_client_capabilities() diff --git a/lua/navigator/render.lua b/lua/navigator/render.lua index 8154ef3..2b9f2e7 100644 --- a/lua/navigator/render.lua +++ b/lua/navigator/render.lua @@ -122,8 +122,8 @@ function M.prepare_for_render(items, opts) if item.definition then ts_report = ts_report .. '🦕 ' end - local header_len = #ts_report + 2 -- magic number 2 - trace(ts_report) + local header_len = #ts_report + 4 -- magic number 2 + log(ts_report, header_len) item.text = item.text:gsub('%s*[%[%(%{]*%s*$', '') if item.call_by ~= nil and #item.call_by > 0 then diff --git a/lua/navigator/symbols.lua b/lua/navigator/symbols.lua index 03bc7a2..80139f4 100644 --- a/lua/navigator/symbols.lua +++ b/lua/navigator/symbols.lua @@ -75,7 +75,9 @@ function M.workspace_symbols(opts) end function M.document_symbol_handler(err, _, result, _, bufnr) - if err then print(bufnr, "failed to get document symbol") end + if err then + print(bufnr, "failed to get document symbol") + end if not result or vim.tbl_isempty(result) then print(bufnr, "symbol not found for buf") @@ -96,10 +98,12 @@ function M.document_symbol_handler(err, _, result, _, bufnr) item.uri = uri item.selectionRange = result[i].selectionRange item.detail = result[i].detail or "" - if item.detail == "()" then item.detail = "func" end + if item.detail == "()" then + item.detail = "func" + end item.lnum = result[i].range.start.line + 1 - item.text = "[" .. kind .. "]" .. item.detail .. " " .. item.name + item.text = "[" .. kind .. "]" .. item.name .. " " .. item.detail item.filename = fname @@ -116,7 +120,7 @@ function M.document_symbol_handler(err, _, result, _, bufnr) child.uri = uri child.lnum = c.range.start.line + 1 child.detail = c.detail or "" - child.text = "  [" .. ckind .. "] " .. child.detail .. " " .. child.name + child.text = "  [" .. ckind .. "] " .. child.name .. " " .. child.detail table.insert(locations, child) end end @@ -149,7 +153,9 @@ function M.document_symbol_handler(err, _, result, _, bufnr) end function M.workspace_symbol_handler(err, _, result, _, bufnr) - if err then print(bufnr, "failed to get workspace symbol") end + if err then + print(bufnr, "failed to get workspace symbol") + end if not result or vim.tbl_isempty(result) then print(bufnr, "symbol not found for buf") return