1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
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 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('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
|