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:
fdschmidt93
2021-03-03 22:33:03 +01:00
committed by GitHub
parent 390e5fa9f5
commit db7615578b
9 changed files with 199 additions and 6 deletions

View File

@@ -18,6 +18,7 @@ globals = {
"TelescopeCachedTails",
"TelescopeCachedNgrams",
"_TelescopeConfigurationValues",
"__TelescopeKeymapStore",
}
-- Global objects defined by the C code

View File

@@ -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_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_diagnostics` | Lists LSP Diagnostics in the current document. |
| .................................. | Your next awesome picker function here :D |
### Git Pickers

View File

@@ -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
reading, cache, highlighting, displaying directories and provides a
callback which can be used, to jump to a line in the buffer.
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
{bufnr} (number) Where the content will be written
{opts} (table) keys: `use_ft_detect`, `bufname` and `callback`
previewers.cat() *previewers.cat()*

View File

@@ -64,6 +64,7 @@ builtin.spell_suggest = require('telescope.builtin.internal').spell_suggest
builtin.lsp_references = require('telescope.builtin.lsp').references
builtin.lsp_document_symbols = require('telescope.builtin.lsp').document_symbols
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_workspace_symbols = require('telescope.builtin.lsp').workspace_symbols

View File

@@ -64,7 +64,10 @@ lsp.document_symbols = function(opts)
entry_maker = opts.entry_maker or make_entry.gen_from_lsp_symbols(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
@@ -180,7 +183,32 @@ lsp.workspace_symbols = function(opts)
entry_maker = opts.entry_maker or make_entry.gen_from_lsp_symbols(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()
end

View File

@@ -161,6 +161,7 @@ function config.set_defaults(defaults)
set("default_mappings", nil)
set("generic_sorter", sorters.get_generic_fuzzy_sorter)
set("prefilter_sorter", sorters.prefilter)
set("file_sorter", sorters.get_fuzzy_file)
set("file_ignore_patterns", nil)

View File

@@ -27,6 +27,13 @@ local lsp_type_highlight = {
["Variable"] = "TelescopeResultsVariable",
}
local lsp_type_diagnostic = {
[1] = "Error",
[2] = "Warning",
[3] = "Information",
[4] = "Hint"
}
local make_entry = {}
do
@@ -847,6 +854,77 @@ function make_entry.gen_from_ctags(opts)
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(_)
local displayer = entry_display.create {
separator = "",

View File

@@ -39,6 +39,7 @@ function Sorter:new(opts)
return setmetatable({
state = {},
filter_function = opts.filter_function,
scoring_function = opts.scoring_function,
highlighter = opts.highlighter,
discard = opts.discard,
@@ -84,7 +85,13 @@ function Sorter:score(prompt, entry)
return FILTERED
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
self:_mark_discarded(prompt, ordinal)
@@ -467,4 +474,45 @@ sorters.get_substr_matcher = function()
}
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

View File

@@ -82,6 +82,41 @@ utils.quickfix_items_to_entries = function(locations)
return results
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 :)
-- NOTE: Don't use this yet. It will segfault sometimes.
--