Regenerate nvim config
This commit is contained in:
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022-2023 Chinmay Dalal
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@ -0,0 +1,202 @@
|
||||

|
||||
|
||||
Requires Neovim 0.7+
|
||||
|
||||
## Installation
|
||||
Install this plugin using any plugin/package manager or see [`:h packages`](https://neovim.io/doc/user/repeat.html#packages)
|
||||
|
||||
## Configuration:
|
||||
Set up clangd via lspconfig/vim.lsp.start, as usual.
|
||||
You don't need to call `require("clangd_extensions").setup` if you like the defaults:
|
||||
```lua
|
||||
require("clangd_extensions").setup({
|
||||
inlay_hints = {
|
||||
inline = vim.fn.has("nvim-0.10") == 1,
|
||||
-- Options other than `highlight' and `priority' only work
|
||||
-- if `inline' is disabled
|
||||
-- Only show inlay hints for the current line
|
||||
only_current_line = false,
|
||||
-- Event which triggers a refresh of the inlay hints.
|
||||
-- You can make this { "CursorMoved" } or { "CursorMoved,CursorMovedI" } but
|
||||
-- note that this may cause higher CPU usage.
|
||||
-- This option is only respected when only_current_line is true.
|
||||
only_current_line_autocmd = { "CursorHold" },
|
||||
-- whether to show parameter hints with the inlay hints or not
|
||||
show_parameter_hints = true,
|
||||
-- prefix for parameter hints
|
||||
parameter_hints_prefix = "<- ",
|
||||
-- prefix for all the other hints (type, chaining)
|
||||
other_hints_prefix = "=> ",
|
||||
-- whether to align to the length of the longest line in the file
|
||||
max_len_align = false,
|
||||
-- padding from the left if max_len_align is true
|
||||
max_len_align_padding = 1,
|
||||
-- whether to align to the extreme right or not
|
||||
right_align = false,
|
||||
-- padding from the right if right_align is true
|
||||
right_align_padding = 7,
|
||||
-- The color of the hints
|
||||
highlight = "Comment",
|
||||
-- The highlight group priority for extmark
|
||||
priority = 100,
|
||||
},
|
||||
ast = {
|
||||
-- These are unicode, should be available in any font
|
||||
role_icons = {
|
||||
type = "🄣",
|
||||
declaration = "🄓",
|
||||
expression = "🄔",
|
||||
statement = ";",
|
||||
specifier = "🄢",
|
||||
["template argument"] = "🆃",
|
||||
},
|
||||
kind_icons = {
|
||||
Compound = "🄲",
|
||||
Recovery = "🅁",
|
||||
TranslationUnit = "🅄",
|
||||
PackExpansion = "🄿",
|
||||
TemplateTypeParm = "🅃",
|
||||
TemplateTemplateParm = "🅃",
|
||||
TemplateParamObject = "🅃",
|
||||
},
|
||||
--[[ These require codicons (https://github.com/microsoft/vscode-codicons)
|
||||
role_icons = {
|
||||
type = "",
|
||||
declaration = "",
|
||||
expression = "",
|
||||
specifier = "",
|
||||
statement = "",
|
||||
["template argument"] = "",
|
||||
},
|
||||
|
||||
kind_icons = {
|
||||
Compound = "",
|
||||
Recovery = "",
|
||||
TranslationUnit = "",
|
||||
PackExpansion = "",
|
||||
TemplateTypeParm = "",
|
||||
TemplateTemplateParm = "",
|
||||
TemplateParamObject = "",
|
||||
}, ]]
|
||||
|
||||
highlights = {
|
||||
detail = "Comment",
|
||||
},
|
||||
},
|
||||
memory_usage = {
|
||||
border = "none",
|
||||
},
|
||||
symbol_info = {
|
||||
border = "none",
|
||||
},
|
||||
})
|
||||
```
|
||||
## Features:
|
||||
### [Switch between source/header](https://clangd.llvm.org/extensions#switch-between-sourceheader)
|
||||
### Usage
|
||||
`:ClangdSwitchSourceHeader`
|
||||
### [Inlay hints](https://clangd.llvm.org/extensions#inlay-hints)
|
||||

|
||||
#### Usage
|
||||
Add this to your nvim-lspconfig / `vim.lsp.start()`'s `on_attach`:
|
||||
```lua
|
||||
require("clangd_extensions.inlay_hints").setup_autocmd()
|
||||
require("clangd_extensions.inlay_hints").set_inlay_hints()
|
||||
```
|
||||
|
||||
You can also enable, disable or toggle the hints with `ClangdSetInlayHints`, `ClangdDisableInlayHints` and `ClangdToggleInlayHints`.
|
||||
Toggling returns the current state of the hints, this is useful if you want to hook a callback when toggling inlay hints:
|
||||
```lua
|
||||
if require("clangd_extensions.inlay_hints").toggle_inlay_hints() then
|
||||
-- Inlay hints are enabled
|
||||
else
|
||||
-- Inlay hints are disabled
|
||||
end
|
||||
```
|
||||
For example if you have autocommands related to Clangd inlay hints you might want to disable/enable them when toggling inlay hints:
|
||||
```lua
|
||||
on_attach = function(_, buf)
|
||||
local group = vim.api.nvim_create_augroup("clangd_no_inlay_hints_in_insert", { clear = true })
|
||||
|
||||
vim.keymap.set("n", "<leader>lh", function()
|
||||
if require("clangd_extensions.inlay_hints").toggle_inlay_hints() then
|
||||
vim.api.nvim_create_autocmd("InsertEnter", { group = group, buffer = buf,
|
||||
callback = require("clangd_extensions.inlay_hints").disable_inlay_hints
|
||||
})
|
||||
vim.api.nvim_create_autocmd({ "TextChanged", "InsertLeave" }, { group = group, buffer = buf,
|
||||
callback = require("clangd_extensions.inlay_hints").set_inlay_hints
|
||||
})
|
||||
else
|
||||
vim.api.nvim_clear_autocmds({ group = group, buffer = buf })
|
||||
end
|
||||
end, { buffer = buf, desc = "[l]sp [h]ints toggle" })
|
||||
end,
|
||||
}
|
||||
```
|
||||
|
||||
### [View AST](https://clangd.llvm.org/extensions#ast)
|
||||

|
||||
You can fold nodes using `zc` and friends - the AST window has `shiftwidth=2` and `foldmethod=indent`.
|
||||
|
||||
#### Usage
|
||||
`:ClangdAST` to view the ast with the current line as the range, `:'<,'>ClangdAST` with a visual selection to view the ast with the selected lines as range.
|
||||
See how ranges are handled at https://clangd.llvm.org/extensions#ast
|
||||
### [Completion scores](https://clangd.llvm.org/extensions#code-completion-scores)
|
||||
Usage: For nvim-cmp
|
||||
```lua
|
||||
local cmp = require "cmp"
|
||||
cmp.setup {
|
||||
-- ... rest of your cmp setup ...
|
||||
|
||||
sorting = {
|
||||
comparators = {
|
||||
cmp.config.compare.offset,
|
||||
cmp.config.compare.exact,
|
||||
cmp.config.compare.recently_used,
|
||||
require("clangd_extensions.cmp_scores"),
|
||||
cmp.config.compare.kind,
|
||||
cmp.config.compare.sort_text,
|
||||
cmp.config.compare.length,
|
||||
cmp.config.compare.order,
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
### [Symbol info](https://clangd.llvm.org/extensions#symbol-info-request)
|
||||

|
||||
#### Usage
|
||||
`:ClangdSymbolInfo` with the cursor at the desired symbol.
|
||||
### [Type hierarchy](https://clangd.llvm.org/extensions#type-hierarchy)
|
||||
|
||||

|
||||
#### Usage
|
||||
`:ClangdTypeHierarchy` with the cursor over the desired type or a symbol of that type.
|
||||
`gd` with the cursor over a type in a window to go to its definition.
|
||||
### [Memory usage](https://clangd.llvm.org/extensions#memory-usage)
|
||||
You can fold items using `zc` and friends - the memory usage window has `shiftwidth=2` and `foldmethod=indent`.
|
||||

|
||||
#### Usage
|
||||
`:ClangdMemoryUsage`. Preamble can be large so it is collapsed by default, to expand it use `:ClangdMemoryUsage expand_preamble`
|
||||
|
||||
## Implementation status of [extensions](https://clangd.llvm.org/extensions)
|
||||
☑️ Memory usage
|
||||
|
||||
☑️ AST
|
||||
|
||||
☑️ Symbol info request
|
||||
|
||||
☑️ Type hierarchy
|
||||
|
||||
☑️ Inlay hints
|
||||
|
||||
☑️ Switch between source/header
|
||||
|
||||
☑️ File status (see lsp-status.nvim)
|
||||
|
||||
☑️ Compilation commands (can be specified in `vim.lsp.start()`/lspconfig `init_options` and `settings`)
|
||||
|
||||
☑️ Code completion scores
|
||||
|
||||
⬜ Force diagnostics generation (not sure)
|
||||
## Credits
|
||||
[simrat39](https://github.com/simrat39) - the code for inlay hints was taken from [rust-tools.nvim](https://github.com/simrat39/rust-tools.nvim) with very minor changes.
|
||||
@ -0,0 +1,183 @@
|
||||
local fmt = string.format
|
||||
local api = vim.api
|
||||
local conf = require("clangd_extensions.config").options.ast
|
||||
|
||||
local M = {}
|
||||
--- node_pos[source_buf][ast_buf][linenum] = { start = start, end = end }
|
||||
--- position of node in `source_buf` corresponding to line no. `linenum` in `ast_buf`
|
||||
M.node_pos = {}
|
||||
--- detail_pos[ast_buf][linenum] = { start = start, end = end }
|
||||
--- position of `detail` in line no. `linenum` of `ast_buf`
|
||||
M.detail_pos = {}
|
||||
M.nsid = vim.api.nvim_create_namespace("clangd_extensions")
|
||||
|
||||
local function setup_hl_autocmd(source_buf, ast_buf)
|
||||
local group = api.nvim_create_augroup("ClangdExtensions", {})
|
||||
api.nvim_create_autocmd("CursorMoved", {
|
||||
group = group,
|
||||
buffer = ast_buf,
|
||||
callback = function() M.update_highlight(source_buf, ast_buf) end,
|
||||
})
|
||||
api.nvim_create_autocmd("BufLeave", {
|
||||
group = group,
|
||||
buffer = ast_buf,
|
||||
callback = function() M.clear_highlight(source_buf) end,
|
||||
})
|
||||
end
|
||||
|
||||
local function icon_prefix(role, kind)
|
||||
if conf.kind_icons[kind] then
|
||||
return conf.kind_icons[kind] .. " "
|
||||
elseif conf.role_icons[role] then
|
||||
return conf.role_icons[role] .. " "
|
||||
else
|
||||
return " "
|
||||
end
|
||||
end
|
||||
|
||||
local function describe(role, kind, detail)
|
||||
local str = ""
|
||||
local icon = icon_prefix(role, kind)
|
||||
local detailpos = nil
|
||||
str = str .. kind
|
||||
if
|
||||
not (
|
||||
role == "expression"
|
||||
or role == "statement"
|
||||
or role == "declaration"
|
||||
or role == "template name"
|
||||
)
|
||||
then
|
||||
str = str .. " " .. role
|
||||
end
|
||||
if detail then
|
||||
detailpos = {
|
||||
start = string.len(str) + vim.fn.strlen(icon) + 1,
|
||||
["end"] = string.len(str) + vim.fn.strlen(icon) + string.len(
|
||||
detail
|
||||
) + 1,
|
||||
}
|
||||
str = str .. " " .. detail
|
||||
end
|
||||
return (icon .. str), detailpos
|
||||
end
|
||||
|
||||
local function walk_tree(node, visited, result, padding, hl_bufs)
|
||||
visited[node] = true
|
||||
local str, detpos = describe(node.role, node.kind, node.detail)
|
||||
table.insert(result, padding .. str)
|
||||
|
||||
if node.detail and detpos then
|
||||
M.detail_pos[hl_bufs.ast_buf][#result] = {
|
||||
start = string.len(padding) + detpos.start,
|
||||
["end"] = string.len(padding) + detpos["end"],
|
||||
}
|
||||
end
|
||||
|
||||
if node.range then
|
||||
M.node_pos[hl_bufs.source_buf][hl_bufs.ast_buf][#result] = {
|
||||
start = { node.range.start.line, node.range.start.character },
|
||||
["end"] = { node.range["end"].line, node.range["end"].character },
|
||||
}
|
||||
end
|
||||
|
||||
if node.children then
|
||||
for _, child in pairs(node.children) do
|
||||
if not visited[child] then
|
||||
walk_tree(child, visited, result, padding .. " ", hl_bufs)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
local function highlight_detail(ast_buf)
|
||||
for linenum, range in pairs(M.detail_pos[ast_buf]) do
|
||||
vim.highlight.range(
|
||||
ast_buf,
|
||||
M.nsid,
|
||||
conf.highlights.detail,
|
||||
{ linenum - 1, range.start },
|
||||
{ linenum - 1, range["end"] },
|
||||
"v",
|
||||
false,
|
||||
110
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
local function handler(err, ASTNode)
|
||||
if err or not ASTNode then
|
||||
return
|
||||
else
|
||||
local source_buf = api.nvim_get_current_buf()
|
||||
vim.cmd.vsplit(fmt("%s: AST", ASTNode.detail))
|
||||
local ast_buf = api.nvim_get_current_buf()
|
||||
api.nvim_set_option_value("filetype", "ClangdAST", { buf = ast_buf })
|
||||
if not M.node_pos[source_buf] then M.node_pos[source_buf] = {} end
|
||||
M.node_pos[source_buf][ast_buf] = {}
|
||||
M.detail_pos[ast_buf] = {}
|
||||
|
||||
local lines = walk_tree(
|
||||
ASTNode,
|
||||
{},
|
||||
{},
|
||||
"",
|
||||
{ source_buf = source_buf, ast_buf = ast_buf }
|
||||
)
|
||||
api.nvim_buf_set_lines(ast_buf, 0, -1, true, lines)
|
||||
vim.bo.buftype = "nofile"
|
||||
vim.bo.bufhidden = "wipe"
|
||||
vim.bo.modifiable = false
|
||||
vim.bo.shiftwidth = 2
|
||||
vim.wo.foldmethod = "indent"
|
||||
api.nvim_set_option_value("number", false, { scope = "local" })
|
||||
api.nvim_set_option_value("relativenumber", false, { scope = "local" })
|
||||
api.nvim_set_option_value("spell", false, { scope = "local" })
|
||||
api.nvim_set_option_value("cursorline", false, { scope = "local" })
|
||||
setup_hl_autocmd(source_buf, ast_buf)
|
||||
highlight_detail(ast_buf)
|
||||
end
|
||||
end
|
||||
|
||||
function M.clear_highlight(source_buf)
|
||||
api.nvim_buf_clear_namespace(source_buf, M.nsid, 0, -1)
|
||||
end
|
||||
|
||||
function M.update_highlight(source_buf, ast_buf)
|
||||
M.clear_highlight(source_buf)
|
||||
if api.nvim_get_current_buf() ~= ast_buf then return end
|
||||
local curline = vim.fn.getcurpos()[2]
|
||||
local curline_ranges = M.node_pos[source_buf][ast_buf][curline]
|
||||
if curline_ranges then
|
||||
vim.highlight.range(
|
||||
source_buf,
|
||||
M.nsid,
|
||||
"Search",
|
||||
curline_ranges.start,
|
||||
curline_ranges["end"],
|
||||
"v",
|
||||
false,
|
||||
110
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
function M.display_ast(line1, line2)
|
||||
vim.lsp.buf_request(0, "textDocument/ast", {
|
||||
textDocument = { uri = vim.uri_from_bufnr(0) },
|
||||
range = {
|
||||
start = {
|
||||
line = line1 - 1,
|
||||
character = 0,
|
||||
},
|
||||
["end"] = {
|
||||
line = line2,
|
||||
character = 0,
|
||||
},
|
||||
},
|
||||
}, handler)
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,10 @@
|
||||
return function(entry1, entry2)
|
||||
local diff
|
||||
if entry1.completion_item.score and entry2.completion_item.score then
|
||||
diff = (entry2.completion_item.score * entry2.score)
|
||||
- (entry1.completion_item.score * entry1.score)
|
||||
else
|
||||
diff = entry2.score - entry1.score
|
||||
end
|
||||
return (diff < 0)
|
||||
end
|
||||
@ -0,0 +1,57 @@
|
||||
local M = {}
|
||||
|
||||
M.options = {
|
||||
inlay_hints = {
|
||||
inline = vim.fn.has("nvim-0.10") == 1,
|
||||
only_current_line = false,
|
||||
only_current_line_autocmd = { "CursorHold" },
|
||||
show_parameter_hints = true,
|
||||
parameter_hints_prefix = "<- ",
|
||||
other_hints_prefix = "=> ",
|
||||
max_len_align = false,
|
||||
max_len_align_padding = 1,
|
||||
right_align = false,
|
||||
right_align_padding = 7,
|
||||
highlight = "Comment",
|
||||
priority = 100,
|
||||
},
|
||||
|
||||
ast = {
|
||||
role_icons = {
|
||||
type = "🄣",
|
||||
declaration = "🄓",
|
||||
expression = "🄔",
|
||||
statement = ";",
|
||||
specifier = "🄢",
|
||||
["template argument"] = "🆃",
|
||||
},
|
||||
|
||||
kind_icons = {
|
||||
Compound = "🄲",
|
||||
Recovery = "🅁",
|
||||
TranslationUnit = "🅄",
|
||||
PackExpansion = "🄿",
|
||||
TemplateTypeParm = "🅃",
|
||||
TemplateTemplateParm = "🅃",
|
||||
TemplateParamObject = "🅃",
|
||||
},
|
||||
|
||||
highlights = {
|
||||
detail = "Comment",
|
||||
},
|
||||
},
|
||||
|
||||
memory_usage = {
|
||||
border = "none",
|
||||
},
|
||||
|
||||
symbol_info = {
|
||||
border = "none",
|
||||
},
|
||||
}
|
||||
|
||||
function M.setup(options)
|
||||
M.options = vim.tbl_deep_extend("force", {}, M.options, options or {})
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,5 @@
|
||||
return {
|
||||
setup = function(options)
|
||||
require("clangd_extensions.config").setup(options)
|
||||
end,
|
||||
}
|
||||
@ -0,0 +1,311 @@
|
||||
-- MIT License
|
||||
--
|
||||
-- Copyright (c) 2020 simrat39
|
||||
--
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
--
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
--
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
local M = {}
|
||||
local config = require("clangd_extensions.config")
|
||||
local api = vim.api
|
||||
|
||||
-- Update inlay hints when opening a new buffer and when writing a buffer to a
|
||||
-- file
|
||||
-- opts is a string representation of the table of options
|
||||
function M.setup_autocmd()
|
||||
local events = { "BufEnter", "BufWinEnter", "TabEnter", "BufWritePost" }
|
||||
if config.options.inlay_hints.only_current_line then
|
||||
vim.list_extend(
|
||||
events,
|
||||
config.options.inlay_hints.only_current_line_autocmd
|
||||
)
|
||||
end
|
||||
|
||||
local augroup = vim.api.nvim_create_augroup("ClangdInlayHints", {})
|
||||
local buffer = api.nvim_get_current_buf()
|
||||
api.nvim_clear_autocmds({
|
||||
buffer = buffer,
|
||||
group = augroup,
|
||||
})
|
||||
api.nvim_create_autocmd(events, {
|
||||
buffer = buffer,
|
||||
group = augroup,
|
||||
callback = M.set_inlay_hints,
|
||||
})
|
||||
end
|
||||
|
||||
local function get_inline_params()
|
||||
return {
|
||||
textDocument = vim.lsp.util.make_text_document_params(),
|
||||
range = {
|
||||
start = {
|
||||
line = 0,
|
||||
character = 0,
|
||||
},
|
||||
["end"] = {
|
||||
line = vim.api.nvim_buf_line_count(0),
|
||||
character = 0,
|
||||
},
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
local namespace = vim.api.nvim_create_namespace("clangd/inlayHints")
|
||||
-- whether the hints are enabled or not
|
||||
local enabled = nil
|
||||
|
||||
-- parses the result into a easily parsable format
|
||||
-- example:
|
||||
-- {
|
||||
-- ["12"] = { {
|
||||
-- kind = "TypeHint",
|
||||
-- label = "String"
|
||||
-- } },
|
||||
-- ["13"] = { {
|
||||
-- kind = "TypeHint",
|
||||
-- label = "usize"
|
||||
-- } },
|
||||
-- ["15"] = { {
|
||||
-- kind = "ParameterHint",
|
||||
-- label = "styles"
|
||||
-- }, {
|
||||
-- kind = "ParameterHint",
|
||||
-- label = "len"
|
||||
-- } },
|
||||
-- ["7"] = { {
|
||||
-- kind = "ChainingHint",
|
||||
-- label = "Result<String, VarError>"
|
||||
-- }, {
|
||||
-- kind = "ParameterHint",
|
||||
-- label = "key"
|
||||
-- } },
|
||||
-- ["8"] = { {
|
||||
-- kind = "ParameterHint",
|
||||
-- label = "op"
|
||||
-- } }
|
||||
-- }
|
||||
--
|
||||
local function parseHints(result)
|
||||
local map = {}
|
||||
local only_current_line = config.options.inlay_hints.only_current_line
|
||||
|
||||
if type(result) ~= "table" then return {} end
|
||||
for _, value in pairs(result) do
|
||||
local line = tostring(value.range["end"].line)
|
||||
local label = value.label
|
||||
local kind = value.kind
|
||||
local current_line = vim.api.nvim_win_get_cursor(0)[1]
|
||||
|
||||
local function add_line()
|
||||
if map[line] ~= nil then
|
||||
table.insert(map[line], { label = label, kind = kind })
|
||||
else
|
||||
map[line] = { { label = label, kind = kind } }
|
||||
end
|
||||
end
|
||||
|
||||
if only_current_line then
|
||||
if line == tostring(current_line - 1) then add_line() end
|
||||
else
|
||||
add_line()
|
||||
end
|
||||
end
|
||||
return map
|
||||
end
|
||||
|
||||
local function handler(err, result, ctx)
|
||||
if err then return end
|
||||
local opts = config.options.inlay_hints
|
||||
local bufnr = ctx.bufnr
|
||||
|
||||
if vim.api.nvim_get_current_buf() ~= bufnr then return end
|
||||
|
||||
-- clean it up at first
|
||||
M.disable_inlay_hints()
|
||||
|
||||
local ret = parseHints(result)
|
||||
local max_len = -1
|
||||
|
||||
for key, _ in pairs(ret) do
|
||||
local line = tonumber(key)
|
||||
local current_line =
|
||||
vim.api.nvim_buf_get_lines(bufnr, line, line + 1, false)[1]
|
||||
if current_line then
|
||||
local current_line_len = string.len(current_line)
|
||||
max_len = math.max(max_len, current_line_len)
|
||||
end
|
||||
end
|
||||
|
||||
for key, value in pairs(ret) do
|
||||
local virt_text = ""
|
||||
local line = tonumber(key)
|
||||
|
||||
local current_line =
|
||||
vim.api.nvim_buf_get_lines(bufnr, line, line + 1, false)[1]
|
||||
|
||||
if current_line then
|
||||
local current_line_len = string.len(current_line)
|
||||
|
||||
local param_hints = {}
|
||||
local other_hints = {}
|
||||
|
||||
-- segregate paramter hints and other hints
|
||||
for _, value_inner in ipairs(value) do
|
||||
if value_inner.kind == "parameter" then
|
||||
table.insert(param_hints, value_inner.label:sub(1, -3))
|
||||
else
|
||||
local hint_text = value_inner.label
|
||||
if hint_text:sub(1, 2) == ": " then
|
||||
hint_text = hint_text:sub(3)
|
||||
end
|
||||
table.insert(other_hints, hint_text)
|
||||
end
|
||||
end
|
||||
|
||||
-- show parameter hints inside brackets with commas and a thin arrow
|
||||
if
|
||||
not vim.tbl_isempty(param_hints) and opts.show_parameter_hints
|
||||
then
|
||||
virt_text = virt_text .. opts.parameter_hints_prefix .. "("
|
||||
for i, value_inner_inner in ipairs(param_hints) do
|
||||
virt_text = virt_text .. value_inner_inner
|
||||
if i ~= #param_hints then virt_text = virt_text .. ", " end
|
||||
end
|
||||
virt_text = virt_text .. ") "
|
||||
end
|
||||
|
||||
-- show other hints with commas and a thicc arrow
|
||||
if not vim.tbl_isempty(other_hints) then
|
||||
virt_text = virt_text .. opts.other_hints_prefix
|
||||
for i, value_inner_inner in ipairs(other_hints) do
|
||||
virt_text = virt_text .. value_inner_inner
|
||||
if i ~= #other_hints then virt_text = virt_text .. ", " end
|
||||
end
|
||||
end
|
||||
|
||||
if config.options.inlay_hints.right_align then
|
||||
virt_text = virt_text
|
||||
.. string.rep(
|
||||
" ",
|
||||
config.options.inlay_hints.right_align_padding
|
||||
)
|
||||
end
|
||||
|
||||
if config.options.inlay_hints.max_len_align then
|
||||
virt_text = string.rep(
|
||||
" ",
|
||||
max_len
|
||||
- current_line_len
|
||||
+ config.options.inlay_hints.max_len_align_padding
|
||||
) .. virt_text
|
||||
end
|
||||
|
||||
-- set the virtual text
|
||||
vim.api.nvim_buf_set_extmark(bufnr, namespace, line, 0, {
|
||||
virt_text_pos = config.options.inlay_hints.right_align
|
||||
and "right_align"
|
||||
or "eol",
|
||||
virt_text = {
|
||||
{ virt_text, config.options.inlay_hints.highlight },
|
||||
},
|
||||
hl_mode = "combine",
|
||||
priority = config.options.inlay_hints.priority,
|
||||
})
|
||||
|
||||
-- update state
|
||||
enabled = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function inline_handler(err, result, ctx)
|
||||
if err then return end
|
||||
local bufnr = ctx.bufnr
|
||||
|
||||
if vim.api.nvim_get_current_buf() ~= bufnr then return end
|
||||
local current_line = vim.api.nvim_win_get_cursor(0)[1]
|
||||
|
||||
-- clean it up first
|
||||
M.disable_inlay_hints()
|
||||
|
||||
for _, hint in pairs(result) do
|
||||
local text = hint.label
|
||||
if hint.paddingLeft then text = " " .. text end
|
||||
if hint.paddingRight then text = text .. " " end
|
||||
local line = hint.position.line
|
||||
if
|
||||
line == current_line - 1
|
||||
or not config.options.inlay_hints.only_current_line
|
||||
then
|
||||
local col = hint.position.character
|
||||
vim.api.nvim_buf_set_extmark(bufnr, namespace, line, col, {
|
||||
virt_text_pos = "inline",
|
||||
virt_text = {
|
||||
{ text, config.options.inlay_hints.highlight },
|
||||
},
|
||||
hl_mode = "combine",
|
||||
priority = config.options.inlay_hints.priority,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.toggle_inlay_hints()
|
||||
if enabled then
|
||||
M.disable_inlay_hints()
|
||||
else
|
||||
M.set_inlay_hints()
|
||||
end
|
||||
enabled = not enabled
|
||||
return enabled
|
||||
end
|
||||
|
||||
function M.disable_inlay_hints()
|
||||
-- clear namespace which clears the virtual text as well
|
||||
vim.api.nvim_buf_clear_namespace(0, namespace, 0, -1)
|
||||
end
|
||||
|
||||
-- Sends the request to clangd to get the inlay hints and handle them
|
||||
function M.set_inlay_hints()
|
||||
local buf = vim.api.nvim_get_current_buf()
|
||||
local clients = vim.lsp.get_clients and vim.lsp.get_clients({ bufnr = buf })
|
||||
or vim.lsp.buf_get_clients(buf)
|
||||
-- ensure clangd is running and request doesn't cause error
|
||||
for _, c in pairs(clients) do
|
||||
if c.name == "clangd" then
|
||||
if config.options.inlay_hints.inline then
|
||||
vim.lsp.buf_request(
|
||||
0,
|
||||
"textDocument/inlayHint",
|
||||
get_inline_params(),
|
||||
inline_handler
|
||||
)
|
||||
else
|
||||
vim.lsp.buf_request(
|
||||
0,
|
||||
"clangd/inlayHints",
|
||||
{ textDocument = vim.lsp.util.make_text_document_params() },
|
||||
handler
|
||||
)
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,112 @@
|
||||
local api = vim.api
|
||||
local fmt = string.format
|
||||
|
||||
local function display(lines)
|
||||
for k, line in pairs(lines) do -- Pad lines
|
||||
if k ~= 1 then lines[k] = " " .. line .. " " end
|
||||
end
|
||||
local vim_width = api.nvim_get_option("columns")
|
||||
local vim_height = api.nvim_get_option("lines")
|
||||
local height = math.ceil(vim_height * 0.7 - 4)
|
||||
local width = math.ceil(vim_width * 0.7)
|
||||
local row = math.ceil((vim_height - height) / 2 - 1)
|
||||
local col = math.ceil((vim_width - width) / 2)
|
||||
local buf = api.nvim_create_buf(false, true)
|
||||
api.nvim_open_win(buf, true, {
|
||||
style = "minimal",
|
||||
relative = "editor",
|
||||
width = width,
|
||||
height = height,
|
||||
row = row,
|
||||
col = col,
|
||||
border = require("clangd_extensions.config").options.memory_usage.border,
|
||||
})
|
||||
vim.bo.shiftwidth = 2
|
||||
vim.wo.foldmethod = "indent"
|
||||
api.nvim_buf_set_lines(buf, 0, -1, true, lines)
|
||||
api.nvim_set_option_value("bufhidden", "wipe", { buf = buf })
|
||||
api.nvim_set_option_value("modifiable", false, { buf = buf })
|
||||
api.nvim_set_option_value("buftype", "nofile", { buf = buf })
|
||||
api.nvim_buf_set_keymap(buf, "n", "q", ":bd<CR>", {
|
||||
noremap = true,
|
||||
silent = true,
|
||||
})
|
||||
api.nvim_buf_set_keymap(buf, "n", "<ESC>", ":bd<CR>", {
|
||||
noremap = true,
|
||||
silent = true,
|
||||
})
|
||||
end
|
||||
|
||||
local function format_name(name)
|
||||
if name:sub(1, 7) == "file://" then name = vim.uri_to_fname(name) end
|
||||
local cwd = vim.fn.getcwd()
|
||||
if name:sub(1, string.len(cwd)) == cwd then
|
||||
name = name:sub(string.len(cwd) + 2, -1)
|
||||
end
|
||||
return name
|
||||
end
|
||||
|
||||
local function format_tree(
|
||||
node,
|
||||
visited,
|
||||
result,
|
||||
padding,
|
||||
prefix,
|
||||
expand_preamble
|
||||
)
|
||||
if padding == "" then
|
||||
table.insert(
|
||||
result,
|
||||
fmt("Total: self = %s, total = %s", node._self, node._total)
|
||||
)
|
||||
end
|
||||
visited[prefix] = true
|
||||
for child_name, child_node in pairs(node) do
|
||||
if
|
||||
child_name ~= "_self"
|
||||
and child_name ~= "_total"
|
||||
and not visited[prefix .. child_name]
|
||||
then
|
||||
child_name = format_name(child_name)
|
||||
table.insert(
|
||||
result,
|
||||
padding
|
||||
.. fmt(
|
||||
"%s: self = %s, total = %s",
|
||||
child_name,
|
||||
child_node._self,
|
||||
child_node._total
|
||||
)
|
||||
)
|
||||
if child_name ~= "preamble" or expand_preamble then
|
||||
format_tree(
|
||||
child_node,
|
||||
visited,
|
||||
result,
|
||||
padding .. " ",
|
||||
prefix .. child_name,
|
||||
expand_preamble
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
local function handler(err, result, expand_preamble)
|
||||
if err then return end
|
||||
display(format_tree(result, {}, { "" }, "", "", expand_preamble))
|
||||
end
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.show_memory_usage(expand_preamble)
|
||||
vim.lsp.buf_request(
|
||||
0,
|
||||
"$/memoryUsage",
|
||||
nil,
|
||||
function(err, result) handler(err, result, expand_preamble) end
|
||||
)
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,19 @@
|
||||
local function handler(_err, uri)
|
||||
if not uri or uri == "" then
|
||||
vim.api.nvim_echo({ { "Corresponding file cannot be determined" } }, false, {})
|
||||
return
|
||||
end
|
||||
local file_name = vim.uri_to_fname(uri)
|
||||
vim.api.nvim_cmd({
|
||||
cmd = "edit",
|
||||
args = { file_name },
|
||||
}, {})
|
||||
end
|
||||
|
||||
return {
|
||||
switch_source_header = function()
|
||||
vim.lsp.buf_request(0, "textDocument/switchSourceHeader", {
|
||||
uri = vim.uri_from_bufnr(0),
|
||||
}, handler)
|
||||
end,
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
local function handler(err, result)
|
||||
if err or (#result == 0) then return end
|
||||
local name_str = string.format("name: %s", result[1].name)
|
||||
local container_str =
|
||||
string.format("container: %s", result[1].containerName)
|
||||
vim.lsp.util.open_floating_preview({ name_str, container_str }, "", {
|
||||
height = 2,
|
||||
width = math.max(string.len(name_str), string.len(container_str)),
|
||||
focusable = false,
|
||||
focus = false,
|
||||
border = require("clangd_extensions.config").options.symbol_info.border,
|
||||
})
|
||||
end
|
||||
|
||||
local M = {}
|
||||
|
||||
function M.show_symbol_info()
|
||||
vim.lsp.buf_request(0, "textDocument/symbolInfo", {
|
||||
textDocument = {
|
||||
uri = vim.uri_from_bufnr(0),
|
||||
},
|
||||
position = {
|
||||
line = vim.fn.getcurpos()[2] - 1,
|
||||
character = vim.fn.getcurpos()[3] - 1,
|
||||
},
|
||||
}, handler)
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,28 @@
|
||||
return {
|
||||
"File",
|
||||
"Module",
|
||||
"Namespace",
|
||||
"Package",
|
||||
"Class",
|
||||
"Method",
|
||||
"Property",
|
||||
"Field",
|
||||
"Constructor",
|
||||
"Enum",
|
||||
"Interface",
|
||||
"Function",
|
||||
"Variable",
|
||||
"Constant",
|
||||
"String",
|
||||
"Number",
|
||||
"Boolean",
|
||||
"Array",
|
||||
"Object",
|
||||
"Key",
|
||||
"Null",
|
||||
"EnumMember",
|
||||
"Struct",
|
||||
"Event",
|
||||
"Operator",
|
||||
"TypeParameter",
|
||||
}
|
||||
@ -0,0 +1,144 @@
|
||||
local symbol_kind = require("clangd_extensions.symbol_kind")
|
||||
local fmt = string.format
|
||||
local api = vim.api
|
||||
local type_hierarchy_augroup =
|
||||
api.nvim_create_augroup("ClangdTypeHierarchy", {})
|
||||
|
||||
local M = {}
|
||||
M.type_to_location = {}
|
||||
M.offset_encoding = {}
|
||||
|
||||
local function format_tree(node, visited, result, padding, type_to_location)
|
||||
visited[node.data] = true
|
||||
table.insert(
|
||||
result,
|
||||
padding .. fmt(" • %s: %s", node.name, symbol_kind[node.kind])
|
||||
)
|
||||
|
||||
type_to_location[node.name] = { uri = node.uri, range = node.range }
|
||||
|
||||
if node.parents then
|
||||
if #node.parents > 0 then
|
||||
table.insert(result, padding .. " Parents:")
|
||||
for _, parent in pairs(node.parents) do
|
||||
if not visited[parent.data] then
|
||||
format_tree(
|
||||
parent,
|
||||
visited,
|
||||
result,
|
||||
padding .. " ",
|
||||
type_to_location
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if node.children then
|
||||
if #node.children > 0 then
|
||||
table.insert(result, padding .. " Children:")
|
||||
for _, child in pairs(node.children) do
|
||||
if not visited[child.data] then
|
||||
format_tree(
|
||||
child,
|
||||
visited,
|
||||
result,
|
||||
padding .. " ",
|
||||
type_to_location
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
local function handler(err, TypeHierarchyItem, ctx)
|
||||
if err or not TypeHierarchyItem then
|
||||
return
|
||||
else
|
||||
-- Save old state
|
||||
local source_win = api.nvim_get_current_win()
|
||||
|
||||
-- Init
|
||||
M.offset_encoding[ctx.client_id] =
|
||||
vim.lsp.get_client_by_id(ctx.client_id).offset_encoding
|
||||
vim.cmd.split(fmt("%s: type hierarchy", TypeHierarchyItem.name))
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
M.type_to_location[bufnr] = {}
|
||||
|
||||
-- Set content
|
||||
local lines = format_tree(
|
||||
TypeHierarchyItem,
|
||||
{},
|
||||
{},
|
||||
"",
|
||||
M.type_to_location[bufnr]
|
||||
)
|
||||
api.nvim_buf_set_lines(bufnr, 0, -1, true, lines)
|
||||
|
||||
-- Set options
|
||||
vim.bo.modifiable = false
|
||||
vim.bo.filetype = "ClangdTypeHierarchy"
|
||||
vim.bo.buftype = "nofile"
|
||||
vim.bo.bufhidden = "wipe"
|
||||
vim.bo.buflisted = true
|
||||
api.nvim_set_option_value("number", false, { scope = "local" })
|
||||
api.nvim_set_option_value("relativenumber", false, { scope = "local" })
|
||||
api.nvim_set_option_value("spell", false, { scope = "local" })
|
||||
api.nvim_set_option_value("cursorline", false, { scope = "local" })
|
||||
local winbar = api.nvim_get_option_value("winbar", {})
|
||||
local numlines = winbar == "" and #lines or #lines + 1
|
||||
local winheight = math.min(numlines, 15)
|
||||
api.nvim_win_set_height(0, winheight)
|
||||
|
||||
-- Set highlights
|
||||
vim.cmd([[
|
||||
syntax clear
|
||||
syntax match ClangdTypeName "\( \{2,\}• \)\@<=\w\+\(:\)\@="
|
||||
]])
|
||||
vim.api.nvim_set_hl(0, "ClangdTypeName", { link = "Underlined" })
|
||||
|
||||
-- Set keymap
|
||||
vim.keymap.set("n", "gd", function()
|
||||
local word = vim.fn.expand("<cWORD>")
|
||||
word = string.gsub(word, ":$", "")
|
||||
local location = M.type_to_location[bufnr][word]
|
||||
if location ~= nil then
|
||||
api.nvim_set_current_win(source_win)
|
||||
vim.lsp.util.jump_to_location(
|
||||
location,
|
||||
M.offset_encoding[ctx.client_id]
|
||||
)
|
||||
end
|
||||
end, {
|
||||
buffer = bufnr,
|
||||
desc = "go to definition of type under cursor",
|
||||
})
|
||||
|
||||
-- Clear `type_to_location` for this buffer when it is wiped out
|
||||
api.nvim_create_autocmd("BufWipeOut", {
|
||||
buffer = bufnr,
|
||||
group = type_hierarchy_augroup,
|
||||
callback = function() M.type_to_location[bufnr] = nil end,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
function M.show_hierarchy()
|
||||
vim.lsp.buf_request(0, "textDocument/typeHierarchy", {
|
||||
textDocument = {
|
||||
uri = vim.uri_from_bufnr(0),
|
||||
},
|
||||
position = {
|
||||
line = vim.fn.getcurpos()[2] - 1,
|
||||
character = vim.fn.getcurpos()[3] - 1,
|
||||
},
|
||||
-- TODO make these configurable (config + command args)
|
||||
resolve = 3,
|
||||
direction = 2,
|
||||
}, handler)
|
||||
end
|
||||
|
||||
return M
|
||||
@ -0,0 +1,5 @@
|
||||
---
|
||||
base: lua51
|
||||
globals:
|
||||
vim:
|
||||
any: true
|
||||
@ -0,0 +1,42 @@
|
||||
local create_command = vim.api.nvim_create_user_command
|
||||
|
||||
create_command('ClangdSetInlayHints', function()
|
||||
require("clangd_extensions.inlay_hints").set_inlay_hints()
|
||||
end, {})
|
||||
|
||||
create_command('ClangdDisableInlayHints', function()
|
||||
require("clangd_extensions.inlay_hints").disable_inlay_hints()
|
||||
end, {})
|
||||
|
||||
create_command('ClangdToggleInlayHints', function()
|
||||
require("clangd_extensions.inlay_hints").toggle_inlay_hints()
|
||||
end, {})
|
||||
|
||||
create_command('ClangdAST', function(opts)
|
||||
require("clangd_extensions.ast").display_ast(opts.line1, opts.line2)
|
||||
end, { range = true })
|
||||
|
||||
create_command('ClangdTypeHierarchy', function()
|
||||
require("clangd_extensions.type_hierarchy").show_hierarchy()
|
||||
end, {})
|
||||
|
||||
create_command('ClangdSymbolInfo', function()
|
||||
require("clangd_extensions.symbol_info").show_symbol_info()
|
||||
end, {})
|
||||
|
||||
create_command(
|
||||
'ClangdMemoryUsage',
|
||||
function(opts)
|
||||
require("clangd_extensions.memory_usage").show_memory_usage(opts.args == 'expand_preamble')
|
||||
end,
|
||||
{
|
||||
nargs = '?',
|
||||
complete = function(_, _, _)
|
||||
return { 'expand_preamble' }
|
||||
end
|
||||
}
|
||||
)
|
||||
|
||||
create_command('ClangdSwitchSourceHeader', function()
|
||||
require("clangd_extensions.switch_source_header").switch_source_header()
|
||||
end, {})
|
||||
@ -0,0 +1 @@
|
||||
std = "nvim"
|
||||
@ -0,0 +1,4 @@
|
||||
indent_width = 4
|
||||
column_width = 80
|
||||
indent_type = "Spaces"
|
||||
collapse_simple_statement = "Always"
|
||||
Reference in New Issue
Block a user