mirror of
https://github.com/amix/vimrc
synced 2024-11-24 12:43:03 +00:00
Added the copilot.vim to sources_non_forked
This commit is contained in:
parent
4fa0cde32e
commit
e6f509e6e1
33 changed files with 203319 additions and 0 deletions
2
sources_non_forked/copilot.vim/.gitattributes
vendored
Normal file
2
sources_non_forked/copilot.vim/.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
*.vim eol=lf
|
||||||
|
/dist/** -whitespace -diff
|
1
sources_non_forked/copilot.vim/.github/pull_request_template.md
vendored
Normal file
1
sources_non_forked/copilot.vim/.github/pull_request_template.md
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
At the moment we are not accepting contributions to the repository.
|
1
sources_non_forked/copilot.vim/.gitignore
vendored
Normal file
1
sources_non_forked/copilot.vim/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/doc/tags
|
4
sources_non_forked/copilot.vim/LICENSE.md
Normal file
4
sources_non_forked/copilot.vim/LICENSE.md
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
GitHub Copilot is offered under the [GitHub Terms of
|
||||||
|
Service](https://docs.github.com/en/site-policy/github-terms/github-terms-for-additional-products-and-features#github-copilot).
|
||||||
|
|
||||||
|
Copyright (C) 2023 GitHub, Inc. - All Rights Reserved.
|
64
sources_non_forked/copilot.vim/README.md
Normal file
64
sources_non_forked/copilot.vim/README.md
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
# Copilot.vim
|
||||||
|
|
||||||
|
GitHub Copilot uses OpenAI Codex to suggest code and entire functions in
|
||||||
|
real-time right from your editor. Trained on billions of lines of public
|
||||||
|
code, GitHub Copilot turns natural language prompts including comments and
|
||||||
|
method names into coding suggestions across dozens of languages.
|
||||||
|
|
||||||
|
Copilot.vim is a Vim/Neovim plugin for GitHub Copilot.
|
||||||
|
|
||||||
|
To learn more, visit
|
||||||
|
[https://github.com/features/copilot](https://github.com/features/copilot).
|
||||||
|
|
||||||
|
## Subscription
|
||||||
|
|
||||||
|
GitHub Copilot requires a subscription. It is free for verified students and
|
||||||
|
maintainers of popular open source projects on GitHub.
|
||||||
|
|
||||||
|
GitHub Copilot is subject to the [GitHub Additional Product
|
||||||
|
Terms](https://docs.github.com/en/site-policy/github-terms/github-terms-for-additional-products-and-features).
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
1. Install [Neovim][] or the latest patch of [Vim][] (9.0.0185 or newer).
|
||||||
|
|
||||||
|
2. Install [Node.js][].
|
||||||
|
|
||||||
|
3. Install `github/copilot.vim` using vim-plug, packer.nvim, or any other
|
||||||
|
plugin manager. Or to install manually, run one of the following
|
||||||
|
commands:
|
||||||
|
|
||||||
|
* Vim, Linux/macOS:
|
||||||
|
|
||||||
|
git clone https://github.com/github/copilot.vim.git \
|
||||||
|
~/.vim/pack/github/start/copilot.vim
|
||||||
|
|
||||||
|
* Neovim, Linux/macOS:
|
||||||
|
|
||||||
|
git clone https://github.com/github/copilot.vim.git \
|
||||||
|
~/.config/nvim/pack/github/start/copilot.vim
|
||||||
|
|
||||||
|
* Vim, Windows (PowerShell command):
|
||||||
|
|
||||||
|
git clone https://github.com/github/copilot.vim.git `
|
||||||
|
$HOME/vimfiles/pack/github/start/copilot.vim
|
||||||
|
|
||||||
|
* Neovim, Windows (PowerShell command):
|
||||||
|
|
||||||
|
git clone https://github.com/github/copilot.vim.git `
|
||||||
|
$HOME/AppData/Local/nvim/pack/github/start/copilot.vim
|
||||||
|
|
||||||
|
4. Start Neovim and invoke `:Copilot setup`.
|
||||||
|
|
||||||
|
[Node.js]: https://nodejs.org/en/download/
|
||||||
|
[Neovim]: https://github.com/neovim/neovim/releases/latest
|
||||||
|
[Vim]: https://github.com/vim/vim
|
||||||
|
|
||||||
|
Suggestions are displayed inline and can be accepted by pressing the tab key.
|
||||||
|
See `:help copilot` for more information.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
We’d love to get your help in making GitHub Copilot better! If you have
|
||||||
|
feedback or encounter any problems, please reach out on our [Feedback
|
||||||
|
forum](https://github.com/orgs/community/discussions/categories/copilot).
|
4
sources_non_forked/copilot.vim/SECURITY.md
Normal file
4
sources_non_forked/copilot.vim/SECURITY.md
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
If you discover a security issue in this repo, please submit it through the
|
||||||
|
[GitHub Security Bug Bounty](https://hackerone.com/github).
|
||||||
|
|
||||||
|
Thanks for helping make GitHub Copilot safe for everyone.
|
818
sources_non_forked/copilot.vim/autoload/copilot.vim
Normal file
818
sources_non_forked/copilot.vim/autoload/copilot.vim
Normal file
|
@ -0,0 +1,818 @@
|
||||||
|
if exists('g:autoloaded_copilot')
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
let g:autoloaded_copilot = 1
|
||||||
|
|
||||||
|
scriptencoding utf-8
|
||||||
|
|
||||||
|
let s:has_nvim_ghost_text = has('nvim-0.6') && exists('*nvim_buf_get_mark')
|
||||||
|
let s:vim_minimum_version = '9.0.0185'
|
||||||
|
let s:has_vim_ghost_text = has('patch-' . s:vim_minimum_version) && has('textprop')
|
||||||
|
let s:has_ghost_text = s:has_nvim_ghost_text || s:has_vim_ghost_text
|
||||||
|
|
||||||
|
let s:hlgroup = 'CopilotSuggestion'
|
||||||
|
let s:annot_hlgroup = 'CopilotAnnotation'
|
||||||
|
|
||||||
|
if s:has_vim_ghost_text && empty(prop_type_get(s:hlgroup))
|
||||||
|
call prop_type_add(s:hlgroup, {'highlight': s:hlgroup})
|
||||||
|
endif
|
||||||
|
if s:has_vim_ghost_text && empty(prop_type_get(s:annot_hlgroup))
|
||||||
|
call prop_type_add(s:annot_hlgroup, {'highlight': s:annot_hlgroup})
|
||||||
|
endif
|
||||||
|
|
||||||
|
function! s:Echo(msg) abort
|
||||||
|
if has('nvim') && &cmdheight == 0
|
||||||
|
call v:lua.vim.notify(a:msg, v:null, {'title': 'GitHub Copilot'})
|
||||||
|
else
|
||||||
|
echo a:msg
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:EditorConfiguration() abort
|
||||||
|
let filetypes = copy(s:filetype_defaults)
|
||||||
|
if type(get(g:, 'copilot_filetypes')) == v:t_dict
|
||||||
|
call extend(filetypes, g:copilot_filetypes)
|
||||||
|
endif
|
||||||
|
return {
|
||||||
|
\ 'enableAutoCompletions': empty(get(g:, 'copilot_enabled', 1)) ? v:false : v:true,
|
||||||
|
\ 'disabledLanguages': map(sort(keys(filter(filetypes, { k, v -> empty(v) }))), { _, v -> {'languageId': v}}),
|
||||||
|
\ }
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:StatusNotification(params, ...) abort
|
||||||
|
let status = get(a:params, 'status', '')
|
||||||
|
if status ==? 'error'
|
||||||
|
let s:agent_error = a:params.message
|
||||||
|
else
|
||||||
|
unlet! s:agent_error
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#Init(...) abort
|
||||||
|
call timer_start(0, { _ -> s:Start() })
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:Running() abort
|
||||||
|
return exists('s:agent.job') || exists('s:agent.client_id')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:Start() abort
|
||||||
|
if s:Running()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let s:agent = copilot#agent#New({'methods': {
|
||||||
|
\ 'statusNotification': function('s:StatusNotification'),
|
||||||
|
\ 'PanelSolution': function('copilot#panel#Solution'),
|
||||||
|
\ 'PanelSolutionsDone': function('copilot#panel#SolutionsDone'),
|
||||||
|
\ 'copilot/openURL': function('s:OpenURL'),
|
||||||
|
\ },
|
||||||
|
\ 'editorConfiguration' : s:EditorConfiguration()})
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:Stop() abort
|
||||||
|
if exists('s:agent')
|
||||||
|
let agent = remove(s:, 'agent')
|
||||||
|
call agent.Close()
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#Agent() abort
|
||||||
|
call s:Start()
|
||||||
|
return s:agent
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#RunningAgent() abort
|
||||||
|
if s:Running()
|
||||||
|
return s:agent
|
||||||
|
else
|
||||||
|
return v:null
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:NodeVersionWarning() abort
|
||||||
|
if exists('s:agent.node_version') && s:agent.node_version =~# '^16\.'
|
||||||
|
echohl WarningMsg
|
||||||
|
echo "Warning: Node.js 16 is approaching end of life and support will be dropped in a future release of copilot.vim."
|
||||||
|
echohl NONE
|
||||||
|
elseif exists('s:agent.node_version_warning')
|
||||||
|
echohl WarningMsg
|
||||||
|
echo 'Warning:' s:agent.node_version_warning
|
||||||
|
echohl NONE
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#Request(method, params, ...) abort
|
||||||
|
let agent = copilot#Agent()
|
||||||
|
return call(agent.Request, [a:method, a:params] + a:000)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#Call(method, params, ...) abort
|
||||||
|
let agent = copilot#Agent()
|
||||||
|
return call(agent.Call, [a:method, a:params] + a:000)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#Notify(method, params, ...) abort
|
||||||
|
let agent = copilot#Agent()
|
||||||
|
return call(agent.Notify, [a:method, a:params] + a:000)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#NvimNs() abort
|
||||||
|
return nvim_create_namespace('github-copilot')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#Clear() abort
|
||||||
|
if exists('g:_copilot_timer')
|
||||||
|
call timer_stop(remove(g:, '_copilot_timer'))
|
||||||
|
endif
|
||||||
|
if exists('b:_copilot')
|
||||||
|
call copilot#agent#Cancel(get(b:_copilot, 'first', {}))
|
||||||
|
call copilot#agent#Cancel(get(b:_copilot, 'cycling', {}))
|
||||||
|
endif
|
||||||
|
call s:UpdatePreview()
|
||||||
|
unlet! b:_copilot
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:Reject(bufnr) abort
|
||||||
|
try
|
||||||
|
let dict = getbufvar(a:bufnr, '_copilot')
|
||||||
|
if type(dict) == v:t_dict && !empty(get(dict, 'shown_choices', {}))
|
||||||
|
call copilot#Request('notifyRejected', {'uuids': keys(dict.shown_choices)})
|
||||||
|
let dict.shown_choices = {}
|
||||||
|
endif
|
||||||
|
catch
|
||||||
|
call copilot#logger#Exception()
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#Dismiss() abort
|
||||||
|
call s:Reject('%')
|
||||||
|
call copilot#Clear()
|
||||||
|
call s:UpdatePreview()
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
let s:filetype_defaults = {
|
||||||
|
\ 'yaml': 0,
|
||||||
|
\ 'markdown': 0,
|
||||||
|
\ 'help': 0,
|
||||||
|
\ 'gitcommit': 0,
|
||||||
|
\ 'gitrebase': 0,
|
||||||
|
\ 'hgcommit': 0,
|
||||||
|
\ 'svn': 0,
|
||||||
|
\ 'cvs': 0,
|
||||||
|
\ '.': 0}
|
||||||
|
|
||||||
|
function! s:BufferDisabled() abort
|
||||||
|
if &buftype =~# '^\%(help\|prompt\|quickfix\|terminal\)$'
|
||||||
|
return 5
|
||||||
|
endif
|
||||||
|
if exists('b:copilot_disabled')
|
||||||
|
return empty(b:copilot_disabled) ? 0 : 3
|
||||||
|
endif
|
||||||
|
if exists('b:copilot_enabled')
|
||||||
|
return empty(b:copilot_enabled) ? 4 : 0
|
||||||
|
endif
|
||||||
|
let short = empty(&l:filetype) ? '.' : split(&l:filetype, '\.', 1)[0]
|
||||||
|
let config = {}
|
||||||
|
if type(get(g:, 'copilot_filetypes')) == v:t_dict
|
||||||
|
let config = g:copilot_filetypes
|
||||||
|
endif
|
||||||
|
if has_key(config, &l:filetype)
|
||||||
|
return empty(config[&l:filetype])
|
||||||
|
elseif has_key(config, short)
|
||||||
|
return empty(config[short])
|
||||||
|
elseif has_key(config, '*')
|
||||||
|
return empty(config['*'])
|
||||||
|
else
|
||||||
|
return get(s:filetype_defaults, short, 1) == 0 ? 2 : 0
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#Enabled() abort
|
||||||
|
return get(g:, 'copilot_enabled', 1)
|
||||||
|
\ && empty(s:BufferDisabled())
|
||||||
|
\ && empty(copilot#Agent().StartupError())
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#Complete(...) abort
|
||||||
|
if exists('g:_copilot_timer')
|
||||||
|
call timer_stop(remove(g:, '_copilot_timer'))
|
||||||
|
endif
|
||||||
|
let params = copilot#doc#Params()
|
||||||
|
if !exists('b:_copilot.params') || b:_copilot.params !=# params
|
||||||
|
let b:_copilot = {'params': params, 'first':
|
||||||
|
\ copilot#Request('getCompletions', params)}
|
||||||
|
let g:_copilot_last = b:_copilot
|
||||||
|
endif
|
||||||
|
let completion = b:_copilot.first
|
||||||
|
if !a:0
|
||||||
|
return completion.Await()
|
||||||
|
else
|
||||||
|
call copilot#agent#Result(completion, a:1)
|
||||||
|
if a:0 > 1
|
||||||
|
call copilot#agent#Error(completion, a:2)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:HideDuringCompletion() abort
|
||||||
|
return get(g:, 'copilot_hide_during_completion', 1)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:SuggestionTextWithAdjustments() abort
|
||||||
|
try
|
||||||
|
if mode() !~# '^[iR]' || (s:HideDuringCompletion() && pumvisible()) || !exists('b:_copilot.suggestions')
|
||||||
|
return ['', 0, 0, '']
|
||||||
|
endif
|
||||||
|
let choice = get(b:_copilot.suggestions, b:_copilot.choice, {})
|
||||||
|
if !has_key(choice, 'range') || choice.range.start.line != line('.') - 1 || type(choice.text) !=# v:t_string
|
||||||
|
return ['', 0, 0, '']
|
||||||
|
endif
|
||||||
|
let line = getline('.')
|
||||||
|
let offset = col('.') - 1
|
||||||
|
let choice_text = strpart(line, 0, copilot#doc#UTF16ToByteIdx(line, choice.range.start.character)) . choice.text
|
||||||
|
let typed = strpart(line, 0, offset)
|
||||||
|
let end_offset = copilot#doc#UTF16ToByteIdx(line, choice.range.end.character)
|
||||||
|
if end_offset < 0
|
||||||
|
let end_offset = len(line)
|
||||||
|
endif
|
||||||
|
let delete = strpart(line, offset, end_offset - offset)
|
||||||
|
let uuid = get(choice, 'uuid', '')
|
||||||
|
if typed =~# '^\s*$'
|
||||||
|
let leading = matchstr(choice_text, '^\s\+')
|
||||||
|
let unindented = strpart(choice_text, len(leading))
|
||||||
|
if strpart(typed, 0, len(leading)) == leading && unindented !=# delete
|
||||||
|
return [unindented, len(typed) - len(leading), strchars(delete), uuid]
|
||||||
|
endif
|
||||||
|
elseif typed ==# strpart(choice_text, 0, offset)
|
||||||
|
return [strpart(choice_text, offset), 0, strchars(delete), uuid]
|
||||||
|
endif
|
||||||
|
catch
|
||||||
|
call copilot#logger#Exception()
|
||||||
|
endtry
|
||||||
|
return ['', 0, 0, '']
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
|
||||||
|
function! s:Advance(count, context, ...) abort
|
||||||
|
if a:context isnot# get(b:, '_copilot', {})
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let a:context.choice += a:count
|
||||||
|
if a:context.choice < 0
|
||||||
|
let a:context.choice += len(a:context.suggestions)
|
||||||
|
endif
|
||||||
|
let a:context.choice %= len(a:context.suggestions)
|
||||||
|
call s:UpdatePreview()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:GetSuggestionsCyclingCallback(context, result) abort
|
||||||
|
let callbacks = remove(a:context, 'cycling_callbacks')
|
||||||
|
let seen = {}
|
||||||
|
for suggestion in a:context.suggestions
|
||||||
|
let seen[suggestion.text] = 1
|
||||||
|
endfor
|
||||||
|
for suggestion in get(a:result, 'completions', [])
|
||||||
|
if !has_key(seen, suggestion.text)
|
||||||
|
call add(a:context.suggestions, suggestion)
|
||||||
|
let seen[suggestion.text] = 1
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
for Callback in callbacks
|
||||||
|
call Callback(a:context)
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:GetSuggestionsCycling(callback) abort
|
||||||
|
if exists('b:_copilot.cycling_callbacks')
|
||||||
|
call add(b:_copilot.cycling_callbacks, a:callback)
|
||||||
|
elseif exists('b:_copilot.cycling')
|
||||||
|
call a:callback(b:_copilot)
|
||||||
|
elseif exists('b:_copilot.suggestions')
|
||||||
|
let b:_copilot.cycling_callbacks = [a:callback]
|
||||||
|
let b:_copilot.cycling = copilot#Request('getCompletionsCycling',
|
||||||
|
\ b:_copilot.first.params,
|
||||||
|
\ function('s:GetSuggestionsCyclingCallback', [b:_copilot]),
|
||||||
|
\ function('s:GetSuggestionsCyclingCallback', [b:_copilot]),
|
||||||
|
\ )
|
||||||
|
call s:UpdatePreview()
|
||||||
|
endif
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#Next() abort
|
||||||
|
return s:GetSuggestionsCycling(function('s:Advance', [1]))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#Previous() abort
|
||||||
|
return s:GetSuggestionsCycling(function('s:Advance', [-1]))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#GetDisplayedSuggestion() abort
|
||||||
|
let [text, outdent, delete, uuid] = s:SuggestionTextWithAdjustments()
|
||||||
|
|
||||||
|
return {
|
||||||
|
\ 'uuid': uuid,
|
||||||
|
\ 'text': text,
|
||||||
|
\ 'outdentSize': outdent,
|
||||||
|
\ 'deleteSize': delete}
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:ClearPreview() abort
|
||||||
|
if s:has_nvim_ghost_text
|
||||||
|
call nvim_buf_del_extmark(0, copilot#NvimNs(), 1)
|
||||||
|
elseif s:has_vim_ghost_text
|
||||||
|
call prop_remove({'type': s:hlgroup, 'all': v:true})
|
||||||
|
call prop_remove({'type': s:annot_hlgroup, 'all': v:true})
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:UpdatePreview() abort
|
||||||
|
try
|
||||||
|
let [text, outdent, delete, uuid] = s:SuggestionTextWithAdjustments()
|
||||||
|
let text = split(text, "\n", 1)
|
||||||
|
if empty(text[-1])
|
||||||
|
call remove(text, -1)
|
||||||
|
endif
|
||||||
|
if empty(text) || !s:has_ghost_text
|
||||||
|
return s:ClearPreview()
|
||||||
|
endif
|
||||||
|
if exists('b:_copilot.cycling_callbacks')
|
||||||
|
let annot = '(1/…)'
|
||||||
|
elseif exists('b:_copilot.cycling')
|
||||||
|
let annot = '(' . (b:_copilot.choice + 1) . '/' . len(b:_copilot.suggestions) . ')'
|
||||||
|
else
|
||||||
|
let annot = ''
|
||||||
|
endif
|
||||||
|
call s:ClearPreview()
|
||||||
|
if s:has_nvim_ghost_text
|
||||||
|
let data = {'id': 1}
|
||||||
|
let data.virt_text_win_col = virtcol('.') - 1
|
||||||
|
let append = strpart(getline('.'), col('.') - 1 + delete)
|
||||||
|
let data.virt_text = [[text[0] . append . repeat(' ', delete - len(text[0])), s:hlgroup]]
|
||||||
|
if len(text) > 1
|
||||||
|
let data.virt_lines = map(text[1:-1], { _, l -> [[l, s:hlgroup]] })
|
||||||
|
if !empty(annot)
|
||||||
|
let data.virt_lines[-1] += [[' '], [annot, s:annot_hlgroup]]
|
||||||
|
endif
|
||||||
|
elseif len(annot)
|
||||||
|
let data.virt_text += [[' '], [annot, s:annot_hlgroup]]
|
||||||
|
endif
|
||||||
|
let data.hl_mode = 'combine'
|
||||||
|
call nvim_buf_set_extmark(0, copilot#NvimNs(), line('.')-1, col('.')-1, data)
|
||||||
|
else
|
||||||
|
call prop_add(line('.'), col('.'), {'type': s:hlgroup, 'text': text[0]})
|
||||||
|
for line in text[1:]
|
||||||
|
call prop_add(line('.'), 0, {'type': s:hlgroup, 'text_align': 'below', 'text': line})
|
||||||
|
endfor
|
||||||
|
if !empty(annot)
|
||||||
|
call prop_add(line('.'), col('$'), {'type': s:annot_hlgroup, 'text': ' ' . annot})
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
if !has_key(b:_copilot.shown_choices, uuid)
|
||||||
|
let b:_copilot.shown_choices[uuid] = v:true
|
||||||
|
call copilot#Request('notifyShown', {'uuid': uuid})
|
||||||
|
endif
|
||||||
|
catch
|
||||||
|
return copilot#logger#Exception()
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:HandleTriggerResult(result) abort
|
||||||
|
if !exists('b:_copilot')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let b:_copilot.suggestions = get(a:result, 'completions', [])
|
||||||
|
let b:_copilot.choice = 0
|
||||||
|
let b:_copilot.shown_choices = {}
|
||||||
|
call s:UpdatePreview()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#Suggest() abort
|
||||||
|
try
|
||||||
|
call copilot#Complete(function('s:HandleTriggerResult'), function('s:HandleTriggerResult'))
|
||||||
|
catch
|
||||||
|
call copilot#logger#Exception()
|
||||||
|
endtry
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:Trigger(bufnr, timer) abort
|
||||||
|
let timer = get(g:, '_copilot_timer', -1)
|
||||||
|
unlet! g:_copilot_timer
|
||||||
|
if a:bufnr !=# bufnr('') || a:timer isnot# timer || mode() !=# 'i'
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
return copilot#Suggest()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#IsMapped() abort
|
||||||
|
return get(g:, 'copilot_assume_mapped') ||
|
||||||
|
\ hasmapto('copilot#Accept(', 'i')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#Schedule(...) abort
|
||||||
|
if !s:has_ghost_text || !copilot#Enabled() || !copilot#IsMapped()
|
||||||
|
call copilot#Clear()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
call s:UpdatePreview()
|
||||||
|
let delay = a:0 ? a:1 : get(g:, 'copilot_idle_delay', 15)
|
||||||
|
let g:_copilot_timer = timer_start(delay, function('s:Trigger', [bufnr('')]))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#OnInsertLeave() abort
|
||||||
|
return copilot#Clear()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#OnInsertEnter() abort
|
||||||
|
return copilot#Schedule()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#OnCompleteChanged() abort
|
||||||
|
if s:HideDuringCompletion()
|
||||||
|
return copilot#Clear()
|
||||||
|
else
|
||||||
|
return copilot#Schedule()
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#OnCursorMovedI() abort
|
||||||
|
return copilot#Schedule()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#OnBufUnload() abort
|
||||||
|
call s:Reject(+expand('<abuf>'))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#OnVimLeavePre() abort
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#TextQueuedForInsertion() abort
|
||||||
|
try
|
||||||
|
return remove(s:, 'suggestion_text')
|
||||||
|
catch
|
||||||
|
return ''
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#Accept(...) abort
|
||||||
|
let s = copilot#GetDisplayedSuggestion()
|
||||||
|
if !empty(s.text)
|
||||||
|
unlet! b:_copilot
|
||||||
|
let text = ''
|
||||||
|
if a:0 > 1
|
||||||
|
let text = substitute(matchstr(s.text, "\n*" . '\%(' . a:2 .'\)'), "\n*$", '', '')
|
||||||
|
endif
|
||||||
|
if empty(text)
|
||||||
|
let text = s.text
|
||||||
|
endif
|
||||||
|
call copilot#Request('notifyAccepted', {'uuid': s.uuid, 'acceptedLength': copilot#doc#UTF16Width(text)})
|
||||||
|
call s:ClearPreview()
|
||||||
|
let s:suggestion_text = text
|
||||||
|
return repeat("\<Left>\<Del>", s.outdentSize) . repeat("\<Del>", s.deleteSize) .
|
||||||
|
\ "\<C-R>\<C-O>=copilot#TextQueuedForInsertion()\<CR>" . (a:0 > 1 ? '' : "\<End>")
|
||||||
|
endif
|
||||||
|
let default = get(g:, 'copilot_tab_fallback', pumvisible() ? "\<C-N>" : "\t")
|
||||||
|
if !a:0
|
||||||
|
return default
|
||||||
|
elseif type(a:1) == v:t_string
|
||||||
|
return a:1
|
||||||
|
elseif type(a:1) == v:t_func
|
||||||
|
try
|
||||||
|
return call(a:1, [])
|
||||||
|
catch
|
||||||
|
return default
|
||||||
|
endtry
|
||||||
|
else
|
||||||
|
return default
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#AcceptWord(...) abort
|
||||||
|
return copilot#Accept(a:0 ? a:1 : '', '\%(\k\@!.\)*\k*')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#AcceptLine(...) abort
|
||||||
|
return copilot#Accept(a:0 ? a:1 : "\r", "[^\n]\\+")
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:BrowserCallback(into, code) abort
|
||||||
|
let a:into.code = a:code
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#Browser() abort
|
||||||
|
if type(get(g:, 'copilot_browser')) == v:t_list
|
||||||
|
let cmd = copy(g:copilot_browser)
|
||||||
|
elseif type(get(g:, 'open_command')) == v:t_list
|
||||||
|
let cmd = copy(g:open_command)
|
||||||
|
elseif has('win32')
|
||||||
|
let cmd = ['rundll32', 'url.dll,FileProtocolHandler']
|
||||||
|
elseif has('mac')
|
||||||
|
let cmd = ['open']
|
||||||
|
elseif executable('wslview')
|
||||||
|
return ['wslview']
|
||||||
|
elseif executable('xdg-open')
|
||||||
|
return ['xdg-open']
|
||||||
|
else
|
||||||
|
return []
|
||||||
|
endif
|
||||||
|
if executable(get(cmd, 0, ''))
|
||||||
|
return cmd
|
||||||
|
else
|
||||||
|
return []
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:OpenURL(params) abort
|
||||||
|
echo a:params.target
|
||||||
|
let browser = copilot#Browser()
|
||||||
|
if empty(browser)
|
||||||
|
return v:false
|
||||||
|
endif
|
||||||
|
let status = {}
|
||||||
|
call copilot#job#Stream(browser + [a:params.target], v:null, v:null, function('s:BrowserCallback', [status]))
|
||||||
|
let time = reltime()
|
||||||
|
while empty(status) && reltimefloat(reltime(time)) < 1
|
||||||
|
sleep 10m
|
||||||
|
endwhile
|
||||||
|
return get(status, 'code') ? v:false : v:true
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
let s:commands = {}
|
||||||
|
|
||||||
|
function! s:EnabledStatusMessage() abort
|
||||||
|
let buf_disabled = s:BufferDisabled()
|
||||||
|
if !s:has_ghost_text
|
||||||
|
if has('nvim')
|
||||||
|
return "Neovim 0.6 required to support ghost text"
|
||||||
|
else
|
||||||
|
return "Vim " . s:vim_minimum_version . " required to support ghost text"
|
||||||
|
endif
|
||||||
|
elseif !copilot#IsMapped()
|
||||||
|
return '<Tab> map has been disabled or is claimed by another plugin'
|
||||||
|
elseif !get(g:, 'copilot_enabled', 1)
|
||||||
|
return 'Disabled globally by :Copilot disable'
|
||||||
|
elseif buf_disabled is# 5
|
||||||
|
return 'Disabled for current buffer by buftype=' . &buftype
|
||||||
|
elseif buf_disabled is# 4
|
||||||
|
return 'Disabled for current buffer by b:copilot_enabled'
|
||||||
|
elseif buf_disabled is# 3
|
||||||
|
return 'Disabled for current buffer by b:copilot_disabled'
|
||||||
|
elseif buf_disabled is# 2
|
||||||
|
return 'Disabled for filetype=' . &filetype . ' by internal default'
|
||||||
|
elseif buf_disabled
|
||||||
|
return 'Disabled for filetype=' . &filetype . ' by g:copilot_filetypes'
|
||||||
|
elseif !copilot#Enabled()
|
||||||
|
return 'BUG: Something is wrong with enabling/disabling'
|
||||||
|
else
|
||||||
|
return ''
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:VerifySetup() abort
|
||||||
|
let error = copilot#Agent().StartupError()
|
||||||
|
if !empty(error)
|
||||||
|
echo 'Copilot: ' . error
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
let status = copilot#Call('checkStatus', {})
|
||||||
|
|
||||||
|
if !has_key(status, 'user')
|
||||||
|
echo 'Copilot: Not authenticated. Invoke :Copilot setup'
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
if status.status ==# 'NoTelemetryConsent'
|
||||||
|
echo 'Copilot: Telemetry terms not accepted. Invoke :Copilot setup'
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
return 1
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:commands.status(opts) abort
|
||||||
|
if !s:VerifySetup()
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
let status = s:EnabledStatusMessage()
|
||||||
|
if !empty(status)
|
||||||
|
echo 'Copilot: ' . status
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
let startup_error = copilot#Agent().StartupError()
|
||||||
|
if !empty(startup_error)
|
||||||
|
echo 'Copilot: ' . startup_error
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
if exists('s:agent_error')
|
||||||
|
echo 'Copilot: ' . s:agent_error
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
let status = copilot#Call('checkStatus', {})
|
||||||
|
if status.status ==# 'NotAuthorized'
|
||||||
|
echo 'Copilot: Not authorized'
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
echo 'Copilot: Enabled and online'
|
||||||
|
call s:NodeVersionWarning()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:commands.signout(opts) abort
|
||||||
|
let status = copilot#Call('checkStatus', {'options': {'localChecksOnly': v:true}})
|
||||||
|
if has_key(status, 'user')
|
||||||
|
echo 'Copilot: Signed out as GitHub user ' . status.user
|
||||||
|
else
|
||||||
|
echo 'Copilot: Not signed in'
|
||||||
|
endif
|
||||||
|
call copilot#Call('signOut', {})
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:commands.setup(opts) abort
|
||||||
|
let startup_error = copilot#Agent().StartupError()
|
||||||
|
if !empty(startup_error)
|
||||||
|
echo 'Copilot: ' . startup_error
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
|
||||||
|
let browser = copilot#Browser()
|
||||||
|
|
||||||
|
let status = copilot#Call('checkStatus', {})
|
||||||
|
if has_key(status, 'user')
|
||||||
|
let data = {}
|
||||||
|
else
|
||||||
|
let data = copilot#Call('signInInitiate', {})
|
||||||
|
endif
|
||||||
|
|
||||||
|
if has_key(data, 'verificationUri')
|
||||||
|
let uri = data.verificationUri
|
||||||
|
if has('clipboard')
|
||||||
|
let @+ = data.userCode
|
||||||
|
let @* = data.userCode
|
||||||
|
endif
|
||||||
|
call s:Echo("First copy your one-time code: " . data.userCode)
|
||||||
|
try
|
||||||
|
if len(&mouse)
|
||||||
|
let mouse = &mouse
|
||||||
|
set mouse=
|
||||||
|
endif
|
||||||
|
if get(a:opts, 'bang')
|
||||||
|
call s:Echo("In your browser, visit " . uri)
|
||||||
|
elseif len(browser)
|
||||||
|
call s:Echo("Press ENTER to open GitHub in your browser")
|
||||||
|
let c = getchar()
|
||||||
|
while c isnot# 13 && c isnot# 10 && c isnot# 0
|
||||||
|
let c = getchar()
|
||||||
|
endwhile
|
||||||
|
let status = {}
|
||||||
|
call copilot#job#Stream(browser + [uri], v:null, v:null, function('s:BrowserCallback', [status]))
|
||||||
|
let time = reltime()
|
||||||
|
while empty(status) && reltimefloat(reltime(time)) < 5
|
||||||
|
sleep 10m
|
||||||
|
endwhile
|
||||||
|
if get(status, 'code', browser[0] !=# 'xdg-open') != 0
|
||||||
|
call s:Echo("Failed to open browser. Visit " . uri)
|
||||||
|
else
|
||||||
|
call s:Echo("Opened " . uri)
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
call s:Echo("Could not find browser. Visit " . uri)
|
||||||
|
endif
|
||||||
|
call s:Echo("Waiting (could take up to 5 seconds)")
|
||||||
|
let request = copilot#Request('signInConfirm', {'userCode': data.userCode}).Wait()
|
||||||
|
finally
|
||||||
|
if exists('mouse')
|
||||||
|
let &mouse = mouse
|
||||||
|
endif
|
||||||
|
endtry
|
||||||
|
if request.status ==# 'error'
|
||||||
|
return 'echoerr ' . string('Copilot: Authentication failure: ' . request.error.message)
|
||||||
|
else
|
||||||
|
let status = request.result
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
let user = get(status, 'user', '<unknown>')
|
||||||
|
|
||||||
|
echo 'Copilot: Authenticated as GitHub user ' . user
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
let s:commands.auth = s:commands.setup
|
||||||
|
|
||||||
|
function! s:commands.help(opts) abort
|
||||||
|
return a:opts.mods . ' help ' . (len(a:opts.arg) ? ':Copilot_' . a:opts.arg : 'copilot')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:commands.version(opts) abort
|
||||||
|
let info = copilot#agent#EditorInfo()
|
||||||
|
echo 'copilot.vim ' .info.editorPluginInfo.version
|
||||||
|
echo info.editorInfo.name . ' ' . info.editorInfo.version
|
||||||
|
if exists('s:agent.node_version')
|
||||||
|
echo 'dist/agent.js ' . s:agent.Call('getVersion', {}).version
|
||||||
|
echo 'Node.js ' . s:agent.node_version
|
||||||
|
call s:NodeVersionWarning()
|
||||||
|
else
|
||||||
|
echo 'dist/agent.js not running'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:UpdateEditorConfiguration() abort
|
||||||
|
try
|
||||||
|
if s:Running()
|
||||||
|
call copilot#Notify('notifyChangeConfiguration', {'settings': s:EditorConfiguration()})
|
||||||
|
endif
|
||||||
|
catch
|
||||||
|
call copilot#logger#Exception()
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
let s:feedback_url = 'https://github.com/orgs/community/discussions/categories/copilot'
|
||||||
|
function! s:commands.feedback(opts) abort
|
||||||
|
echo s:feedback_url
|
||||||
|
let browser = copilot#Browser()
|
||||||
|
if len(browser)
|
||||||
|
call copilot#job#Stream(browser + [s:feedback_url], v:null, v:null, v:null)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:commands.restart(opts) abort
|
||||||
|
call s:Stop()
|
||||||
|
let err = copilot#Agent().StartupError()
|
||||||
|
if !empty(err)
|
||||||
|
return 'echoerr ' . string('Copilot: ' . err)
|
||||||
|
endif
|
||||||
|
echo 'Copilot: Restarting agent.'
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:commands.disable(opts) abort
|
||||||
|
let g:copilot_enabled = 0
|
||||||
|
call s:UpdateEditorConfiguration()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:commands.enable(opts) abort
|
||||||
|
let g:copilot_enabled = 1
|
||||||
|
call s:UpdateEditorConfiguration()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:commands.panel(opts) abort
|
||||||
|
if s:VerifySetup()
|
||||||
|
return copilot#panel#Open(a:opts)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#CommandComplete(arg, lead, pos) abort
|
||||||
|
let args = matchstr(strpart(a:lead, 0, a:pos), 'C\%[opilot][! ] *\zs.*')
|
||||||
|
if args !~# ' '
|
||||||
|
return sort(filter(map(keys(s:commands), { k, v -> tr(v, '_', '-') }),
|
||||||
|
\ { k, v -> strpart(v, 0, len(a:arg)) ==# a:arg }))
|
||||||
|
else
|
||||||
|
return []
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#Command(line1, line2, range, bang, mods, arg) abort
|
||||||
|
let cmd = matchstr(a:arg, '^\%(\\.\|\S\)\+')
|
||||||
|
let arg = matchstr(a:arg, '\s\zs\S.*')
|
||||||
|
if cmd ==# 'log'
|
||||||
|
return a:mods . ' split +$ ' . fnameescape(copilot#logger#File())
|
||||||
|
endif
|
||||||
|
if !empty(cmd) && !has_key(s:commands, tr(cmd, '-', '_'))
|
||||||
|
return 'echoerr ' . string('Copilot: unknown command ' . string(cmd))
|
||||||
|
endif
|
||||||
|
try
|
||||||
|
let err = copilot#Agent().StartupError()
|
||||||
|
if !empty(err)
|
||||||
|
return 'echo ' . string('Copilot: ' . err)
|
||||||
|
endif
|
||||||
|
try
|
||||||
|
let opts = copilot#Call('checkStatus', {'options': {'localChecksOnly': v:true}})
|
||||||
|
catch
|
||||||
|
call copilot#logger#Exception()
|
||||||
|
let opts = {'status': 'VimException'}
|
||||||
|
endtry
|
||||||
|
if empty(cmd)
|
||||||
|
if opts.status ==# 'VimException'
|
||||||
|
return a:mods . ' split +$ ' . fnameescape(copilot#logger#File())
|
||||||
|
elseif opts.status !=# 'OK' && opts.status !=# 'MaybeOK'
|
||||||
|
let cmd = 'setup'
|
||||||
|
else
|
||||||
|
let cmd = 'panel'
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
call extend(opts, {'line1': a:line1, 'line2': a:line2, 'range': a:range, 'bang': a:bang, 'mods': a:mods, 'arg': arg})
|
||||||
|
let retval = s:commands[tr(cmd, '-', '_')](opts)
|
||||||
|
if type(retval) == v:t_string
|
||||||
|
return retval
|
||||||
|
else
|
||||||
|
return ''
|
||||||
|
endif
|
||||||
|
catch /^Copilot:/
|
||||||
|
return 'echoerr ' . string(v:exception)
|
||||||
|
endtry
|
||||||
|
endfunction
|
603
sources_non_forked/copilot.vim/autoload/copilot/agent.vim
Normal file
603
sources_non_forked/copilot.vim/autoload/copilot/agent.vim
Normal file
|
@ -0,0 +1,603 @@
|
||||||
|
if exists('g:autoloaded_copilot_agent')
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
let g:autoloaded_copilot_agent = 1
|
||||||
|
|
||||||
|
scriptencoding utf-8
|
||||||
|
|
||||||
|
let s:plugin_version = '1.13.0'
|
||||||
|
|
||||||
|
let s:error_exit = -1
|
||||||
|
|
||||||
|
let s:root = expand('<sfile>:h:h:h')
|
||||||
|
|
||||||
|
if !exists('s:instances')
|
||||||
|
let s:instances = {}
|
||||||
|
endif
|
||||||
|
|
||||||
|
" allow sourcing this file to reload the Lua file too
|
||||||
|
if has('nvim')
|
||||||
|
lua package.loaded._copilot = nil
|
||||||
|
endif
|
||||||
|
|
||||||
|
let s:jobstop = function(exists('*jobstop') ? 'jobstop' : 'job_stop')
|
||||||
|
function! s:Kill(agent, ...) abort
|
||||||
|
if has_key(a:agent, 'job')
|
||||||
|
call s:jobstop(a:agent.job)
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:AgentClose() dict abort
|
||||||
|
if !has_key(self, 'job')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
if exists('*chanclose')
|
||||||
|
call chanclose(self.job, 'stdin')
|
||||||
|
else
|
||||||
|
call ch_close_in(self.job)
|
||||||
|
endif
|
||||||
|
call copilot#logger#Info('agent stopped')
|
||||||
|
call timer_start(2000, function('s:Kill', [self]))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:LogSend(request, line) abort
|
||||||
|
return '--> ' . a:line
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:RejectRequest(request, error) abort
|
||||||
|
if a:request.status ==# 'canceled'
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let a:request.waiting = {}
|
||||||
|
call remove(a:request, 'resolve')
|
||||||
|
let reject = remove(a:request, 'reject')
|
||||||
|
let a:request.status = 'error'
|
||||||
|
let a:request.error = a:error
|
||||||
|
for Cb in reject
|
||||||
|
let a:request.waiting[timer_start(0, function('s:Callback', [a:request, 'error', Cb]))] = 1
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:Send(agent, request) abort
|
||||||
|
try
|
||||||
|
call ch_sendexpr(a:agent.job, a:request)
|
||||||
|
return v:true
|
||||||
|
catch /^Vim\%((\a\+)\)\=:E631:/
|
||||||
|
return v:false
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:AgentNotify(method, params) dict abort
|
||||||
|
return s:Send(self, {'method': a:method, 'params': a:params})
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:RequestWait() dict abort
|
||||||
|
while self.status ==# 'running'
|
||||||
|
sleep 1m
|
||||||
|
endwhile
|
||||||
|
while !empty(get(self, 'waiting', {}))
|
||||||
|
sleep 1m
|
||||||
|
endwhile
|
||||||
|
return self
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:RequestAwait() dict abort
|
||||||
|
call self.Wait()
|
||||||
|
if has_key(self, 'result')
|
||||||
|
return self.result
|
||||||
|
endif
|
||||||
|
throw 'copilot#agent(' . self.error.code . '): ' . self.error.message
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:RequestAgent() dict abort
|
||||||
|
return get(s:instances, self.agent_id, v:null)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
if !exists('s:id')
|
||||||
|
let s:id = 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
function! s:SetUpRequest(agent, id, method, params, ...) abort
|
||||||
|
let request = {
|
||||||
|
\ 'agent_id': a:agent.id,
|
||||||
|
\ 'id': a:id,
|
||||||
|
\ 'method': a:method,
|
||||||
|
\ 'params': a:params,
|
||||||
|
\ 'Agent': function('s:RequestAgent'),
|
||||||
|
\ 'Wait': function('s:RequestWait'),
|
||||||
|
\ 'Await': function('s:RequestAwait'),
|
||||||
|
\ 'Cancel': function('s:RequestCancel'),
|
||||||
|
\ 'resolve': [],
|
||||||
|
\ 'reject': [],
|
||||||
|
\ 'status': 'running'}
|
||||||
|
let a:agent.requests[a:id] = request
|
||||||
|
let args = a:000[2:-1]
|
||||||
|
if len(args)
|
||||||
|
if !empty(a:1)
|
||||||
|
call add(request.resolve, { v -> call(a:1, [v] + args)})
|
||||||
|
endif
|
||||||
|
if !empty(a:2)
|
||||||
|
call add(request.reject, { v -> call(a:2, [v] + args)})
|
||||||
|
endif
|
||||||
|
return request
|
||||||
|
endif
|
||||||
|
if a:0 && !empty(a:1)
|
||||||
|
call add(request.resolve, a:1)
|
||||||
|
endif
|
||||||
|
if a:0 > 1 && !empty(a:2)
|
||||||
|
call add(request.reject, a:2)
|
||||||
|
endif
|
||||||
|
return request
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:UrlEncode(str) abort
|
||||||
|
return substitute(iconv(a:str, 'latin1', 'utf-8'),'[^A-Za-z0-9._~!$&''()*+,;=:@/-]','\="%".printf("%02X",char2nr(submatch(0)))','g')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
let s:slash = exists('+shellslash') ? '\' : '/'
|
||||||
|
function! s:UriFromBufnr(bufnr) abort
|
||||||
|
let absolute = tr(bufname(a:bufnr), s:slash, '/')
|
||||||
|
if absolute !~# '^\a\+:\|^/\|^$' && getbufvar(a:bufnr, 'buftype') =~# '^\%(nowrite\)\=$'
|
||||||
|
let absolute = substitute(tr(getcwd(), s:slash, '/'), '/\=$', '/', '') . absolute
|
||||||
|
endif
|
||||||
|
if has('win32') && absolute =~# '^\a://\@!'
|
||||||
|
return 'file:///' . strpart(absolute, 0, 2) . s:UrlEncode(strpart(absolute, 2))
|
||||||
|
elseif absolute =~# '^/'
|
||||||
|
return 'file://' . s:UrlEncode(absolute)
|
||||||
|
elseif absolute =~# '^\a[[:alnum:].+-]*:\|^$'
|
||||||
|
return absolute
|
||||||
|
else
|
||||||
|
return ''
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:BufferText(bufnr) abort
|
||||||
|
return join(getbufline(a:bufnr, 1, '$'), "\n") . "\n"
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:LogMessage(params) abort
|
||||||
|
call copilot#logger#Raw(get(a:params, 'level', 3), get(a:params, 'message', ''))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:ShowMessageRequest(params) abort
|
||||||
|
let choice = inputlist([a:params.message . "\n\nRequest Actions:"] +
|
||||||
|
\ map(copy(get(a:params, 'actions', [])), { i, v -> (i + 1) . '. ' . v.title}))
|
||||||
|
return choice > 0 ? get(a:params.actions, choice - 1, v:null) : v:null
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:SendRequest(agent, request) abort
|
||||||
|
if empty(s:Send(a:agent, a:request)) && has_key(a:agent.requests, a:request.id)
|
||||||
|
call s:RejectRequest(remove(a:agent.requests, a:request.id), {'code': 257, 'message': 'Write failed'})
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:AgentRequest(method, params, ...) dict abort
|
||||||
|
let s:id += 1
|
||||||
|
let request = {'method': a:method, 'params': deepcopy(a:params), 'id': s:id}
|
||||||
|
for doc in filter([get(request.params, 'doc', {}), get(request.params, 'textDocument',{})], 'type(get(v:val, "uri", "")) == v:t_number')
|
||||||
|
let bufnr = doc.uri
|
||||||
|
let doc.uri = s:UriFromBufnr(doc.uri)
|
||||||
|
let uri = doc.uri
|
||||||
|
let languageId = copilot#doc#LanguageForFileType(getbufvar(bufnr, '&filetype'))
|
||||||
|
let doc_version = getbufvar(bufnr, 'changedtick')
|
||||||
|
if has_key(self.open_buffers, bufnr) && (
|
||||||
|
\ self.open_buffers[bufnr].uri !=# doc.uri ||
|
||||||
|
\ self.open_buffers[bufnr].languageId !=# languageId)
|
||||||
|
call remove(self.open_buffers, bufnr)
|
||||||
|
sleep 1m
|
||||||
|
endif
|
||||||
|
if !has_key(self.open_buffers, bufnr)
|
||||||
|
let td_item = {
|
||||||
|
\ 'uri': doc.uri,
|
||||||
|
\ 'version': doc_version,
|
||||||
|
\ 'languageId': languageId,
|
||||||
|
\ 'text': s:BufferText(bufnr)}
|
||||||
|
call self.Notify('textDocument/didOpen', {'textDocument': td_item})
|
||||||
|
let self.open_buffers[bufnr] = {
|
||||||
|
\ 'uri': doc.uri,
|
||||||
|
\ 'version': doc_version,
|
||||||
|
\ 'languageId': languageId}
|
||||||
|
else
|
||||||
|
let vtd_id = {
|
||||||
|
\ 'uri': doc.uri,
|
||||||
|
\ 'version': doc_version}
|
||||||
|
call self.Notify('textDocument/didChange', {
|
||||||
|
\ 'textDocument': vtd_id,
|
||||||
|
\ 'contentChanges': [{'text': s:BufferText(bufnr)}]})
|
||||||
|
let self.open_buffers[bufnr].version = doc_version
|
||||||
|
endif
|
||||||
|
let doc.version = doc_version
|
||||||
|
endfor
|
||||||
|
call timer_start(0, { _ -> s:SendRequest(self, request) })
|
||||||
|
return call('s:SetUpRequest', [self, s:id, a:method, a:params] + a:000)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:AgentCall(method, params, ...) dict abort
|
||||||
|
let request = call(self.Request, [a:method, a:params] + a:000)
|
||||||
|
if a:0
|
||||||
|
return request
|
||||||
|
endif
|
||||||
|
return request.Await()
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:AgentCancel(request) dict abort
|
||||||
|
if has_key(self.requests, get(a:request, 'id', ''))
|
||||||
|
call remove(self.requests, a:request.id)
|
||||||
|
call self.Notify('$/cancelRequest', {'id': a:request.id})
|
||||||
|
endif
|
||||||
|
if get(a:request, 'status', '') ==# 'running'
|
||||||
|
let a:request.status = 'canceled'
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:RequestCancel() dict abort
|
||||||
|
let agent = self.Agent()
|
||||||
|
if !empty(agent)
|
||||||
|
call agent.Cancel(self)
|
||||||
|
elseif get(self, 'status', '') ==# 'running'
|
||||||
|
let self.status = 'canceled'
|
||||||
|
endif
|
||||||
|
return self
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:DispatchMessage(agent, handler, id, params, ...) abort
|
||||||
|
try
|
||||||
|
let response = {'result': call(a:handler, [a:params])}
|
||||||
|
if response.result is# 0
|
||||||
|
let response.result = v:null
|
||||||
|
endif
|
||||||
|
catch
|
||||||
|
call copilot#logger#Exception()
|
||||||
|
let response = {'error': {'code': -32000, 'message': v:exception}}
|
||||||
|
endtry
|
||||||
|
if !empty(a:id)
|
||||||
|
call s:Send(a:agent, extend({'id': a:id}, response))
|
||||||
|
endif
|
||||||
|
return response
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:OnMessage(agent, body, ...) abort
|
||||||
|
if !has_key(a:body, 'method')
|
||||||
|
return s:OnResponse(a:agent, a:body)
|
||||||
|
endif
|
||||||
|
let request = a:body
|
||||||
|
let id = get(request, 'id', v:null)
|
||||||
|
let params = get(request, 'params', v:null)
|
||||||
|
if has_key(a:agent.methods, request.method)
|
||||||
|
return s:DispatchMessage(a:agent, a:agent.methods[request.method], id, params)
|
||||||
|
elseif !empty(id)
|
||||||
|
call s:Send(a:agent, {"id": id, "error": {"code": -32700, "message": "Method not found: " . request.method}})
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:OnResponse(agent, response, ...) abort
|
||||||
|
let response = a:response
|
||||||
|
let id = get(a:response, 'id', v:null)
|
||||||
|
if !has_key(a:agent.requests, id)
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let request = remove(a:agent.requests, id)
|
||||||
|
if request.status ==# 'canceled'
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let request.waiting = {}
|
||||||
|
let resolve = remove(request, 'resolve')
|
||||||
|
let reject = remove(request, 'reject')
|
||||||
|
if has_key(response, 'result')
|
||||||
|
let request.status = 'success'
|
||||||
|
let request.result = response.result
|
||||||
|
for Cb in resolve
|
||||||
|
let request.waiting[timer_start(0, function('s:Callback', [request, 'result', Cb]))] = 1
|
||||||
|
endfor
|
||||||
|
else
|
||||||
|
let request.status = 'error'
|
||||||
|
let request.error = response.error
|
||||||
|
for Cb in reject
|
||||||
|
let request.waiting[timer_start(0, function('s:Callback', [request, 'error', Cb]))] = 1
|
||||||
|
endfor
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:OnErr(agent, line, ...) abort
|
||||||
|
call copilot#logger#Debug('<-! ' . a:line)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:OnExit(agent, code, ...) abort
|
||||||
|
let a:agent.exit_status = a:code
|
||||||
|
if has_key(a:agent, 'job')
|
||||||
|
call remove(a:agent, 'job')
|
||||||
|
endif
|
||||||
|
if has_key(a:agent, 'client_id')
|
||||||
|
call remove(a:agent, 'client_id')
|
||||||
|
endif
|
||||||
|
let code = a:code < 0 || a:code > 255 ? 256 : a:code
|
||||||
|
for id in sort(keys(a:agent.requests), { a, b -> +a > +b })
|
||||||
|
call s:RejectRequest(remove(a:agent.requests, id), {'code': code, 'message': 'Agent exited', 'data': {'status': a:code}})
|
||||||
|
endfor
|
||||||
|
call timer_start(0, { _ -> get(s:instances, a:agent.id) is# a:agent ? remove(s:instances, a:agent.id) : {} })
|
||||||
|
call copilot#logger#Info('agent exited with status ' . a:code)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#agent#LspInit(agent_id, initialize_result) abort
|
||||||
|
if !has_key(s:instances, a:agent_id)
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let instance = s:instances[a:agent_id]
|
||||||
|
call timer_start(0, { _ -> s:GetCapabilitiesResult(a:initialize_result, instance)})
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#agent#LspExit(agent_id, code, signal) abort
|
||||||
|
if !has_key(s:instances, a:agent_id)
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let instance = remove(s:instances, a:agent_id)
|
||||||
|
call s:OnExit(instance, a:code)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#agent#LspResponse(agent_id, opts, ...) abort
|
||||||
|
if !has_key(s:instances, a:agent_id)
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
call s:OnResponse(s:instances[a:agent_id], a:opts)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:LspRequest(method, params, ...) dict abort
|
||||||
|
let id = v:lua.require'_copilot'.lsp_request(self.id, a:method, a:params)
|
||||||
|
if id isnot# v:null
|
||||||
|
return call('s:SetUpRequest', [self, id, a:method, a:params] + a:000)
|
||||||
|
endif
|
||||||
|
if has_key(self, 'client_id')
|
||||||
|
call copilot#agent#LspExit(self.client_id, -1, -1)
|
||||||
|
endif
|
||||||
|
throw 'copilot#agent: LSP client not available'
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:LspClose() dict abort
|
||||||
|
if !has_key(self, 'client_id')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
return luaeval('vim.lsp.get_client_by_id(_A).stop()', self.client_id)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:LspNotify(method, params) dict abort
|
||||||
|
return v:lua.require'_copilot'.rpc_notify(self.id, a:method, a:params)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#agent#LspHandle(agent_id, request) abort
|
||||||
|
if !has_key(s:instances, a:agent_id)
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
return s:OnMessage(s:instances[a:agent_id], a:request)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:GetNodeVersion(command) abort
|
||||||
|
let out = []
|
||||||
|
let err = []
|
||||||
|
let status = copilot#job#Stream(a:command + ['--version'], function('add', [out]), function('add', [err]))
|
||||||
|
let string = matchstr(join(out, ''), '^v\zs\d\+\.[^[:space:]]*')
|
||||||
|
if status != 0
|
||||||
|
let string = ''
|
||||||
|
endif
|
||||||
|
let major = str2nr(string)
|
||||||
|
let minor = str2nr(matchstr(string, '\.\zs\d\+'))
|
||||||
|
return {'status': status, 'string': string, 'major': major, 'minor': minor}
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:Command() abort
|
||||||
|
if !has('nvim-0.6') && v:version < 900
|
||||||
|
return [v:null, '', 'Vim version too old']
|
||||||
|
endif
|
||||||
|
let node = get(g:, 'copilot_node_command', '')
|
||||||
|
if empty(node)
|
||||||
|
let node = ['node']
|
||||||
|
elseif type(node) == type('')
|
||||||
|
let node = [expand(node)]
|
||||||
|
endif
|
||||||
|
if !executable(get(node, 0, ''))
|
||||||
|
if get(node, 0, '') ==# 'node'
|
||||||
|
return [v:null, '', 'Node.js not found in PATH']
|
||||||
|
else
|
||||||
|
return [v:null, '', 'Node.js executable `' . get(node, 0, '') . "' not found"]
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
let node_version = s:GetNodeVersion(node)
|
||||||
|
let warning = ''
|
||||||
|
if !get(g:, 'copilot_ignore_node_version') && node_version.major < 18 && get(node, 0, '') !=# 'node' && executable('node')
|
||||||
|
let node_version_from_path = s:GetNodeVersion(['node'])
|
||||||
|
if node_version_from_path.major >= 18
|
||||||
|
let warning = 'Ignoring g:copilot_node_command: Node.js ' . node_version.string . ' is end-of-life'
|
||||||
|
let node = ['node']
|
||||||
|
let node_version = node_version_from_path
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
if node_version.status != 0
|
||||||
|
return [v:null, '', 'Node.js exited with status ' . node_version.status]
|
||||||
|
endif
|
||||||
|
if !get(g:, 'copilot_ignore_node_version')
|
||||||
|
if node_version.major == 0
|
||||||
|
return [v:null, node_version.string, 'Could not determine Node.js version']
|
||||||
|
elseif node_version.major < 16 || node_version.major == 16 && node_version.minor < 14 || node_version.major == 17 && node_version.minor < 3
|
||||||
|
" 16.14+ and 17.3+ still work for now, but are end-of-life
|
||||||
|
return [v:null, node_version.string, 'Node.js version 18.x or newer required but found ' . node_version.string]
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
let agent = get(g:, 'copilot_agent_command', '')
|
||||||
|
if empty(agent) || !filereadable(agent)
|
||||||
|
let agent = s:root . '/dist/agent.js'
|
||||||
|
if !filereadable(agent)
|
||||||
|
return [v:null, node_version.string, 'Could not find dist/agent.js (bad install?)']
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
return [node + [agent, '--stdio'], node_version.string, warning]
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:UrlDecode(str) abort
|
||||||
|
return substitute(a:str, '%\(\x\x\)', '\=iconv(nr2char("0x".submatch(1)), "utf-8", "latin1")', 'g')
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#agent#EditorInfo() abort
|
||||||
|
if !exists('s:editor_version')
|
||||||
|
if has('nvim')
|
||||||
|
let s:editor_version = matchstr(execute('version'), 'NVIM v\zs[^[:space:]]\+')
|
||||||
|
else
|
||||||
|
let s:editor_version = (v:version / 100) . '.' . (v:version % 100) . (exists('v:versionlong') ? printf('.%04d', v:versionlong % 1000) : '')
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
let info = {
|
||||||
|
\ 'editorInfo': {'name': has('nvim') ? 'Neovim': 'Vim', 'version': s:editor_version},
|
||||||
|
\ 'editorPluginInfo': {'name': 'copilot.vim', 'version': s:plugin_version}}
|
||||||
|
if type(get(g:, 'copilot_proxy')) == v:t_string
|
||||||
|
let proxy = g:copilot_proxy
|
||||||
|
else
|
||||||
|
let proxy = ''
|
||||||
|
endif
|
||||||
|
let match = matchlist(proxy, '\c^\%([^:]\+://\)\=\%(\([^/#]\+@\)\)\=\%(\([^/:#]\+\)\|\[\([[:xdigit:]:]\+\)\]\)\%(:\(\d\+\)\)\=\%(/\|$\|?strict_\=ssl=\(.*\)\)')
|
||||||
|
if !empty(match)
|
||||||
|
let info.networkProxy = {'host': match[2] . match[3], 'port': empty(match[4]) ? 80 : +match[4]}
|
||||||
|
if match[5] =~? '^[0f]'
|
||||||
|
let info.networkProxy.rejectUnauthorized = v:false
|
||||||
|
elseif match[5] =~? '^[1t]'
|
||||||
|
let info.networkProxy.rejectUnauthorized = v:true
|
||||||
|
elseif exists('g:copilot_proxy_strict_ssl')
|
||||||
|
let info.networkProxy.rejectUnauthorized = empty(g:copilot_proxy_strict_ssl) ? v:false : v:true
|
||||||
|
endif
|
||||||
|
if !empty(match[1])
|
||||||
|
let info.networkProxy.username = s:UrlDecode(matchstr(match[1], '^[^:@]*'))
|
||||||
|
let info.networkProxy.password = s:UrlDecode(matchstr(match[1], ':\zs[^@]*'))
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
return info
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:GetCapabilitiesResult(result, agent) abort
|
||||||
|
let a:agent.capabilities = get(a:result, 'capabilities', {})
|
||||||
|
let info = copilot#agent#EditorInfo()
|
||||||
|
call a:agent.Request('setEditorInfo', extend({'editorConfiguration': a:agent.editorConfiguration}, info))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:GetCapabilitiesError(error, agent) abort
|
||||||
|
if a:error.code == s:error_exit
|
||||||
|
let a:agent.startup_error = 'Agent exited with status ' . a:error.data.status
|
||||||
|
else
|
||||||
|
let a:agent.startup_error = 'Unexpected error ' . a:error.code . ' calling agent: ' . a:error.message
|
||||||
|
call a:agent.Close()
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:AgentStartupError() dict abort
|
||||||
|
while (has_key(self, 'job') || has_key(self, 'client_id')) && !has_key(self, 'startup_error') && !has_key(self, 'capabilities')
|
||||||
|
sleep 10m
|
||||||
|
endwhile
|
||||||
|
if has_key(self, 'capabilities')
|
||||||
|
return ''
|
||||||
|
else
|
||||||
|
return get(self, 'startup_error', 'Something unexpected went wrong spawning the agent')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#agent#New(...) abort
|
||||||
|
let opts = a:0 ? a:1 : {}
|
||||||
|
let instance = {'requests': {},
|
||||||
|
\ 'editorConfiguration': get(opts, 'editorConfiguration', {}),
|
||||||
|
\ 'Close': function('s:AgentClose'),
|
||||||
|
\ 'Notify': function('s:AgentNotify'),
|
||||||
|
\ 'Request': function('s:AgentRequest'),
|
||||||
|
\ 'Call': function('s:AgentCall'),
|
||||||
|
\ 'Cancel': function('s:AgentCancel'),
|
||||||
|
\ 'StartupError': function('s:AgentStartupError'),
|
||||||
|
\ }
|
||||||
|
let instance.methods = extend({
|
||||||
|
\ 'LogMessage': function('s:LogMessage'),
|
||||||
|
\ 'window/logMessage': function('s:LogMessage'),
|
||||||
|
\ }, get(opts, 'methods', {}))
|
||||||
|
let [command, node_version, command_error] = s:Command()
|
||||||
|
if len(command_error)
|
||||||
|
if empty(command)
|
||||||
|
let instance.id = -1
|
||||||
|
let instance.startup_error = command_error
|
||||||
|
return instance
|
||||||
|
else
|
||||||
|
let instance.node_version_warning = command_error
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
let instance.node_version = node_version
|
||||||
|
if has('nvim')
|
||||||
|
call extend(instance, {
|
||||||
|
\ 'Close': function('s:LspClose'),
|
||||||
|
\ 'Notify': function('s:LspNotify'),
|
||||||
|
\ 'Request': function('s:LspRequest')})
|
||||||
|
let instance.client_id = v:lua.require'_copilot'.lsp_start_client(command, keys(instance.methods))
|
||||||
|
let instance.id = instance.client_id
|
||||||
|
else
|
||||||
|
let state = {'headers': {}, 'mode': 'headers', 'buffer': ''}
|
||||||
|
let instance.open_buffers = {}
|
||||||
|
let instance.methods = extend({'window/showMessageRequest': function('s:ShowMessageRequest')}, instance.methods)
|
||||||
|
let instance.job = job_start(command, {
|
||||||
|
\ 'cwd': copilot#job#Cwd(),
|
||||||
|
\ 'in_mode': 'lsp',
|
||||||
|
\ 'out_mode': 'lsp',
|
||||||
|
\ 'out_cb': { j, d -> timer_start(0, function('s:OnMessage', [instance, d])) },
|
||||||
|
\ 'err_cb': { j, d -> timer_start(0, function('s:OnErr', [instance, d])) },
|
||||||
|
\ 'exit_cb': { j, d -> timer_start(0, function('s:OnExit', [instance, d])) },
|
||||||
|
\ })
|
||||||
|
let instance.id = exists('*jobpid') ? jobpid(instance.job) : job_info(instance.job).process
|
||||||
|
let capabilities = {'workspace': {'workspaceFolders': v:true}, 'copilot': {}}
|
||||||
|
for name in keys(instance.methods)
|
||||||
|
if name =~# '^copilot/'
|
||||||
|
let capabilities.copilot[matchstr(name, '/\zs.*')] = v:true
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
let request = instance.Request('initialize', {'capabilities': capabilities}, function('s:GetCapabilitiesResult'), function('s:GetCapabilitiesError'), instance)
|
||||||
|
endif
|
||||||
|
let s:instances[instance.id] = instance
|
||||||
|
return instance
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#agent#Cancel(request) abort
|
||||||
|
if type(a:request) == type({}) && has_key(a:request, 'Cancel')
|
||||||
|
call a:request.Cancel()
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:Callback(request, type, callback, timer) abort
|
||||||
|
call remove(a:request.waiting, a:timer)
|
||||||
|
if has_key(a:request, a:type)
|
||||||
|
call a:callback(a:request[a:type])
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#agent#Result(request, callback) abort
|
||||||
|
if has_key(a:request, 'resolve')
|
||||||
|
call add(a:request.resolve, a:callback)
|
||||||
|
elseif has_key(a:request, 'result')
|
||||||
|
let a:request.waiting[timer_start(0, function('s:Callback', [a:request, 'result', a:callback]))] = 1
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#agent#Error(request, callback) abort
|
||||||
|
if has_key(a:request, 'reject')
|
||||||
|
call add(a:request.reject, a:callback)
|
||||||
|
elseif has_key(a:request, 'error')
|
||||||
|
let a:request.waiting[timer_start(0, function('s:Callback', [a:request, 'error', a:callback]))] = 1
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:CloseBuffer(bufnr) abort
|
||||||
|
for instance in values(s:instances)
|
||||||
|
try
|
||||||
|
if has_key(instance, 'job') && has_key(instance.open_buffers, a:bufnr)
|
||||||
|
let buffer = remove(instance.open_buffers, a:bufnr)
|
||||||
|
call instance.Notify('textDocument/didClose', {'textDocument': {'uri': buffer.uri}})
|
||||||
|
endif
|
||||||
|
catch
|
||||||
|
call copilot#logger#Exception()
|
||||||
|
endtry
|
||||||
|
endfor
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
augroup copilot_agent
|
||||||
|
autocmd!
|
||||||
|
if !has('nvim')
|
||||||
|
autocmd BufUnload * call s:CloseBuffer(+expand('<abuf>'))
|
||||||
|
endif
|
||||||
|
augroup END
|
116
sources_non_forked/copilot.vim/autoload/copilot/doc.vim
Normal file
116
sources_non_forked/copilot.vim/autoload/copilot/doc.vim
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
if exists('g:autoloaded_copilot_prompt')
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
let g:autoloaded_copilot_prompt = 1
|
||||||
|
|
||||||
|
scriptencoding utf-8
|
||||||
|
|
||||||
|
let s:slash = exists('+shellslash') ? '\' : '/'
|
||||||
|
|
||||||
|
function copilot#doc#UTF16Width(str) abort
|
||||||
|
return strchars(substitute(a:str, "\\%#=2[^\u0001-\uffff]", " ", 'g'))
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
if exists('*utf16idx')
|
||||||
|
|
||||||
|
function! copilot#doc#UTF16ToByteIdx(str, utf16_idx) abort
|
||||||
|
return byteidx(a:str, a:utf16_idx, 1)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
elseif has('nvim')
|
||||||
|
|
||||||
|
function! copilot#doc#UTF16ToByteIdx(str, utf16_idx) abort
|
||||||
|
try
|
||||||
|
return v:lua.vim.str_byteindex(a:str, a:utf16_idx, 1)
|
||||||
|
catch /^Vim(return):E5108:/
|
||||||
|
return -1
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
function! copilot#doc#UTF16ToByteIdx(str, utf16_idx) abort
|
||||||
|
if copilot#doc#UTF16Width(a:str) < a:utf16_idx
|
||||||
|
return -1
|
||||||
|
endif
|
||||||
|
let end_offset = len(a:str)
|
||||||
|
while copilot#doc#UTF16Width(strpart(a:str, 0, end_offset)) > a:utf16_idx && end_offset > 0
|
||||||
|
let end_offset -= 1
|
||||||
|
endwhile
|
||||||
|
return end_offset
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
let s:language_normalization_map = {
|
||||||
|
\ "bash": "shellscript",
|
||||||
|
\ "bst": "bibtex",
|
||||||
|
\ "cs": "csharp",
|
||||||
|
\ "cuda": "cuda-cpp",
|
||||||
|
\ "dosbatch": "bat",
|
||||||
|
\ "dosini": "ini",
|
||||||
|
\ "gitcommit": "git-commit",
|
||||||
|
\ "gitrebase": "git-rebase",
|
||||||
|
\ "make": "makefile",
|
||||||
|
\ "objc": "objective-c",
|
||||||
|
\ "objcpp": "objective-cpp",
|
||||||
|
\ "ps1": "powershell",
|
||||||
|
\ "raku": "perl6",
|
||||||
|
\ "sh": "shellscript",
|
||||||
|
\ "text": "plaintext",
|
||||||
|
\ }
|
||||||
|
function copilot#doc#LanguageForFileType(filetype) abort
|
||||||
|
let filetype = substitute(a:filetype, '\..*', '', '')
|
||||||
|
return get(s:language_normalization_map, empty(filetype) ? "text" : filetype, filetype)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:RelativePath(absolute) abort
|
||||||
|
if exists('b:copilot_relative_path')
|
||||||
|
return b:copilot_relative_path
|
||||||
|
elseif exists('b:copilot_root')
|
||||||
|
let root = b:copilot_root
|
||||||
|
elseif len(get(b:, 'projectionist', {}))
|
||||||
|
let root = sort(keys(b:projectionist), { a, b -> a < b })[0]
|
||||||
|
else
|
||||||
|
let root = getcwd()
|
||||||
|
endif
|
||||||
|
let root = tr(root, s:slash, '/') . '/'
|
||||||
|
if strpart(tr(a:absolute, 'A-Z', 'a-z'), 0, len(root)) ==# tr(root, 'A-Z', 'a-z')
|
||||||
|
return strpart(a:absolute, len(root))
|
||||||
|
else
|
||||||
|
return fnamemodify(a:absolute, ':t')
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#doc#Get() abort
|
||||||
|
let absolute = tr(@%, s:slash, '/')
|
||||||
|
if absolute !~# '^\a\+:\|^/\|^$' && &buftype =~# '^\%(nowrite\)\=$'
|
||||||
|
let absolute = substitute(tr(getcwd(), s:slash, '/'), '/\=$', '/', '') . absolute
|
||||||
|
endif
|
||||||
|
let doc = {
|
||||||
|
\ 'uri': bufnr(''),
|
||||||
|
\ 'version': getbufvar('', 'changedtick'),
|
||||||
|
\ 'relativePath': s:RelativePath(absolute),
|
||||||
|
\ 'insertSpaces': &expandtab ? v:true : v:false,
|
||||||
|
\ 'tabSize': shiftwidth(),
|
||||||
|
\ 'indentSize': shiftwidth(),
|
||||||
|
\ }
|
||||||
|
let line = getline('.')
|
||||||
|
let col_byte = col('.') - (mode() =~# '^[iR]' || empty(line))
|
||||||
|
let col_utf16 = copilot#doc#UTF16Width(strpart(line, 0, col_byte))
|
||||||
|
let doc.position = {'line': line('.') - 1, 'character': col_utf16}
|
||||||
|
return doc
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#doc#Params(...) abort
|
||||||
|
let extra = a:0 ? a:1 : {}
|
||||||
|
let params = extend({'doc': extend(copilot#doc#Get(), get(extra, 'doc', {}))}, extra, 'keep')
|
||||||
|
let params.textDocument = {
|
||||||
|
\ 'uri': params.doc.uri,
|
||||||
|
\ 'version': params.doc.version,
|
||||||
|
\ 'relativePath': params.doc.relativePath,
|
||||||
|
\ }
|
||||||
|
let params.position = params.doc.position
|
||||||
|
return params
|
||||||
|
endfunction
|
111
sources_non_forked/copilot.vim/autoload/copilot/job.vim
Normal file
111
sources_non_forked/copilot.vim/autoload/copilot/job.vim
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
if exists('g:autoloaded_copilot_job')
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
let g:autoloaded_copilot_job = 1
|
||||||
|
|
||||||
|
scriptencoding utf-8
|
||||||
|
|
||||||
|
function copilot#job#Nop(...) abort
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:Jobs(job_or_jobs) abort
|
||||||
|
let jobs = type(a:job_or_jobs) == v:t_list ? copy(a:job_or_jobs) : [a:job_or_jobs]
|
||||||
|
call map(jobs, { k, v -> type(v) == v:t_dict ? get(v, 'job', '') : v })
|
||||||
|
call filter(jobs, { k, v -> type(v) !=# type('') })
|
||||||
|
return jobs
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
let s:job_stop = exists('*job_stop') ? 'job_stop' : 'jobstop'
|
||||||
|
function! copilot#job#Stop(job) abort
|
||||||
|
for job in s:Jobs(a:job)
|
||||||
|
call call(s:job_stop, [job])
|
||||||
|
endfor
|
||||||
|
return copilot#job#Wait(a:job)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
let s:sleep = has('patch-8.2.2366') ? 'sleep! 1m' : 'sleep 1m'
|
||||||
|
function! copilot#job#Wait(jobs) abort
|
||||||
|
let jobs = s:Jobs(a:jobs)
|
||||||
|
if exists('*jobwait')
|
||||||
|
call jobwait(jobs)
|
||||||
|
else
|
||||||
|
for job in jobs
|
||||||
|
while ch_status(job) !=# 'closed' || job_status(job) ==# 'run'
|
||||||
|
exe s:sleep
|
||||||
|
endwhile
|
||||||
|
endfor
|
||||||
|
endif
|
||||||
|
return a:jobs
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:VimExitCallback(result, exit_cb, job, data) abort
|
||||||
|
let a:result.exit_status = a:data
|
||||||
|
if !has_key(a:result, 'closed')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
call remove(a:result, 'closed')
|
||||||
|
call a:exit_cb(a:result.exit_status)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:VimCloseCallback(result, exit_cb, job) abort
|
||||||
|
if !has_key(a:result, 'exit_status')
|
||||||
|
let a:result.closed = v:true
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
call a:exit_cb(a:result.exit_status)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:NvimCallback(cb, job, data, type) dict abort
|
||||||
|
let self[a:type][0] .= remove(a:data, 0)
|
||||||
|
call extend(self[a:type], a:data)
|
||||||
|
while len(self[a:type]) > 1
|
||||||
|
call a:cb(substitute(remove(self[a:type], 0), "\r$", '', ''))
|
||||||
|
endwhile
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:NvimExitCallback(out_cb, err_cb, exit_cb, job, data, type) dict abort
|
||||||
|
if len(self.stderr[0])
|
||||||
|
call a:err_cb(substitute(self.stderr[0], "\r$", '', ''))
|
||||||
|
endif
|
||||||
|
call a:exit_cb(a:data)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#job#Cwd() abort
|
||||||
|
let home = expand("~")
|
||||||
|
if !isdirectory(home) && isdirectory($VIM)
|
||||||
|
return $VIM
|
||||||
|
endif
|
||||||
|
return home
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#job#Stream(argv, out_cb, err_cb, ...) abort
|
||||||
|
let exit_status = []
|
||||||
|
let ExitCb = function(a:0 && !empty(a:1) ? a:1 : { e -> add(exit_status, e) }, a:000[2:-1])
|
||||||
|
let OutCb = function(empty(a:out_cb) ? 'copilot#job#Nop' : a:out_cb, a:000[2:-1])
|
||||||
|
let ErrCb = function(empty(a:err_cb) ? 'copilot#job#Nop' : a:err_cb, a:000[2:-1])
|
||||||
|
let state = {'headers': {}, 'mode': 'headers', 'buffer': ''}
|
||||||
|
if exists('*job_start')
|
||||||
|
let result = {}
|
||||||
|
let job = job_start(a:argv, {
|
||||||
|
\ 'cwd': copilot#job#Cwd(),
|
||||||
|
\ 'out_mode': 'raw',
|
||||||
|
\ 'out_cb': { j, d -> OutCb(d) },
|
||||||
|
\ 'err_cb': { j, d -> ErrCb(d) },
|
||||||
|
\ 'exit_cb': function('s:VimExitCallback', [result, ExitCb]),
|
||||||
|
\ 'close_cb': function('s:VimCloseCallback', [result, ExitCb]),
|
||||||
|
\ })
|
||||||
|
else
|
||||||
|
let jopts = {
|
||||||
|
\ 'cwd': copilot#job#Cwd(),
|
||||||
|
\ 'stderr': [''],
|
||||||
|
\ 'on_stdout': { j, d, t -> OutCb(join(d, "\n")) },
|
||||||
|
\ 'on_stderr': function('s:NvimCallback', [ErrCb]),
|
||||||
|
\ 'on_exit': function('s:NvimExitCallback', [OutCb, ErrCb, ExitCb])}
|
||||||
|
let job = jobstart(a:argv, jopts)
|
||||||
|
endif
|
||||||
|
if a:0
|
||||||
|
return job
|
||||||
|
endif
|
||||||
|
call copilot#job#Wait(job)
|
||||||
|
return exit_status[0]
|
||||||
|
endfunction
|
72
sources_non_forked/copilot.vim/autoload/copilot/logger.vim
Normal file
72
sources_non_forked/copilot.vim/autoload/copilot/logger.vim
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
if exists('g:autoloaded_copilot_log')
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
let g:autoloaded_copilot_log = 1
|
||||||
|
|
||||||
|
if !exists('s:log_file')
|
||||||
|
let s:log_file = tempname() . '-copilot.log'
|
||||||
|
try
|
||||||
|
call writefile([], s:log_file)
|
||||||
|
catch
|
||||||
|
endtry
|
||||||
|
endif
|
||||||
|
|
||||||
|
function! copilot#logger#File() abort
|
||||||
|
return s:log_file
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#logger#Raw(level, message) abort
|
||||||
|
if $COPILOT_AGENT_VERBOSE !~# '^\%(1\|true\)$' && a:level < 1
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let lines = type(a:message) == v:t_list ? copy(a:message) : split(a:message, "\n", 1)
|
||||||
|
try
|
||||||
|
if !filewritable(s:log_file)
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
call map(lines, { k, L -> type(L) == v:t_func ? call(L, []) : L })
|
||||||
|
call writefile(lines, s:log_file, 'a')
|
||||||
|
catch
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#logger#Trace(...) abort
|
||||||
|
call copilot#logger#Raw(-1, a:000)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#logger#Debug(...) abort
|
||||||
|
call copilot#logger#Raw(0, a:000)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#logger#Info(...) abort
|
||||||
|
call copilot#logger#Raw(1, a:000)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#logger#Warn(...) abort
|
||||||
|
call copilot#logger#Raw(2, a:000)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#logger#Error(...) abort
|
||||||
|
call copilot#logger#Raw(3, a:000)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#logger#Exception() abort
|
||||||
|
if !empty(v:exception) && v:exception !=# 'Vim:Interrupt'
|
||||||
|
call copilot#logger#Error('Exception: ' . v:exception . ' @ ' . v:throwpoint)
|
||||||
|
let agent = copilot#RunningAgent()
|
||||||
|
if !empty(agent)
|
||||||
|
let stacklines = []
|
||||||
|
for frame in split(substitute(substitute(v:throwpoint, ', \S\+ \(\d\+\)$', '[\1]', ''), '^function ', '', ''), '\.\@<!\.\.\.\@!')
|
||||||
|
if frame =~# '[\/]'
|
||||||
|
call add(stacklines, '[redacted]')
|
||||||
|
else
|
||||||
|
call add(stacklines, substitute(frame, '^<SNR>\d\+_', '<SID>', ''))
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
call agent.Request('telemetry/exception', {
|
||||||
|
\ 'origin': 'copilot.vim',
|
||||||
|
\ 'stacktrace': join([v:exception] + stacklines, "\n")
|
||||||
|
\ })
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
160
sources_non_forked/copilot.vim/autoload/copilot/panel.vim
Normal file
160
sources_non_forked/copilot.vim/autoload/copilot/panel.vim
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
if exists('g:autoloaded_copilot_panel')
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
let g:autoloaded_copilot_panel = 1
|
||||||
|
|
||||||
|
scriptencoding utf-8
|
||||||
|
|
||||||
|
if !exists('s:panel_id')
|
||||||
|
let s:panel_id = 0
|
||||||
|
endif
|
||||||
|
|
||||||
|
let s:separator = repeat('─', 72)
|
||||||
|
|
||||||
|
function! s:Solutions(state) abort
|
||||||
|
return sort(values(get(a:state, 'solutions', {})), { a, b -> a.score < b.score })
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:Render(panel_id) abort
|
||||||
|
let bufnr = bufnr('^' . a:panel_id . '$')
|
||||||
|
let state = getbufvar(bufnr, 'copilot_panel')
|
||||||
|
if !bufloaded(bufnr) || type(state) != v:t_dict
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let sorted = s:Solutions(state)
|
||||||
|
if !empty(get(state, 'status', ''))
|
||||||
|
let lines = ['Error: ' . state.status]
|
||||||
|
else
|
||||||
|
let target = get(state, 'count_target', '?')
|
||||||
|
let received = has_key(state, 'status') ? target : len(sorted)
|
||||||
|
let lines = ['Synthesiz' . (has_key(state, 'status') ? 'ed ' : 'ing ') . received . '/' . target . ' solutions (Duplicates hidden)']
|
||||||
|
endif
|
||||||
|
if len(sorted)
|
||||||
|
call add(lines, 'Press <CR> on a solution to accept')
|
||||||
|
endif
|
||||||
|
for solution in sorted
|
||||||
|
let lines += [s:separator] + split(solution.displayText, "\n", 1)
|
||||||
|
endfor
|
||||||
|
try
|
||||||
|
call setbufvar(bufnr, '&modifiable', 1)
|
||||||
|
call setbufvar(bufnr, '&readonly', 0)
|
||||||
|
call setbufline(bufnr, 1, lines)
|
||||||
|
finally
|
||||||
|
call setbufvar(bufnr, '&modifiable', 0)
|
||||||
|
call setbufvar(bufnr, '&readonly', 1)
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#panel#Solution(params, ...) abort
|
||||||
|
let state = getbufvar('^' . a:params.panelId . '$', 'copilot_panel')
|
||||||
|
if !bufloaded(a:params.panelId) || type(state) != v:t_dict
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let state.solutions[a:params.solutionId] = a:params
|
||||||
|
call s:Render(a:params.panelId)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#panel#SolutionsDone(params, ...) abort
|
||||||
|
let state = getbufvar('^' . a:params.panelId . '$', 'copilot_panel')
|
||||||
|
if !bufloaded(a:params.panelId) || type(state) != v:t_dict
|
||||||
|
call copilot#logger#Debug('SolutionsDone: ' . a:params.panelId)
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let state.status = get(a:params, 'message', '')
|
||||||
|
call s:Render(a:params.panelId)
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#panel#Accept(...) abort
|
||||||
|
let state = get(b:, 'copilot_panel', {})
|
||||||
|
let solutions = s:Solutions(state)
|
||||||
|
if empty(solutions)
|
||||||
|
return ''
|
||||||
|
endif
|
||||||
|
if !has_key(state, 'bufnr') || !bufloaded(get(state, 'bufnr', -1))
|
||||||
|
return "echoerr 'Buffer was closed'"
|
||||||
|
endif
|
||||||
|
let at = a:0 ? a:1 : line('.')
|
||||||
|
let solution_index = 0
|
||||||
|
for lnum in range(1, at)
|
||||||
|
if getline(lnum) ==# s:separator
|
||||||
|
let solution_index += 1
|
||||||
|
endif
|
||||||
|
endfor
|
||||||
|
if solution_index > 0 && solution_index <= len(solutions)
|
||||||
|
let solution = solutions[solution_index - 1]
|
||||||
|
let lnum = solution.range.start.line + 1
|
||||||
|
if getbufline(state.bufnr, lnum) !=# [state.line]
|
||||||
|
return 'echoerr "Buffer has changed since synthesizing solution"'
|
||||||
|
endif
|
||||||
|
let lines = split(solution.displayText, "\n", 1)
|
||||||
|
let old_first = getline(solution.range.start.line + 1)
|
||||||
|
let lines[0] = strpart(old_first, 0, copilot#doc#UTF16ToByteIdx(old_first, solution.range.start.character)) . lines[0]
|
||||||
|
let old_last = getline(solution.range.end.line + 1)
|
||||||
|
let lines[-1] .= strpart(old_last, copilot#doc#UTF16ToByteIdx(old_last, solution.range.start.character))
|
||||||
|
call setbufline(state.bufnr, solution.range.start.line + 1, lines[0])
|
||||||
|
call appendbufline(state.bufnr, solution.range.start.line + 1, lines[1:-1])
|
||||||
|
call copilot#Request('notifyAccepted', {'uuid': solution.solutionId})
|
||||||
|
bwipeout
|
||||||
|
let win = bufwinnr(state.bufnr)
|
||||||
|
if win > 0
|
||||||
|
exe win . 'wincmd w'
|
||||||
|
exe solution.range.start.line + len(lines)
|
||||||
|
if state.was_insert
|
||||||
|
startinsert!
|
||||||
|
else
|
||||||
|
normal! $
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:Initialize(state) abort
|
||||||
|
let &l:filetype = 'copilot' . (empty(a:state.filetype) ? '' : '.' . a:state.filetype)
|
||||||
|
let &l:tabstop = a:state.tabstop
|
||||||
|
call clearmatches()
|
||||||
|
call matchadd('CopilotSuggestion', '\C^' . s:separator . '\n\zs' . escape(a:state.line, '][^$.*\~'), 10, 4)
|
||||||
|
nmap <buffer><script> <CR> <Cmd>exe copilot#panel#Accept()<CR>
|
||||||
|
nmap <buffer><script> [[ <Cmd>call search('^─\{9,}\n.', 'bWe')<CR>
|
||||||
|
nmap <buffer><script> ]] <Cmd>call search('^─\{9,}\n.', 'We')<CR>
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:BufReadCmd() abort
|
||||||
|
setlocal bufhidden=wipe buftype=nofile nobuflisted readonly nomodifiable
|
||||||
|
let state = get(b:, 'copilot_panel')
|
||||||
|
if type(state) != v:t_dict
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
call s:Initialize(state)
|
||||||
|
call s:Render(expand('<amatch>'))
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! copilot#panel#Open(opts) abort
|
||||||
|
let s:panel_id += 1
|
||||||
|
let state = {'solutions': {}, 'filetype': &filetype, 'line': getline('.'), 'bufnr': bufnr(''), 'tabstop': &tabstop}
|
||||||
|
let bufname = 'copilot:///' . s:panel_id
|
||||||
|
let params = copilot#doc#Params({'panelId': bufname})
|
||||||
|
let state.was_insert = mode() =~# '^[iR]'
|
||||||
|
if state.was_insert
|
||||||
|
stopinsert
|
||||||
|
else
|
||||||
|
let params.doc.position.character = copilot#doc#UTF16Width(state.line)
|
||||||
|
let params.position.character = params.doc.position.character
|
||||||
|
endif
|
||||||
|
let response = copilot#Request('getPanelCompletions', params).Wait()
|
||||||
|
if response.status ==# 'error'
|
||||||
|
return 'echoerr ' . string(response.error.message)
|
||||||
|
endif
|
||||||
|
let state.count_target = response.result.solutionCountTarget
|
||||||
|
exe substitute(a:opts.mods, '\C\<tab\>', '-tab', 'g') 'keepalt split' bufname
|
||||||
|
let b:copilot_panel = state
|
||||||
|
call s:Initialize(state)
|
||||||
|
call s:Render(@%)
|
||||||
|
return ''
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
augroup github_copilot_panel
|
||||||
|
autocmd!
|
||||||
|
autocmd BufReadCmd copilot:///* exe s:BufReadCmd()
|
||||||
|
augroup END
|
722
sources_non_forked/copilot.vim/dist/agent.js
vendored
Normal file
722
sources_non_forked/copilot.vim/dist/agent.js
vendored
Normal file
File diff suppressed because one or more lines are too long
6
sources_non_forked/copilot.vim/dist/agent.js.map
vendored
Normal file
6
sources_non_forked/copilot.vim/dist/agent.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
sources_non_forked/copilot.vim/dist/compiled/darwin/arm64/kerberos.node
vendored
Normal file
BIN
sources_non_forked/copilot.vim/dist/compiled/darwin/arm64/kerberos.node
vendored
Normal file
Binary file not shown.
BIN
sources_non_forked/copilot.vim/dist/compiled/darwin/x64/kerberos.node
vendored
Normal file
BIN
sources_non_forked/copilot.vim/dist/compiled/darwin/x64/kerberos.node
vendored
Normal file
Binary file not shown.
BIN
sources_non_forked/copilot.vim/dist/compiled/linux/arm64/kerberos.node
vendored
Normal file
BIN
sources_non_forked/copilot.vim/dist/compiled/linux/arm64/kerberos.node
vendored
Normal file
Binary file not shown.
BIN
sources_non_forked/copilot.vim/dist/compiled/linux/x64/kerberos.node
vendored
Normal file
BIN
sources_non_forked/copilot.vim/dist/compiled/linux/x64/kerberos.node
vendored
Normal file
Binary file not shown.
BIN
sources_non_forked/copilot.vim/dist/compiled/win32/x64/kerberos.node
vendored
Normal file
BIN
sources_non_forked/copilot.vim/dist/compiled/win32/x64/kerberos.node
vendored
Normal file
Binary file not shown.
BIN
sources_non_forked/copilot.vim/dist/crypt32.node
vendored
Normal file
BIN
sources_non_forked/copilot.vim/dist/crypt32.node
vendored
Normal file
Binary file not shown.
100260
sources_non_forked/copilot.vim/dist/resources/cl100k/tokenizer_cushman002.json
vendored
Normal file
100260
sources_non_forked/copilot.vim/dist/resources/cl100k/tokenizer_cushman002.json
vendored
Normal file
File diff suppressed because it is too large
Load diff
100001
sources_non_forked/copilot.vim/dist/resources/cl100k/vocab_cushman002.bpe
vendored
Normal file
100001
sources_non_forked/copilot.vim/dist/resources/cl100k/vocab_cushman002.bpe
vendored
Normal file
File diff suppressed because it is too large
Load diff
BIN
sources_non_forked/copilot.vim/dist/tree-sitter-go.wasm
vendored
Normal file
BIN
sources_non_forked/copilot.vim/dist/tree-sitter-go.wasm
vendored
Normal file
Binary file not shown.
BIN
sources_non_forked/copilot.vim/dist/tree-sitter-javascript.wasm
vendored
Normal file
BIN
sources_non_forked/copilot.vim/dist/tree-sitter-javascript.wasm
vendored
Normal file
Binary file not shown.
BIN
sources_non_forked/copilot.vim/dist/tree-sitter-python.wasm
vendored
Normal file
BIN
sources_non_forked/copilot.vim/dist/tree-sitter-python.wasm
vendored
Normal file
Binary file not shown.
BIN
sources_non_forked/copilot.vim/dist/tree-sitter-ruby.wasm
vendored
Normal file
BIN
sources_non_forked/copilot.vim/dist/tree-sitter-ruby.wasm
vendored
Normal file
Binary file not shown.
BIN
sources_non_forked/copilot.vim/dist/tree-sitter-tsx.wasm
vendored
Normal file
BIN
sources_non_forked/copilot.vim/dist/tree-sitter-tsx.wasm
vendored
Normal file
Binary file not shown.
BIN
sources_non_forked/copilot.vim/dist/tree-sitter-typescript.wasm
vendored
Normal file
BIN
sources_non_forked/copilot.vim/dist/tree-sitter-typescript.wasm
vendored
Normal file
Binary file not shown.
BIN
sources_non_forked/copilot.vim/dist/tree-sitter.wasm
vendored
Normal file
BIN
sources_non_forked/copilot.vim/dist/tree-sitter.wasm
vendored
Normal file
Binary file not shown.
167
sources_non_forked/copilot.vim/doc/copilot.txt
Normal file
167
sources_non_forked/copilot.vim/doc/copilot.txt
Normal file
|
@ -0,0 +1,167 @@
|
||||||
|
*copilot.txt* GitHub Copilot - Your AI pair programmer
|
||||||
|
|
||||||
|
GETTING STARTED *copilot*
|
||||||
|
|
||||||
|
Invoke `:Copilot setup` to authenticate and enable GitHub Copilot.
|
||||||
|
|
||||||
|
Suggestions are displayed inline and can be accepted by pressing <Tab>. If
|
||||||
|
inline suggestions do not appear to be working, invoke `:Copilot status` to
|
||||||
|
verify Copilot is enabled and not experiencing any issues.
|
||||||
|
|
||||||
|
COMMANDS *:Copilot*
|
||||||
|
|
||||||
|
*:Copilot_disable*
|
||||||
|
:Copilot disable Globally disable GitHub Copilot inline suggestions.
|
||||||
|
|
||||||
|
*:Copilot_enable*
|
||||||
|
:Copilot enable Re-enable GitHub Copilot after :Copilot disable.
|
||||||
|
|
||||||
|
*:Copilot_setup*
|
||||||
|
:Copilot setup Authenticate and enable GitHub Copilot.
|
||||||
|
|
||||||
|
*:Copilot_signout*
|
||||||
|
:Copilot signout Sign out of GitHub Copilot.
|
||||||
|
|
||||||
|
*:Copilot_status*
|
||||||
|
:Copilot status Check if GitHub Copilot is operational for the current
|
||||||
|
buffer and report on any issues.
|
||||||
|
|
||||||
|
*:Copilot_panel*
|
||||||
|
:Copilot panel Open a window with up to 10 completions for the
|
||||||
|
current buffer. Use <CR> to accept a solution. Maps
|
||||||
|
are also provided for [[ and ]] to jump from solution
|
||||||
|
to solution. This is the default command if :Copilot
|
||||||
|
is called without an argument.
|
||||||
|
|
||||||
|
*:Copilot_version*
|
||||||
|
:Copilot version Show version information.
|
||||||
|
|
||||||
|
*:Copilot_feedback*
|
||||||
|
:Copilot feedback Open the website for providing GitHub Copilot
|
||||||
|
feedback. Be sure to include |:Copilot_version|
|
||||||
|
output when reporting a bug.
|
||||||
|
|
||||||
|
OPTIONS *copilot-options*
|
||||||
|
|
||||||
|
*g:copilot_filetypes*
|
||||||
|
g:copilot_filetypes A dictionary mapping file types to their enabled
|
||||||
|
status. Most file types are enabled by default, so
|
||||||
|
generally this is used for opting out.
|
||||||
|
>
|
||||||
|
let g:copilot_filetypes = {
|
||||||
|
\ 'xml': v:false,
|
||||||
|
\ }
|
||||||
|
<
|
||||||
|
Disabling all file types can be done by setting the
|
||||||
|
special key "*". File types can then be turned back
|
||||||
|
on individually.
|
||||||
|
>
|
||||||
|
let g:copilot_filetypes = {
|
||||||
|
\ '*': v:false,
|
||||||
|
\ 'python': v:true,
|
||||||
|
\ }
|
||||||
|
<
|
||||||
|
*b:copilot_enabled*
|
||||||
|
b:copilot_enabled Set to v:false to disable GitHub Copilot for the
|
||||||
|
current buffer. Or set to v:true to force enabling
|
||||||
|
it, overriding g:copilot_filetypes.
|
||||||
|
|
||||||
|
*g:copilot_node_command*
|
||||||
|
g:copilot_node_command Tell Copilot what `node` binary to use with
|
||||||
|
g:copilot_node_command. This is useful if the `node`
|
||||||
|
in your PATH is an unsupported version.
|
||||||
|
>
|
||||||
|
let g:copilot_node_command =
|
||||||
|
\ "~/.nodenv/versions/18.18.0/bin/node"
|
||||||
|
<
|
||||||
|
*g:copilot_proxy*
|
||||||
|
g:copilot_proxy Tell Copilot what proxy server to use. This is a
|
||||||
|
string in the format of `hostname:port` or
|
||||||
|
`username:password@host:port`.
|
||||||
|
>
|
||||||
|
let g:copilot_proxy = 'localhost:3128'
|
||||||
|
<
|
||||||
|
*g:copilot_proxy_strict_ssl*
|
||||||
|
g:copilot_proxy_strict_ssl
|
||||||
|
Corporate proxies sometimes use a man-in-the-middle
|
||||||
|
SSL certificate which is incompatible with GitHub
|
||||||
|
Copilot. To work around this, SSL certificate
|
||||||
|
verification can be disabled:
|
||||||
|
>
|
||||||
|
let g:copilot_proxy_strict_ssl = v:false
|
||||||
|
<
|
||||||
|
MAPS *copilot-maps*
|
||||||
|
|
||||||
|
*copilot-i_<Tab>*
|
||||||
|
Copilot.vim uses <Tab> to accept the current suggestion. If you have an
|
||||||
|
existing <Tab> map, that will be used as the fallback when no suggestion is
|
||||||
|
displayed.
|
||||||
|
|
||||||
|
*copilot#Accept()*
|
||||||
|
If you'd rather use a key that isn't <Tab>, define an <expr> map that calls
|
||||||
|
copilot#Accept(). Here's an example with CTRL-J:
|
||||||
|
>
|
||||||
|
imap <silent><script><expr> <C-J> copilot#Accept("\<CR>")
|
||||||
|
let g:copilot_no_tab_map = v:true
|
||||||
|
<
|
||||||
|
Lua version:
|
||||||
|
>
|
||||||
|
vim.keymap.set('i', '<C-J>', 'copilot#Accept("\<CR>")', {
|
||||||
|
expr = true,
|
||||||
|
replace_keycodes = false
|
||||||
|
})
|
||||||
|
vim.g.copilot_no_tab_map = true
|
||||||
|
<
|
||||||
|
The argument to copilot#Accept() is the fallback for when no suggestion is
|
||||||
|
displayed. In this example, a regular carriage return is used. If no
|
||||||
|
fallback is desired, use an argument of "" (an empty string).
|
||||||
|
|
||||||
|
Other Maps ~
|
||||||
|
|
||||||
|
Note that M- (a.k.a. meta or alt) maps are highly dependent on your terminal
|
||||||
|
to function correctly and may be unsupported with your setup. As an
|
||||||
|
alternative, you can create your own versions that invoke the <Plug> maps
|
||||||
|
instead. Here's an example that maps CTRL-L to accept one word of the
|
||||||
|
current suggestion:
|
||||||
|
>
|
||||||
|
imap <C-L> <Plug>(copilot-accept-word)
|
||||||
|
<
|
||||||
|
Lua version:
|
||||||
|
>
|
||||||
|
vim.keymap.set('i', '<C-L>', '<Plug>(copilot-accept-word)')
|
||||||
|
<
|
||||||
|
*copilot-i_CTRL-]*
|
||||||
|
<C-]> Dismiss the current suggestion.
|
||||||
|
<Plug>(copilot-dismiss)
|
||||||
|
|
||||||
|
*copilot-i_ALT-]*
|
||||||
|
<M-]> Cycle to the next suggestion, if one is available.
|
||||||
|
<Plug>(copilot-next)
|
||||||
|
|
||||||
|
*copilot-i_ALT-[*
|
||||||
|
<M-[> Cycle to the previous suggestion.
|
||||||
|
<Plug>(copilot-previous)
|
||||||
|
|
||||||
|
*copilot-i_ALT-\*
|
||||||
|
<M-\> Explicitly request a suggestion, even if Copilot
|
||||||
|
<Plug>(copilot-suggest) is disabled.
|
||||||
|
|
||||||
|
*copilot-i_ALT-Right*
|
||||||
|
<M-Right> Accept the next word of the current suggestion.
|
||||||
|
<Plug>(copilot-accept-word)
|
||||||
|
|
||||||
|
*copilot-i_ALT-CTRL-Right*
|
||||||
|
|
||||||
|
<M-C-Right> Accept the next line of the current suggestion.
|
||||||
|
<Plug>(copilot-accept-line)
|
||||||
|
|
||||||
|
SYNTAX HIGHLIGHTING *copilot-highlighting*
|
||||||
|
|
||||||
|
Inline suggestions are highlighted using the CopilotSuggestion group,
|
||||||
|
defaulting to a medium gray. The best place to override this is a file named
|
||||||
|
after/colors/<colorschemename>.vim in your 'runtimepath' (e.g.,
|
||||||
|
~/.config/nvim/after/colors/solarized.vim). Example declaration:
|
||||||
|
>
|
||||||
|
highlight CopilotSuggestion guifg=#555555 ctermfg=8
|
||||||
|
<
|
||||||
|
vim:tw=78:et:ft=help:norl:
|
75
sources_non_forked/copilot.vim/lua/_copilot.lua
Normal file
75
sources_non_forked/copilot.vim/lua/_copilot.lua
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
local copilot = {}
|
||||||
|
|
||||||
|
copilot.lsp_start_client = function(cmd, handler_names)
|
||||||
|
local capabilities = vim.lsp.protocol.make_client_capabilities()
|
||||||
|
local handlers = {}
|
||||||
|
local id
|
||||||
|
for _, name in ipairs(handler_names) do
|
||||||
|
handlers[name] = function(err, result)
|
||||||
|
if result then
|
||||||
|
local retval = vim.call('copilot#agent#LspHandle', id, {method = name, params = result})
|
||||||
|
if type(retval) == 'table' then return retval.result, retval.error end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if name:match('^copilot/') then
|
||||||
|
capabilities.copilot = capabilities.copilot or {}
|
||||||
|
capabilities.copilot[name:match('^copilot/(.*)$')] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
id = vim.lsp.start_client({
|
||||||
|
cmd = cmd,
|
||||||
|
cmd_cwd = vim.call('copilot#job#Cwd'),
|
||||||
|
name = 'copilot',
|
||||||
|
capabilities = capabilities,
|
||||||
|
handlers = handlers,
|
||||||
|
get_language_id = function(bufnr, filetype)
|
||||||
|
return vim.call('copilot#doc#LanguageForFileType', filetype)
|
||||||
|
end,
|
||||||
|
on_init = function(client, initialize_result)
|
||||||
|
vim.call('copilot#agent#LspInit', client.id, initialize_result)
|
||||||
|
end,
|
||||||
|
on_exit = function(code, signal, client_id)
|
||||||
|
vim.schedule(function()
|
||||||
|
vim.call('copilot#agent#LspExit', client_id, code, signal)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
})
|
||||||
|
return id
|
||||||
|
end
|
||||||
|
|
||||||
|
copilot.lsp_request = function(client_id, method, params)
|
||||||
|
local client = vim.lsp.get_client_by_id(client_id)
|
||||||
|
if not client then return end
|
||||||
|
vim.lsp.buf_attach_client(0, client_id)
|
||||||
|
for _, doc in ipairs({params.doc, params.textDocument}) do
|
||||||
|
if doc and type(doc.uri) == 'number' then
|
||||||
|
local bufnr = doc.uri
|
||||||
|
vim.lsp.buf_attach_client(bufnr, client_id)
|
||||||
|
doc.uri = vim.uri_from_bufnr(bufnr)
|
||||||
|
doc.version = vim.lsp.util.buf_versions[bufnr]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local _, id
|
||||||
|
_, id = client.request(method, params, function(err, result)
|
||||||
|
vim.call('copilot#agent#LspResponse', client_id, {id = id, error = err, result = result})
|
||||||
|
end)
|
||||||
|
return id
|
||||||
|
end
|
||||||
|
|
||||||
|
copilot.rpc_request = function(client_id, method, params)
|
||||||
|
local client = vim.lsp.get_client_by_id(client_id)
|
||||||
|
if not client then return end
|
||||||
|
local _, id
|
||||||
|
_, id = client.rpc.request(method, params, function(err, result)
|
||||||
|
vim.call('copilot#agent#LspResponse', client_id, {id = id, error = err, result = result})
|
||||||
|
end)
|
||||||
|
return id
|
||||||
|
end
|
||||||
|
|
||||||
|
copilot.rpc_notify = function(client_id, method, params)
|
||||||
|
local client = vim.lsp.get_client_by_id(client_id)
|
||||||
|
if not client then return end
|
||||||
|
return client.rpc.notify(method, params)
|
||||||
|
end
|
||||||
|
|
||||||
|
return copilot
|
113
sources_non_forked/copilot.vim/plugin/copilot.vim
Normal file
113
sources_non_forked/copilot.vim/plugin/copilot.vim
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
if exists('g:loaded_copilot')
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
let g:loaded_copilot = 1
|
||||||
|
|
||||||
|
scriptencoding utf-8
|
||||||
|
|
||||||
|
command! -bang -nargs=? -range=-1 -complete=customlist,copilot#CommandComplete Copilot exe copilot#Command(<line1>, <count>, +"<range>", <bang>0, "<mods>", <q-args>)
|
||||||
|
|
||||||
|
if v:version < 800 || !exists('##CompleteChanged')
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
|
function! s:ColorScheme() abort
|
||||||
|
if &t_Co == 256
|
||||||
|
hi def CopilotSuggestion guifg=#808080 ctermfg=244
|
||||||
|
else
|
||||||
|
hi def CopilotSuggestion guifg=#808080 ctermfg=8
|
||||||
|
endif
|
||||||
|
hi def link CopilotAnnotation Normal
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:MapTab() abort
|
||||||
|
if get(g:, 'copilot_no_tab_map') || get(g:, 'copilot_no_maps')
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let tab_map = maparg('<Tab>', 'i', 0, 1)
|
||||||
|
if !has_key(tab_map, 'rhs')
|
||||||
|
imap <script><silent><nowait><expr> <Tab> copilot#Accept()
|
||||||
|
elseif tab_map.rhs !~# 'copilot'
|
||||||
|
if tab_map.expr
|
||||||
|
let tab_fallback = '{ -> ' . tab_map.rhs . ' }'
|
||||||
|
else
|
||||||
|
let tab_fallback = substitute(json_encode(tab_map.rhs), '<', '\\<', 'g')
|
||||||
|
endif
|
||||||
|
let tab_fallback = substitute(tab_fallback, '<SID>', '<SNR>' . get(tab_map, 'sid') . '_', 'g')
|
||||||
|
if get(tab_map, 'noremap') || get(tab_map, 'script') || mapcheck('<Left>', 'i') || mapcheck('<Del>', 'i')
|
||||||
|
exe 'imap <script><silent><nowait><expr> <Tab> copilot#Accept(' . tab_fallback . ')'
|
||||||
|
else
|
||||||
|
exe 'imap <silent><nowait><expr> <Tab> copilot#Accept(' . tab_fallback . ')'
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
function! s:Event(type) abort
|
||||||
|
try
|
||||||
|
call call('copilot#On' . a:type, [])
|
||||||
|
catch
|
||||||
|
call copilot#logger#Exception()
|
||||||
|
endtry
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
augroup github_copilot
|
||||||
|
autocmd!
|
||||||
|
autocmd InsertLeave * call s:Event('InsertLeave')
|
||||||
|
autocmd BufLeave * if mode() =~# '^[iR]'|call s:Event('InsertLeave')|endif
|
||||||
|
autocmd InsertEnter * call s:Event('InsertEnter')
|
||||||
|
autocmd BufEnter * if mode() =~# '^[iR]'|call s:Event('InsertEnter')|endif
|
||||||
|
autocmd CursorMovedI * call s:Event('CursorMovedI')
|
||||||
|
autocmd CompleteChanged * call s:Event('CompleteChanged')
|
||||||
|
autocmd ColorScheme,VimEnter * call s:ColorScheme()
|
||||||
|
autocmd VimEnter * call s:MapTab()
|
||||||
|
autocmd BufUnload * call s:Event('BufUnload')
|
||||||
|
autocmd VimLeavePre * call s:Event('VimLeavePre')
|
||||||
|
autocmd BufReadCmd copilot://* setlocal buftype=nofile bufhidden=wipe nobuflisted readonly nomodifiable
|
||||||
|
augroup END
|
||||||
|
|
||||||
|
call s:ColorScheme()
|
||||||
|
call s:MapTab()
|
||||||
|
if !get(g:, 'copilot_no_maps')
|
||||||
|
imap <Plug>(copilot-dismiss) <Cmd>call copilot#Dismiss()<CR>
|
||||||
|
if empty(mapcheck('<C-]>', 'i'))
|
||||||
|
imap <silent><script><nowait><expr> <C-]> copilot#Dismiss() . "\<C-]>"
|
||||||
|
endif
|
||||||
|
imap <Plug>(copilot-next) <Cmd>call copilot#Next()<CR>
|
||||||
|
imap <Plug>(copilot-previous) <Cmd>call copilot#Previous()<CR>
|
||||||
|
imap <Plug>(copilot-suggest) <Cmd>call copilot#Suggest()<CR>
|
||||||
|
imap <script><silent><nowait><expr> <Plug>(copilot-accept-word) copilot#AcceptWord()
|
||||||
|
imap <script><silent><nowait><expr> <Plug>(copilot-accept-line) copilot#AcceptLine()
|
||||||
|
try
|
||||||
|
if !has('nvim') && &encoding ==# 'utf-8'
|
||||||
|
" avoid 8-bit meta collision with UTF-8 characters
|
||||||
|
let s:restore_encoding = 1
|
||||||
|
set encoding=cp949
|
||||||
|
endif
|
||||||
|
if empty(mapcheck('<M-]>', 'i'))
|
||||||
|
imap <M-]> <Plug>(copilot-next)
|
||||||
|
endif
|
||||||
|
if empty(mapcheck('<M-[>', 'i'))
|
||||||
|
imap <M-[> <Plug>(copilot-previous)
|
||||||
|
endif
|
||||||
|
if empty(mapcheck('<M-Bslash>', 'i'))
|
||||||
|
imap <M-Bslash> <Plug>(copilot-suggest)
|
||||||
|
endif
|
||||||
|
if empty(mapcheck('<M-Right>', 'i'))
|
||||||
|
imap <M-Right> <Plug>(copilot-accept-word)
|
||||||
|
endif
|
||||||
|
if empty(mapcheck('<M-C-Right>', 'i'))
|
||||||
|
imap <M-Down> <Plug>(copilot-accept-line)
|
||||||
|
endif
|
||||||
|
finally
|
||||||
|
if exists('s:restore_encoding')
|
||||||
|
set encoding=utf-8
|
||||||
|
endif
|
||||||
|
endtry
|
||||||
|
endif
|
||||||
|
|
||||||
|
call copilot#Init()
|
||||||
|
|
||||||
|
let s:dir = expand('<sfile>:h:h')
|
||||||
|
if getftime(s:dir . '/doc/copilot.txt') > getftime(s:dir . '/doc/tags')
|
||||||
|
silent! execute 'helptags' fnameescape(s:dir . '/doc')
|
||||||
|
endif
|
19
sources_non_forked/copilot.vim/syntax/copilot.vim
Normal file
19
sources_non_forked/copilot.vim/syntax/copilot.vim
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
scriptencoding utf-8
|
||||||
|
|
||||||
|
if exists("b:current_syntax")
|
||||||
|
finish
|
||||||
|
endif
|
||||||
|
|
||||||
|
let s:subtype = matchstr(&l:filetype, '\<copilot\.\zs[[:alnum:]_-]\+')
|
||||||
|
if !empty(s:subtype) && s:subtype !=# 'copilot'
|
||||||
|
exe 'syn include @copilotLanguageTop syntax/' . s:subtype . '.vim'
|
||||||
|
unlet! b:current_syntax
|
||||||
|
endif
|
||||||
|
|
||||||
|
syn region copilotHeader start="\%^" end="^─\@="
|
||||||
|
syn region copilotSolution matchgroup=copilotSeparator start="^─\{9,}$" end="\%(^─\{9,\}$\)\@=\|\%$" keepend contains=@copilotLanguageTop
|
||||||
|
|
||||||
|
hi def link copilotHeader PreProc
|
||||||
|
hi def link copilotSeparator Comment
|
||||||
|
|
||||||
|
let b:current_syntax = "copilot"
|
Loading…
Reference in a new issue