Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 10 additions & 14 deletions lua/copilot/api.lua
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,20 @@ end

---@alias copilot_editor_info { name: string, version: string }
---@alias copilot_editor_plugin_info { name: string, version: string }
---@alias copilot_auth_provider { url: string }
---@alias copilot_network_proxy { host: string, port: integer, username?: string, password?: string, rejectUnauthorized?: boolean }
---@alias copilot_set_editor_info_params { editorInfo: copilot_editor_info, editorPluginInfo: copilot_editor_plugin_info, editorConfiguration: copilot_editor_configuration, networkProxy?: copilot_network_proxy, authProvider?: copilot_auth_provider }

---@param params copilot_set_editor_info_params
---@return any|nil err
---@return nil data
---@return table ctx
function mod.set_editor_info(client, params, callback)
return mod.request(client, "setEditorInfo", params, callback)
end
---@alias copilot_settings_http { proxy: string, proxyStrictSSL: boolean, proxyKerberosServicePrincipal?: string }
---@alias github_settings_telemetry { telemetryLevel: string }
---@alias copilot_settings_github-enterprise { uri: string }
---@alias copilot_settings { http?: copilot_settings_http, telemetry: github_settings_telemetry, github-enterprise?: copilot_settings_github-enterprise }

---@alias copilot_editor_configuration { enableAutoCompletions: boolean, disabledLanguages: string[] }
---@alias copilot_notify_change_configuration_params { settings: copilot_editor_configuration }
---@alias copilot_workspace_selected_completion_model { selectedCompletionModel: string }
---@alias copilot_workspace_copilot { copilot: copilot_workspace_copilot }
---@alias copilot_workspace_configuration { enableAutoCompletions: boolean, disabledLanguages: string[], github: copilot_workspace_configuration }
---@alias copilot_workspace_configurations { settings: copilot_workspace_configuration }

---@param params copilot_notify_change_configuration_params
---@param params copilot_workspace_configurations
function mod.notify_change_configuration(client, params)
return mod.notify(client, "notifyChangeConfiguration", params)
return mod.notify(client, "workspace/didChangeConfiguration", params)
end

---@alias copilot_nofify_set_trace_params { value: 'off'|'messages'|'verbose' }
Expand Down
52 changes: 33 additions & 19 deletions lua/copilot/client.lua
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,32 @@ local function prepare_client_config(overrides)
end

local editor_info = util.get_editor_info()
local provider_url = config.get("auth_provider_url") --[[@as string|nil]]
local proxy_uri = vim.g.copilot_proxy

local settings = { ---@type copilot_settings
telemetry = { ---@type github_settings_telemetry
telemetryLevel = "all",
},
}

if proxy_uri then
vim.tbl_extend("force", settings, {
http = { ---@type copilot_settings_http
proxy = proxy_uri,
proxyStrictSSL = vim.g.copilot_proxy_strict_ssl or false,
proxyKerberosServicePrincipal = nil,
},
})
end

if provider_url then
vim.tbl_extend("force", settings, {
["github-enterprise"] = { ---@type copilot_settings_github-enterprise
uri = provider_url,
},
})
end

