added full LSP support

main
bhagwan 3 years ago
parent 48e9515b99
commit 49c1e2f1ea

@ -70,14 +70,6 @@ use { 'ibhagwan/fzf-lua',
'vijaymarupudi/nvim-fzf' }
}
```
>**There's currently an issue with [nvim-fzf and some neovim 0.5
>releases](https://github.com/vijaymarupudi/nvim-fzf/pull/15), I already fixed
>it my fork and waiting for the PR to be merged, for now you can replace
>`vijaymarupudi/nvim-fzf` with `ibhagwan/nvim-fzf`**
>```lua
>use { 'ibhagwan/fzf-lua', requires = { 'ibhagwan/nvim-fzf' } }
>```
> **Note** if you already have fzf installed you do not need to install `fzf`
> or `fzf.vim`, however if you do not have it installed, **you only need** fzf
> which can be installed with (fzf.vim is not a requirement nor conflict):
@ -129,6 +121,21 @@ nnoremap <c-P> <cmd>lua require('fzf-lua').files()<CR>
|`man_pages`|man pages|
|`colorschemes`|color schemes|
## LSP Commands
| Command | List |
| --- | --- |
|`lsp_references`|References|
|`lsp_definitions`|Definitions|
|`lsp_declarations`|Declarations|
|`lsp_typedefs`|Type Definitions|
|`lsp_implementations`|Implementations|
|`lsp_document_symbols`|Document Symbols|
|`lsp_workspace_symbols`|Workspace Symbols|
|`lsp_code_actions`|Code Actions|
|`lsp_document_diagnostics`|Document Diagnostics|
|`lsp_workspace_diagnostics`|Workspace Diagnostics|
## Customization
I tried to make it as customizable as possible, if you find you need to change something that isnt below, open an issue and Ill do my best to add it.
@ -147,8 +154,8 @@ require'fzf-lua'.setup {
win_col = 0.50, -- window col position (0=left, 1=right)
-- win_border = false, -- window border? or borderchars?
win_border = { '╭', '─', '╮', '│', '╯', '─', '╰', '│' },
fzf_args = '', -- adv: fzf extra args, empty unless adv
fzf_layout = 'reverse', -- fzf '--layout='
fzf_args = '', -- adv: fzf extra args, empty unless adv
preview_cmd = '', -- 'head -n $FZF_PREVIEW_LINES',
preview_border = 'border', -- border|noborder
preview_wrap = 'nowrap', -- wrap|nowrap
@ -174,10 +181,27 @@ require'fzf-lua'.setup {
["ctrl-y"] = function(selected) print(selected[2]) end,
}
},
git = {
prompt = 'GitFiles ',
cmd = 'git ls-files --exclude-standard',
git_icons = true, -- show git icons?
file_icons = true, -- show file icons?
color_icons = true, -- colorize file|git icons
icons = {
["M"] = { icon = "M", color = "yellow" },
["D"] = { icon = "D", color = "red" },
["A"] = { icon = "A", color = "green" },
["?"] = { icon = "?", color = "magenta" },
-- ["M"] = { icon = "★", color = "red" },
-- ["D"] = { icon = "✗", color = "red" },
-- ["A"] = { icon = "+", color = "green" },
},
},
grep = {
prompt = 'Rg ',
input_prompt = 'Grep For ',
-- cmd = "rg --vimgrep",
rg_opts = "--hidden --column --line-number --no-heading --color=always --smart-case -g '!{.git,node_modules}/*'",
git_icons = true, -- show git icons?
file_icons = true, -- show file icons?
color_icons = true, -- colorize file|git icons
@ -194,13 +218,6 @@ require'fzf-lua'.setup {
prompt = 'History ',
cwd_only = false,
},
git = {
prompt = 'GitFiles ',
cmd = 'git ls-files --exclude-standard',
git_icons = true, -- show git icons?
file_icons = true, -- show file icons?
color_icons = true, -- colorize file|git icons
},
buffers = {
prompt = 'Buffers ',
file_icons = true, -- show file icons?
@ -233,8 +250,23 @@ require'fzf-lua'.setup {
end,
},
quickfix = {
cwd = vim.loop.cwd(),
-- cwd = vim.loop.cwd(),
file_icons = true,
git_icons = true,
},
lsp = {
prompt = ' ',
-- cwd = vim.loop.cwd(),
file_icons = true,
git_icons = false,
lsp_icons = true,
severity = "hint",
icons = {
["Error"] = { icon = "", color = "red" }, -- error
["Warning"] = { icon = "", color = "yellow" }, -- warning
["Information"] = { icon = "", color = "blue" }, -- info
["Hint"] = { icon = "", color = "magenta" }, -- hint
},
},
-- placeholders for additional user customizations
loclist = {},
@ -243,18 +275,6 @@ require'fzf-lua'.setup {
file_icon_colors = { -- override colors for extensions
["lua"] = "blue",
},
git_icons = { -- override colors for git icons
["M"] = "M", --"★",
["D"] = "D", --"✗",
["A"] = "A", --"+",
["?"] = "?"
},
git_icon_colors = { -- override colors for git icon colors
["M"] = "yellow",
["D"] = "red",
["A"] = "green",
["?"] = "magenta"
},
fzf_binds = { -- fzf '--bind=' options
'f2:toggle-preview',
'f3:toggle-preview-wrap',
@ -265,11 +285,11 @@ require'fzf-lua'.setup {
'ctrl-f:page-down',
'ctrl-b:page-up',
'ctrl-a:toggle-all',
'ctrl-u:clear-query',
'ctrl-l:clear-query',
},
window_on_create = function() -- nvim window options override
vim.cmd("set winhl=Normal:Normal") -- popup bg match normal windows
end
end,
}
```
@ -292,22 +312,22 @@ EOF
## TODO
- [ ] Add built-in plugin documentation
- [ ] Add "hidden" options documentation
- [ ] Add FAQ
- Add more providers
+ [x] ~~LSP (refs, symbols, etc)~~ (2021-07-20)
+ [ ] git commits
+ [ ] git branches
+ [ ] vim commands
+ [ ] vim command history
+ [ ] vim keymaps
+ [ ] vim options
+ [ ] search terms history
+ [ ] search history
+ [ ] tags
+ [ ] marks
+ [ ] registers
+ [ ] spelling suggestions
+ [ ] git commits
+ [ ] git branches
+ [ ] LSP (refs, symbols, etc)
- [ ] Add built-in plugin documentation
- [ ] Add "hidden" options documentation
- [ ] Add FAQ
### Credits

