From 4fa078b8bf12b5177dbf0f1a6db5051e0fcedeb7 Mon Sep 17 00:00:00 2001 From: Henry Barreto Date: Tue, 28 Jul 2026 20:32:16 -0300 Subject: [PATCH 1/2] Add OpenAI-compatible API endpoint and model configuration --- autoload/copilot.vim | 13 +++++++++++-- autoload/copilot/client.vim | 21 +++++++++++++++++++++ doc/copilot.txt | 27 +++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/autoload/copilot.vim b/autoload/copilot.vim index dfdc443..fd1156f 100644 --- a/autoload/copilot.vim +++ b/autoload/copilot.vim @@ -787,17 +787,26 @@ function! s:commands.model(opts) abort return 'echoerr ' . string('Copilot: Error retrieving completions models: ' . response.error.message) endif let models = filter(response.result, { _, m -> index(m.scopes, 'completion') >= 0 }) + let current_model = get(g:, 'copilot_model', '') if len(models) == 0 - echo 'Copilot: Could not retrieve completions models' - elseif len(models) == 1 + if !empty(current_model) + echo 'Copilot: Current/only completions model is ' . current_model . ' (set via g:copilot_model)' + else + echo 'Copilot: Could not retrieve completions models' + endif + elseif len(models) == 1 && empty(current_model) echo 'Copilot: Current/only completions model is ' . s:FmtModel(models[0]) else + if !empty(current_model) + call insert(models, {'modelName': current_model, 'id': current_model, 'scopes': ['completion']}) + endif let choices = map(copy(models), { i, m -> (i + 1) . '. ' . s:FmtModel(m) }) let choice = inputlist(['Select a completions model:'] + choices) if choice < 1 || choice > len(models) return endif let model = models[choice - 1] + let g:copilot_model = model.id if type(get(g:, 'copilot_settings')) != v:t_dict let g:copilot_settings = {} endif diff --git a/autoload/copilot/client.vim b/autoload/copilot/client.vim index c3ec862..6d341bd 100644 --- a/autoload/copilot/client.vim +++ b/autoload/copilot/client.vim @@ -596,6 +596,21 @@ function! copilot#client#Settings() abort if type(settings.http.proxy) ==# v:t_string && settings.http.proxy =~# '^[^/]\+$' let settings.http.proxy = 'http://' . settings.http.proxy endif + if type(get(g:, 'copilot_api_url')) == v:t_string + let settings.api = {'url': g:copilot_api_url} + endif + if type(get(g:, 'copilot_api_key')) == v:t_string + if !has_key(settings, 'api') + let settings.api = {} + endif + let settings.api.key = g:copilot_api_key + endif + if type(get(g:, 'copilot_model')) == v:t_string + if !has_key(settings, 'api') + let settings.api = {} + endif + let settings.api.model = g:copilot_model + endif if type(get(g:, 'copilot_settings')) == v:t_dict let settings.github = {'copilot': g:copilot_settings} endif @@ -718,6 +733,12 @@ function! copilot#client#New() abort if type(get(g:, 'copilot_integration_id')) == v:t_string let opts.initializationOptions.copilotIntegrationId = g:copilot_integration_id endif + if type(get(g:, 'copilot_model')) == v:t_string + if type(get(g:, 'copilot_settings')) != v:t_dict + let g:copilot_settings = {} + endif + let g:copilot_settings.selectedCompletionModel = g:copilot_model + endif let opts.workspaceFolders = [] let settings = copilot#client#Settings() if type(get(g:, 'copilot_workspace_folders')) == v:t_list diff --git a/doc/copilot.txt b/doc/copilot.txt index f6418d7..ce62eb8 100644 --- a/doc/copilot.txt +++ b/doc/copilot.txt @@ -34,6 +34,10 @@ COMMANDS *:Copilot* completions models is one, rendering this command inert. + The model can also be set via |g:copilot_model| in your + vimrc to specify an arbitrary model without the + interactive prompt. + *:Copilot_panel* :Copilot panel Open a window with up to 10 completions for the current buffer. Use to accept a completion. @@ -125,6 +129,29 @@ g:copilot_proxy_strict_ssl by setting the $NODE_TLS_REJECT_UNAUTHORIZED environment variable to "0". + *g:copilot_api_url* +g:copilot_api_url Specify an OpenAI API compatible endpoint URL for + completions. When set, this URL will be passed to the + language server for use with any OpenAI-compatible API. +> + let g:copilot_api_url = 'https://api.openai.com/v1' + let g:copilot_api_url = 'http://localhost:11434/v1' +< + *g:copilot_api_key* +g:copilot_api_key Specify an API key for use with the API endpoint + configured via |g:copilot_api_url|. +> + let g:copilot_api_key = 'sk-...' +< + *g:copilot_model* +g:copilot_model Specify the model to use for completions, bypassing the + interactive |:Copilot_model| command. Setting this + also populates |g:copilot_settings| with the given + model. +> + let g:copilot_model = 'gpt-4o' + let g:copilot_model = 'codellama' +< *g:copilot_workspace_folders* g:copilot_workspace_folders A list of "workspace folders" or project roots that From b7045edd638094866bcf25aefac0829a79697f94 Mon Sep 17 00:00:00 2001 From: Henry Barreto Date: Mon, 3 Aug 2026 08:24:13 -0300 Subject: [PATCH 2/2] Remove signin, signout, and auth commands Drop all GitHub/Microsoft authentication: signIn/signOut LSP calls, device code flow, browser-based auth UI, enterprise URI config, and the showDocument/showMessageRequest handlers. The plugin now relies on g:copilot_api_url/g:copilot_api_key for API access. --- autoload/copilot.vim | 98 +---------------------------------- autoload/copilot/client.vim | 7 +-- autoload/copilot/handlers.vim | 28 ---------- doc/copilot.txt | 15 ------ lua/_copilot.lua | 11 +--- 5 files changed, 3 insertions(+), 156 deletions(-) diff --git a/autoload/copilot.vim b/autoload/copilot.vim index fd1156f..c350a09 100644 --- a/autoload/copilot.vim +++ b/autoload/copilot.vim @@ -536,29 +536,6 @@ function! copilot#AcceptLine(...) abort return copilot#Accept(a:0 ? a:1 : "\r", "[^\n]\\+") 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 - let s:commands = {} function! s:EnabledStatusMessage() abort @@ -623,69 +600,6 @@ function! s:commands.status(opts) abort call s:EditorVersionWarning() endfunction -function! s:commands.signout(opts) abort - echo 'Copilot: Signed out' - call copilot#Call('signOut', {}) -endfunction - -function! s:commands.setup(opts) abort - let startup_error = copilot#Client().StartupError() - if !empty(startup_error) - echo 'Copilot: ' . startup_error - return - endif - - let data = copilot#Call('signIn', {}) - - if has_key(data, 'verificationUri') - let uri = data.verificationUri - if has('clipboard') - try - let @+ = data.userCode - catch - endtry - try - let @* = data.userCode - catch - endtry - endif - let codemsg = "First copy your one-time code: " . data.userCode . "\n" - try - if len(&mouse) - let mouse = &mouse - set mouse= - endif - if get(a:opts, 'bang') - call s:Echo(codemsg . "In your browser, visit " . uri) - let request = copilot#Request('signInConfirm', {}) - else - call input(codemsg . "Press ENTER to open GitHub in your browser\n") - let request = copilot#Request('workspace/executeCommand', data.command) - endif - call s:Echo("Waiting for " . data.userCode . " at " . uri . " (could take up to 5 seconds)") - call request.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 data = request.result - endif - elseif get(data, 'status', '') isnot# 'AlreadySignedIn' - return 'echoerr ' . string('Copilot: Something went wrong') - endif - - let user = get(data, 'user', '') - - echo 'Copilot: Authenticated as GitHub user ' . user -endfunction - -let s:commands.auth = s:commands.setup -let s:commands.signin = s:commands.setup - function! s:commands.help(opts) abort return a:opts.mods . ' help ' . (len(a:opts.arg) ? ':Copilot_' . a:opts.arg : 'copilot') endfunction @@ -842,17 +756,7 @@ function! copilot#Command(line1, line2, range, bang, mods, arg) abort if !s:Running() let cmd = 'restart' else - try - let opts = copilot#Call('checkStatus', {'options': {'localChecksOnly': v:true}}) - if opts.status !=# 'OK' && opts.status !=# 'MaybeOK' - let cmd = 'setup' - else - let cmd = 'status' - endif - catch - call copilot#logger#Exception() - let cmd = 'log' - endtry + let cmd = 'status' endif endif let opts = {'line1': a:line1, 'line2': a:line2, 'range': a:range, 'bang': a:bang, 'mods': a:mods, 'arg': arg} diff --git a/autoload/copilot/client.vim b/autoload/copilot/client.vim index 6d341bd..68eb3a6 100644 --- a/autoload/copilot/client.vim +++ b/autoload/copilot/client.vim @@ -591,7 +591,6 @@ function! copilot#client#Settings() abort \ 'http': { \ 'proxy': get(g:, 'copilot_proxy', v:null), \ 'proxyStrictSSL': get(g:, 'copilot_proxy_strict_ssl', v:null)}, - \ 'github-enterprise': {'uri': get(g:, 'copilot_enterprise_uri', get(g:, 'copilot_auth_provider_url', v:null))}, \ } if type(settings.http.proxy) ==# v:t_string && settings.http.proxy =~# '^[^/]\+$' let settings.http.proxy = 'http://' . settings.http.proxy @@ -686,14 +685,10 @@ let s:notifications = { \ 'window/logMessage': function('copilot#handlers#window_logMessage'), \ } -let s:vim_handlers = { - \ 'window/showMessageRequest': function('copilot#handlers#window_showMessageRequest'), - \ 'window/showDocument': function('copilot#handlers#window_showDocument'), - \ } +let s:vim_handlers = {} let s:vim_capabilities = { \ 'workspace': {'workspaceFolders': v:true}, - \ 'window': {'showDocument': {'support': v:true}}, \ } function! copilot#client#New() abort diff --git a/autoload/copilot/handlers.vim b/autoload/copilot/handlers.vim index 8c3a364..b4d1cb1 100644 --- a/autoload/copilot/handlers.vim +++ b/autoload/copilot/handlers.vim @@ -1,31 +1,3 @@ function! copilot#handlers#window_logMessage(params, ...) abort call copilot#logger#Raw(get(a:params, 'type', 6), get(a:params, 'message', '')) endfunction - -function! copilot#handlers#window_showMessageRequest(params, instance, ...) abort - let choice = inputlist([a:instance.name . "\n" . 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:BrowserCallback(into, code) abort - let a:into.code = a:code -endfunction - -function! copilot#handlers#window_showDocument(params, ...) abort - echo a:params.uri - if empty(get(a:params, 'external')) - return {'success': v:false} - endif - let browser = copilot#Browser() - if empty(browser) - return {'success': v:false} - endif - let status = {} - call copilot#job#Stream(browser + [a:params.uri], v:null, v:null, function('s:BrowserCallback', [status])) - let time = reltime() - while empty(status) && reltimefloat(reltime(time)) < 1 - sleep 10m - endwhile - return {'success': get(status, 'code') ? v:false : v:true} -endfunction diff --git a/doc/copilot.txt b/doc/copilot.txt index ce62eb8..02e0d13 100644 --- a/doc/copilot.txt +++ b/doc/copilot.txt @@ -2,8 +2,6 @@ GETTING STARTED *copilot* -Invoke `:Copilot setup` to authenticate and enable GitHub Copilot. - Suggestions are displayed inline and can be accepted by pressing . If inline suggestions do not appear to be working, invoke `:Copilot status` to verify Copilot is enabled and not experiencing any issues. @@ -16,12 +14,6 @@ COMMANDS *:Copilot* *: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. @@ -100,13 +92,6 @@ g:copilot_node_command Tell Copilot what `node` binary to use with > let g:copilot_node_command = \ "~/.nodenv/versions/18.18.0/bin/node" -< - *g:copilot_enterprise_uri* -g:copilot_enterprise_uri - If you are using GitHub Copilot Enterprise, set this - to the URI of your GitHub Enterprise instance. -> - let g:copilot_enterprise_uri = 'https://DOMAIN.ghe.com' < *g:copilot_proxy* g:copilot_proxy Tell Copilot what proxy server to use. diff --git a/lua/_copilot.lua b/lua/_copilot.lua index f8aa272..5daee68 100644 --- a/lua/_copilot.lua +++ b/lua/_copilot.lua @@ -1,16 +1,7 @@ local copilot = {} -local showDocument = function(err, result, ctx, _) - local fallback = vim.lsp.handlers['window/showDocument'] - if not fallback or (result.external and vim.g.copilot_browser) then - return vim.fn['copilot#handlers#window_showDocument'](result) - else - return fallback(err, result, ctx, _) - end -end - copilot.lsp_start_client = function(cmd, client_name, handler_names, opts, settings) - local handlers = {['window/showDocument'] = showDocument} + local handlers = {} local id for _, name in ipairs(handler_names) do handlers[name] = function(err, result, ctx, _)