-- LSP config, not to be confused with config.lua
return vim.tbl_deep_extend("force", {
Expand All @@ -250,26 +276,16 @@ local function prepare_client_config(overrides)
end

vim.schedule(function()
local set_editor_info_params = util.get_editor_info() --[[@as copilot_set_editor_info_params]]
set_editor_info_params.editorConfiguration = util.get_editor_configuration()
set_editor_info_params.networkProxy = util.get_network_proxy()
local provider_url = config.get("auth_provider_url")
set_editor_info_params.authProvider = provider_url and {
url = provider_url,
} or nil

logger.debug("data for setEditorInfo LSP call", set_editor_info_params)
api.set_editor_info(client, set_editor_info_params, function(err)
if err then
logger.error(string.format("setEditorInfo failure: %s", err))
end
end)
logger.trace("setEditorInfo has been called")
local configurations = util.get_workspace_configurations()
api.notify_change_configuration(client, configurations)
logger.trace("workspace configuration", configurations)

-- to activate tracing if we want it
local logger_conf = config.get("logger") --[[@as copilot_config_logging]]
local trace_params = { value = logger_conf.trace_lsp } --[[@as copilot_nofify_set_trace_params]]
api.notify_set_trace(client, trace_params)

-- prevent requests to copilot prior to being initialized
M.initialized = true
end)
end,
Expand All @@ -289,13 +305,11 @@ local function prepare_client_config(overrides)
end,
handlers = get_handlers(),
init_options = {
copilotIntegrationId = "vscode-chat",
-- Fix LSP warning: editorInfo and editorPluginInfo will soon be required in initializationOptions
-- We are sending these twice for the time being as it will become required here and we get a warning if not set.
-- However if not passed in setEditorInfo, that one returns an error.
copilotIntegrationId = "vscode-chat", -- can be safely removed with copilot v1.291
editorInfo = editor_info.editorInfo,
editorPluginInfo = editor_info.editorPluginInfo,
},
settings = settings,
workspace_folders = workspace_folders,
trace = config.get("trace") or "off",
}, overrides)
Expand Down
83 changes: 11 additions & 72 deletions lua/copilot/util.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
local config = require("copilot.config")
local logger = require("copilot.logger")
local unpack = unpack or table.unpack

local M = {}

Expand Down Expand Up @@ -186,8 +185,8 @@ M.get_completion_params = function(opts)
return M.get_doc_params(opts)
end

---@return copilot_editor_configuration
function M.get_editor_configuration()
---@return copilot_workspace_configurations
function M.get_workspace_configurations()
local conf = config.get() --[[@as copilot_config]]

local filetypes = vim.deepcopy(conf.filetypes) --[[@as table<string, boolean>]]
Expand All @@ -205,77 +204,17 @@ function M.get_editor_configuration()
table.sort(disabled_filetypes)

return {
github = {
copilot = {
selectedCompletionModel = copilot_model,
settings = {
github = {
copilot = {
selectedCompletionModel = copilot_model,
},
},
enableAutoCompletions = not not (conf.panel.enabled or conf.suggestion.enabled),
disabledLanguages = vim.tbl_map(function(ft)
return { languageId = ft }
end, disabled_filetypes),
},
enableAutoCompletions = not not (conf.panel.enabled or conf.suggestion.enabled),
disabledLanguages = vim.tbl_map(function(ft)
return { languageId = ft }
end, disabled_filetypes),
}
end

---@param str string
local function url_decode(str)
return vim.fn.substitute(str, [[%\(\x\x\)]], [[\=iconv(nr2char("0x".submatch(1)), "utf-8", "latin1")]], "g")
end

---@return copilot_network_proxy|nil
function M.get_network_proxy()
local proxy_uri = vim.g.copilot_proxy

if type(proxy_uri) ~= "string" then
return
end

proxy_uri = string.gsub(proxy_uri, "^[^:]+://", "")

---@type string|nil, string|nil
local user_pass, host_port = unpack(vim.split(proxy_uri, "@", { plain = true, trimempty = true }))

if not host_port then
host_port = user_pass --[[@as string]]
user_pass = nil
end

local query_string
host_port, query_string = unpack(vim.split(host_port, "?", { plain = true, trimempty = true }))

local rejectUnauthorized = vim.g.copilot_proxy_strict_ssl

if query_string then
local query_params = vim.split(query_string, "&", { plain = true, trimempty = true })
for _, query_param in ipairs(query_params) do
local strict_ssl = string.match(query_param, "strict_?ssl=(.*)")

if string.find(strict_ssl, "^[1t]") then
rejectUnauthorized = true
break
end

if string.find(strict_ssl, "^[0f]") then
rejectUnauthorized = false
break
end
end
end

local host, port = unpack(vim.split(host_port, ":", { plain = true, trimempty = true }))
local username, password

if user_pass then
username, password = unpack(vim.split(user_pass, ":", { plain = true, trimempty = true }))
username, password = username and url_decode(username), password and url_decode(password)
end

return {
host = host,
port = tonumber(port or 80),
username = username,
password = password,
rejectUnauthorized = rejectUnauthorized,
}
end

Expand Down