Skip to content

Commit d526a41

Browse files
committed
CopilotPanel Improvements and reorg
1 parent 38c6358 commit d526a41

File tree

5 files changed

+197
-95
lines changed

5 files changed

+197
-95
lines changed

lua/copilot/client.lua

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,25 @@
11
local M = { params = {} }
2-
local util = require("copilot.util")
2+
3+
local register_autocmd = function ()
4+
vim.api.nvim_create_autocmd({ "BufEnter" }, {
5+
callback = vim.schedule_wrap(M.buf_attach_copilot),
6+
})
7+
end
38

49
M.buf_attach_copilot = function()
510
if vim.tbl_contains(M.params.ft_disable, vim.bo.filetype) then return end
611
if not vim.bo.buflisted or not vim.bo.buftype == "" then return end
7-
local client_id = util.find_copilot_client()
8-
local buf_clients = vim.lsp.buf_get_clients(0)
9-
if not buf_clients and client_id or (client_id and not buf_clients[client_id]) then
10-
vim.lsp.buf_attach_client(0, client_id)
11-
end
12-
end
13-
14-
local register_autocmd = function ()
15-
if vim.fn.has("nvim-0.7") > 0 then
16-
vim.api.nvim_create_autocmd({ "BufEnter" }, {
17-
callback = vim.schedule_wrap(M.buf_attach_copilot),
18-
})
19-
else
20-
vim.cmd("au BufEnter * lua vim.schedule(function() require('copilot.client').buf_attach_copilot() end)")
12+
local name = M.params.server_opts_overrides.name or "copilot"
13+
local client = vim.lsp.get_active_clients({name=name})[1]
14+
if client and not vim.lsp.buf_is_attached(0, client.id) then
15+
vim.lsp.buf_attach_client(0, client.id)
2116
end
2217
end
2318

