diff --git a/README.md b/README.md index 000227b..4a1dffc 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,8 @@ Plug 'nvim-lua/lsp_extensions.nvim' ### Available Features -#### Rust -- [Inlay Hints](#inlay-hints-rust-analyzer) +#### Rust/C++ +- [Inlay Hints](#inlay-hints-rust-analyzerclangd-14) #### Dart - [Closing Labels](#closing-labels-dartls) @@ -24,39 +24,61 @@ Plug 'nvim-lua/lsp_extensions.nvim' - [Diagnostics](#workspace-diagnostics) -## Inlay Hints (rust-analyzer) +## Inlay Hints (rust-analyzer/clangd-14) ![Customized](https://i.imgur.com/FRRas1c.png) +![CustomizedCpp](https://i.imgur.com/SofDfdh.png) + +**Note**: Minial requirement for clangd inlay hints is clangd-14, you need to set `clangdInlayHintsProvider` to true in clangd's `init_options` +```lua +lspconfig.clangd.setup { + ... + init_options = { + clangdInlayHintsProvider = true, + ... + }, + ... +} +``` Inlay hints for the whole file: ```vimscript nnoremap T :lua require'lsp_extensions'.inlay_hints() +" For C++ set lsp_client to clangd +nnoremap T :lua require'lsp_extensions'.inlay_hints{ lsp_client = "clangd" } ``` Only current line: ```vimscript nnoremap t :lua require'lsp_extensions'.inlay_hints{ only_current_line = true } +" For C++ set lsp_client to clangd +nnoremap t :lua require'lsp_extensions'.inlay_hints{ lsp_client = "clangd", only_current_line = true } ``` Run on showing file or new file in buffer: ```vimscript autocmd BufEnter,BufWinEnter,TabEnter *.rs :lua require'lsp_extensions'.inlay_hints{} +" For C++ set lsp_client to clangd +autocmd BufEnter,BufWinEnter,TabEnter *.cpp :lua require'lsp_extensions'.inlay_hints{ lsp_client = "clangd" } ``` On cursor hover, get hints for current line: ```vimscript autocmd CursorHold,CursorHoldI *.rs :lua require'lsp_extensions'.inlay_hints{ only_current_line = true } +" For C++ set lsp_client to clangd +autocmd CursorHold,CursorHoldI *.cpp :lua require'lsp_extensions'.inlay_hints{ lsp_client = "clangd", only_current_line = true } ``` -By default only ChainingHint is enabled. This is due to Neovim not able to add virtual text injected into a line. To enable all hints: -**Note:** Hints will overwrite if other hints using this. Only the last hint will be shown. - +By default only ChainingHint is enabled. This is due to Neovim not able to add virtual text injected into a line. To enable all hints: +**Note:** Not all hints will be displayed if this is set. For easier readability, only hints of one type are shown per line. +**Note:** For clangd you have to explicitly specify the type of the hints to provide, currently, it have "parameter" and "type" [clangd doc](https://clangd.llvm.org/extensions#inlay-hints) ```vimscript :lua require('lsp_extensions').inlay_hints{ enabled = {"TypeHint", "ChainingHint", "ParameterHint"} } +:lua require('lsp_extensions').inlay_hints{ lsp_client = "clangd", enabled = {"parameter", "type"} } ``` Available Options (Showing defaults): @@ -65,6 +87,7 @@ Available Options (Showing defaults): require'lsp_extensions'.inlay_hints{ highlight = "Comment", prefix = " > ", + lsp_client = "rust-analyzer", aligned = false, only_current_line = false, enabled = { "ChainingHint" } @@ -73,6 +96,8 @@ require'lsp_extensions'.inlay_hints{ ```vimscript autocmd InsertLeave,BufEnter,BufWinEnter,TabEnter,BufWritePost *.rs :lua require'lsp_extensions'.inlay_hints{ prefix = ' » ', highlight = "NonText", enabled = {"ChainingHint"} } +" For C++ +autocmd InsertLeave,BufEnter,BufWinEnter,TabEnter,BufWritePost *.cpp :lua require'lsp_extensions'.inlay_hints{ lsp_client = "clangd" prefix = ' » ', highlight = "NonText", enabled = {"type"} } ``` ## Closing Labels (dartls) diff --git a/examples/inlay_hints_inline.lua b/examples/inlay_hints_inline.lua index 6754b58..d3f071a 100644 --- a/examples/inlay_hints_inline.lua +++ b/examples/inlay_hints_inline.lua @@ -4,13 +4,15 @@ local M = {} -- Global function, so you can just call it on the lua side ShowInlineInlayHints = function() - vim.lsp.buf_request(0, 'rust-analyzer/inlayHints', inlay_hints.get_params(), inlay_hints.get_callback { + -- For C++ replace "rust-analyzer" with "clangd" + vim.lsp.buf_request(0, inlay_hints.request_name{ lsp_client = "rust-analyzer"}, inlay_hints.get_params(), inlay_hints.get_callback { only_current_line = true }) end -- @rockerboo M.show_line_hints_on_cursor_events = function() + -- For C++ replace *.rs with *.cpp vim.cmd [[augroup ShowLineHints]] vim.cmd [[ au!]] vim.cmd [[ autocmd CursorHold,CursorHoldI,CursorMoved *.rs :lua ShowInlineInlayHints()]] diff --git a/lua/lsp_extensions/init.lua b/lua/lsp_extensions/init.lua index 0607079..8caa219 100644 --- a/lua/lsp_extensions/init.lua +++ b/lua/lsp_extensions/init.lua @@ -21,7 +21,7 @@ local extensions = {} local inlay_hints = require('lsp_extensions.inlay_hints') extensions.inlay_hints = function(opts) - vim.lsp.buf_request(0, 'rust-analyzer/inlayHints', inlay_hints.get_params(), inlay_hints.get_callback(opts)) + vim.lsp.buf_request(0, inlay_hints.request_name(opts), inlay_hints.get_params(), inlay_hints.get_callback(opts)) end return extensions diff --git a/lua/lsp_extensions/inlay_hints.lua b/lua/lsp_extensions/inlay_hints.lua index 2e5bf8b..f3d54a2 100644 --- a/lua/lsp_extensions/inlay_hints.lua +++ b/lua/lsp_extensions/inlay_hints.lua @@ -25,7 +25,7 @@ interface InlayHint { label: string, } ``` ---]] +--]] local util = require('lsp_extensions.util') @@ -33,8 +33,12 @@ local inlay_hints = {} local inlay_hints_ns = vim.api.nvim_create_namespace("lsp_extensions.inlay_hints") +inlay_hints.request_name = function(opts) + return string.format("%s/inlayHints", opts.lsp_client or "rust-analyzer") +end + inlay_hints.request = function(opts, bufnr) - vim.lsp.buf_request(bufnr or 0, "rust-analyzer/inlayHints", inlay_hints.get_params(), + vim.lsp.buf_request(bufnr or 0, inlay_hints.request_name(opts), inlay_hints.get_params(), inlay_hints.get_callback(opts)) -- TODO: At some point, rust probably adds this? @@ -83,8 +87,12 @@ inlay_hints.get_callback = function(opts) for _, hint in ipairs(result) do local finish = hint.range["end"].line - if not hint_store[finish] and in_list(enabled)(hint.kind) then - hint_store[finish] = hint + if in_list(enabled)(hint.kind) then + if not hint_store[finish] then + hint_store[finish] = {hint} + elseif hint_store[finish][1].kind == hint.kind then + table.insert(hint_store[finish], hint) + end if aligned then longest_line = math.max(longest_line, @@ -93,8 +101,8 @@ inlay_hints.get_callback = function(opts) end end - local display_virt_text = function(hint) - local end_line = hint.range["end"].line + local display_virt_text = function(hints) + local end_line = hints[1].range["end"].line -- Check for any existing / more important virtual text on the line. -- TODO: Figure out how stackable virtual text works? What happens if there is more than one?? @@ -103,25 +111,27 @@ inlay_hints.get_callback = function(opts) if not vim.tbl_isempty(existing_virt_text) then return end local text + for _, hint in ipairs(hints) do + text = (text or "") .. prefix .. hint.label + end + if aligned then - local line_length = #vim.api.nvim_buf_get_lines(ctx.bufnr, end_line, end_line + 1, false)[1] - text = string.format("%s %s", (" "):rep(longest_line - line_length), prefix .. hint.label) - else - text = prefix .. hint.label + local line_length = #vim.api.nvim_buf_get_lines(bufnr, end_line, end_line + 1, false)[1] + text = string.format("%s %s", (" "):rep(longest_line - line_length), text) end vim.api.nvim_buf_set_virtual_text(ctx.bufnr, inlay_hints_ns, end_line, {{text, highlight}}, {}) end if only_current_line then - local hint = hint_store[vim.api.nvim_win_get_cursor(0)[1] - 1] + local hints = hint_store[vim.api.nvim_win_get_cursor(0)[1] - 1] - if not hint then + if not hints then return else - display_virt_text(hint) + display_virt_text(hints) end else - for _, hint in pairs(hint_store) do display_virt_text(hint) end + for _, hints in pairs(hint_store) do display_virt_text(hints) end end end) end