Skip to content
This repository was archived by the owner on Jul 7, 2022. It is now read-only.

Add clangd-14 inlay hints support #36

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 31 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 <Leader>T :lua require'lsp_extensions'.inlay_hints()
" For C++ set lsp_client to clangd
nnoremap <Leader>T :lua require'lsp_extensions'.inlay_hints{ lsp_client = "clangd" }
```

Only current line:

```vimscript
nnoremap <Leader>t :lua require'lsp_extensions'.inlay_hints{ only_current_line = true }
" For C++ set lsp_client to clangd
nnoremap <Leader>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):
Expand All @@ -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" }
Expand All @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion examples/inlay_hints_inline.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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()]]
Expand Down
2 changes: 1 addition & 1 deletion lua/lsp_extensions/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
38 changes: 24 additions & 14 deletions lua/lsp_extensions/inlay_hints.lua
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,20 @@ interface InlayHint {
label: string,
}
```
--]]
--]]

local util = require('lsp_extensions.util')

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?
Expand Down Expand Up @@ -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,
Expand All @@ -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??
Expand All @@ -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
Expand Down