2419
M.merge_server_opts = function (params)
2520
return vim.tbl_deep_extend("force", {
2621
cmd = { "node", require("copilot.util").get_copilot_path(params.plugin_manager_path) },
2722
name = "copilot",
28-
trace = "messages",
2923
root_dir = vim.loop.cwd(),
3024
autostart = true,
3125
on_init = function(_, _)
@@ -41,9 +35,7 @@ end
4135

4236
M.start = function(params)
4337
M.params = params
44-
local client_id = vim.lsp.start_client(M.merge_server_opts(params))
45-
local client = vim.lsp.get_client_by_id(client_id)
46-
return { client_id, client }
38+
vim.lsp.start_client(M.merge_server_opts(params))
4739
end
4840

4941
return M

lua/copilot/extensions/panel.lua

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,18 @@ local panel = {
77
method = "getPanelCompletions",
88
usecmp = false,
99
buf = "",
10-
uri = "",
10+
uri = "copilot:///placeholder",
1111
}
1212

13-
local existing_matches= {}
14-
1513
panel.send_request = function (callback)
1614
local completion_params = util.get_completion_params()
1715
completion_params.panelId = panel.uri
1816
callback = callback or function () end
1917
vim.lsp.buf_request(0, panel.method, completion_params, callback)
2018
end
2119

20+
local existing_matches= {}
21+
2222
local verify_existing = function (context)
2323
existing_matches[context.bufnr] = existing_matches[context.bufnr] or {}
2424
existing_matches[context.bufnr][context.cursor.row] = existing_matches[context.bufnr][context.cursor.row] or {}
@@ -60,35 +60,8 @@ function panel.create (max_results)
6060
panel.uri = vim.uri_from_bufnr(panel.buf)
6161

6262
vim.api.nvim_create_user_command("CopilotPanel", function ()
63+
panel.send_request()
6364
print_buf.create(panel.buf)
64-
local items = {}
65-
handler.add_handler_callback("PanelSolution", "pb", function (result)
66-
local formatted = format.deindent(result.displayText)
67-
items[formatted] = 1
68-
end)
69-
handler.add_handler_callback("PanelSolutionsDone", "pb", function ()
70-
local item_list = vim.tbl_add_reverse_lookup(vim.tbl_keys(items))
71-
local result_text = vim.tbl_flatten(vim.tbl_map(function(v)
72-
local s = vim.fn.split(v, '\n')
73-
local text = vim.tbl_map(function (t)
74-
local number_string = "[" .. item_list[v] .. "]"
75-
local str = (s[1] == t and number_string .. string.rep(' ', vim.o.shiftwidth)) or string.rep(' ', vim.o.shiftwidth+string.len(number_string))
76-
return str .. t
77-
end, s)
78-
table.insert(text, '')
79-
return text
80-
end, item_list))
81-
print_buf.set_text(result_text)
82-
items = {}
83-
end)
84-
vim.api.nvim_create_autocmd("WinClosed", {
85-
pattern = { tostring(print_buf.win) },
86-
callback = function ()
87-
handler.remove_handler_callback("PanelSolution", "pb")
88-
handler.remove_handler_callback("PanelSolutionsDone", "pb")
89-
end,
90-
once = true,
91-
})
9265
end, {})
9366

9467
return panel
Lines changed: 176 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,84 @@
11
local a = vim.api
22
local cmd = vim.cmd
33
local wo = vim.wo
4+
local handler = require("copilot.handlers")
5+
local format = require("copilot_cmp.format")
6+
local print_panel = {}
47

5-
local print_buf = {}
8+
local set_text = function (full_text)
9+
vim.api.nvim_buf_set_lines(print_panel.bufnr, 0, -1, false, {})
10+
vim.api.nvim_buf_set_option(print_panel.bufnr, "modifiable", true)
11+
vim.api.nvim_buf_set_option(print_panel.bufnr, "readonly", false)
612

7-
print_buf.set_text = function (full_text)
813
local ft = vim.bo.filetype
9-
vim.api.nvim_buf_call(print_buf.bufnr, function ()
14+
vim.api.nvim_buf_call(print_panel.bufnr, function ()
1015
vim.bo.filetype = ft
1116
end)
12-
vim.api.nvim_buf_set_lines(print_buf.bufnr, 0, -1, false, {})
13-
vim.api.nvim_buf_set_var(print_buf.bufnr, "modifiable", 1)
14-
vim.api.nvim_buf_set_var(print_buf.bufnr, "readonly", 0)
15-
vim.api.nvim_buf_set_lines(print_buf.bufnr, 0, #full_text, false,full_text)
16-
17-
vim.schedule(function()
18-
vim.api.nvim_buf_set_var(print_buf.bufnr, "modifiable", 0)
19-
vim.api.nvim_buf_set_var(print_buf.bufnr, "readonly", 1)
17+
vim.api.nvim_buf_set_lines(print_panel.bufnr, 0, #full_text, false,full_text)
18+
19+
vim.api.nvim_buf_set_option(print_panel.bufnr, "modifiable", false)
20+
vim.api.nvim_buf_set_option(print_panel.bufnr, "readonly", true)
21+
end
22+
23+
local format_entry = function (number, str)
24+
local lines = {}
25+
for s in str:gmatch("[^\r\n]+") do table.insert(lines, s) end
26+
table.insert(lines, '')
27+
return {
28+
len = #lines,
29+
lines = lines,
30+
number = number,
31+
}
32+
end
33+
34+
local sort_items = function (items)
35+
local sorted = {}
36+
for fmt_string, value in pairs(items) do
37+
sorted[value.score] = fmt_string
38+
end
39+
return sorted
40+
end
41+
42+
local make_entries = function (items)
43+
local entries = {}
44+
items = sort_items(items)
45+
for number, str in ipairs(vim.tbl_values(items)) do
46+
table.insert(entries, format_entry(number, str))
47+
end
48+
for index, _ in ipairs(entries) do
49+
local last = entries[index-1]
50+
entries[index].linenr = last and last.linenr + last.len or 1
51+
end
52+
return entries
53+
end
54+
55+
local get_full_text = function (entries)
56+
return vim.tbl_flatten(vim.tbl_map(function(e)
57+
return e.lines
58+
end, entries))
59+
end
60+
61+
print_panel.add_panel_callbacks = function ()
62+
local items = {}
63+
64+
handler.add_handler_callback("PanelSolution", "pb", function (result)
65+
local formatted = format.deindent(result.displayText)
66+
items[formatted] = result
67+
end)
68+
69+
handler.add_handler_callback("PanelSolutionsDone", "pb", function ()
70+
if vim.tbl_isempty(items) then return end
71+
print_panel.entries = make_entries(items)
72+
print_panel.current = 1
73+
set_text(get_full_text(print_panel.entries))
74+
items = {}
2075
end)
2176
end
2277

2378
local create_win = function ()
2479
local oldwin = a.nvim_get_current_win() --record current window
25-
cmd("vsplit")
80+
local height = tostring(math.floor(vim.api.nvim_win_get_height(oldwin)*.3))
81+
cmd(height .. "split")
2682
local win = a.nvim_get_current_win()
2783
wo.number = false
2884
wo.relativenumber = false
@@ -32,10 +88,113 @@ local create_win = function ()
3288
return win
3389
end
3490

35-
print_buf.create = function (bufnr)
36-
print_buf.bufnr = bufnr
37-
print_buf.win = create_win()
38-
a.nvim_win_set_buf(print_buf.win, print_buf.bufnr)
91+
print_panel.select = function (id)
92+
if not id then id = print_panel.current or 1 end
93+
local selection = print_panel.entries[id]
94+
vim.api.nvim_win_set_cursor(print_panel.win, {selection.linenr, 0})
95+
vim.cmd("normal zt")
96+
print_panel.current = id
97+
print_panel.linenr = selection.linenr
98+
end
99+
100+
print_panel.next = function ()
101+
local entries = print_panel.entries
102+
local current = print_panel.current
103+
local id = entries[current+1] and current+1 or 1
104+
print_panel.select(id)
39105
end
40106

41-
return print_buf
107+
print_panel.prev = function ()
108+
local entries = print_panel.entries
109+
local current = print_panel.current
110+
local id = entries[current-1] and current-1 or #entries
111+
print_panel.select(id)
112+
end
113+
114+
print_panel.set_options = function ()
115+
local opts = {
116+
win = { fcs = "eob: ", signcolumn = "no", list = false},
117+
buf = { bufhidden = "wipe", buftype = "nofile", swapfile = false, buflisted = false, }
118+
}
119+
for option, value in pairs(opts.win) do
120+
vim.api.nvim_win_set_option(print_panel.win, option, value)
121+
end
122+
123+
for option, value in pairs(opts.buf) do
124+
vim.api.nvim_buf_set_option(print_panel.bufnr, option, value)
125+
end
126+
end
127+
128+
print_panel.create = function (bufnr)
129+
print_panel.bufnr = bufnr
130+
print_panel.win = create_win()
131+
print_panel.last = 1
132+
a.nvim_win_set_buf(print_panel.win, print_panel.bufnr)
133+
print_panel.set_options()
134+
print_panel.add_panel_callbacks()
135+
136+
local keymaps = {
137+
["j"] = print_panel.next,
138+
["k"] = print_panel.prev,
139+
["<CR>"] = print_panel.select,
140+
}
141+
142+
for key, fn in pairs(keymaps) do
143+
vim.keymap.set("n", key, fn, {
144+
silent = true,
145+
buffer = print_panel.bufnr,
146+
})
147+
end
148+
149+
local id = vim.api.nvim_create_augroup("Panel", {
150+
clear = false
151+
})
152+
153+
vim.api.nvim_create_autocmd({"TextChangedI", "TextChangedP"}, {
154+
callback = function ()
155+
print("callback")
156+
require("copilot.extensions.panel").send_request()
157+
end,
158+
group = id,
159+
})
160+
161+
vim.api.nvim_create_autocmd("WinEnter", {
162+
callback = function ()
163+
if print_panel.entries then
164+
print_panel.select(print_panel.entries.current)
165+
end
166+
end,
167+
buffer = print_panel.bufnr,
168+
group = id,
169+
})
170+
171+
vim.api.nvim_create_autocmd("WinClosed", {
172+
pattern = { tostring(print_panel.win) },
173+
callback = function ()
174+
-- cleanup panel triggers
175+
vim.api.nvim_create_augroup("Panel", { clear = true })
176+
handler.remove_handler_callback("PanelSolution", "pb")
177+
handler.remove_handler_callback("PanelSolutionsDone", "pb")
178+
end,
179+
once = true,
180+
group = id,
181+
})
182+
end
183+
184+
return print_panel
185+
186+
-- if you add back numbering:
187+
--
188+
-- local add_prefix_spacing = function (str, number)
189+
-- return string.rep(' ', number) .. str
190+
-- end
191+
--
192+
-- local entry_str = "[" .. number .. "]"
193+
-- for index, value in ipairs(lines) do
194+
-- if index == 1 then
195+
-- lines[index] = entry_str .. add_prefix_spacing(value, vim.o.shiftwidth)
196+
-- else
197+
-- lines[index] = add_prefix_spacing(value, vim.o.shiftwidth+entry_str:len())
198+
-- end
199+
-- end
200+

lua/copilot/init.lua

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@ local client = require("copilot.client")
33

44
local defaults = {
55
cmp = {
6-
method = "getPanelCompletions",
6+
method = "getCompletionsCycling",
77
max_results = 5,
88
},
99
extensions = {
10-
getPanelCompletions = function (max_results)
11-
local panel = require("copilot.extensions.panel").create(max_results)
12-
require("copilot_cmp").setup(panel.complete)
10+
getPanelCompletions = function ()
11+
require("copilot_cmp").setup(require("copilot.panel").complete)
1312
end,
1413
getCompletionsCycling = function ()
1514
require("copilot_cmp").setup()
@@ -33,6 +32,7 @@ end
3332

3433
M.setup = function(opts)
3534
local user_config = config_handler(opts)
35+
require("copilot.extensions.panel").create()
3636
vim.schedule(function () client.start(user_config) end)
3737
end
3838

lua/copilot/util.lua

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,5 @@
11
local M = {}
22

3-
local oldprint = print
4-
local print = function (args)
5-
if type(args) == "table" then
6-
oldprint(vim.inspect(args))
7-
else
8-
oldprint(args)
9-
end
10-
end
11-
123
local format_pos = function()
134
local pos = vim.api.nvim_win_get_cursor(0)
145
return { character = pos[2], line = pos[1] - 1 }
@@ -20,23 +11,10 @@ local get_relfile = function()
2011
end
2112

2213
M.find_copilot_client = function()
23-
for _, client in ipairs(vim.lsp.get_active_clients()) do
24-
if client.name == "copilot" then
25-
return client.id
26-
end
27-
end
14+
vim.lsp.get_active_clients({name="copilot"})
2815
end
2916

30-
M.find_copilot_buf_client = function()
31-
for _, client in ipairs(vim.lsp.buf_get_clients(0)) do
32-
if client.name == "copilot" then
33-
return client.id
34-
end
35-
end
36-
end
37-
38-
39-
M.get_completion_params = function(method)
17+
M.get_completion_params = function()
4018
local rel_path = get_relfile()
4119
local uri = vim.uri_from_bufnr(0)
4220
local params = {

0 commit comments

Comments
 (0)