From 92bfd6a9672a9b8ab2a133a475a1945e7a9640df Mon Sep 17 00:00:00 2001 From: Kai Xia Date: Fri, 29 Nov 2024 20:14:55 +1100 Subject: [PATCH] merge #264 --- lua/codeium/api.lua | 584 +++++++++++++++++++++++++--------------- lua/codeium/blink.lua | 182 +++++++++++++ lua/codeium/health.lua | 31 +-- lua/codeium/init.lua | 17 +- lua/codeium/source.lua | 187 ------------- lua/powershell/gzip.ps1 | 26 -- 6 files changed, 563 insertions(+), 464 deletions(-) create mode 100644 lua/codeium/blink.lua delete mode 100644 lua/codeium/source.lua delete mode 100644 lua/powershell/gzip.ps1 diff --git a/lua/codeium/api.lua b/lua/codeium/api.lua index ff3955b..e4a701d 100644 --- a/lua/codeium/api.lua +++ b/lua/codeium/api.lua @@ -12,6 +12,8 @@ local status = { api_key_error = nil, } +local function noop(...) end + local function find_port(manager_dir, start_time) local files = io.readdir(manager_dir) @@ -45,7 +47,30 @@ local function get_request_metadata(request_id) } end -local Server = {} +--- +--- Codeium Server API +--- @class codeium.Server +--- @field port? number +--- @field job? plenary.job +--- @field current_cookie? number +--- @field workspaces table +--- @field healthy boolean +--- @field last_heartbeat? number +--- @field last_heartbeat_error? string +--- @field enabled boolean +--- @field pending_request table +local Server = { + port = nil, + job = nil, + current_cookie = nil, + workspaces = {}, + healthy = false, + last_heartbeat = nil, + last_heartbeat_error = nil, + enabled = true, + pending_request = { 0, noop }, +} + Server.__index = Server function Server.check_status() @@ -156,284 +181,397 @@ function Server.authenticate() prompt() end -function Server:new() - local m = {} - setmetatable(m, self) +---@return codeium.Server +function Server.new() + local m = setmetatable({}, Server) + m.__index = m + return m +end - local o = {} - setmetatable(o, m) +---@param fn string +---@param payload table +---@param callback function +function Server:request(fn, payload, callback) + local url = "http://127.0.0.1:" + .. self.port + .. "/exa.language_server_pb.LanguageServerService/" + .. fn + io.post(url, { + body = payload, + callback = callback, + }) +end - local port = nil - local job = nil - local current_cookie = nil - local workspaces = {} - local healthy = false - local last_heartbeat = nil - local last_heartbeat_error = nil +function Server:start() + self:shutdown() - local function request(fn, payload, callback) - local url = "http://127.0.0.1:" - .. port - .. "/exa.language_server_pb.LanguageServerService/" - .. fn - io.post(url, { - body = payload, - callback = callback, - }) - end + self.current_cookie = next_cookie() - local function do_heartbeat() - request("Heartbeat", { - metadata = get_request_metadata(), - }, function(_, err) - last_heartbeat = os.time() - last_heartbeat_error = nil - if err then - notify.warn("heartbeat failed", err) - last_heartbeat_error = err - else - healthy = true - end - end) + if not api_key then + io.timer(1000, 0, self:start()) + return end - function m.is_healthy() - return healthy + local manager_dir = config.manager_path + if not manager_dir then + manager_dir = io.tempdir("codeium/manager") + vim.fn.mkdir(manager_dir, "p") end - function m.checkhealth(logger) - logger.info("Checking server status") - if m.is_healthy() then - logger.ok("Server is healthy on port: " .. port) - else - logger.warn("Server is unhealthy") + local start_time = io.touch(manager_dir .. "/start") + + local function on_exit(_, err) + if not self.current_cookie then + return end - logger.info("Language Server binary: " .. update.get_bin_info().bin) + self.healthy = false + if err then + self.job = nil + self.current_cookie = nil - if last_heartbeat == nil then - logger.warn("No heartbeat executed") - else - logger.info("Last heartbeat: " .. os.date("%D %H:%M:%S", last_heartbeat)) - if last_heartbeat_error ~= nil then - logger.error(last_heartbeat_error) - else - logger.ok("Heartbeat ok") - end + notify.error("codeium server crashed", err) + io.timer(1000, 0, function() + log.debug("restarting server after crash") + self:start() + end) end end - function m.start() - m.shutdown() + local function on_output(_, v, j) + log.debug(j.pid .. ": " .. v) + end - current_cookie = next_cookie() + local api_server_url = "https://" + .. config.options.api.host + .. ":" + .. config.options.api.port + .. (config.options.api.path and "/" .. config.options.api.path:gsub("^/", "") or "") + + local job_args = { + update.get_bin_info().bin, + "--api_server_url", + api_server_url, + "--manager_dir", + manager_dir, + "--file_watch_max_dir_count", + config.options.file_watch_max_dir_count, + enable_handlers = true, + enable_recording = false, + on_exit = on_exit, + on_stdout = on_output, + on_stderr = on_output, + } - if not api_key then - io.timer(1000, 0, m.start) - return - end + if config.options.enable_chat then + table.insert(job_args, "--enable_chat_web_server") + table.insert(job_args, "--enable_chat_client") + end - local manager_dir = config.manager_path - if not manager_dir then - manager_dir = io.tempdir("codeium/manager") - vim.fn.mkdir(manager_dir, "p") - end + if config.options.enable_local_search then + table.insert(job_args, "--enable_local_search") + end + + if config.options.enable_index_service then + table.insert(job_args, "--enable_index_service") + table.insert(job_args, "--search_max_workspace_file_count") + table.insert(job_args, config.options.search_max_workspace_file_count) + end - local start_time = io.touch(manager_dir .. "/start") + if config.options.api.portal_url then + table.insert(job_args, "--portal_url") + table.insert(job_args, "https://" .. config.options.api.portal_url) + end - local function on_exit(_, err) - if not current_cookie then - return - end + if config.options.enterprise_mode then + table.insert(job_args, "--enterprise_mode") + end - healthy = false - if err then - job = nil - current_cookie = nil - - notify.error("codeium server crashed", err) - io.timer(1000, 0, function() - log.debug("restarting server after crash") - m.start() - end) - end - end + if config.options.detect_proxy ~= nil then + table.insert(job_args, "--detect_proxy=" .. tostring(config.options.detect_proxy)) + end - local function on_output(_, v, j) - log.debug(j.pid .. ": " .. v) - end + self.job = io.job(job_args) + self.job:start() - local api_server_url = "https://" - .. config.options.api.host - .. ":" - .. config.options.api.port - .. (config.options.api.path and "/" .. config.options.api.path:gsub("^/", "") or "") - - local job_args = { - update.get_bin_info().bin, - "--api_server_url", - api_server_url, - "--manager_dir", - manager_dir, - "--file_watch_max_dir_count", - config.options.file_watch_max_dir_count, - enable_handlers = true, - enable_recording = false, - on_exit = on_exit, - on_stdout = on_output, - on_stderr = on_output, - } - - if config.options.enable_local_search then - table.insert(job_args, "--enable_local_search") - end + local function start_heartbeat() + io.timer(100, 5000, function(cancel_heartbeat) + if not self.current_cookie then + cancel_heartbeat() + else + self:do_heartbeat() + end + end) + end - if config.options.enable_index_service then - table.insert(job_args, "--enable_index_service") - table.insert(job_args, "--search_max_workspace_file_count") - table.insert(job_args, config.options.search_max_workspace_file_count) + io.timer(100, 500, function(cancel) + if not self.current_cookie then + cancel() + return end - if config.options.api.portal_url then - table.insert(job_args, "--portal_url") - table.insert(job_args, "https://" .. config.options.api.portal_url) + self.port = find_port(manager_dir, start_time) + if self.port then + cancel() + start_heartbeat() end + end) +end - if config.options.enterprise_mode then - table.insert(job_args, "--enterprise_mode") - end +function Server:is_healthy() + return self.healthy +end - if config.options.detect_proxy ~= nil then - table.insert(job_args, "--detect_proxy=" .. tostring(config.options.detect_proxy)) - end +function Server:checkhealth(logger) + logger.info("Checking server status") + if self:is_healthy() then + logger.ok("Server is healthy on port: " .. self.port) + else + logger.warn("Server is unhealthy") + end - local job = io.job(job_args) - job:start() + logger.info("Language Server binary: " .. update.get_bin_info().bin) - local function start_heartbeat() - io.timer(100, 5000, function(cancel_heartbeat) - if not current_cookie then - cancel_heartbeat() - else - do_heartbeat() - end - end) + if self.last_heartbeat == nil then + logger.warn("No heartbeat executed") + else + logger.info("Last heartbeat: " .. os.date("%D %H:%M:%S", self.last_heartbeat)) + if self.last_heartbeat_error ~= nil then + logger.error(self.last_heartbeat_error) + else + logger.ok("Heartbeat ok") end + end +end - io.timer(100, 500, function(cancel) - if not current_cookie then - cancel() - return - end +function Server:do_heartbeat() + self:request("Heartbeat", { + metadata = get_request_metadata(), + }, function(_, err) + self.last_heartbeat = os.time() + self.last_heartbeat_error = nil + if err then + notify.warn("heartbeat failed", err) + self.last_heartbeat_error = err + else + self.healthy = true + end + end) +end - port = find_port(manager_dir, start_time) - if port then - cancel() - start_heartbeat() - end - end) +function Server:request_completion(document, editor_options, other_documents, callback) + if not self.enabled or not self.port then + return end + self.pending_request[2](true) - local function noop(...) end - - local pending_request = { 0, noop } - function m.request_completion(document, editor_options, other_documents, callback) - pending_request[2](true) + local metadata = get_request_metadata() + local this_pending_request - local metadata = get_request_metadata() - local this_pending_request + local complete + complete = function(...) + complete = noop + this_pending_request(false) + callback(...) + end - local complete - complete = function(...) - complete = noop - this_pending_request(false) - callback(...) + this_pending_request = function(is_complete) + if self.pending_request[1] == metadata.request_id then + self.pending_request = { 0, noop } end + this_pending_request = noop - this_pending_request = function(is_complete) - if pending_request[1] == metadata.request_id then - pending_request = { 0, noop } + self:request("CancelRequest", { + metadata = get_request_metadata(), + request_id = metadata.request_id, + }, function(_, err) + if err then + log.warn("failed to cancel in-flight request", err) end - this_pending_request = noop - - request("CancelRequest", { - metadata = get_request_metadata(), - request_id = metadata.request_id, - }, function(_, err) - if err then - log.warn("failed to cancel in-flight request", err) - end - end) + end) - if is_complete then - complete(false, nil) - end + if is_complete then + complete(false, nil) end - pending_request = { metadata.request_id, this_pending_request } - - request("GetCompletions", { - metadata = metadata, - editor_options = editor_options, - document = document, - other_documents = other_documents, - }, function(body, err) - if err then - if err.status == 503 or err.status == 408 then - -- Service Unavailable or Timeout error - return complete(false, nil) - end + end + self.pending_request = { metadata.request_id, this_pending_request } + + self:request("GetCompletions", { + metadata = metadata, + editor_options = editor_options, + document = document, + other_documents = other_documents, + }, function(body, err) + if err then + if err.status == 503 or err.status == 408 then + -- Service Unavailable or Timeout error + return complete(false, nil) + end - local ok, json = pcall(vim.fn.json_decode, err.response.body) - if ok and json then - if json.state and json.state.state == "CODEIUM_STATE_INACTIVE" then - if json.state.message then - log.debug("completion request failed", json.state.message) - end - return complete(false, nil) - end - if json.code == "canceled" then - log.debug("completion request cancelled at the server", json.message) - return complete(false, nil) + local ok, json = pcall(vim.fn.json_decode, err.response.body) + if ok and json then + if json.state and json.state.state == "CODEIUM_STATE_INACTIVE" then + if json.state.message then + log.debug("completion request failed", json.state.message) end + return complete(false, nil) + end + if json.code == "canceled" then + log.debug("completion request cancelled at the server", json.message) + return complete(false, nil) end - - notify.error("completion request failed", err) - complete(false, nil) - return - end - - local ok, json = pcall(vim.fn.json_decode, body) - if not ok then - notify.error("completion request failed", "invalid JSON:", json) - return end - log.trace("completion: ", json) - complete(true, json) - end) + notify.error("completion request failed: " .. err.response.body) + complete(false, nil) + return + end - return function() - this_pending_request(true) + local ok, json = pcall(vim.fn.json_decode, body) + if not ok then + notify.error("completion request failed: " .. "invalid JSON:" .. json) + return end + + log.trace("completion: ", json) + complete(true, json) + end) + + return function() + this_pending_request(true) end +end - function m.accept_completion(completion_id) - request("AcceptCompletion", { - metadata = get_request_metadata(), - completion_id = completion_id, - }, noop) +function Server:accept_completion(completion_id) + self:request("AcceptCompletion", { + metadata = get_request_metadata(), + completion_id = completion_id, + }, noop) +end + +function Server:refresh_context() + -- bufnr for current buffer is 0 + local bufnr = 0 + + local line_ending = util.get_newline(bufnr) + local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true) + + -- Ensure that there is always a newline at the end of the file + table.insert(lines, "") + local text = table.concat(lines, line_ending) + + local filetype = vim.bo.filetype + local language = enums.languages[filetype] or enums.languages.unspecified + + local doc = { + editor_language = filetype, + language = language, + cursor_offset = 0, + text = text, + line_ending = line_ending, + absolute_uri = util.get_uri(vim.api.nvim_buf_get_name(bufnr)), + workspace_uri = util.get_uri(util.get_project_root()), + } + + self:request("RefreshContextForIdeAction", { + active_document = doc, + }, function(_, err) + if err then + notify.error("failed refresh context: " .. err.out) + return + end + end) +end + +function Server:add_workspace() + local project_root = util.get_project_root() + -- workspace already tracked by server + if self.workspaces[project_root] then + return + end + -- unable to track hidden path + for entry in project_root:gmatch("[^/]+") do + if entry:sub(1, 1) == "." then + return + end end - function m.shutdown() - current_cookie = nil - if job then - job.on_exit = nil - job:shutdown() + self:request("AddTrackedWorkspace", { workspace = project_root }, function(_, err) + if err then + notify.error("failed to add workspace: " .. err.out) + return end + self.workspaces[project_root] = true + end) +end + +function Server:get_chat_ports() + self:request("GetProcesses", { + metadata = get_request_metadata(), + }, function(body, err) + if err then + notify.error("failed to get chat ports", err) + return + end + local ports = vim.fn.json_decode(body) + local url = "http://127.0.0.1:" + .. ports.chatClientPort + .. "?api_key=" + .. api_key + .. "&has_enterprise_extension=" + .. (config.options.enterprise_mode and "true" or "false") + .. "&web_server_url=ws://127.0.0.1:" + .. ports.chatWebServerPort + .. "&ide_name=neovim" + .. "&ide_version=" + .. versions.nvim + .. "&app_name=codeium.nvim" + .. "&extension_name=codeium.nvim" + .. "&extension_version=" + .. versions.extension + .. "&ide_telemetry_enabled=true" + .. "&has_index_service=" + .. (config.options.enable_index_service and "true" or "false") + .. "&locale=en_US" + + -- cross-platform solution to open the web app + local os_info = io.get_system_info() + if os_info.os == "linux" then + os.execute("xdg-open '" .. url .. "'") + elseif os_info.os == "macos" then + os.execute("open '" .. url .. "'") + elseif os_info.os == "windows" then + os.execute(string.format('start "" "%s"', url)) + else + notify.error("Unsupported operating system") + end + end) +end + +function Server:shutdown() + self.current_cookie = nil + if self.job then + self.job.on_exit = nil + self.job:shutdown() end +end - m.__index = m - return o +function Server:enable() + self.enabled = true + notify.info("Codeium enabled") +end + +function Server:disable() + self.enabled = false + notify.info("Codeium disabled") +end + +function Server:toggle() + if self.enabled then + self:disable() + else + self:enable() + end end return Server diff --git a/lua/codeium/blink.lua b/lua/codeium/blink.lua new file mode 100644 index 0000000..77ad6b3 --- /dev/null +++ b/lua/codeium/blink.lua @@ -0,0 +1,182 @@ +local enums = require("codeium.enums") +local util = require("codeium.util") + +local function utf8len(str) + if not str then + return 0 + end + return str:len() +end + +local function codeium_to_item(comp, offset, right) + local documentation = comp.completion.text + + local label = documentation:sub(offset) + if label:sub(-#right) == right then + label = label:sub(1, -#right - 1) + end + + -- We get the completion part that has the largest offset + local max_offset = offset + if comp.completionParts then + for _, v in pairs(comp.completionParts) do + local part_offset = tonumber(v.offset) + if part_offset > max_offset then + max_offset = part_offset + end + end + end + + -- We get where the suffix difference between the completion and the range of code + local suffix_diff = comp.range.endOffset - max_offset + + local range = { + start = { + -- Codeium returns an empty row for the first line + line = (tonumber(comp.range.startPosition.row) or 0), + character = offset - 1, + }, + ["end"] = { + -- Codeium returns an empty row for the first line + line = (tonumber(comp.range.endPosition.row) or 0), + -- We only want to replace up to where the completion ends + character = (comp.range.endPosition.col or suffix_diff) - suffix_diff, + }, + } + + local display_label = string.match(label, "([^\n]*)") + if display_label ~= label then + display_label = display_label .. "  " + end + + return { + type = 1, + documentation = { + kind = "markdown", + value = table.concat({ + "```" .. vim.api.nvim_get_option_value("filetype", {}), + label, + "```", + }, "\n"), + }, + label = display_label, + insertText = label, + kind = 1, -- Text + insertTextFormat = vim.lsp.protocol.InsertTextFormat.PlainText, + textEdit = { + newText = label, + insert = range, + replace = range, + }, + cmp = { + kind_text = "Codeium", + kind_hl_group = "BlinkCmpKindCodeium", + }, + codeium_completion_id = comp.completion.completionId, + } +end + +--- @class blink.cmp.Source +--- @field server codeium.Server +local M = {} + +function M.new() + local o = {} + o.server = require("codeium").s + return setmetatable(o, { __index = M }) +end + +function M:get_trigger_characters() + return { '"', "`", "[", "]", ".", " ", "\n" } +end +-- +function M:enabled() + return self.server.enabled +end + +function M:get_completions(ctx, callback) + local context = ctx + local offset = ctx.bounds.start_col -- ctx.offset -- param.offset + local cursor = context.cursor + local bufnr = context.bufnr + local filetype = vim.api.nvim_get_option_value("filetype", { buf = ctx.bufnr }) + filetype = enums.filetype_aliases[filetype] or filetype or "text" + local language = enums.languages[filetype] or enums.languages.unspecified + local after_line = string.sub(ctx.line, cursor[2]) + local before_line = string.sub(ctx.line, 1, cursor[2] - 1) + local line_ending = util.get_newline(bufnr) + local line_ending_len = utf8len(line_ending) + local editor_options = util.get_editor_options(bufnr) + + -- We need to calculate the number of bytes prior to the current character, + -- that starts with all the prior lines + local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true) + + -- For the current line, we want to exclude any extra characters that were + -- entered after the popup displayed + lines[cursor[1]] = context.line + + -- We exclude the current line from the loop below, so add it's length here + local cursor_offset = utf8len(before_line) + for i = 1, (cursor[1] - 1) do + local line = lines[i] + cursor_offset = cursor_offset + utf8len(line) + line_ending_len + end + + -- Ensure that there is always a newline at the end of the file + table.insert(lines, "") + local text = table.concat(lines, line_ending) + + local function handle_completions(completion_items) + local duplicates = {} + local completions = {} + for _, comp in ipairs(completion_items) do + if not duplicates[comp.completion.text] then + duplicates[comp.completion.text] = true + table.insert(completions, codeium_to_item(comp, offset, after_line)) + end + end + callback({ + is_incomplete_forward = false, + is_incomplete_backward = false, + items = completions, + context = ctx, + }) + end + + local other_documents = util.get_other_documents(bufnr) + + self.server:request_completion( + { + text = text, + editor_language = filetype, + language = language, + cursor_position = { row = cursor[1] - 1, col = cursor[2] }, + absolute_uri = util.get_uri(vim.api.nvim_buf_get_name(bufnr)), + workspace_uri = util.get_uri(util.get_project_root()), + line_ending = line_ending, + cursor_offset = cursor_offset, + }, + editor_options, + other_documents, + function(success, json) + if not success then + return nil + end + + if + json + and json.state + and json.state.state == "CODEIUM_STATE_SUCCESS" + and json.completionItems + then + handle_completions(json.completionItems) + else + return nil + end + end + ) + return function() end +end + +return M diff --git a/lua/codeium/health.lua b/lua/codeium/health.lua index 2025cb4..bc9024c 100644 --- a/lua/codeium/health.lua +++ b/lua/codeium/health.lua @@ -13,26 +13,27 @@ local error = vim.health.error or vim.health.report_error local info = vim.health.info or vim.health.report_info local health_logger = { ok = ok, info = info, warn = warn, error = error } -local checkhealth = nil +local instance = nil function M.check() - start("Codeium: checking Codeium server status") - local server_status = Server.check_status() - if server_status.api_key_error ~= nil then - error("API key not loaded: " .. server_status.api_key_error) - else - ok("API key properly loaded") - end + start("Codeium: checking Codeium server status") + local server_status = Server.check_status() + if server_status.api_key_error ~= nil then + error("API key not loaded: " .. server_status.api_key_error) + else + ok("API key properly loaded") + end - if checkhealth == nil then - warn("Codeium: checkhealth is not set") - return - end - checkhealth(health_logger) + if instance == nil then + warn("Codeium: checkhealth is not set") + return + end + instance:checkhealth(health_logger) end -function M.register(callback) - checkhealth = callback +---@param server codeium.Server +function M.register(server) + instance = server end return M diff --git a/lua/codeium/init.lua b/lua/codeium/init.lua index 5a1d1f1..0d19007 100644 --- a/lua/codeium/init.lua +++ b/lua/codeium/init.lua @@ -1,20 +1,19 @@ local M = {} function M.setup(options) - local Source = require("codeium.source") local Server = require("codeium.api") local update = require("codeium.update") local health = require("codeium.health") require("codeium.config").setup(options) - local s = Server:new() + M.s = Server.new() update.download(function(err) if not err then Server.load_api_key() - s.start() + M.s:start() end end) - health.register(s.checkhealth) + health.register(M.s) vim.api.nvim_create_user_command("Codeium", function(opts) local args = opts.fargs @@ -25,19 +24,11 @@ function M.setup(options) nargs = 1, complete = function() local commands = { "Auth" } - if require("codeium.config").options.enable_chat then - commands = vim.list_extend(commands, { "Chat" }) - end return commands end, }) - local source = Source:new(s) - if require("codeium.config").options.enable_cmp_source then - require("cmp").register_source("codeium", source) - end - - require("codeium.virtual_text").setup(s) + require("codeium.virtual_text").setup(M.s) end return M diff --git a/lua/codeium/source.lua b/lua/codeium/source.lua deleted file mode 100644 index dcbee60..0000000 --- a/lua/codeium/source.lua +++ /dev/null @@ -1,187 +0,0 @@ -local enums = require("codeium.enums") -local util = require("codeium.util") - -local function utf8len(str) - if not str then - return 0 - end - -- TODO: Figure out how to convert the document encoding to UTF8 length - -- Bonus points for doing it with raw codepoints instead of converting the - -- string wholesale - return str:len() -end - -local function codeium_to_cmp(comp, offset, right) - local documentation = comp.completion.text - - local label = documentation:sub(offset) - if label:sub(-#right) == right then - label = label:sub(1, -#right - 1) - end - - -- We get the completion part that has the largest offset - local max_offset = offset - if comp.completionParts then - for _, v in pairs(comp.completionParts) do - local part_offset = tonumber(v.offset) - if part_offset > max_offset then - max_offset = part_offset - end - end - end - - -- We get where the suffix difference between the completion and the range of code - local suffix_diff = comp.range.endOffset - max_offset - - local range = { - start = { - -- Codeium returns an empty row for the first line - line = (tonumber(comp.range.startPosition.row) or 0), - character = offset - 1, - }, - ["end"] = { - -- Codeium returns an empty row for the first line - line = (tonumber(comp.range.endPosition.row) or 0), - -- We only want to replace up to where the completion ends - character = (comp.range.endPosition.col or suffix_diff) - suffix_diff, - }, - } - - return { - type = 1, - documentation = { - kind = "markdown", - value = table.concat({ - "```" .. vim.api.nvim_buf_get_option(0, "filetype"), - label, - "```", - }, "\n"), - }, - label = label, - insertText = label, - textEdit = { - newText = label, - insert = range, - replace = range, - }, - cmp = { - kind_text = "Codeium", - kind_hl_group = "CmpItemKindCodeium", - }, - codeium_completion_id = comp.completion.completionId, - } -end - -local Source = { - server = nil, -} -Source.__index = Source - -function Source:new(server) - local o = {} - setmetatable(o, self) - - o.server = server - return o -end - -function Source:is_available() - return self.server.is_healthy() -end - -function Source:get_position_encoding_kind() - return "utf-8" -end - --- Import `cmp` but don't error if it is not installed, as it might be when only using virtual text -local imported_cmp, cmp = pcall(require, "cmp") -if imported_cmp then - cmp.event:on("confirm_done", function(event) - if - event.entry - and event.entry.source - and event.entry.source.name == "codeium" - and event.entry.completion_item - and event.entry.completion_item.codeium_completion_id - and event.entry.source.source - and event.entry.source.source.server - then - event.entry.source.source.server.accept_completion(event.entry.completion_item.codeium_completion_id) - end - end) -end - -function Source:complete(params, callback) - local context = params.context - local offset = params.offset - local cursor = context.cursor - local bufnr = context.bufnr - local filetype = enums.filetype_aliases[context.filetype] or context.filetype or "text" - local language = enums.languages[filetype] or enums.languages.unspecified - local after_line = context.cursor_after_line - local before_line = context.cursor_before_line - local line_ending = util.get_newline(bufnr) - local line_ending_len = utf8len(line_ending) - local editor_options = util.get_editor_options(bufnr) - - -- We need to calculate the number of bytes prior to the current character, - -- that starts with all the prior lines - local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true) - - -- For the current line, we want to exclude any extra characters that were - -- entered after the popup displayed - lines[cursor.row] = context.cursor_line - - -- We exclude the current line from the loop below, so add it's length here - local cursor_offset = utf8len(before_line) - for i = 1, (cursor.row - 1) do - local line = lines[i] - cursor_offset = cursor_offset + utf8len(line) + line_ending_len - end - - -- Ensure that there is always a newline at the end of the file - table.insert(lines, "") - local text = table.concat(lines, line_ending) - - local function handle_completions(completion_items) - local duplicates = {} - local completions = {} - for _, comp in ipairs(completion_items) do - if not duplicates[comp.completion.text] then - duplicates[comp.completion.text] = true - table.insert(completions, codeium_to_cmp(comp, offset, after_line)) - end - end - callback(completions) - end - - local other_documents = util.get_other_documents(bufnr) - - self.server.request_completion( - { - text = text, - editor_language = filetype, - language = language, - cursor_position = { row = cursor.row - 1, col = cursor.col - 1 }, - absolute_uri = util.get_uri(vim.api.nvim_buf_get_name(bufnr)), - workspace_uri = util.get_uri(util.get_project_root()), - line_ending = line_ending, - cursor_offset = cursor_offset, - }, - editor_options, - other_documents, - function(success, json) - if not success then - callback(nil) - end - - if json and json.state and json.state.state == "CODEIUM_STATE_SUCCESS" and json.completionItems then - handle_completions(json.completionItems) - else - callback(nil) - end - end - ) -end - -return Source diff --git a/lua/powershell/gzip.ps1 b/lua/powershell/gzip.ps1 deleted file mode 100644 index 0c2cddb..0000000 --- a/lua/powershell/gzip.ps1 +++ /dev/null @@ -1,26 +0,0 @@ -Function Expand-File -{ - Param( - $infile, - $outfile = ($infile -replace '\.gz$','') - ) - - $in = New-Object System.IO.FileStream $inFile, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read) - $output = New-Object System.IO.FileStream $outFile, ([IO.FileMode]::Create), ([IO.FileAccess]::Write), ([IO.FileShare]::None) - $gzipStream = New-Object System.IO.Compression.GzipStream $in, ([IO.Compression.CompressionMode]::Decompress) - - $buffer = New-Object byte[](1024) - while($true) - { - $read = $gzipstream.Read($buffer, 0, 1024) - if ($read -le 0) - {break - } - $output.Write($buffer, 0, $read) - } - - $gzipStream.Close() - $output.Close() - $in.Close() - Remove-Item $infile -}