|
@@ -0,0 +1,140 @@
|
|
|
+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 <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(_, 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 floting 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('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 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
|