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_buf_set_var(bufnr, "lsp_floating_window", winnr) -- Set some autocmds to close the window vim.api.nvim_command( "autocmd QuitPre ++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(_, method, result) if result == nil or vim.tbl_isempty(result) then print("peek: No location found: " .. method) 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 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", "", ":lua require('lsp.peek').open_file()", { 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 success, _ = pcall( vim.lsp.buf_request, 0, "textDocument/" .. what, params, preview_location_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