Skip to content

Commit e87b231

Browse files
DanBradburyDanBradbury
authored andcommitted
initital push of copilot skeleton
1 parent cd7f010 commit e87b231

File tree

2 files changed

+236
-0
lines changed

2 files changed

+236
-0
lines changed

copilot_chat.vim

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
function! CopilotChat()
2+
" Open a new split window for the chat
3+
split
4+
enew
5+
setlocal buftype=nofile
6+
setlocal bufhidden=hide
7+
setlocal noswapfile
8+
setlocal nonumber
9+
setlocal norelativenumber
10+
setlocal wrap
11+
12+
" Set the buffer name to indicate it's a chat window
13+
file CopilotChat
14+
15+
" Add initial message
16+
call append(0, 'Welcome to Copilot Chat! Type your message below:')
17+
18+
" Move cursor to the end of the buffer
19+
normal! G
20+
endfunction
21+
22+
function! SubmitChatMessage()
23+
" Get the last line of the buffer (user's message)
24+
let l:message = getline('$')
25+
26+
" Call the CoPilot API to get a response
27+
let l:response = CopilotAPIRequest(l:message)
28+
29+
" Append the parsed response to the buffer
30+
call append(line('$'), 'Copilot: ' . l:response)
31+
32+
" Move cursor to the end of the buffer
33+
normal! G
34+
endfunction
35+
36+
function! GetBearerToken()
37+
" Replace with actual token setup and device registry logic
38+
let l:token_url = 'https://github.com/login/device/code'
39+
" headers = {
40+
" 'accept': 'application/json',
41+
" 'editor-version': 'Neovim/0.6.1',
42+
" 'editor-plugin-version': 'copilot.vim/1.16.0',
43+
" 'content-type': 'application/json',
44+
" 'user-agent': 'GithubCopilot/1.155.0',
45+
" 'accept-encoding': 'gzip,deflate,br'
46+
" }
47+
48+
let l:token_headers = [
49+
\ 'Accept: application/json',
50+
\ 'User-Agent: GithubCopilot/1.155.0',
51+
\ 'Accept-Encoding: gzip,deflate,br',
52+
\ 'Editor-Plugin-Version: copilot.vim/1.16.0',
53+
\ 'Editor-Version: Neovim/0.6.1',
54+
\ 'Content-Type: application/json',
55+
\ ]
56+
let l:token_data = json_encode({
57+
\ 'client_id': 'Iv1.b507a08c87ecfe98',
58+
\ 'scope': 'read:user'
59+
\ })
60+
61+
" Construct the curl command for token setup
62+
let l:curl_cmd = 'curl -s -X POST --compressed '
63+
for header in l:token_headers
64+
let l:curl_cmd .= '-H "' . header . '" '
65+
endfor
66+
let l:curl_cmd .= "-d '" . l:token_data . "' " . l:token_url
67+
echom l:curl_cmd
68+
69+
" Execute the curl command
70+
let l:response = system(l:curl_cmd)
71+
72+
" Check for errors in the response
73+
if v:shell_error != 0
74+
echom 'Error: ' . v:shell_error
75+
return ''
76+
endif
77+
78+
" Parse the response to get the device code and user code
79+
let l:json_response = json_decode(l:response)
80+
let l:device_code = l:json_response.device_code
81+
let l:user_code = l:json_response.user_code
82+
let l:verification_uri = l:json_response.verification_uri
83+
84+
" Display the user code and verification URI to the user
85+
echom 'Please visit ' . l:verification_uri . ' and enter the code: ' . l:user_code
86+
87+
" Wait for the user to complete the device verification
88+
sleep 30
89+
90+
" Poll the token endpoint to get the Bearer token
91+
let l:token_poll_url = 'https://github.com/login/oauth/access_token'
92+
let l:token_poll_data = json_encode({
93+
\ 'client_id': 'Iv1.b507a08c87ecfe98',
94+
\ 'device_code': l:device_code,
95+
\ 'grant_type': 'urn:ietf:params:oauth:grant-type:device_code'
96+
\ })
97+
98+
" Construct the curl command for token polling
99+
let l:curl_cmd = 'curl -s -X POST --compressed '
100+
for header in l:token_headers
101+
let l:curl_cmd .= '-H "' . header . '" '
102+
endfor
103+
let l:curl_cmd .= "-d '" . l:token_poll_data . "' " . l:token_poll_url
104+
105+
" Execute the curl command
106+
let l:response = system(l:curl_cmd)
107+
108+
" Check for errors in the response
109+
if v:shell_error != 0
110+
echom 'Error: ' . v:shell_error
111+
return ''
112+
endif
113+
114+
" Parse the response to get the Bearer token
115+
let l:json_response = json_decode(l:response)
116+
let l:bearer_token = l:json_response.access_token
117+
let $COPILOT_BEARER_TOKEN = l:bearer_token
118+
119+
" Return the Bearer token
120+
return l:bearer_token
121+
endfunction
122+
123+
function! GetChatToken()
124+
let l:token_url = 'https://api.github.com/copilot_internal/v2/token'
125+
let l:token_headers = [
126+
\ 'Content-Type: application/json',
127+
\ 'Editor-Version: vscode/1.80.1',
128+
\ 'Authorization: token ' . $COPILOT_BEARER_TOKEN,
129+
\ ]
130+
let l:token_data = json_encode({
131+
\ 'client_id': 'Iv1.b507a08c87ecfe98',
132+
\ 'scope': 'read:user'
133+
\ })
134+
135+
" Construct the curl command for token setup
136+
let l:curl_cmd = 'curl -s -X GET '
137+
for header in l:token_headers
138+
let l:curl_cmd .= '-H "' . header . '" '
139+
endfor
140+
let l:curl_cmd .= "-d '" . l:token_data . "' " . l:token_url
141+
142+
" Execute the curl command
143+
let l:response = system(l:curl_cmd)
144+
echom l:response
145+
146+
" Check for errors in the response
147+
if v:shell_error != 0
148+
echom 'Error: ' . v:shell_error
149+
return ''
150+
endif
151+
152+
" Parse the response to get the device code and user code
153+
let l:json_response = json_decode(l:response)
154+
return l:json_response.token
155+
endfunction
156+
157+
function! CopilotAPIRequest(message)
158+
" Replace with actual API call logic
159+
let l:url = 'https://api.githubcopilot.com/chat/completions'
160+
if exists('$COPILOT_BEARER_TOKEN')
161+
let l:bearer_token = $COPILOT_BEARER_TOKEN
162+
else
163+
let l:bearer_token = GetBearerToken()
164+
endif
165+
166+
let l:chat_token = GetChatToken()
167+
let l:headers = [
168+
\ 'Content-Type: application/json',
169+
\ 'Authorization: Bearer ' . l:chat_token,
170+
\ 'Editor-Version: vscode/1.80.1'
171+
\ ]
172+
let l:messages = [{'content': a:message, 'role': 'user'}]
173+
let l:data = json_encode({
174+
\ 'intent': v:false,
175+
\ 'model': 'gpt-4o',
176+
\ 'temperature': 0,
177+
\ 'top_p': 1,
178+
\ 'n': 1,
179+
\ 'stream': v:true,
180+
\ 'messages': l:messages
181+
\ })
182+
183+
" Construct the curl command as a single string
184+
let l:curl_cmd = 'curl -s -X POST '
185+
for header in l:headers
186+
let l:curl_cmd .= '-H "' . header . '" '
187+
endfor
188+
let l:curl_cmd .= "-d '" . l:data . "' " . l:url
189+
190+
" Print the curl command for debugging
191+
echom l:curl_cmd
192+
193+
" Execute the curl command
194+
let l:response = system(l:curl_cmd)
195+
196+
" Print the raw response for debugging
197+
echom 'Response: ' . l:response
198+
199+
" Check for errors in the response
200+
if v:shell_error != 0
201+
echom 'Error: ' . v:shell_error
202+
return 'Error: ' . l:response
203+
endif
204+
205+
" Parse the response
206+
let l:result = ''
207+
let l:resp_text_lines = split(l:response, "\n")
208+
for line in l:resp_text_lines
209+
if line =~ '^data: {'
210+
let l:json_completion = json_decode(line[6:])
211+
try
212+
let l:result .= l:json_completion.choices[0].delta.content
213+
catch
214+
let l:result .= '\\n'
215+
endtry
216+
endif
217+
endfor
218+
219+
" Return the parsed response
220+
return l:result
221+
endfunction
222+
223+
" Map the command to open the chat
224+
command! CopilotChat call CopilotChat()
225+
226+
" Map the command to submit a chat message
227+
command! SubmitChatMessage call SubmitChatMessage()
228+
229+
" Add key mapping to submit chat message
230+
nnoremap <buffer> <leader>cs :SubmitChatMessage<CR>

plugin/copilot.vim

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,9 @@ let s:dir = expand('<sfile>:h:h')
112112
if getftime(s:dir . '/doc/copilot.txt') > getftime(s:dir . '/doc/tags')
113113
silent! execute 'helptags' fnameescape(s:dir . '/doc')
114114
endif
115+
116+
" Source the copilot_chat.vim file
117+
source /Users/bradbd/Documents/Github/copilot.vim/copilot_chat.vim
118+
119+
" Add key mapping to open Copilot Chat
120+
nnoremap <leader>cc :CopilotChat<CR>

0 commit comments

Comments
 (0)