LunarVim/lua/lvim/lsp/peek.lua

152 lines
4.5 KiB
Lua

local M = {
floating_buf = nil,
floating_win = nil,
prev_result = nil,
}
local function create_floating_file(location, opts)
vim.validate {
location = { location, "t" },
opts = { opts, "t", true },
}
-- Set some defaults
opts = opts or {}
local close_events = opts.close_events or { "CursorMoved", "CursorMovedI", "BufHidden", "InsertCharPre" }
-- location may be LocationLink or Location
local uri = location.targetUri or location.uri
if uri == nil then
return
end
local bufnr = vim.uri_to_bufnr(uri)
if not vim.api.nvim_buf_is_loaded(bufnr) then
vim.fn.bufload(bufnr)
end
local range = location.targetRange or location.range
local contents = vim.api.nvim_buf_get_lines(
bufnr,
range.start.line,
math.min(range["end"].line + 1 + (opts.context or 10), range.start.line + (opts.max_height or 15)), -- Don't let the window be more that 15 lines long(height)
false
)
local width, height = vim.lsp.util._make_floating_popup_size(contents, opts)
opts = vim.lsp.util.make_floating_popup_options(width, height, opts)
-- Don't make it minimal as it is meant to be fully featured
opts["style"] = nil
vim.api.nvim_buf_set_option(bufnr, "bufhidden", "wipe")
local winnr = vim.api.nvim_open_win(bufnr, false, opts)
vim.api.nvim_win_set_option(winnr, "winblend", 0)
vim.api.nvim_win_set_cursor(winnr, { range.start.line + 1, range.start.character })
vim.api.nvim_buf_set_var(bufnr, "lsp_floating_window", winnr)
-- Set some autocmds to close the window
vim.api.nvim_command(
"autocmd QuitPre <buffer> ++nested ++once lua pcall(vim.api.nvim_win_close, " .. winnr .. ", true)"
)
vim.lsp.util.close_preview_autocmd(close_events, winnr)
return bufnr, winnr
end
local function preview_location_callback(result)
if result == nil or vim.tbl_isempty(result) then
return nil
end
local opts = {
border = "rounded",
context = 10,
}
if vim.tbl_islist(result) then
M.prev_result = result[1]
M.floating_buf, M.floating_win = create_floating_file(result[1], opts)
else
M.prev_result = result
M.floating_buf, M.floating_win = create_floating_file(result, opts)
end
end
local function preview_location_callback_old_signature(_, _, result)
return preview_location_callback(result)
end
local function preview_location_callback_new_signature(_, result)
return preview_location_callback(result)
end
function M.open_file()
-- Get the file currently open in the floating window
local filepath = vim.fn.expand "%:."
if not filepath then
print "peek: Unable to open the file!"
return
end
-- Close the floating window
pcall(vim.api.nvim_win_close, M.floating_win, true)
-- Edit the file
vim.cmd("edit " .. filepath)
local winnr = vim.api.nvim_get_current_win()
-- Set the cursor at the right position
M.set_cursor_to_prev_pos(winnr)
end
function M.set_cursor_to_prev_pos(winnr)
-- Get position of the thing to peek at
local location = M.prev_result
local range = location.targetRange or location.range
local cursor_pos = { range.start.line + 1, range.start.character }
-- Set the winnr to the floating window if none was passed in
winnr = winnr or M.floating_win
-- Set the cursor at the correct position in the floating window
vim.api.nvim_win_set_cursor(winnr, cursor_pos)
end
function M.Peek(what)
-- If a window already exists, focus it at the right position!
if vim.tbl_contains(vim.api.nvim_list_wins(), M.floating_win) then
local success_1, _ = pcall(vim.api.nvim_set_current_win, M.floating_win)
if not success_1 then
print "peek: You cannot edit the current file in a preview!"
return
end
-- Set the cursor at the correct position in the floating window
M.set_cursor_to_prev_pos()
vim.api.nvim_buf_set_keymap(
M.floating_buf,
"n",
"<CR>",
":lua require('lvim.lsp.peek').open_file()<CR>",
{ noremap = true, silent = true }
)
else
-- Make a new request and then create the new window in the callback
local params = vim.lsp.util.make_position_params()
local preview_callback = preview_location_callback_old_signature
if vim.fn.has "nvim-0.5.1" > 0 then
preview_callback = preview_location_callback_new_signature
end
local success, _ = pcall(vim.lsp.buf_request, 0, "textDocument/" .. what, params, preview_callback)
if not success then
print(
'peek: Error calling LSP method "textDocument/' .. what .. '". The current language lsp might not support it.'
)
end
end
end
return M