Skip to content

Commit e4293f3

Browse files
authored
feat: added signin support (#7)
1 parent bbdb662 commit e4293f3

File tree

3 files changed

+137
-3
lines changed

3 files changed

+137
-3
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
### To Do
1616

17-
- Sign In Flow
17+
- [x] Sign In Flow
1818
- Status Notification
1919

2020
## Usage

lsp/copilot.lua

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
local version = vim.version()
2+
13
---@type vim.lsp.Config
24
return {
35
--NOTE: This name means that existing blink completion works
@@ -7,8 +9,10 @@ return {
79
"--stdio",
810
},
911
init_options = {
10-
--TODO: Grab versions from the editor
11-
editorInfo = { name = "neovim", version = "0.11" },
12+
editorInfo = {
13+
name = "neovim",
14+
version = string.format("%d.%d.%d", version.major, version.minor, version.patch),
15+
},
1216
editorPluginInfo = {
1317
name = "Github Copilot LSP for Neovim",
1418
version = "0.0.1",
@@ -19,6 +23,11 @@ return {
1923
enabled = true,
2024
},
2125
},
26+
handlers = setmetatable({}, {
27+
__index = function(_, method)
28+
return require("copilot-lsp.handlers")[method]
29+
end,
30+
}),
2231
root_dir = vim.uv.cwd(),
2332
on_init = function(client)
2433
vim.api.nvim_set_hl(0, "NesAdd", { link = "DiffAdd", default = true })

lua/copilot-lsp/handlers.lua

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
---@type table<string, lsp.Handler>
2+
local M = {}
3+
4+
local methods = {
5+
signIn = "signIn",
6+
didChangeStatus = "didChangeStatus",
7+
}
8+
9+
-- copy from copilot.lua
10+
local function open_signin_popup(code, url)
11+
local lines = {
12+
" [Copilot-lsp] ",
13+
"",
14+
" First copy your one-time code: ",
15+
" " .. code .. " ",
16+
" In your browser, visit: ",
17+
" " .. url .. " ",
18+
"",
19+
" ...waiting, it might take a while and ",
20+
" this popup will auto close once done... ",
21+
}
22+
local height, width = #lines, math.max(unpack(vim.tbl_map(function(line)
23+
return #line
24+
end, lines)))
25+
26+
local bufnr = vim.api.nvim_create_buf(false, true)
27+
vim.bo[bufnr].buflisted = false
28+
vim.bo[bufnr].buftype = "nofile"
29+
vim.bo[bufnr].bufhidden = "wipe"
30+
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
31+
32+
local winnr = vim.api.nvim_open_win(bufnr, true, {
33+
relative = "editor",
34+
style = "minimal",
35+
border = "single",
36+
row = (vim.o.lines - height) / 2,
37+
col = (vim.o.columns - width) / 2,
38+
height = height,
39+
width = width,
40+
})
41+
vim.wo[winnr].winhighlight = "Normal:Normal"
42+
vim.wo[winnr].winblend = 0
43+
44+
return function()
45+
vim.api.nvim_win_close(winnr, true)
46+
end
47+
end
48+
49+
local function copy_to_clipboard(s)
50+
vim.fn.setreg("+", s)
51+
vim.fn.setreg("*", s)
52+
end
53+
54+
---@param res {command: lsp.Command, userCode: string, verificationUri: string}
55+
M[methods.signIn] = function(err, res, ctx)
56+
if err then
57+
vim.notify("[copilot-lsp] failed to start signin flow: " .. vim.inspect(err), vim.log.levels.ERROR)
58+
return
59+
end
60+
61+
local client = vim.lsp.get_client_by_id(ctx.client_id)
62+
if not client then
63+
return
64+
end
65+
66+
vim.g.copilot_lsp_signin_pending = true
67+
68+
local close_signin_popup = open_signin_popup(res.userCode, res.verificationUri)
69+
copy_to_clipboard(res.userCode)
70+
71+
client:exec_cmd(
72+
res.command,
73+
{ bufnr = ctx.bufnr },
74+
75+
---@param cmd_res {status: string, user: string}
76+
function(cmd_err, cmd_res)
77+
vim.g.copilot_lsp_signin_pending = nil
78+
close_signin_popup()
79+
80+
if cmd_err then
81+
vim.notify("[copilot-lsp] failed to open browser: " .. vim.inspect(cmd_err), vim.log.levels.WARN)
82+
return
83+
end
84+
if cmd_res.status == "OK" then
85+
vim.notify("[copilot-lsp] successfully signed in as: " .. cmd_res.user, vim.log.levels.INFO)
86+
else
87+
vim.notify("[copilot-lsp] failed to sign in: " .. vim.inspect(cmd_res), vim.log.levels.ERROR)
88+
end
89+
end
90+
)
91+
end
92+
93+
---@param client_id integer
94+
---@param bufnr integer
95+
local function sign_in(client_id, bufnr)
96+
if vim.g.copilot_lsp_signin_pending then
97+
return
98+
end
99+
100+
local client = vim.lsp.get_client_by_id(client_id)
101+
if not client then
102+
return
103+
end
104+
105+
for _, req in pairs(client.requests) do
106+
if req.method == methods.signIn and req.type == "pending" then
107+
return
108+
end
109+
end
110+
111+
client:request(methods.signIn, vim.empty_dict(), nil, bufnr)
112+
end
113+
114+
---@param res {busy: boolean, kind: 'Normal'|'Error'|'Warning'|'Incative', message: string}
115+
M["didChangeStatus"] = function(err, res, ctx)
116+
if err then
117+
return
118+
end
119+
-- real error message: You are not signed into GitHub. Please sign in to use Copilot.
120+
if res.kind == "Error" and res.message:find("not signed into") then
121+
sign_in(ctx.client_id, ctx.bufnr)
122+
end
123+
end
124+
125+
return M

0 commit comments

Comments
 (0)