-
Notifications
You must be signed in to change notification settings - Fork 64
/
Copy pathpeek.lua
150 lines (124 loc) Β· 4.48 KB
/
peek.lua
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
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 15), range.start.line + (opts.max_height or 15)),
false
)
if next(contents) == nil then
vim.notify("peek: Unable to get contents of the file!", vim.log.levels.WARN)
return
end
local width, height = vim.lsp.util._make_floating_popup_size(contents, opts)
local if_nil = vim.F.if_nil
opts = vim.lsp.util.make_floating_popup_options(if_nil(width, 30), if_nil(height, 15), opts)
-- Don't make it minimal as it is meant to be fully featured
opts["style"] = nil
vim.api.nvim_set_option_value("bufhidden", "wipe", { buf = bufnr })
local winnr = vim.api.nvim_open_win(bufnr, false, opts)
vim.api.nvim_set_option_value("winblend", 0, { win = 0, scope = "local" })
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(
string.format("autocmd %s <buffer> ++once lua pcall(vim.api.nvim_win_close, %d, true)", unpack(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.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_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
vim.notify("peek: Unable to open the file!", vim.log.levels.ERROR)
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
vim.notify("peek: You cannot edit the current file in a preview!", vim.log.levels.ERROR)
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('user.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(0, "utf-16")
local preview_callback = preview_location_callback_new_signature
local success, _ = pcall(vim.lsp.buf_request, 0, "textDocument/" .. what, params, preview_callback)
if not success then
vim.notify(
'peek: Error calling LSP method "textDocument/' .. what .. '". The current language lsp might not support it.',
vim.log.levels.ERROR
)
end
end
end
return M