diff options
author | Geet Sethi <[email protected]> | 2021-07-31 19:14:08 +0530 |
---|---|---|
committer | GitHub <[email protected]> | 2021-07-31 13:44:08 +0000 |
commit | cf16a2e826774e89d1bfe5812b6f73c3dd049db2 (patch) | |
tree | 863859063ddc4615a8ac0b81c6f38604dea8c9e7 /lua | |
parent | 8157f50d1308f42f3db1c7f69c226eb2e5c0b796 (diff) |
Add the better peek functions (#1172)
Diffstat (limited to 'lua')
-rw-r--r-- | lua/core/which-key.lua | 6 | ||||
-rw-r--r-- | lua/lsp/keybinds.lua | 67 | ||||
-rw-r--r-- | lua/lsp/peek.lua | 140 |
3 files changed, 147 insertions, 66 deletions
diff --git a/lua/core/which-key.lua b/lua/core/which-key.lua index 595e076e..17995e87 100644 --- a/lua/core/which-key.lua +++ b/lua/core/which-key.lua @@ -152,6 +152,12 @@ M.config = function() "<cmd>lua vim.lsp.diagnostic.goto_prev({popup_opts = {border = lvim.lsp.popup_border}})<cr>", "Prev Diagnostic", }, + p = { + name = "Peek", + d = { "<cmd>lua require('lsp.peek').Peek('definition')<cr>", "Definition" }, + t = { "<cmd>lua require('lsp.peek').Peek('typeDefinition')<cr>", "Type Definition" }, + i = { "<cmd>lua require('lsp.peek').Peek('implementation')<cr>", "Implementation" }, + }, q = { "<cmd>Telescope quickfix<cr>", "Quickfix" }, r = { "<cmd>lua vim.lsp.buf.rename()<cr>", "Rename" }, s = { "<cmd>Telescope lsp_document_symbols<cr>", "Document Symbols" }, diff --git a/lua/lsp/keybinds.lua b/lua/lsp/keybinds.lua index cc0d4ec9..21f29994 100644 --- a/lua/lsp/keybinds.lua +++ b/lua/lsp/keybinds.lua @@ -1,70 +1,5 @@ local M = {} --- Taken from https://www.reddit.com/r/neovim/comments/gyb077/nvimlsp_peek_defination_javascript_ttserver/ -function M.preview_location(location, context, before_context) - -- location may be LocationLink or Location (more useful for the former) - context = context or 15 - before_context = before_context or 0 - 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 - before_context, - range["end"].line + 1 + context, - false - ) - local filetype = vim.api.nvim_buf_get_option(bufnr, "filetype") - return vim.lsp.util.open_floating_preview(contents, filetype, { border = lvim.lsp.popup_border }) -end - -function M.preview_location_callback(_, method, result) - local context = 15 - if result == nil or vim.tbl_isempty(result) then - print("No location found: " .. method) - return nil - end - if vim.tbl_islist(result) then - M.floating_buf, M.floating_win = M.preview_location(result[1], context) - else - M.floating_buf, M.floating_win = M.preview_location(result, context) - end -end - -function M.PeekDefinition() - if vim.tbl_contains(vim.api.nvim_list_wins(), M.floating_win) then - vim.api.nvim_set_current_win(M.floating_win) - else - local params = vim.lsp.util.make_position_params() - return vim.lsp.buf_request(0, "textDocument/definition", params, M.preview_location_callback) - end -end - -function M.PeekTypeDefinition() - if vim.tbl_contains(vim.api.nvim_list_wins(), M.floating_win) then - vim.api.nvim_set_current_win(M.floating_win) - else - local params = vim.lsp.util.make_position_params() - return vim.lsp.buf_request(0, "textDocument/typeDefinition", params, M.preview_location_callback) - end -end - -function M.PeekImplementation() - if vim.tbl_contains(vim.api.nvim_list_wins(), M.floating_win) then - vim.api.nvim_set_current_win(M.floating_win) - else - local params = vim.lsp.util.make_position_params() - return vim.lsp.buf_request(0, "textDocument/implementation", params, M.preview_location_callback) - end -end - function M.setup() if lvim.lsp.default_keybinds then vim.cmd "nnoremap <silent> gd <cmd>lua vim.lsp.buf.definition()<CR>" @@ -78,7 +13,7 @@ function M.setup() { noremap = true, silent = true } ) - vim.cmd "nnoremap <silent> gp <cmd>lua require'lsp.keybinds'.PeekDefinition()<CR>" + vim.cmd "nnoremap <silent> gp <cmd>lua require'lsp.peek'.Peek('definition')<CR>" vim.cmd "nnoremap <silent> K :lua vim.lsp.buf.hover()<CR>" vim.cmd "nnoremap <silent> <C-p> :lua vim.lsp.diagnostic.goto_prev({popup_opts = {border = lvim.lsp.popup_border}})<CR>" vim.cmd "nnoremap <silent> <C-n> :lua vim.lsp.diagnostic.goto_next({popup_opts = {border = lvim.lsp.popup_border}})<CR>" diff --git a/lua/lsp/peek.lua b/lua/lsp/peek.lua new file mode 100644 index 00000000..e512eee0 --- /dev/null +++ b/lua/lsp/peek.lua @@ -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 |