diff --git a/NEWS.md b/NEWS.md index 34edd6d6..adeab6ea 100644 --- a/NEWS.md +++ b/NEWS.md @@ -32,6 +32,7 @@ Additionally, some core plugins have been moved to extras. - `mini.surround` - `mini.indentscope` scopes are now also highlighted with `indent-blankline` - `nvim-treesitter-context` + - `vim-illuminate`: document highlights now use native lsp functionality by default - There's a new extra for the `nvim-treesitter` **rewrite**. Since the rewrite is not backward compatible, some plugins will be disabled diff --git a/lua/lazyvim/plugins/editor.lua b/lua/lazyvim/plugins/editor.lua index 61f9cd86..7bcf9973 100644 --- a/lua/lazyvim/plugins/editor.lua +++ b/lua/lazyvim/plugins/editor.lua @@ -409,46 +409,6 @@ return { }, }, - -- Automatically highlights other instances of the word under your cursor. - -- This works with LSP, Treesitter, and regexp matching to find the other - -- instances. - { - "RRethy/vim-illuminate", - event = "LazyFile", - opts = { - delay = 200, - large_file_cutoff = 2000, - large_file_overrides = { - providers = { "lsp" }, - }, - }, - config = function(_, opts) - require("illuminate").configure(opts) - - local function map(key, dir, buffer) - vim.keymap.set("n", key, function() - require("illuminate")["goto_" .. dir .. "_reference"](false) - end, { desc = dir:sub(1, 1):upper() .. dir:sub(2) .. " Reference", buffer = buffer }) - end - - map("]]", "next") - map("[[", "prev") - - -- also set it after loading ftplugins, since a lot overwrite [[ and ]] - vim.api.nvim_create_autocmd("FileType", { - callback = function() - local buffer = vim.api.nvim_get_current_buf() - map("]]", "next", buffer) - map("[[", "prev", buffer) - end, - }) - end, - keys = { - { "]]", desc = "Next Reference" }, - { "[[", desc = "Prev Reference" }, - }, - }, - -- buffer remove { "echasnovski/mini.bufremove", diff --git a/lua/lazyvim/plugins/extras/editor/illuminate.lua b/lua/lazyvim/plugins/extras/editor/illuminate.lua new file mode 100644 index 00000000..6fef79b4 --- /dev/null +++ b/lua/lazyvim/plugins/extras/editor/illuminate.lua @@ -0,0 +1,45 @@ +-- Automatically highlights other instances of the word under your cursor. +-- This works with LSP, Treesitter, and regexp matching to find the other +-- instances. +return { + { + "RRethy/vim-illuminate", + event = "LazyFile", + opts = { + delay = 200, + large_file_cutoff = 2000, + large_file_overrides = { + providers = { "lsp" }, + }, + }, + config = function(_, opts) + require("illuminate").configure(opts) + + local function map(key, dir, buffer) + vim.keymap.set("n", key, function() + require("illuminate")["goto_" .. dir .. "_reference"](false) + end, { desc = dir:sub(1, 1):upper() .. dir:sub(2) .. " Reference", buffer = buffer }) + end + + map("]]", "next") + map("[[", "prev") + + -- also set it after loading ftplugins, since a lot overwrite [[ and ]] + vim.api.nvim_create_autocmd("FileType", { + callback = function() + local buffer = vim.api.nvim_get_current_buf() + map("]]", "next", buffer) + map("[[", "prev", buffer) + end, + }) + end, + keys = { + { "]]", desc = "Next Reference" }, + { "[[", desc = "Prev Reference" }, + }, + }, + { + "neovim/nvim-lspconfig", + opts = { document_highlight = { enabed = false } }, + }, +} diff --git a/lua/lazyvim/plugins/lsp/init.lua b/lua/lazyvim/plugins/lsp/init.lua index f66b21a6..3a6ae964 100644 --- a/lua/lazyvim/plugins/lsp/init.lua +++ b/lua/lazyvim/plugins/lsp/init.lua @@ -46,6 +46,10 @@ return { codelens = { enabled = false, }, + -- Enable lsp cursor word highlighting + document_highlight = { + enabled = true, + }, -- add any global capabilities here capabilities = {}, -- options for vim.lsp.buf.format @@ -128,6 +132,8 @@ return { return ret end + LazyVim.lsp.words.setup(opts.document_highlight) + -- diagnostics signs if vim.fn.has("nvim-0.10.0") == 0 then if type(opts.diagnostics.signs) ~= "boolean" then diff --git a/lua/lazyvim/util/lsp.lua b/lua/lazyvim/util/lsp.lua index e712120a..c3a72ff6 100644 --- a/lua/lazyvim/util/lsp.lua +++ b/lua/lazyvim/util/lsp.lua @@ -21,7 +21,7 @@ function M.get_clients(opts) return opts and opts.filter and vim.tbl_filter(opts.filter, ret) or ret end ----@param on_attach fun(client, buffer) +---@param on_attach fun(client:lsp.Client, buffer) function M.on_attach(on_attach) vim.api.nvim_create_autocmd("LspAttach", { callback = function(args) @@ -125,4 +125,76 @@ function M.format(opts) end end +---@alias LspWord {from:{[1]:number, [2]:number}, to:{[1]:number, [2]:number}, current?:boolean} 1-0 indexed +M.words = {} +M.words.ns = vim.api.nvim_create_namespace("vim_lsp_references") + +---@param opts? {enabled?: boolean} +function M.words.setup(opts) + opts = opts or {} + if not opts.enabled then + return + end + M.on_attach(function(client, buf) + if client.supports_method("textDocument/documentHighlight") then + vim.api.nvim_create_autocmd({ "CursorHold", "CursorHoldI", "CursorMoved", "CursorMovedI" }, { + group = vim.api.nvim_create_augroup("lsp_word_" .. buf, { clear = true }), + buffer = buf, + callback = function(ev) + if not M.words.at() then + if ev.event:find("CursorMoved") then + vim.lsp.buf.clear_references() + else + vim.lsp.buf.document_highlight() + end + end + end, + }) + vim.keymap.set("n", "]]", function() + M.words.jump(vim.v.count1) + end, { buffer = buf }) + vim.keymap.set("n", "[[", function() + M.words.jump(-vim.v.count1) + end, { buffer = buf }) + end + end) +end + +---@return LspWord[] +function M.words.get() + local cursor = vim.api.nvim_win_get_cursor(0) + return vim.tbl_map(function(extmark) + local ret = { + from = { extmark[2] + 1, extmark[3] }, + to = { extmark[4].end_row + 1, extmark[4].end_col }, + } + if cursor[1] >= ret.from[1] and cursor[1] <= ret.to[1] and cursor[2] >= ret.from[2] and cursor[2] <= ret.to[2] then + ret.current = true + end + return ret + end, vim.api.nvim_buf_get_extmarks(0, M.words.ns, 0, -1, { details = true })) +end + +---@param words? LspWord[] +---@return LspWord?, number? +function M.words.at(words) + for idx, word in ipairs(words or M.words.get()) do + if word.current then + return word, idx + end + end +end + +function M.words.jump(count) + local words = M.words.get() + local _, idx = M.words.at(words) + if not idx then + return + end + local target = words[idx + count] + if target then + vim.api.nvim_win_set_cursor(0, target.from) + end +end + return M