@ -124,6 +124,12 @@ M.git = {
color_icons = true,
git_icons = true,
actions = M.files.actions,
icons = {
["M"] = { icon = "M", color = "yellow" },
["D"] = { icon = "D", color = "red" },
["A"] = { icon = "A", color = "green" },
["?"] = { icon = "?", color = "magenta" },
},
}
M.buffers = {
@ -177,12 +183,19 @@ M.manpages = {
}
M.lsp = {
prompt = 'LSP> ',
timeout = 1000,
prompt = '> ',
file_icons = true and M._has_devicons,
color_icons = true,
git_icons = false,
lsp_icons = true,
severity = "hint",
actions = M.files.actions,
icons = {
["Error"] = { icon = "", color = "red" }, -- error
["Warning"] = { icon = "", color = "yellow" }, -- warning
["Information"] = { icon = "", color = "blue" }, -- info
["Hint"] = { icon = "", color = "magenta" }, -- hint
},
}
-- <F2> toggle preview
@ -238,19 +251,6 @@ M.file_icon_colors = {
["desktop"] = "magenta",
}
M.git_icons = {
["M"] = "M",
["D"] = "D",
["A"] = "A",
["?"] = "?"
}
M.git_icon_colors = {
["M"] = "yellow",
["D"] = "red",
["A"] = "green",
["?"] = "magenta"
}
M.window_on_create = function()
-- Set popup background same as normal windows

@ -6,12 +6,6 @@ local actions = require "fzf-lua.actions"
local M = {}
-- invisible unicode char as icon|git separator
-- this way we can split our string by space
-- this causes "invalid escape sequence" error
-- local nbsp = "\u{00a0}"
local nbsp = " "
M.get_devicon = function(file, ext)
local icon = ''
if not file or #file == 0 then return icon end
@ -99,22 +93,14 @@ local get_untracked_files = function()
return untracked_files
end
local color_icon = function(icon, ext)
if ext then
return utils.ansi_codes[config.file_icon_colors[ext] or "dark_grey"](icon)
else
return utils.ansi_codes[config.git_icon_colors[icon] or "green"](icon)
end
end
local get_git_icon = function(file, diff_files, untracked_files)
local get_git_indicator = function(file, diff_files, untracked_files)
if diff_files and diff_files[file] then
return config.git_icons[diff_files[file]]
return diff_files[file]
end
if untracked_files and untracked_files[file] then
return config.git_icons[untracked_files[file]]
return untracked_files[file]
end
return nbsp
return utils.nbsp
end
@ -136,16 +122,24 @@ M.make_entry_file = function(opts, x)
x = path.relative(x, opts.cwd)
end
if opts.file_icons then
local extension = path.extension(x)
icon = M.get_devicon(x, extension)
if opts.color_icons then icon = color_icon(icon, extension) end
local ext = path.extension(x)
icon = M.get_devicon(x, ext)
if opts.color_icons then
icon = utils.ansi_codes[config.file_icon_colors[ext] or "dark_grey"](icon)
end
prefix = prefix .. icon
end
if opts.git_icons then
local filepath = x:match("^[^:]+")
icon = get_git_icon(filepath, opts.diff_files, opts.untracked_files)
if opts.color_icons then icon = color_icon(icon) end
prefix = prefix .. utils._if(#prefix>0, nbsp, '') .. icon
local indicator = get_git_indicator(filepath, opts.diff_files, opts.untracked_files)
icon = indicator
if config.git.icons[indicator] then
icon = config.git.icons[indicator].icon
if opts.color_icons then
icon = utils.ansi_codes[config.git.icons[indicator].color or "dark_grey"](icon)
end
end
prefix = prefix .. utils._if(#prefix>0, utils.nbsp, '') .. icon
end
if #prefix > 0 then
x = prefix .. " " .. x
@ -180,7 +174,7 @@ M.fzf_files = function(opts)
opts.untracked_files = get_untracked_files()
end
local has_prefix = opts.file_icons or opts.git_icons
local has_prefix = opts.file_icons or opts.git_icons or opts.lsp_icons
if not opts.filespec then
opts.filespec = utils._if(has_prefix, "{2}", "{1}")
end
@ -189,6 +183,10 @@ M.fzf_files = function(opts)
M.build_fzf_cli(opts),
config.winopts(opts.winopts))
if opts.post_select_cb then
opts.post_select_cb()
end
if not selected then return end
if #selected > 1 then

@ -124,7 +124,10 @@ function M.setup(opts)
setopts(config.lsp, opts.lsp, {
prompt = "string",
cwd = "string",
timeout = "number",
severity = "string",
severity_exact = "string",
severity_bound = "string",
lsp_icons = "boolean",
git_icons = "boolean",
file_icons = "boolean",
color_icons = "boolean",
@ -169,8 +172,8 @@ function M.setup(opts)
setopt_tbl(config[k], opts[k], "actions")
setopt_tbl(config[k], opts[k], "winopts")
end
setopt_tbl(config, opts, "git_icons")
setopt_tbl(config, opts, "git_icon_colors")
setopt_tbl(config.git, opts.git, "icons")
setopt_tbl(config.lsp, opts.lsp, "icons")
setopt_tbl(config, opts, "file_icon_colors")
-- override the bat preview theme if set by caller
if config.bat_theme and #config.bat_theme > 0 then
@ -202,6 +205,15 @@ M.help_tags = require'fzf-lua.providers.helptags'.helptags
M.man_pages = require'fzf-lua.providers.manpages'.manpages
M.colorschemes = require'fzf-lua.providers.colorschemes'.colorschemes
M.lsp_refs = require'fzf-lua.providers.lsp'.refs_async
M.lsp_typedefs = require'fzf-lua.providers.lsp'.typedefs
M.lsp_references = require'fzf-lua.providers.lsp'.references
M.lsp_definitions = require'fzf-lua.providers.lsp'.definitions
M.lsp_declarations = require'fzf-lua.providers.lsp'.declarations
M.lsp_implementations = require'fzf-lua.providers.lsp'.implementations
M.lsp_document_symbols = require'fzf-lua.providers.lsp'.document_symbols
M.lsp_workspace_symbols = require'fzf-lua.providers.lsp'.workspace_symbols
M.lsp_code_actions = require'fzf-lua.providers.lsp'.code_actions
M.lsp_document_diagnostics = require'fzf-lua.providers.lsp'.diagnostics
M.lsp_workspace_diagnostics = require'fzf-lua.providers.lsp'.workspace_diagnostics
return M

@ -56,7 +56,6 @@ M.grep = function(opts)
-- save the next search as last_search so we
-- let the caller have an option to run the
-- same search again
-- print("1", opts.last_search, opts.search)
if not opts.search or #opts.search == 0 then
config.grep.last_search = vim.fn.input(opts.input_prompt)
else

@ -2,103 +2,284 @@ if not pcall(require, "fzf") then
return
end
-- local fzf = require "fzf"
local fzf = require "fzf"
-- local fzf_helpers = require("fzf.helpers")
-- local path = require "fzf-lua.path"
local core = require "fzf-lua.core"
local utils = require "fzf-lua.utils"
local config = require "fzf-lua.config"
local actions = require "fzf-lua.actions"
local M = {}
local getopts_lsp = function(opts, cfg)
opts = config.getopts(opts, cfg, {
"cwd", "prompt", "actions", "winopts",
"file_icons", "color_icons", "git_icons",
"separator"
})
local function location_handler(opts, cb, _, result)
result = vim.tbl_islist(result) and result or {result}
-- Jump immediately if there is only one location
-- TODO: we can't preform the jump due to fzf already
-- being open resulting in:
-- Error executing vim.schedule lua callback:
-- /usr/share/nvim/runtime/lua/vim/lsp/util.lua:976:
-- Vim(normal):Can't re-enter normal mode from terminal mode
--[[ if #result == 1 then
utils.send_ctrl_c()
return vim.lsp.util.jump_to_location(result[1])
end ]]
local items = vim.lsp.util.locations_to_items(result)
for _, entry in ipairs(items) do
entry = core.make_entry_lcol(opts, entry)
entry = core.make_entry_file(opts, entry)
cb(entry, function(err)
if err then return end
end)
end
end
if not opts.timeout then
opts.timeout = config.lsp.timeout or 10000
local function symbol_handler(opts, cb, _, result)
result = vim.tbl_islist(result) and result or {result}
local items = vim.lsp.util.symbols_to_items(result)
for _, entry in ipairs(items) do
entry.filename = opts.filename
entry = core.make_entry_lcol(opts, entry)
entry = core.make_entry_file(opts, entry)
cb(entry, function(err)
if err then return end
end)
end
return opts
end
local set_fzf_args = function(opts)
local line_placeholder = 2
if opts.file_icons == true or opts.git_icons == true then
line_placeholder = 3
local function code_action_handler(opts, cb, _, code_actions)
opts.code_actions = {}
for i, action in ipairs(code_actions) do
local text = string.format("%s %s",
utils.ansi_codes.magenta(string.format("%d:", i)),
action.title)
opts.code_actions[tostring(i)] = action
cb(text, function(err)
if err then return end
end)
end
end
opts.cli_args = "--nth=3 --delimiter='[: \\t]'"
opts.preview_args = string.format("--highlight-line={%d}", line_placeholder)
opts.preview_offset = string.format("+{%d}-/2", line_placeholder)
return opts
local function diagnostics_handler(opts, cb, _, entry)
local type = entry.type
entry = core.make_entry_lcol(opts, entry)
entry = core.make_entry_file(opts, entry)
if opts.lsp_icons and opts.cfg.icons[type] then
local severity = opts.cfg.icons[type]
local icon = severity.icon
if opts.color_icons then
icon = utils.ansi_codes[severity.color or "dark_grey"](icon)
end
if opts.file_icons or opts.git_icons then
-- entry = icon .. utils.nbsp .. utils.nbsp .. entry
entry = icon .. utils.nbsp .. utils.nbsp .. entry
else
-- entry = icon .. utils.nbsp .. " " .. entry
entry = icon .. utils.nbsp .. " " .. entry
end
end
cb(entry, function(err)
if err then return end
end)
end
M.refs_async = function(opts)
local function wrap_handler(handler)
return function(err, method, result, client_id, bufnr, lspcfg)
local ret
if err then
ret = utils.err(err.message)
utils.send_ctrl_c()
elseif not result or vim.tbl_isempty(result) then
ret = utils.info(string.format('No %s found', string.lower(handler.label)))
utils.send_ctrl_c()
else
ret = handler.target(err, method, result, client_id, bufnr, lspcfg)
end
return ret
end
end
opts = getopts_lsp(opts, config.lsp)
local function set_lsp_fzf_fn(opts)
-- hangs/returns empty if inside the coroutine
local params = vim.lsp.util.make_position_params()
params.context = { includeDeclaration = true }
local results_lsp, lsp_err = vim.lsp.buf_request_sync(0, "textDocument/references", params, opts.timeout)
if lsp_err then
utils.err("Error finding LSP references: " .. lsp_err)
return
-- we must make the params here while we're on
-- our current buffer window, anything inside
-- fzf_fn is run while fzf term is open
opts.bufnr = vim.api.nvim_get_current_buf()
opts.filename = vim.api.nvim_buf_get_name(opts.bufnr)
if not opts.lsp_params then
opts.lsp_params = vim.lsp.util.make_position_params()
opts.lsp_params.context = { includeDeclaration = true }
end
opts.fzf_fn = function (cb)
coroutine.wrap(function ()
local co = coroutine.running()
local locations = {}
for _, server_results in pairs(results_lsp) do
if server_results.result then
vim.list_extend(locations, vim.lsp.util.locations_to_items(server_results.result) or {})
end
end
if vim.tbl_isempty(locations) then
utils.info("LSP references is empty.")
vim.api.nvim_feedkeys(
vim.api.nvim_replace_termcodes("<C-c>", true, false, true),
'n', true)
return
-- callback when a location is found
-- we use this passthrough so we can send the
-- coroutine variable (not used rn but who knows?)
opts.lsp_handler.target = function(_, _, result)
return opts.lsp_handler.handler(opts, cb, co, result)
end
for _, entry in ipairs(locations) do
entry = core.make_entry_lcol(opts, entry)
entry = core.make_entry_file(opts, entry)
cb(entry, function(err)
if err then return end
coroutine.resume(co)
-- cb(nil) -- to close the pipe to fzf, this removes the loading
-- indicator in fzf
end)
coroutine.yield()
local _, cancel_all = vim.lsp.buf_request(opts.bufnr,
opts.lsp_handler.method, opts.lsp_params,
wrap_handler(opts.lsp_handler))
-- cancel all remaining LSP requests
-- once the user made their selection
-- or closed the fzf popup
opts.post_select_cb = function()
if cancel_all then cancel_all() end
end
-- coroutine.yield()
end)()
end
opts = set_fzf_args(opts)
return opts
end
local set_fzf_files_args = function(opts)
local line_placeholder = 2
if opts.file_icons or opts.git_icons or opts.lsp_icons then
line_placeholder = line_placeholder+1
end
opts.cli_args = opts.cli_args or "--delimiter='[: \\t]'"
opts.filespec = string.format("{%d}", line_placeholder-1)
opts.preview_args = string.format("--highlight-line={%d}", line_placeholder)
opts.preview_offset = string.format("+{%d}-/2", line_placeholder)
return opts
end
local normalize_lsp_opts = function(opts, cfg)
opts = config.getopts(opts, cfg, {
"cwd", "actions", "winopts",
"file_icons", "color_icons",
"git_icons", "lsp_icons", "severity",
"severity_exact", "severity_bound",
})
if not opts.cwd then opts.cwd = vim.loop.cwd() end
if not opts.prompt then
opts.prompt = opts.lsp_handler.label .. cfg.prompt
end
opts.cfg = nil
opts.bufnr = nil
opts.filename = nil
opts.lsp_params = nil
opts.code_actions = nil
return opts
end
local function fzf_lsp_locations(opts)
opts = normalize_lsp_opts(opts, config.lsp)
opts = set_fzf_files_args(opts)
opts = set_lsp_fzf_fn(opts)
return core.fzf_files(opts)
end
-- define the functions for wrap_module_fncs
M.references = function(opts)
return fzf_lsp_locations(opts)
end
M.definitions = function(opts)
return fzf_lsp_locations(opts)
end
M.declarations = function(opts)
return fzf_lsp_locations(opts)
end
M.typedefs = function(opts)
return fzf_lsp_locations(opts)
end
M.implementations = function(opts)
return fzf_lsp_locations(opts)
end
M.document_symbols = function(opts)
if not opts then opts = {} end
-- TODO: filename hiding
-- since single document
opts.ignore_filename = true
return fzf_lsp_locations(opts)
end
M.workspace_symbols = function(opts)
return fzf_lsp_locations(opts)
end
M.code_actions = function(opts)
opts = normalize_lsp_opts(opts, config.lsp)
opts.lsp_params = vim.lsp.util.make_range_params()
opts.lsp_params.context = {
diagnostics = vim.lsp.diagnostic.get_line_diagnostics()
}
-- "apply action" as default function
if not opts.actions then opts.actions = {} end
opts.actions.default = (function(selected)
local idx = selected[2]:match("(%d+)")
local action = opts.code_actions[idx]
if not action then return end
if action.edit or type(action.command) == 'table' then
if action.edit then
vim.lsp.util.apply_workspace_edit(action.edit)
end
if type(action.command) == 'table' then
vim.lsp.buf.execute_command(action.command)
end
else
vim.lsp.buf.execute_command(action)
end
end)
opts.nomulti = true
opts.preview_window = 'right:0'
opts.cli_args = "--delimiter=':'"
opts = set_lsp_fzf_fn(opts)
coroutine.wrap(function ()
local selected = fzf.fzf(opts.fzf_fn,
core.build_fzf_cli(opts),
config.winopts(opts.winopts))
if opts.post_select_cb then
opts.post_select_cb()
end
if not selected then return end
actions.act(opts.actions, selected[1], selected)
end)()
end
local convert_diagnostic_type = function(severity)
-- convert from string to int
if type(severity) == 'string' then
if type(severity) == "string" then
-- make sure that e.g. error is uppercased to Error
return vim.lsp.protocol.DiagnosticSeverity[severity:gsub("^%l", string.upper)]
end
-- otherwise keep original value, incl. nil
if type(severity) ~= "number" then return nil end
return severity
end
local filter_diag_severity = function(opts, severity)
if opts.severity ~= nil then
return opts.severity == severity
elseif opts.severity_limit ~= nil then
return severity <= opts.severity_limit
if opts.severity_exact ~= nil then
return opts.severity_exact == severity
elseif opts.severity ~= nil then
return severity <= opts.severity
elseif opts.severity_bound ~= nil then
return severity >= opts.severity_bound
else
@ -106,24 +287,34 @@ local filter_diag_severity = function(opts, severity)
end
end
local diagnostics_to_tbl = function(opts)
opts = opts or {}
local items = {}
M.diagnostics = function(opts)
opts = normalize_lsp_opts(opts, config.lsp)
local lsp_type_diagnostic = vim.lsp.protocol.DiagnosticSeverity
local current_buf = vim.api.nvim_get_current_buf()
-- save this so handler can get the lsp icon
opts.cfg = config.lsp
-- hint = 4
-- information = 3
-- warning = 2
-- error = 1
-- severity: keep any equal or more severe (lower)
-- severity_exact: keep any matching exact severity
-- severity_bound: keep any equal or less severe (higher)
opts.severity = convert_diagnostic_type(opts.severity)
opts.severity_limit = convert_diagnostic_type(opts.severity_limit)
opts.severity_exact = convert_diagnostic_type(opts.severity_exact)
opts.severity_bound = convert_diagnostic_type(opts.severity_bound)
local validate_severity = 0
for _, v in ipairs({opts.severity, opts.severity_limit, opts.severity_bound}) do
for _, v in ipairs({opts.severity_exact, opts.severity, opts.severity_bound}) do
if v ~= nil then
validate_severity = validate_severity + 1
end
if validate_severity > 1 then
utils.info('LSP: invalid severity parameters')
return {}
utils.warn("Invalid severity params, ignoring severity filters")
opts.severity, opts.severity_exact, opts.severity_bound = nil, nil, nil
end
end
@ -148,52 +339,135 @@ local diagnostics_to_tbl = function(opts)
return buffer_diag
end
local buffer_diags = opts.get_all and vim.lsp.diagnostic.get_all() or
{[current_buf] = vim.lsp.diagnostic.get(current_buf, opts.client_id)}
for bufnr, diags in pairs(buffer_diags) do
for _, diag in ipairs(diags) do
-- workspace diagnostics may include empty tables for unused bufnr
if not vim.tbl_isempty(diag) then
if filter_diag_severity(opts, diag.severity) then
table.insert(items, preprocess_diag(diag, bufnr))
opts.fzf_fn = function (cb)
coroutine.wrap(function ()
local co = coroutine.running()
local buffer_diags = opts.diag_all and vim.lsp.diagnostic.get_all() or
{[current_buf] = vim.lsp.diagnostic.get(current_buf, opts.client_id)}
if #buffer_diags == 0 then
utils.info(string.format('No %s found', string.lower(opts.lsp_handler.label)))
utils.send_ctrl_c()
end
for bufnr, diags in pairs(buffer_diags) do
for _, diag in ipairs(diags) do
-- workspace diagnostics may include empty tables for unused bufnr
if not vim.tbl_isempty(diag) then
if filter_diag_severity(opts, diag.severity) then
diagnostics_handler(opts, cb, co,
preprocess_diag(diag, bufnr))
end
end
end
end
end
-- coroutine.yield()
end)()
end
-- sort results by bufnr (prioritize cur buf), severity, lnum
table.sort(items, function(a, b)
if a.bufnr == b.bufnr then
if a.type == b.type then
return a.lnum < b.lnum
else
return a.type < b.type
end
opts = set_fzf_files_args(opts)
return core.fzf_files(opts)
end
M.workspace_diagnostics = function(opts)
if not opts then opts = {} end
opts.diag_all = true
return M.diagnostics(opts)
end
local function check_capabilities(feature)
local clients = vim.lsp.buf_get_clients(0)
local supported_client = false
for _, client in pairs(clients) do
supported_client = client.resolved_capabilities[feature]
if supported_client then break end
end
if supported_client then
return true
else
if #clients == 0 then
utils.info("LSP: no client attached")
else
-- prioritize for current bufnr
if a.bufnr == current_buf then
return true
end
if b.bufnr == current_buf then
return false
end
return a.bufnr < b.bufnr
utils.info("LSP: server does not support " .. feature)
end
end)
return items
return false
end
end
local handlers = {
["code_actions"] = {
label = "Code Actions",
capability = "code_action",
method = "textDocument/codeAction",
handler = code_action_handler },
["references"] = {
label = "References",
capability = "find_references",
method = "textDocument/references",
handler = location_handler },
["definitions"] = {
label = "Definitions",
capability = "goto_definition",
method = "textDocument/definition",
handler = location_handler },
["declarations"] = {
label = "Declarations",
capability = "goto_declaration",
method = "textDocument/declaration",
handler = location_handler },
["typedefs"] = {
label = "Type Definitions",
capability = "type_definition",
method = "textDocument/typeDefinition",
handler = location_handler },
["implementations"] = {
label = "Implementations",
capability = "implementation",
method = "textDocument/implementation",
handler = location_handler },
["document_symbols"] = {
label = "Document Symbols",
capability = "document_symbol",
method = "textDocument/documentSymbol",
handler = symbol_handler },
["workspace_symbols"] = {
label = "Workspace Symbols",
capability = "workspace_symbol",
method = "workspace/symbol",
handler = symbol_handler },
["diagnostics"] = {
label = "Diagnostics",
capability = nil,
method = nil,
handler = diagnostics_handler },
["workspace_diagnostics"] = {
label = "Workspace Diagnostics",
capability = nil,
method = nil,
handler = diagnostics_handler },
}
M.lsp_diag = function(opts)
local locations = diagnostics_to_tbl(opts)
local function wrap_module_fncs(mod)
for k, v in pairs(mod) do
mod[k] = function(opts)
opts = opts or {}
if vim.tbl_isempty(locations) then
utils.info("LSP diagnostics is empty.")
return
if not opts.lsp_handler then opts.lsp_handler = handlers[k] end
if not opts.lsp_handler then
utils.err(string.format("No LSP handler defined for %s", k))
return
end
if opts.lsp_handler and opts.lsp_handler.capability
and not check_capabilities(opts.lsp_handler.capability) then
return
end
v(opts)
end
end
return lsp_run(opts, config.lsp, locations)
return mod
end
return M
return wrap_module_fncs(M)

@ -47,7 +47,6 @@ M.manpages = function(opts)
if #selected > 1 then
for i = 2, #selected do
selected[i] = getmanpage(selected[i])
print(selected[i])
end
end

@ -24,6 +24,8 @@ local quickfix_run = function(opts, cfg, locations)
"separator"
})
if not opts.cwd then opts.cwd = vim.loop.cwd() end
opts.fzf_fn = function (cb)
for _, x in ipairs(results) do
x = core.make_entry_file(opts, x)
@ -41,10 +43,11 @@ local quickfix_run = function(opts, cfg, locations)
local line_placeholder = 2
if opts.file_icons == true or opts.git_icons == true then
line_placeholder = 3
line_placeholder = line_placeholder+1
end
opts.cli_args = "--nth=3 --delimiter='[: \\t]'"
opts.cli_args = "--delimiter='[: \\t]'"
opts.filespec = string.format("{%d}", line_placeholder-1)
opts.preview_args = string.format("--highlight-line={%d}", line_placeholder)
--[[
# Preview with bat, matching line in the middle of the window below

@ -7,6 +7,12 @@ end
local M = {}
-- invisible unicode char as icon|git separator
-- this way we can split our string by space
-- this causes "invalid escape sequence" error
-- local nbsp = "\u{00a0}"
M.nbsp = " "
M._if = function(bool, a, b)
if bool then
return a
@ -182,4 +188,9 @@ function M.get_visual_selection()
return table.concat(lines, "\n")
end
function M.send_ctrl_c()
vim.api.nvim_feedkeys(
vim.api.nvim_replace_termcodes("<C-c>", true, false, true), 'n', true)
end
return M

Loading…
Cancel
Save