feat: lsp diagnostics and prefiltering by entry attribute (#543)
prefiltering for lsp_document_symbols and lsp_workspace_symbols. example: type `:var:` to show all vars
This commit is contained in:
@@ -18,6 +18,7 @@ globals = {
|
|||||||
"TelescopeCachedTails",
|
"TelescopeCachedTails",
|
||||||
"TelescopeCachedNgrams",
|
"TelescopeCachedNgrams",
|
||||||
"_TelescopeConfigurationValues",
|
"_TelescopeConfigurationValues",
|
||||||
|
"__TelescopeKeymapStore",
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Global objects defined by the C code
|
-- Global objects defined by the C code
|
||||||
|
|||||||
@@ -409,6 +409,7 @@ Built-in functions. Ready to be bound to any key you like. :smile:
|
|||||||
| `builtin.lsp_workspace_symbols` | Searches in LSP all workspace symbols. |
|
| `builtin.lsp_workspace_symbols` | Searches in LSP all workspace symbols. |
|
||||||
| `builtin.lsp_code_actions` | Lists LSP action to be trigged on enter. |
|
| `builtin.lsp_code_actions` | Lists LSP action to be trigged on enter. |
|
||||||
| `builtin.lsp_range_code_actions` | Lists LSP range code action to be trigged on enter. |
|
| `builtin.lsp_range_code_actions` | Lists LSP range code action to be trigged on enter. |
|
||||||
|
| `builtin.lsp_diagnostics` | Lists LSP Diagnostics in the current document. |
|
||||||
| .................................. | Your next awesome picker function here :D |
|
| .................................. | Your next awesome picker function here :D |
|
||||||
|
|
||||||
### Git Pickers
|
### Git Pickers
|
||||||
|
|||||||
@@ -252,16 +252,16 @@ previewers.Previewer() *previewers.Previewer()*
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
previewers.buffer_previewer_maker({opts}, {bufnr}, {filepath})*previewers.buffer_previewer_maker()*
|
previewers.buffer_previewer_maker({filepath}, {bufnr}, {opts})*previewers.buffer_previewer_maker()*
|
||||||
A universal way of reading a file into a buffer previewer. It handles async
|
A universal way of reading a file into a buffer previewer. It handles async
|
||||||
reading, cache, highlighting, displaying directories and provides a
|
reading, cache, highlighting, displaying directories and provides a
|
||||||
callback which can be used, to jump to a line in the buffer.
|
callback which can be used, to jump to a line in the buffer.
|
||||||
|
|
||||||
|
|
||||||
Parameters: ~
|
Parameters: ~
|
||||||
{opts} (table) keys: `use_ft_detect`, `bufname` and `callback`
|
|
||||||
{bufnr} (number) Where the content will be written
|
|
||||||
{filepath} (string) String to the filepath, will be expanded
|
{filepath} (string) String to the filepath, will be expanded
|
||||||
|
{bufnr} (number) Where the content will be written
|
||||||
|
{opts} (table) keys: `use_ft_detect`, `bufname` and `callback`
|
||||||
|
|
||||||
|
|
||||||
previewers.cat() *previewers.cat()*
|
previewers.cat() *previewers.cat()*
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ builtin.spell_suggest = require('telescope.builtin.internal').spell_suggest
|
|||||||
builtin.lsp_references = require('telescope.builtin.lsp').references
|
builtin.lsp_references = require('telescope.builtin.lsp').references
|
||||||
builtin.lsp_document_symbols = require('telescope.builtin.lsp').document_symbols
|
builtin.lsp_document_symbols = require('telescope.builtin.lsp').document_symbols
|
||||||
builtin.lsp_code_actions = require('telescope.builtin.lsp').code_actions
|
builtin.lsp_code_actions = require('telescope.builtin.lsp').code_actions
|
||||||
|
builtin.lsp_diagnostics = require('telescope.builtin.lsp').diagnostics
|
||||||
builtin.lsp_range_code_actions = require('telescope.builtin.lsp').range_code_actions
|
builtin.lsp_range_code_actions = require('telescope.builtin.lsp').range_code_actions
|
||||||
builtin.lsp_workspace_symbols = require('telescope.builtin.lsp').workspace_symbols
|
builtin.lsp_workspace_symbols = require('telescope.builtin.lsp').workspace_symbols
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,10 @@ lsp.document_symbols = function(opts)
|
|||||||
entry_maker = opts.entry_maker or make_entry.gen_from_lsp_symbols(opts)
|
entry_maker = opts.entry_maker or make_entry.gen_from_lsp_symbols(opts)
|
||||||
},
|
},
|
||||||
previewer = conf.qflist_previewer(opts),
|
previewer = conf.qflist_previewer(opts),
|
||||||
sorter = conf.generic_sorter(opts),
|
sorter = conf.prefilter_sorter{
|
||||||
|
tag = "symbol_type",
|
||||||
|
sorter = conf.generic_sorter(opts)
|
||||||
|
}
|
||||||
}):find()
|
}):find()
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -180,7 +183,32 @@ lsp.workspace_symbols = function(opts)
|
|||||||
entry_maker = opts.entry_maker or make_entry.gen_from_lsp_symbols(opts)
|
entry_maker = opts.entry_maker or make_entry.gen_from_lsp_symbols(opts)
|
||||||
},
|
},
|
||||||
previewer = conf.qflist_previewer(opts),
|
previewer = conf.qflist_previewer(opts),
|
||||||
sorter = conf.generic_sorter(opts),
|
sorter = conf.prefilter_sorter{
|
||||||
|
tag = "symbol_type",
|
||||||
|
sorter = conf.generic_sorter(opts)
|
||||||
|
}
|
||||||
|
}):find()
|
||||||
|
end
|
||||||
|
|
||||||
|
lsp.diagnostics = function(opts)
|
||||||
|
local locations = utils.diagnostics_to_tbl(opts)
|
||||||
|
|
||||||
|
if vim.tbl_isempty(locations) then
|
||||||
|
print('No diagnostics found')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
pickers.new(opts, {
|
||||||
|
prompt_title = 'LSP Diagnostics',
|
||||||
|
finder = finders.new_table {
|
||||||
|
results = locations,
|
||||||
|
entry_maker = opts.entry_maker or make_entry.gen_from_lsp_diagnostics(opts)
|
||||||
|
},
|
||||||
|
previewer = conf.qflist_previewer(opts),
|
||||||
|
sorter = conf.prefilter_sorter{
|
||||||
|
tag = "type",
|
||||||
|
sorter = conf.generic_sorter(opts)
|
||||||
|
}
|
||||||
}):find()
|
}):find()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ function config.set_defaults(defaults)
|
|||||||
set("default_mappings", nil)
|
set("default_mappings", nil)
|
||||||
|
|
||||||
set("generic_sorter", sorters.get_generic_fuzzy_sorter)
|
set("generic_sorter", sorters.get_generic_fuzzy_sorter)
|
||||||
|
set("prefilter_sorter", sorters.prefilter)
|
||||||
set("file_sorter", sorters.get_fuzzy_file)
|
set("file_sorter", sorters.get_fuzzy_file)
|
||||||
|
|
||||||
set("file_ignore_patterns", nil)
|
set("file_ignore_patterns", nil)
|
||||||
|
|||||||
@@ -27,6 +27,13 @@ local lsp_type_highlight = {
|
|||||||
["Variable"] = "TelescopeResultsVariable",
|
["Variable"] = "TelescopeResultsVariable",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local lsp_type_diagnostic = {
|
||||||
|
[1] = "Error",
|
||||||
|
[2] = "Warning",
|
||||||
|
[3] = "Information",
|
||||||
|
[4] = "Hint"
|
||||||
|
}
|
||||||
|
|
||||||
local make_entry = {}
|
local make_entry = {}
|
||||||
|
|
||||||
do
|
do
|
||||||
@@ -847,6 +854,77 @@ function make_entry.gen_from_ctags(opts)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function make_entry.gen_from_lsp_diagnostics(opts)
|
||||||
|
opts = opts or {}
|
||||||
|
opts.tail_path = utils.get_default(opts.tail_path, true)
|
||||||
|
|
||||||
|
local signs = {}
|
||||||
|
for _, v in pairs(lsp_type_diagnostic) do
|
||||||
|
signs[v] = vim.trim(vim.fn.sign_getdefined("LspDiagnosticsSign" .. v)[1].text)
|
||||||
|
end
|
||||||
|
-- expose line width for longer msg if opts.hide_filename
|
||||||
|
local line_width = utils.get_default(opts.line_width, 48)
|
||||||
|
local displayer = entry_display.create {
|
||||||
|
separator = "▏",
|
||||||
|
items = {
|
||||||
|
{ width = 11 },
|
||||||
|
{ width = line_width },
|
||||||
|
{ remaining = true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local make_display = function(entry)
|
||||||
|
local filename
|
||||||
|
if not opts.hide_filename then
|
||||||
|
filename = entry.filename
|
||||||
|
if opts.tail_path then
|
||||||
|
filename = utils.path_tail(filename)
|
||||||
|
elseif opts.shorten_path then
|
||||||
|
filename = utils.path_shorten(filename)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- add styling of entries
|
||||||
|
local pos = string.format("%3d:%2d", entry.lnum, entry.col)
|
||||||
|
local line_info = {
|
||||||
|
string.format("%s %s", signs[entry.type], pos),
|
||||||
|
string.format("LspDiagnosticsDefault%s", entry.type)
|
||||||
|
}
|
||||||
|
-- remove line break to avoid display issues
|
||||||
|
local text = string.format("%-" .. line_width .."s", entry.text:gsub(".* | ", ""):gsub("[\n]", ""))
|
||||||
|
|
||||||
|
return displayer {
|
||||||
|
line_info,
|
||||||
|
text,
|
||||||
|
filename,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return function(entry)
|
||||||
|
local filename = entry.filename or vim.api.nvim_buf_get_name(entry.bufnr)
|
||||||
|
|
||||||
|
return {
|
||||||
|
valid = true,
|
||||||
|
|
||||||
|
value = entry,
|
||||||
|
ordinal = (
|
||||||
|
not opts.ignore_filename and filename
|
||||||
|
or ''
|
||||||
|
) .. ' ' .. entry.text,
|
||||||
|
display = make_display,
|
||||||
|
bufnr = entry.bufnr,
|
||||||
|
filename = filename,
|
||||||
|
type = entry.type,
|
||||||
|
lnum = entry.lnum,
|
||||||
|
col = entry.col,
|
||||||
|
text = entry.text,
|
||||||
|
start = entry.start,
|
||||||
|
finish = entry.finish,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function make_entry.gen_from_autocommands(_)
|
function make_entry.gen_from_autocommands(_)
|
||||||
local displayer = entry_display.create {
|
local displayer = entry_display.create {
|
||||||
separator = "▏",
|
separator = "▏",
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ function Sorter:new(opts)
|
|||||||
|
|
||||||
return setmetatable({
|
return setmetatable({
|
||||||
state = {},
|
state = {},
|
||||||
|
filter_function = opts.filter_function,
|
||||||
scoring_function = opts.scoring_function,
|
scoring_function = opts.scoring_function,
|
||||||
highlighter = opts.highlighter,
|
highlighter = opts.highlighter,
|
||||||
discard = opts.discard,
|
discard = opts.discard,
|
||||||
@@ -84,7 +85,13 @@ function Sorter:score(prompt, entry)
|
|||||||
return FILTERED
|
return FILTERED
|
||||||
end
|
end
|
||||||
|
|
||||||
local score = self:scoring_function(prompt or "", ordinal, entry)
|
local filter_score
|
||||||
|
if self.filter_function ~= nil then
|
||||||
|
filter_score, prompt = self:filter_function(prompt, entry)
|
||||||
|
end
|
||||||
|
|
||||||
|
local score = (filter_score == FILTERED and FILTERED or
|
||||||
|
self:scoring_function(prompt or "", ordinal, entry))
|
||||||
|
|
||||||
if score == FILTERED then
|
if score == FILTERED then
|
||||||
self:_mark_discarded(prompt, ordinal)
|
self:_mark_discarded(prompt, ordinal)
|
||||||
@@ -467,4 +474,45 @@ sorters.get_substr_matcher = function()
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local substr_matcher = function(_, prompt, line, _)
|
||||||
|
local display = line:lower()
|
||||||
|
local search_terms = util.max_split(prompt, "%s")
|
||||||
|
local matched = 0
|
||||||
|
local total_search_terms = 0
|
||||||
|
for _, word in pairs(search_terms) do
|
||||||
|
total_search_terms = total_search_terms + 1
|
||||||
|
if display:find(word, 1, true) then
|
||||||
|
matched = matched + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return matched == total_search_terms and 0 or FILTERED
|
||||||
|
end
|
||||||
|
|
||||||
|
local filter_function = function(opts)
|
||||||
|
local scoring_function = vim.F.if_nil(opts.filter_function, substr_matcher)
|
||||||
|
local tag = vim.F.if_nil(opts.tag, "ordinal")
|
||||||
|
local delimiter = vim.F.if_nil(opts.delimiter, ":")
|
||||||
|
|
||||||
|
return function(_, prompt, entry)
|
||||||
|
local filter = "^(" .. delimiter .. "(%S+)" .. "[" .. delimiter .. "%s]" .. ")"
|
||||||
|
local matched = prompt:match(filter)
|
||||||
|
|
||||||
|
if matched == nil then
|
||||||
|
return 0, prompt
|
||||||
|
end
|
||||||
|
-- clear prompt of tag
|
||||||
|
prompt = prompt:sub(#matched + 1, -1)
|
||||||
|
local query = vim.trim(matched:gsub(delimiter, ""))
|
||||||
|
return scoring_function(_, query, entry[tag], _), prompt
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
sorters.prefilter = function(opts)
|
||||||
|
local sorter = opts.sorter
|
||||||
|
sorter.filter_function = filter_function(opts)
|
||||||
|
sorter._was_discarded = function() return false end
|
||||||
|
return sorter
|
||||||
|
end
|
||||||
|
|
||||||
return sorters
|
return sorters
|
||||||
|
|||||||
@@ -82,6 +82,41 @@ utils.quickfix_items_to_entries = function(locations)
|
|||||||
return results
|
return results
|
||||||
end
|
end
|
||||||
|
|
||||||
|
utils.diagnostics_to_tbl = function(opts)
|
||||||
|
opts = opts or {}
|
||||||
|
|
||||||
|
local bufnr = vim.api.nvim_get_current_buf()
|
||||||
|
local filename = vim.api.nvim_buf_get_name(bufnr)
|
||||||
|
local buffer_diags = vim.lsp.diagnostic.get(bufnr, opts.client_id)
|
||||||
|
|
||||||
|
local items = {}
|
||||||
|
local lsp_type_diagnostic = {[1] = "Error", [2] = "Warning", [3] = "Information", [4] = "Hint"}
|
||||||
|
local insert_diag = function(diag)
|
||||||
|
local start = diag.range['start']
|
||||||
|
local finish = diag.range['end']
|
||||||
|
local row = start.line
|
||||||
|
local col = start.character
|
||||||
|
|
||||||
|
local line = (vim.api.nvim_buf_get_lines(bufnr, row, row + 1, false) or {""})[1]
|
||||||
|
|
||||||
|
table.insert(items, {
|
||||||
|
bufnr = bufnr,
|
||||||
|
filename = filename,
|
||||||
|
lnum = row + 1,
|
||||||
|
col = col + 1,
|
||||||
|
start = start,
|
||||||
|
finish = finish,
|
||||||
|
text = vim.trim(line .. " | " .. diag.message),
|
||||||
|
type = lsp_type_diagnostic[diag.severity] or lsp_type_diagnostic[1]
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, diag in ipairs(buffer_diags) do insert_diag(diag) end
|
||||||
|
|
||||||
|
table.sort(items, function(a, b) return a.lnum < b.lnum end)
|
||||||
|
return items
|
||||||
|
end
|
||||||
|
|
||||||
-- TODO: Figure out how to do this... could include in plenary :)
|
-- TODO: Figure out how to do this... could include in plenary :)
|
||||||
-- NOTE: Don't use this yet. It will segfault sometimes.
|
-- NOTE: Don't use this yet. It will segfault sometimes.
|
||||||
--
|
--
|
||||||
|
|||||||
Reference in New Issue
Block a user