From 3e29b1c7f209e60e1e63c896aa1c5dcbf42fd9cc Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Sat, 5 Oct 2024 23:22:09 -1000 Subject: [PATCH 01/25] Start on virtual text support --- lua/codeium/config.lua | 6 + lua/codeium/init.lua | 6 +- lua/codeium/source.lua | 29 +-- lua/codeium/util.lua | 27 +++ lua/codeium/virtual_text.lua | 427 +++++++++++++++++++++++++++++++++++ 5 files changed, 466 insertions(+), 29 deletions(-) create mode 100644 lua/codeium/virtual_text.lua diff --git a/lua/codeium/config.lua b/lua/codeium/config.lua index 4d35cf6..cda4aa0 100644 --- a/lua/codeium/config.lua +++ b/lua/codeium/config.lua @@ -23,6 +23,12 @@ function M.defaults() enable_index_service = true, search_max_workspace_file_count = 5000, file_watch_max_dir_count = 50000, + enable_cmp_source = true, + virtual_text = { + enabled = false, + idle_delay = 75, + virtual_text_priority = 65535, + }, workspace_root = { use_lsp = true, find_root = nil, diff --git a/lua/codeium/init.lua b/lua/codeium/init.lua index 4d180c1..cca87ad 100644 --- a/lua/codeium/init.lua +++ b/lua/codeium/init.lua @@ -38,7 +38,11 @@ function M.setup(options) }) local source = Source:new(s) - require("cmp").register_source("codeium", source) + if options.enable_cmp_source then + require("cmp").register_source("codeium", source) + end + + require("codeium.virtual_text").setup(s, require("codeium.config").options.virtual_text) end return M diff --git a/lua/codeium/source.lua b/lua/codeium/source.lua index 9bbeb16..6b147d3 100644 --- a/lua/codeium/source.lua +++ b/lua/codeium/source.lua @@ -72,33 +72,6 @@ local function codeium_to_cmp(comp, offset, right) } end -local function buf_to_codeium(bufnr) - local filetype = enums.filetype_aliases[vim.bo[bufnr].filetype] or vim.bo[bufnr].filetype or "text" - local language = enums.languages[filetype] or enums.languages.unspecified - local line_ending = util.get_newline(bufnr) - local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true) - table.insert(lines, "") - local text = table.concat(lines, line_ending) - return { - editor_language = filetype, - language = language, - text = text, - line_ending = line_ending, - absolute_uri = util.get_uri(vim.api.nvim_buf_get_name(bufnr)), - } -end - -local function get_other_documents(bufnr) - local other_documents = {} - - for _, buf in ipairs(vim.api.nvim_list_bufs()) do - if vim.api.nvim_buf_is_loaded(buf) and vim.bo[buf].filetype ~= "" and buf ~= bufnr then - table.insert(other_documents, buf_to_codeium(buf)) - end - end - return other_documents -end - local Source = { server = nil, } @@ -178,7 +151,7 @@ function Source:complete(params, callback) callback(completions) end - local other_documents = get_other_documents(bufnr) + local other_documents = util.get_other_documents(bufnr) self.server.request_completion( { diff --git a/lua/codeium/util.lua b/lua/codeium/util.lua index 7f15ab4..3c899d1 100644 --- a/lua/codeium/util.lua +++ b/lua/codeium/util.lua @@ -91,4 +91,31 @@ function M.get_uri(path) return "file://" .. path end +local function buf_to_codeium(bufnr) + local filetype = enums.filetype_aliases[vim.bo[bufnr].filetype] or vim.bo[bufnr].filetype or "text" + local language = enums.languages[filetype] or enums.languages.unspecified + local line_ending = M.get_newline(bufnr) + local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, true) + table.insert(lines, "") + local text = table.concat(lines, line_ending) + return { + editor_language = filetype, + language = language, + text = text, + line_ending = line_ending, + absolute_uri = M.get_uri(vim.api.nvim_buf_get_name(bufnr)), + } +end + +function M.get_other_documents(bufnr) + local other_documents = {} + + for _, buf in ipairs(vim.api.nvim_list_bufs()) do + if vim.api.nvim_buf_is_loaded(buf) and vim.bo[buf].filetype ~= "" and buf ~= bufnr then + table.insert(other_documents, buf_to_codeium(buf)) + end + end + return other_documents +end + return M diff --git a/lua/codeium/virtual_text.lua b/lua/codeium/virtual_text.lua new file mode 100644 index 0000000..0ae8ab3 --- /dev/null +++ b/lua/codeium/virtual_text.lua @@ -0,0 +1,427 @@ +local enums = require("codeium.enums") +local util = require("codeium.util") +local notify = require("codeium.notify") +local config = require("codeium.config") + +local M = {} + +local hlgroup = "CodeiumSuggestion" +local request_nonce = 0 +local using_codeium_status = 0 + +local completions + +local server = nil +local options +function M.setup(_server, _options) + server = _server + options = _options + + local augroup = vim.api.nvim_create_augroup("codeium_virtual_text", { clear = true }) + + if not options.enabled then + return + end + + vim.api.nvim_create_autocmd({ "InsertEnter", "CursorMovedI", "CompleteChanged" }, { + group = augroup, + callback = function() + M.DebouncedComplete() + end, + }) + + vim.api.nvim_create_autocmd("BufEnter", { + group = augroup, + callback = function() + if vim.fn.mode():match("^[iR]") then + M.DebouncedComplete() + end + end, + }) + + vim.api.nvim_create_autocmd("InsertLeave", { + group = augroup, + callback = M.Clear, + }) + + vim.api.nvim_create_autocmd("BufLeave", { + group = augroup, + callback = function() + if vim.fn.mode():match("^[iR]") then + M.Clear() + end + end, + }) + + -- vim.api.nvim_create_autocmd({ "ColorScheme", "VimEnter" }, { + -- group = augroup, + -- callback = function() + -- vim.fn["s:SetStyle"]() + -- end, + -- }) + + -- vim.api.nvim_create_autocmd("VimEnter", { + -- group = augroup, + -- callback = function() + -- vim.fn["s:MapTab"]() + -- end, + -- }) +end + +function M.CompletionText() + local completion_text = M.completion_text + M.completion_text = nil + return completion_text or "" +end + +local function CompletionInserter(current_completion, insert_text) + local default = vim.g.codeium_tab_fallback or (vim.fn.pumvisible() == 1 and "" or "\t") + + if not (vim.fn.mode():match("^[iR]") and completions) then + return default + end + + if current_completion == nil then + return default + end + + local range = current_completion.range + local suffix = current_completion.suffix or {} + local suffix_text = suffix.text or "" + local delta = suffix.deltaCursorOffset or 0 + local start_offset = range.startOffset or 0 + local end_offset = range.endOffset or 0 + + local text = insert_text .. suffix_text + if text == "" then + return default + end + + local delete_range = "" + if end_offset - start_offset > 0 then + local delete_bytes = end_offset - start_offset + local delete_chars = vim.fn.strchars(vim.fn.strpart(vim.fn.getline("."), 0, delete_bytes)) + delete_range = ' "_x0"_d' .. delete_chars .. "li" + end + + local insert_text = '=v:lua.require"codeium".CompletionText()' + M.completion_text = text + + local cursor_text = delta == 0 and "" or ':exe "go" line2byte(line("."))+col(".")+(' .. delta .. ")" + + server.accept_completion(current_completion.completion.completionId) + + return delete_range .. insert_text .. cursor_text +end + +function M.Accept() + local current_completion = M.GetCurrentCompletionItem() + return CompletionInserter(current_completion, current_completion and current_completion.completion.text or "") +end + +function M.AcceptNextWord() + local current_completion = M.GetCurrentCompletionItem() + local completion_parts = current_completion and (current_completion.completionParts or {}) or {} + if #completion_parts == 0 then + return "" + end + local prefix_text = completion_parts[1].prefix or "" + local completion_text = completion_parts[1].text or "" + local next_word = completion_text:match("^%W*%w*") + return CompletionInserter(current_completion, prefix_text .. next_word) +end + +function M.AcceptNextLine() + local current_completion = M.GetCurrentCompletionItem() + local text = current_completion and current_completion.completion.text:gsub("\n.*$", "") or "" + return CompletionInserter(current_completion, text) +end + +function M.GetCurrentCompletionItem() + print("GetCurrentCompletionItem") + print(vim.inspect(completions)) + print("abc") + if completions and completions.items and completions.index and completions.index < #completions.items then + return completions.items[completions.index + 1] + end + return nil +end + +local nvim_extmark_ids = {} + +local function ClearCompletion() + local namespace = vim.api.nvim_create_namespace("codeium") + for _, id in ipairs(nvim_extmark_ids) do + vim.api.nvim_buf_del_extmark(0, namespace, id) + end + nvim_extmark_ids = {} +end + +local function RenderCurrentCompletion() + ClearCompletion() + -- TODO enable + -- M.RedrawStatusLine() + + if not vim.fn.mode():match("^[iR]") then + return "" + end + + local current_completion = M.GetCurrentCompletionItem() + if current_completion == nil then + return "" + end + + print("current_completion") + print(vim.inspect(current_completion)) + + local parts = current_completion.completionParts or {} + + local inline_cumulative_cols = 0 + local diff = 0 + for idx, part in ipairs(parts) do + local row = (part.line or 0) + 1 + if row ~= vim.fn.line(".") then + -- TODO: Implement codeium#log#Warn + -- codeium#log#Warn('Ignoring completion, line number is not the current line.') + goto continue + end + local _col + if part.type == "COMPLETION_PART_TYPE_INLINE" then + _col = inline_cumulative_cols + #(part.prefix or "") + 1 + inline_cumulative_cols = _col - 1 + else + _col = #(part.prefix or "") + 1 + end + local text = part.text + + if + (part.type == "COMPLETION_PART_TYPE_INLINE" and idx == 1) + or part.type == "COMPLETION_PART_TYPE_INLINE_MASK" + then + local completion_prefix = part.prefix or "" + local completion_line = completion_prefix .. text + local full_line = vim.fn.getline(row) + local cursor_prefix = full_line:sub(1, vim.fn.col(".") - 1) + local matching_prefix = 0 + for i = 1, #completion_line do + if i <= #full_line and completion_line:sub(i, i) == full_line:sub(i, i) then + matching_prefix = matching_prefix + 1 + else + break + end + end + if #cursor_prefix > #completion_prefix then + diff = #cursor_prefix - #completion_prefix + elseif #cursor_prefix < #completion_prefix then + if matching_prefix >= #completion_prefix then + diff = matching_prefix - #completion_prefix + else + diff = #cursor_prefix - #completion_prefix + end + end + if diff > 0 then + diff = 0 + end + if diff < 0 then + text = completion_prefix:sub(diff + 1) .. text + elseif diff > 0 then + text = text:sub(diff + 1) + end + end + + local priority = vim.b.codeium_virtual_text_priority or vim.g.codeium_virtual_text_priority or 65535 + local _virtcol = vim.fn.virtcol({ row, _col + diff }) + local data = { id = idx + 1, hl_mode = "combine", virt_text_win_col = _virtcol - 1, priority = priority } + if part.type == "COMPLETION_PART_TYPE_INLINE_MASK" then + data.virt_text = { { text, hlgroup } } + elseif part.type == "COMPLETION_PART_TYPE_BLOCK" then + local lines = vim.split(text, "\n", true) + if lines[#lines] == "" then + table.remove(lines) + end + data.virt_lines = vim.tbl_map(function(l) + return { { l, hlgroup } } + end, lines) + else + goto continue + end + + table.insert(nvim_extmark_ids, data.id) + vim.api.nvim_buf_set_extmark(0, vim.api.nvim_create_namespace("codeium"), row - 1, 0, data) + + ::continue:: + end +end + +function M.Clear(...) + print("Clear") + vim.b._codeium_status = 0 + -- TODO enable + -- M.RedrawStatusLine() + if vim.g._codeium_timer then + vim.fn.timer_stop(vim.g._codeium_timer) + vim.g._codeium_timer = nil + end + + if completions then + local request_id = completions.request_id or 0 + if request_id > 0 then + -- TODO: Implement codeium#server#Request + -- codeium#server#Request('CancelRequest', {request_id = request_id}) + end + RenderCurrentCompletion() + completions = nil + end + + if select("#", ...) == 0 then + RenderCurrentCompletion() + end + return "" +end + +function M.CycleCompletions(n) + if M.GetCurrentCompletionItem() == nil then + return + end + + completions.index = completions.index + n + local n_items = #completions.items + + if completions.index < 0 then + completions.index = completions.index + n_items + end + + completions.index = completions.index % n_items + + RenderCurrentCompletion() +end + +function M.get_document(buf_id, cur_line, cur_col) + local lines = vim.api.nvim_buf_get_lines(buf_id, 0, -1, false) + if vim.bo[buf_id].eol then + table.insert(lines, "") + end + + local filetype = vim.bo[buf_id].filetype:gsub("%..*", "") + local language = enums.filetype_aliases[filetype == "" and "text" or filetype] or filetype + if filetype == "" and vim.g.codeium_warn_filetype_missing ~= false then + -- Call your warning function here + vim.g.codeium_warn_filetype_missing = false + end + local editor_language = vim.bo[buf_id].filetype == "" and "unspecified" or vim.bo[buf_id].filetype + + local doc = { + text = table.concat(lines, vim.api.nvim_get_option_value("ff", { buf = buf_id }) == "dos" and "\r\n" or "\n"), + editor_language = editor_language, + language = enums.languages[language] or enums.languages.unspecified, + cursor_position = { row = cur_line - 1, col = cur_col - 1 }, + absolute_path_migrate_me_to_uri = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(buf_id), ":p"), + } + + local line_ending = vim.api.nvim_get_option_value("ff", { buf = buf_id }) == "dos" and "\r\n" or "\n" + if line_ending then + doc.line_ending = line_ending + end + + return doc +end + +function M.Complete(...) + if select("#", ...) == 2 then + local bufnr, timer = ... + + if timer ~= vim.g._codeium_timer then + return + end + + vim.g._codeium_timer = nil + + if vim.fn.mode() ~= "i" or bufnr ~= vim.fn.bufnr("") then + return + end + end + + if vim.g._codeium_timer then + vim.fn.timer_stop(vim.g._codeium_timer) + vim.g._codeium_timer = nil + end + + if vim.o.encoding ~= "latin1" and vim.o.encoding ~= "utf-8" then + error("Only latin1 and utf-8 are supported") + return + end + + local other_documents = {} + local current_bufnr = vim.fn.bufnr("%") + local loaded_buffers = vim.fn.getbufinfo({ bufloaded = 1 }) + for _, buf in ipairs(loaded_buffers) do + if buf.bufnr ~= current_bufnr and vim.fn.getbufvar(buf.bufnr, "&filetype") ~= "" then + table.insert(other_documents, M.get_document(buf.bufnr, 1, 1)) + end + end + + local bufnr = vim.fn.bufnr("") + local data = { + document = M.get_document(bufnr, vim.fn.line("."), vim.fn.col(".")), + editor_options = util.get_editor_options(bufnr), + other_documents = other_documents, + } + + if completions and completions.request_data == data then + return + end + + local request_data = vim.deepcopy(data) + + request_nonce = request_nonce + 1 + local request_id = request_nonce + + vim.b._codeium_status = 1 + + print("requesting") + server.request_completion(data.document, data.editor_options, data.other_documents, function(success, json) + if not success then + return + end + + if json and json.state and json.state.state == "CODEIUM_STATE_SUCCESS" and json.completionItems then + M.handle_completions(json.completionItems) + end + end) + completions = { + request_data = request_data, + request_id = request_id, + } +end + +function M.handle_completions(completion_items) + if not completions then + print("completions was cleared") + return + end + print(vim.inspect(completion_items)) + completions.items = completion_items + completions.index = 0 + RenderCurrentCompletion() +end + +function M.DebouncedComplete() + M.Clear() + if vim.g.codeium_manual or not server.is_healthy() then + return + end + local current_buf = vim.fn.bufnr("") + vim.g._codeium_timer = vim.fn.timer_start(options.idle_delay, function() + M.Complete(current_buf, vim.g._codeium_timer) + end) +end + +function M.CycleOrComplete() + if M.GetCurrentCompletionItem() == nil then + M.Complete() + else + M.CycleCompletions(1) + end +end + +return M From f939d4a14786ade7516a3b7129d1b9ffb413c8b0 Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Sun, 6 Oct 2024 13:10:38 -1000 Subject: [PATCH 02/25] Working accept and clear --- lua/codeium/virtual_text.lua | 51 ++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/lua/codeium/virtual_text.lua b/lua/codeium/virtual_text.lua index 0ae8ab3..6faa547 100644 --- a/lua/codeium/virtual_text.lua +++ b/lua/codeium/virtual_text.lua @@ -10,6 +10,7 @@ local request_nonce = 0 local using_codeium_status = 0 local completions +local idle_timer local server = nil local options @@ -41,7 +42,9 @@ function M.setup(_server, _options) vim.api.nvim_create_autocmd("InsertLeave", { group = augroup, - callback = M.Clear, + callback = function() + M.Clear() + end, }) vim.api.nvim_create_autocmd("BufLeave", { @@ -53,6 +56,16 @@ function M.setup(_server, _options) end, }) + -- TODO make these configurable + vim.keymap.set("i", "", M.Clear, { silent = true }) + vim.keymap.set("i", "", function() + M.CycleCompletions(1) + end, { silent = true }) + vim.keymap.set("i", "", function() + M.CycleCompletions(-1) + end, { silent = true }) + vim.keymap.set("i", "", M.Accept, { silent = true, expr = true, script = true, nowait = true }) + -- vim.api.nvim_create_autocmd({ "ColorScheme", "VimEnter" }, { -- group = augroup, -- callback = function() @@ -77,11 +90,13 @@ end local function CompletionInserter(current_completion, insert_text) local default = vim.g.codeium_tab_fallback or (vim.fn.pumvisible() == 1 and "" or "\t") - if not (vim.fn.mode():match("^[iR]") and completions) then + if not (vim.fn.mode():match("^[iR]")) then + print("bad mode " .. vim.fn.mode()) return default end if current_completion == nil then + print("no current completion") return default end @@ -104,17 +119,19 @@ local function CompletionInserter(current_completion, insert_text) delete_range = ' "_x0"_d' .. delete_chars .. "li" end - local insert_text = '=v:lua.require"codeium".CompletionText()' + local insert_text = '=v:lua.require("codeium.virtual_text").CompletionText()' M.completion_text = text local cursor_text = delta == 0 and "" or ':exe "go" line2byte(line("."))+col(".")+(' .. delta .. ")" server.accept_completion(current_completion.completion.completionId) + print("output: " .. delete_range .. insert_text .. cursor_text) return delete_range .. insert_text .. cursor_text end function M.Accept() + print("Accept") local current_completion = M.GetCurrentCompletionItem() return CompletionInserter(current_completion, current_completion and current_completion.completion.text or "") end @@ -138,9 +155,6 @@ function M.AcceptNextLine() end function M.GetCurrentCompletionItem() - print("GetCurrentCompletionItem") - print(vim.inspect(completions)) - print("abc") if completions and completions.items and completions.index and completions.index < #completions.items then return completions.items[completions.index + 1] end @@ -171,9 +185,6 @@ local function RenderCurrentCompletion() return "" end - print("current_completion") - print(vim.inspect(current_completion)) - local parts = current_completion.completionParts or {} local inline_cumulative_cols = 0 @@ -229,7 +240,7 @@ local function RenderCurrentCompletion() end end - local priority = vim.b.codeium_virtual_text_priority or vim.g.codeium_virtual_text_priority or 65535 + local priority = config.options.virtual_text.priority local _virtcol = vim.fn.virtcol({ row, _col + diff }) local data = { id = idx + 1, hl_mode = "combine", virt_text_win_col = _virtcol - 1, priority = priority } if part.type == "COMPLETION_PART_TYPE_INLINE_MASK" then @@ -258,9 +269,9 @@ function M.Clear(...) vim.b._codeium_status = 0 -- TODO enable -- M.RedrawStatusLine() - if vim.g._codeium_timer then - vim.fn.timer_stop(vim.g._codeium_timer) - vim.g._codeium_timer = nil + if idle_timer then + vim.fn.timer_stop(idle_timer) + idle_timer = nil end if completions then @@ -330,20 +341,20 @@ function M.Complete(...) if select("#", ...) == 2 then local bufnr, timer = ... - if timer ~= vim.g._codeium_timer then + if timer ~= idle_timer then return end - vim.g._codeium_timer = nil + idle_timer = nil if vim.fn.mode() ~= "i" or bufnr ~= vim.fn.bufnr("") then return end end - if vim.g._codeium_timer then - vim.fn.timer_stop(vim.g._codeium_timer) - vim.g._codeium_timer = nil + if idle_timer then + vim.fn.timer_stop(idle_timer) + idle_timer = nil end if vim.o.encoding ~= "latin1" and vim.o.encoding ~= "utf-8" then @@ -411,8 +422,8 @@ function M.DebouncedComplete() return end local current_buf = vim.fn.bufnr("") - vim.g._codeium_timer = vim.fn.timer_start(options.idle_delay, function() - M.Complete(current_buf, vim.g._codeium_timer) + idle_timer = vim.fn.timer_start(options.idle_delay, function() + M.Complete(current_buf, idle_timer) end) end From ee2354c53e918ce2a576959cd7b3e6ddc92ef289 Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Sun, 6 Oct 2024 13:26:58 -1000 Subject: [PATCH 03/25] Map keys. Rename functions as snake case --- lua/codeium/config.lua | 9 +++ lua/codeium/virtual_text.lua | 125 ++++++++++++++++++++--------------- 2 files changed, 80 insertions(+), 54 deletions(-) diff --git a/lua/codeium/config.lua b/lua/codeium/config.lua index cda4aa0..32c7710 100644 --- a/lua/codeium/config.lua +++ b/lua/codeium/config.lua @@ -28,6 +28,15 @@ function M.defaults() enabled = false, idle_delay = 75, virtual_text_priority = 65535, + map_keys = true, + key_bindings = { + accept = "", + accept_word = nil, + accept_line = nil, + clear = "", + next = "", + prev = "", + }, }, workspace_root = { use_lsp = true, diff --git a/lua/codeium/virtual_text.lua b/lua/codeium/virtual_text.lua index 6faa547..c8ca8c1 100644 --- a/lua/codeium/virtual_text.lua +++ b/lua/codeium/virtual_text.lua @@ -1,6 +1,5 @@ local enums = require("codeium.enums") local util = require("codeium.util") -local notify = require("codeium.notify") local config = require("codeium.config") local M = {} @@ -27,7 +26,7 @@ function M.setup(_server, _options) vim.api.nvim_create_autocmd({ "InsertEnter", "CursorMovedI", "CompleteChanged" }, { group = augroup, callback = function() - M.DebouncedComplete() + M.debounced_complete() end, }) @@ -35,7 +34,7 @@ function M.setup(_server, _options) group = augroup, callback = function() if vim.fn.mode():match("^[iR]") then - M.DebouncedComplete() + M.debounced_complete() end end, }) @@ -43,7 +42,7 @@ function M.setup(_server, _options) vim.api.nvim_create_autocmd("InsertLeave", { group = augroup, callback = function() - M.Clear() + M.clear() end, }) @@ -51,20 +50,53 @@ function M.setup(_server, _options) group = augroup, callback = function() if vim.fn.mode():match("^[iR]") then - M.Clear() + M.clear() end end, }) - -- TODO make these configurable - vim.keymap.set("i", "", M.Clear, { silent = true }) - vim.keymap.set("i", "", function() - M.CycleCompletions(1) - end, { silent = true }) - vim.keymap.set("i", "", function() - M.CycleCompletions(-1) - end, { silent = true }) - vim.keymap.set("i", "", M.Accept, { silent = true, expr = true, script = true, nowait = true }) + if config.options.virtual_text.map_keys then + bindings = config.options.virtual_text.key_bindings + if bindings.clear then + vim.keymap.set("i", bindings.accept, function() + M.clear() + end, { silent = true }) + end + + if bindings.next then + vim.keymap.set("i", bindings.next, function() + M.cycle_completions(1) + end, { silent = true }) + end + + if bindings.prev then + vim.keymap.set("i", bindings.prev, function() + M.cycle_completions(-1) + end, { silent = true }) + end + + if bindings.accept then + vim.keymap.set("i", bindings.accept, M.accept, { silent = true, expr = true, script = true, nowait = true }) + end + + if bindings.accept_word then + vim.keymap.set( + "i", + bindings.accept_word, + M.accept_next_word, + { silent = true, expr = true, script = true, nowait = true } + ) + end + + if bindings.accept_line then + vim.keymap.set( + "i", + bindings.accept_line, + M.accept_next_line, + { silent = true, expr = true, script = true, nowait = true } + ) + end + end -- vim.api.nvim_create_autocmd({ "ColorScheme", "VimEnter" }, { -- group = augroup, @@ -72,31 +104,22 @@ function M.setup(_server, _options) -- vim.fn["s:SetStyle"]() -- end, -- }) - - -- vim.api.nvim_create_autocmd("VimEnter", { - -- group = augroup, - -- callback = function() - -- vim.fn["s:MapTab"]() - -- end, - -- }) end -function M.CompletionText() +function M.get_completion_text() local completion_text = M.completion_text M.completion_text = nil return completion_text or "" end -local function CompletionInserter(current_completion, insert_text) +local function completion_inserter(current_completion, insert_text) local default = vim.g.codeium_tab_fallback or (vim.fn.pumvisible() == 1 and "" or "\t") if not (vim.fn.mode():match("^[iR]")) then - print("bad mode " .. vim.fn.mode()) return default end if current_completion == nil then - print("no current completion") return default end @@ -119,25 +142,23 @@ local function CompletionInserter(current_completion, insert_text) delete_range = ' "_x0"_d' .. delete_chars .. "li" end - local insert_text = '=v:lua.require("codeium.virtual_text").CompletionText()' + local insert_text = '=v:lua.require("codeium.virtual_text").get_completion_text()' M.completion_text = text local cursor_text = delta == 0 and "" or ':exe "go" line2byte(line("."))+col(".")+(' .. delta .. ")" server.accept_completion(current_completion.completion.completionId) - print("output: " .. delete_range .. insert_text .. cursor_text) return delete_range .. insert_text .. cursor_text end -function M.Accept() - print("Accept") - local current_completion = M.GetCurrentCompletionItem() - return CompletionInserter(current_completion, current_completion and current_completion.completion.text or "") +function M.accept() + local current_completion = M.get_current_completion_item() + return completion_inserter(current_completion, current_completion and current_completion.completion.text or "") end -function M.AcceptNextWord() - local current_completion = M.GetCurrentCompletionItem() +function M.accept_next_word() + local current_completion = M.get_current_completion_item() local completion_parts = current_completion and (current_completion.completionParts or {}) or {} if #completion_parts == 0 then return "" @@ -145,16 +166,16 @@ function M.AcceptNextWord() local prefix_text = completion_parts[1].prefix or "" local completion_text = completion_parts[1].text or "" local next_word = completion_text:match("^%W*%w*") - return CompletionInserter(current_completion, prefix_text .. next_word) + return completion_inserter(current_completion, prefix_text .. next_word) end -function M.AcceptNextLine() - local current_completion = M.GetCurrentCompletionItem() +function M.accept_next_line() + local current_completion = M.get_current_completion_item() local text = current_completion and current_completion.completion.text:gsub("\n.*$", "") or "" - return CompletionInserter(current_completion, text) + return completion_inserter(current_completion, text) end -function M.GetCurrentCompletionItem() +function M.get_current_completion_item() if completions and completions.items and completions.index and completions.index < #completions.items then return completions.items[completions.index + 1] end @@ -180,7 +201,7 @@ local function RenderCurrentCompletion() return "" end - local current_completion = M.GetCurrentCompletionItem() + local current_completion = M.get_current_completion_item() if current_completion == nil then return "" end @@ -264,8 +285,7 @@ local function RenderCurrentCompletion() end end -function M.Clear(...) - print("Clear") +function M.clear(...) vim.b._codeium_status = 0 -- TODO enable -- M.RedrawStatusLine() @@ -290,8 +310,8 @@ function M.Clear(...) return "" end -function M.CycleCompletions(n) - if M.GetCurrentCompletionItem() == nil then +function M.cycle_completions(n) + if M.get_current_completion_item() == nil then return end @@ -337,7 +357,7 @@ function M.get_document(buf_id, cur_line, cur_col) return doc end -function M.Complete(...) +function M.complete(...) if select("#", ...) == 2 then local bufnr, timer = ... @@ -389,7 +409,6 @@ function M.Complete(...) vim.b._codeium_status = 1 - print("requesting") server.request_completion(data.document, data.editor_options, data.other_documents, function(success, json) if not success then return @@ -407,31 +426,29 @@ end function M.handle_completions(completion_items) if not completions then - print("completions was cleared") return end - print(vim.inspect(completion_items)) completions.items = completion_items completions.index = 0 RenderCurrentCompletion() end -function M.DebouncedComplete() - M.Clear() +function M.debounced_complete() + M.clear() if vim.g.codeium_manual or not server.is_healthy() then return end local current_buf = vim.fn.bufnr("") idle_timer = vim.fn.timer_start(options.idle_delay, function() - M.Complete(current_buf, idle_timer) + M.complete(current_buf, idle_timer) end) end -function M.CycleOrComplete() - if M.GetCurrentCompletionItem() == nil then - M.Complete() +function M.cycle_or_complete() + if M.get_current_completion_item() == nil then + M.complete() else - M.CycleCompletions(1) + M.cycle_completions(1) end end From 3b0314b88084af089aa9071d359f4e46b1c117d7 Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Sun, 6 Oct 2024 13:50:56 -1000 Subject: [PATCH 04/25] Updates and fixes - Add manual setting which disables automatic submission of completion request - Implement cancel of in-flight request in clear function --- lua/codeium/config.lua | 1 + lua/codeium/virtual_text.lua | 41 ++++++++++++++++++++++-------------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/lua/codeium/config.lua b/lua/codeium/config.lua index 32c7710..05fa48c 100644 --- a/lua/codeium/config.lua +++ b/lua/codeium/config.lua @@ -26,6 +26,7 @@ function M.defaults() enable_cmp_source = true, virtual_text = { enabled = false, + manual = false, idle_delay = 75, virtual_text_priority = 65535, map_keys = true, diff --git a/lua/codeium/virtual_text.lua b/lua/codeium/virtual_text.lua index c8ca8c1..c44a737 100644 --- a/lua/codeium/virtual_text.lua +++ b/lua/codeium/virtual_text.lua @@ -1,6 +1,7 @@ +local config = require("codeium.config") local enums = require("codeium.enums") +local notify = require("codeium.notify") local util = require("codeium.util") -local config = require("codeium.config") local M = {} @@ -295,10 +296,8 @@ function M.clear(...) end if completions then - local request_id = completions.request_id or 0 - if request_id > 0 then - -- TODO: Implement codeium#server#Request - -- codeium#server#Request('CancelRequest', {request_id = request_id}) + if completions.cancel then + completions.cancel() end RenderCurrentCompletion() completions = nil @@ -327,6 +326,7 @@ function M.cycle_completions(n) RenderCurrentCompletion() end +local warn_filetype_missing = true function M.get_document(buf_id, cur_line, cur_col) local lines = vim.api.nvim_buf_get_lines(buf_id, 0, -1, false) if vim.bo[buf_id].eol then @@ -335,9 +335,9 @@ function M.get_document(buf_id, cur_line, cur_col) local filetype = vim.bo[buf_id].filetype:gsub("%..*", "") local language = enums.filetype_aliases[filetype == "" and "text" or filetype] or filetype - if filetype == "" and vim.g.codeium_warn_filetype_missing ~= false then - -- Call your warning function here - vim.g.codeium_warn_filetype_missing = false + if filetype == "" and warn_filetype_missing ~= false then + notify.warn("No filetype detected. This will affect completion quality.") + warn_filetype_missing = false end local editor_language = vim.bo[buf_id].filetype == "" and "unspecified" or vim.bo[buf_id].filetype @@ -409,16 +409,25 @@ function M.complete(...) vim.b._codeium_status = 1 - server.request_completion(data.document, data.editor_options, data.other_documents, function(success, json) - if not success then - return - end + local cancel = server.request_completion( + data.document, + data.editor_options, + data.other_documents, + function(success, json) + if completions.request_id == request_id then + completions.cancel = nil + end + if not success then + return + end - if json and json.state and json.state.state == "CODEIUM_STATE_SUCCESS" and json.completionItems then - M.handle_completions(json.completionItems) + if json and json.state and json.state.state == "CODEIUM_STATE_SUCCESS" and json.completionItems then + M.handle_completions(json.completionItems) + end end - end) + ) completions = { + cancel = cancel, request_data = request_data, request_id = request_id, } @@ -435,7 +444,7 @@ end function M.debounced_complete() M.clear() - if vim.g.codeium_manual or not server.is_healthy() then + if config.options.virtual_text.manual or not server.is_healthy() then return end local current_buf = vim.fn.bufnr("") From 41b3136f238a7f65bc215f6c6bf894bb4437b0c1 Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Sun, 6 Oct 2024 13:58:15 -1000 Subject: [PATCH 05/25] some README updates for config --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 3121449..1db5a3a 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,20 @@ in your default browser using the xdg-open command. - `enterprise_mode`: enable enterprise mode - `detect_proxy`: enable or disable proxy detection - `enable_chat`: enable chat functionality +- `enable_cmp_source`: defaults to true. Set `false` to disable the `cmp` source +- `virtual_text`: configuration for the virtual text feature + - `enabled`: defaults to false. Set `true` to enable the virtual text feature + - `manual`: Set `true` to only trigger Codeium using a manual Lua function call + - `idle_delay`: defaults to 75. Time in ms to wait before clearing virtual text + - `virtual_text_priority`: defaults to 65535. Priority of the virtual text + - `map_keys`: defaults to true. Set `false` to disable the default key bindings + - `key_bindings`: key bindings for accepting and cycling through completions + - `accept`: key binding for accepting a completion, default is `` + - `accept_word`: key binding for accepting the next word, default is not set + - `accept_line`: key binding for accepting the next line, default is not set + - `clear`: key binding for clearing the virtual text, default is `` + - `next`: key binding for cycling to the next completion, default is `` + - `prev`: key binding for cycling to the previous completion, default is `` - `workspace_root`: - `use_lsp`: Use Neovim's LSP support to find the workspace root, if possible. - `paths`: paths to files that indicate a workspace root when not using the LSP support From 128fc29f4d351df3d6febef615526e333d47b6bb Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Sun, 6 Oct 2024 14:03:27 -1000 Subject: [PATCH 06/25] permit cmp to not be installed if not using cmp source --- lua/codeium/source.lua | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/lua/codeium/source.lua b/lua/codeium/source.lua index 6b147d3..dcbee60 100644 --- a/lua/codeium/source.lua +++ b/lua/codeium/source.lua @@ -93,19 +93,23 @@ function Source:get_position_encoding_kind() return "utf-8" end -require("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) +-- 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 From c2c512a83263924709c1351cd4df154c872e5f63 Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Sun, 6 Oct 2024 20:17:01 -1000 Subject: [PATCH 07/25] More information on virtual text in README --- README.md | 78 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 1db5a3a..a6db314 100644 --- a/README.md +++ b/README.md @@ -83,17 +83,17 @@ in your default browser using the xdg-open command. - `enterprise_mode`: enable enterprise mode - `detect_proxy`: enable or disable proxy detection - `enable_chat`: enable chat functionality -- `enable_cmp_source`: defaults to true. Set `false` to disable the `cmp` source -- `virtual_text`: configuration for the virtual text feature - - `enabled`: defaults to false. Set `true` to enable the virtual text feature +- `enable_cmp_source`: defaults to true. Set `false` to disable registering a `cmp` source +- `virtual_text`: configuration for showing completions in virtual text + - `enabled`: defaults to `false`. Set `true` to enable the virtual text feature - `manual`: Set `true` to only trigger Codeium using a manual Lua function call - - `idle_delay`: defaults to 75. Time in ms to wait before clearing virtual text - - `virtual_text_priority`: defaults to 65535. Priority of the virtual text - - `map_keys`: defaults to true. Set `false` to disable the default key bindings + - `idle_delay`: defaults to `75`. Time in ms to wait before requesting completions after typing stops. + - `virtual_text_priority`: defaults to `65535`. Priority of the virtual text + - `map_keys`: defaults to `true`. Set `false` to not set any key bindings for completions - `key_bindings`: key bindings for accepting and cycling through completions - `accept`: key binding for accepting a completion, default is `` - - `accept_word`: key binding for accepting the next word, default is not set - - `accept_line`: key binding for accepting the next line, default is not set + - `accept_word`: key binding for accepting only the next word, default is not set + - `accept_line`: key binding for accepting only the next line, default is not set - `clear`: key binding for clearing the virtual text, default is `` - `next`: key binding for cycling to the next completion, default is `` - `prev`: key binding for cycling to the previous completion, default is `` @@ -147,6 +147,66 @@ cmp.setup({ }) ``` +### Virtual Text + +The plugin supports showing completions in virtual text. Set `virtual_text.enabled` in the options to `true` to enable it. + +```lua +require("codeium").setup({ + -- Optionally disable cmp source if using virtual text only + enable_cmp_source = false, + virtual_text = { + enabled = true, + + -- These are the defaults + + -- Set to true if you never want completions to be shown automatically. + manual = false, + -- How long to wait (in ms) before requesting completions after typing stops. + idle_delay = 75, + -- Priority of the virtual text. This usually ensures that the completions appear on top of + -- other plugins that also add virtual text, such as LSP inlay hints, but can be modified if + -- desired. + virtual_text_priority = 65535, + -- Set to false to disable all key bindings for managing completions. + map_keys = true, + -- Key bindings for managing completions in virtual text mode. + key_bindings = { + -- Accept the current completion. + accept = "", + -- Accept the next word. + accept_word = "", + -- Accept the next line. + accept_line = "", + -- Clear the virtual text. + clear = "", + -- Cycle to the next completion. + next = "", + -- Cycle to the previous completion. + prev = "", + } + } +}) +``` + +The plugin defines a number of key bindings for managing completion in virtual text mode. You can override these by +setting `virtual_text.key_bindings`. If you don't want any key bindings, set `virtual_text.map_keys` to `false`, or +you can set specific bindings to `""`. Note that setting a value to `nil` looks the same as not setting in Lua, so the +default will be used in that case. + +When `manual` mode is enabled, you can call any of these functions to show completions: + +```lua +-- Request completions immediately. +require('codeium.virtual_text').complete() + +-- Cycle to the next or previous completion. +require('codeium.virtual_text').cycle_or_complete() + +-- Complete only after idle_delay has passed with no other calls to debounced_complete(). +require('codeium.virtual_text').debounced_complete() +``` + ### Workspace Root Directory The plugin uses a few techniques to find the workspace root directory, which helps to inform the autocomplete and chat context. @@ -187,8 +247,6 @@ require('codeium').setup({ }) ``` - - ## Troubleshooting The plugin log is written to `~/.cache/nvim/codeium.log`. From 9003ea2200b73081c5a70056b6fc57b18d5250bc Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Sun, 6 Oct 2024 20:41:41 -1000 Subject: [PATCH 08/25] Better check for not setting key bindings --- lua/codeium/virtual_text.lua | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lua/codeium/virtual_text.lua b/lua/codeium/virtual_text.lua index c44a737..bdfb570 100644 --- a/lua/codeium/virtual_text.lua +++ b/lua/codeium/virtual_text.lua @@ -58,29 +58,29 @@ function M.setup(_server, _options) if config.options.virtual_text.map_keys then bindings = config.options.virtual_text.key_bindings - if bindings.clear then + if bindings.clear and bindings.clear ~= "" then vim.keymap.set("i", bindings.accept, function() M.clear() end, { silent = true }) end - if bindings.next then + if bindings.next and bindings.next ~= "" then vim.keymap.set("i", bindings.next, function() M.cycle_completions(1) end, { silent = true }) end - if bindings.prev then + if bindings.prev and bindings.prev ~= "" then vim.keymap.set("i", bindings.prev, function() M.cycle_completions(-1) end, { silent = true }) end - if bindings.accept then + if bindings.accept and bindings.accept ~= "" then vim.keymap.set("i", bindings.accept, M.accept, { silent = true, expr = true, script = true, nowait = true }) end - if bindings.accept_word then + if bindings.accept_word and bindings.accept_word ~= "" then vim.keymap.set( "i", bindings.accept_word, @@ -89,7 +89,7 @@ function M.setup(_server, _options) ) end - if bindings.accept_line then + if bindings.accept_line and bindings.accept_line ~= "" then vim.keymap.set( "i", bindings.accept_line, @@ -228,8 +228,8 @@ local function RenderCurrentCompletion() local text = part.text if - (part.type == "COMPLETION_PART_TYPE_INLINE" and idx == 1) - or part.type == "COMPLETION_PART_TYPE_INLINE_MASK" + (part.type == "COMPLETION_PART_TYPE_INLINE" and idx == 1) + or part.type == "COMPLETION_PART_TYPE_INLINE_MASK" then local completion_prefix = part.prefix or "" local completion_line = completion_prefix .. text From a546100a397b545b04a0bb0f9022473951df26b2 Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Sun, 6 Oct 2024 20:50:13 -1000 Subject: [PATCH 09/25] Install highlight styles --- lua/codeium/virtual_text.lua | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/lua/codeium/virtual_text.lua b/lua/codeium/virtual_text.lua index bdfb570..c9d729b 100644 --- a/lua/codeium/virtual_text.lua +++ b/lua/codeium/virtual_text.lua @@ -99,12 +99,21 @@ function M.setup(_server, _options) end end - -- vim.api.nvim_create_autocmd({ "ColorScheme", "VimEnter" }, { - -- group = augroup, - -- callback = function() - -- vim.fn["s:SetStyle"]() - -- end, - -- }) + vim.api.nvim_create_autocmd({ "ColorScheme", "VimEnter" }, { + group = augroup, + callback = function() + M.set_style() + end, + }) +end + +function M.set_style() + if vim.fn.has("termguicolors") == 1 and vim.o.termguicolors then + vim.api.nvim_set_hl(0, "CodeiumSuggestion", { fg = "#808080", default = true }) + else + vim.api.nvim_set_hl(0, "CodeiumSuggestion", { ctermfg = 244, default = true }) + end + vim.api.nvim_set_hl(0, "CodeiumAnnotation", { link = "Normal", default = true }) end function M.get_completion_text() @@ -228,8 +237,8 @@ local function RenderCurrentCompletion() local text = part.text if - (part.type == "COMPLETION_PART_TYPE_INLINE" and idx == 1) - or part.type == "COMPLETION_PART_TYPE_INLINE_MASK" + (part.type == "COMPLETION_PART_TYPE_INLINE" and idx == 1) + or part.type == "COMPLETION_PART_TYPE_INLINE_MASK" then local completion_prefix = part.prefix or "" local completion_line = completion_prefix .. text From fa7bd857bdc7fa9587cf8423bb81c7189c1cd182 Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Mon, 7 Oct 2024 10:03:43 -1000 Subject: [PATCH 10/25] Implement status line --- README.md | 52 +++++++++++++++++++++ lua/codeium/virtual_text.lua | 90 ++++++++++++++++++++++++++++-------- 2 files changed, 122 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index a6db314..aee186f 100644 --- a/README.md +++ b/README.md @@ -207,6 +207,58 @@ require('codeium.virtual_text').cycle_or_complete() require('codeium.virtual_text').debounced_complete() ``` +### Show Codeium status in statusline + +When using virtual text, Codeium status can be generated by calling `require('codeium.virtual_text').status_string()`. +It produces a 3 char long string with Codeium status: + +- `'3/8'` - third suggestion out of 8 +- `'0'` - Codeium returned no suggestions +- `'*'` - waiting for Codeium response + +In order to show it in status line add following line to your `.vimrc`: + +```set statusline+=%3{v:lua.require('codeium.virtual_text').status_string()}``` + +Please check `:help statusline` for further information about building statusline in VIM. + +The `status_string` function can also be used with other statusline plugins. +You can call the `set_statusbar_refresh` function to customize how the plugin refreshes the +status bar. + +For example, this sets up the plugin with lualine: + +```lua +require('codeium.virtual_text').set_statusbar_refresh(function() + require('lualine').refresh() +end) +``` + +For more customization, you can also call the `status` function which returns an object that can be used to create a +status string. + +```lua +function custom_status() + local status = require('codeium.virtual_text').status() + + if status.state == 'idle' then + -- Output was cleared, for example when leaving insert mode + return ' ' + end + + if status.state == 'waiting' then + -- Waiting for response + return "Waiting..." + end + + if status.state == 'completions' and status.total > 0 then + return string.format('%d/%d', status.current, status.total) + end + + return ' 0 ' +end +``` + ### Workspace Root Directory The plugin uses a few techniques to find the workspace root directory, which helps to inform the autocomplete and chat context. diff --git a/lua/codeium/virtual_text.lua b/lua/codeium/virtual_text.lua index c9d729b..b5cadd0 100644 --- a/lua/codeium/virtual_text.lua +++ b/lua/codeium/virtual_text.lua @@ -7,7 +7,8 @@ local M = {} local hlgroup = "CodeiumSuggestion" local request_nonce = 0 -local using_codeium_status = 0 +local using_status_line = false +local codeium_status = "idle" local completions local idle_timer @@ -57,7 +58,7 @@ function M.setup(_server, _options) }) if config.options.virtual_text.map_keys then - bindings = config.options.virtual_text.key_bindings + local bindings = config.options.virtual_text.key_bindings if bindings.clear and bindings.clear ~= "" then vim.keymap.set("i", bindings.accept, function() M.clear() @@ -194,7 +195,7 @@ end local nvim_extmark_ids = {} -local function ClearCompletion() +local function clear_completion() local namespace = vim.api.nvim_create_namespace("codeium") for _, id in ipairs(nvim_extmark_ids) do vim.api.nvim_buf_del_extmark(0, namespace, id) @@ -202,10 +203,9 @@ local function ClearCompletion() nvim_extmark_ids = {} end -local function RenderCurrentCompletion() - ClearCompletion() - -- TODO enable - -- M.RedrawStatusLine() +local function render_current_completion() + clear_completion() + M.redraw_status_line() if not vim.fn.mode():match("^[iR]") then return "" @@ -223,8 +223,7 @@ local function RenderCurrentCompletion() for idx, part in ipairs(parts) do local row = (part.line or 0) + 1 if row ~= vim.fn.line(".") then - -- TODO: Implement codeium#log#Warn - -- codeium#log#Warn('Ignoring completion, line number is not the current line.') + notify.debug("Ignoring completion, line number is not the current line.") goto continue end local _col @@ -296,9 +295,8 @@ local function RenderCurrentCompletion() end function M.clear(...) - vim.b._codeium_status = 0 - -- TODO enable - -- M.RedrawStatusLine() + codeium_status = "idle" + M.redraw_status_line() if idle_timer then vim.fn.timer_stop(idle_timer) idle_timer = nil @@ -308,12 +306,12 @@ function M.clear(...) if completions.cancel then completions.cancel() end - RenderCurrentCompletion() + render_current_completion() completions = nil end if select("#", ...) == 0 then - RenderCurrentCompletion() + render_current_completion() end return "" end @@ -332,11 +330,11 @@ function M.cycle_completions(n) completions.index = completions.index % n_items - RenderCurrentCompletion() + render_current_completion() end local warn_filetype_missing = true -function M.get_document(buf_id, cur_line, cur_col) +local function get_document(buf_id, cur_line, cur_col) local lines = vim.api.nvim_buf_get_lines(buf_id, 0, -1, false) if vim.bo[buf_id].eol then table.insert(lines, "") @@ -396,13 +394,13 @@ function M.complete(...) local loaded_buffers = vim.fn.getbufinfo({ bufloaded = 1 }) for _, buf in ipairs(loaded_buffers) do if buf.bufnr ~= current_bufnr and vim.fn.getbufvar(buf.bufnr, "&filetype") ~= "" then - table.insert(other_documents, M.get_document(buf.bufnr, 1, 1)) + table.insert(other_documents, get_document(buf.bufnr, 1, 1)) end end local bufnr = vim.fn.bufnr("") local data = { - document = M.get_document(bufnr, vim.fn.line("."), vim.fn.col(".")), + document = get_document(bufnr, vim.fn.line("."), vim.fn.col(".")), editor_options = util.get_editor_options(bufnr), other_documents = other_documents, } @@ -416,7 +414,7 @@ function M.complete(...) request_nonce = request_nonce + 1 local request_id = request_nonce - vim.b._codeium_status = 1 + codeium_status = "waiting" local cancel = server.request_completion( data.document, @@ -425,6 +423,7 @@ function M.complete(...) function(success, json) if completions.request_id == request_id then completions.cancel = nil + codeium_status = "idle" end if not success then return @@ -448,7 +447,8 @@ function M.handle_completions(completion_items) end completions.items = completion_items completions.index = 0 - RenderCurrentCompletion() + codeium_status = "completions" + render_current_completion() end function M.debounced_complete() @@ -470,4 +470,54 @@ function M.cycle_or_complete() end end +function M.status() + if codeium_status == "completions" then + if completions and completions.items and completions.index then + return { + state = "completions", + current = completions.index + 1, + total = #completions.items, + } + else + return { state = "idle" } + end + else + return { state = codeium_status } + end +end + +function M.status_string() + using_status_line = true + local status = M.status() + + if status.state == "completions" then + if status.total > 0 then + return string.format("%d/%d", status.current, status.total) + else + return " 0 " + end + elseif status.state == "waiting" then + return " * " + elseif status.state == "idle" then + return " 0 " + else + return " " + end +end + +local refresh_fn = function() + vim.cmd("redrawstatus") +end + +function M.set_statusbar_refresh(refresh) + using_status_line = true + refresh_fn = refresh +end + +function M.redraw_status_line() + if using_status_line then + refresh_fn() + end +end + return M From c1f6022841e9324c4873982e6f26f0c85e211219 Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Mon, 7 Oct 2024 10:22:58 -1000 Subject: [PATCH 11/25] update language --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index aee186f..c266fa2 100644 --- a/README.md +++ b/README.md @@ -191,8 +191,8 @@ require("codeium").setup({ The plugin defines a number of key bindings for managing completion in virtual text mode. You can override these by setting `virtual_text.key_bindings`. If you don't want any key bindings, set `virtual_text.map_keys` to `false`, or -you can set specific bindings to `""`. Note that setting a value to `nil` looks the same as not setting in Lua, so the -default will be used in that case. +you can set specific bindings to `""`. Note that in Lua, setting a value to `nil` looks the same as not setting it at +all, so the default key binding will be installed if you use `nil`. When `manual` mode is enabled, you can call any of these functions to show completions: @@ -200,7 +200,7 @@ When `manual` mode is enabled, you can call any of these functions to show compl -- Request completions immediately. require('codeium.virtual_text').complete() --- Cycle to the next or previous completion. +-- Request a completion, or cycle to the next if we already have some require('codeium.virtual_text').cycle_or_complete() -- Complete only after idle_delay has passed with no other calls to debounced_complete(). From 8e23f729369c87f2fb61e1118ebd0dbf01c4ef59 Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Mon, 7 Oct 2024 13:37:39 -1000 Subject: [PATCH 12/25] Fix virtual text priority --- lua/codeium/virtual_text.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/codeium/virtual_text.lua b/lua/codeium/virtual_text.lua index b5cadd0..e2f1e80 100644 --- a/lua/codeium/virtual_text.lua +++ b/lua/codeium/virtual_text.lua @@ -270,7 +270,7 @@ local function render_current_completion() end end - local priority = config.options.virtual_text.priority + local priority = config.options.virtual_text.virtual_text_priority local _virtcol = vim.fn.virtcol({ row, _col + diff }) local data = { id = idx + 1, hl_mode = "combine", virt_text_win_col = _virtcol - 1, priority = priority } if part.type == "COMPLETION_PART_TYPE_INLINE_MASK" then From 69a5b760179668e8aad1d3b1fe825683ea2ee1a9 Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Tue, 8 Oct 2024 13:46:38 -1000 Subject: [PATCH 13/25] change "unknown filetype" notify to debug --- lua/codeium/virtual_text.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/codeium/virtual_text.lua b/lua/codeium/virtual_text.lua index e2f1e80..66a5b91 100644 --- a/lua/codeium/virtual_text.lua +++ b/lua/codeium/virtual_text.lua @@ -343,7 +343,7 @@ local function get_document(buf_id, cur_line, cur_col) local filetype = vim.bo[buf_id].filetype:gsub("%..*", "") local language = enums.filetype_aliases[filetype == "" and "text" or filetype] or filetype if filetype == "" and warn_filetype_missing ~= false then - notify.warn("No filetype detected. This will affect completion quality.") + notify.debug("No filetype detected. This will affect completion quality.") warn_filetype_missing = false end local editor_language = vim.bo[buf_id].filetype == "" and "unspecified" or vim.bo[buf_id].filetype From 0794afbef9b4d860408207d97f8844608f84ab25 Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Fri, 11 Oct 2024 11:06:09 -1000 Subject: [PATCH 14/25] Use util.get_other_documents and util.get_newline instead of ported Vim implementation. --- lua/codeium/virtual_text.lua | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/lua/codeium/virtual_text.lua b/lua/codeium/virtual_text.lua index 66a5b91..a77d226 100644 --- a/lua/codeium/virtual_text.lua +++ b/lua/codeium/virtual_text.lua @@ -353,14 +353,10 @@ local function get_document(buf_id, cur_line, cur_col) editor_language = editor_language, language = enums.languages[language] or enums.languages.unspecified, cursor_position = { row = cur_line - 1, col = cur_col - 1 }, - absolute_path_migrate_me_to_uri = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(buf_id), ":p"), + absolute_uri = util.get_uri(vim.fn.fnamemodify(vim.api.nvim_buf_get_name(buf_id), ":p")), + line_ending = util.get_newline(buf_id), } - local line_ending = vim.api.nvim_get_option_value("ff", { buf = buf_id }) == "dos" and "\r\n" or "\n" - if line_ending then - doc.line_ending = line_ending - end - return doc end @@ -389,16 +385,8 @@ function M.complete(...) return end - local other_documents = {} - local current_bufnr = vim.fn.bufnr("%") - local loaded_buffers = vim.fn.getbufinfo({ bufloaded = 1 }) - for _, buf in ipairs(loaded_buffers) do - if buf.bufnr ~= current_bufnr and vim.fn.getbufvar(buf.bufnr, "&filetype") ~= "" then - table.insert(other_documents, get_document(buf.bufnr, 1, 1)) - end - end - local bufnr = vim.fn.bufnr("") + local other_documents = util.get_other_documents(bufnr) local data = { document = get_document(bufnr, vim.fn.line("."), vim.fn.col(".")), editor_options = util.get_editor_options(bufnr), From a7ab56f481f910ec6a65b88edd8ccdae9cc132a6 Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Fri, 11 Oct 2024 11:27:00 -1000 Subject: [PATCH 15/25] Pass workspace_uri with completion doc, like Source:complete does --- lua/codeium/virtual_text.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lua/codeium/virtual_text.lua b/lua/codeium/virtual_text.lua index a77d226..4db5985 100644 --- a/lua/codeium/virtual_text.lua +++ b/lua/codeium/virtual_text.lua @@ -348,13 +348,15 @@ local function get_document(buf_id, cur_line, cur_col) end local editor_language = vim.bo[buf_id].filetype == "" and "unspecified" or vim.bo[buf_id].filetype + local line_ending = util.get_newline(buf_id) local doc = { - text = table.concat(lines, vim.api.nvim_get_option_value("ff", { buf = buf_id }) == "dos" and "\r\n" or "\n"), + text = table.concat(lines, line_ending), editor_language = editor_language, language = enums.languages[language] or enums.languages.unspecified, cursor_position = { row = cur_line - 1, col = cur_col - 1 }, absolute_uri = util.get_uri(vim.fn.fnamemodify(vim.api.nvim_buf_get_name(buf_id), ":p")), - line_ending = util.get_newline(buf_id), + workspace_uri = util.get_uri(util.get_project_root()), + line_ending = line_ending, } return doc From 3f3fd5b623829cdccd182ca784704322c5e10e2d Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Fri, 11 Oct 2024 13:58:05 -1000 Subject: [PATCH 16/25] some cleanup --- lua/codeium/virtual_text.lua | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/lua/codeium/virtual_text.lua b/lua/codeium/virtual_text.lua index 4db5985..c6f68ad 100644 --- a/lua/codeium/virtual_text.lua +++ b/lua/codeium/virtual_text.lua @@ -10,10 +10,22 @@ local request_nonce = 0 local using_status_line = false local codeium_status = "idle" +--- @class Completions +--- @field items table[] | nil +--- @field index number | nil +--- @field cancel function +--- @field request_id number +--- @field request_data table + +--- @type Completions | nil local completions local idle_timer -local server = nil +local server = { + is_healthy = function() + return false + end, +} local options function M.setup(_server, _options) server = _server @@ -110,11 +122,10 @@ end function M.set_style() if vim.fn.has("termguicolors") == 1 and vim.o.termguicolors then - vim.api.nvim_set_hl(0, "CodeiumSuggestion", { fg = "#808080", default = true }) + vim.api.nvim_set_hl(0, hlgroup, { fg = "#808080", default = true }) else - vim.api.nvim_set_hl(0, "CodeiumSuggestion", { ctermfg = 244, default = true }) + vim.api.nvim_set_hl(0, hlgroup, { ctermfg = 244, default = true }) end - vim.api.nvim_set_hl(0, "CodeiumAnnotation", { link = "Normal", default = true }) end function M.get_completion_text() @@ -276,7 +287,7 @@ local function render_current_completion() if part.type == "COMPLETION_PART_TYPE_INLINE_MASK" then data.virt_text = { { text, hlgroup } } elseif part.type == "COMPLETION_PART_TYPE_BLOCK" then - local lines = vim.split(text, "\n", true) + local lines = vim.split(text, "\n") if lines[#lines] == "" then table.remove(lines) end @@ -317,7 +328,7 @@ function M.clear(...) end function M.cycle_completions(n) - if M.get_current_completion_item() == nil then + if not completions or M.get_current_completion_item() == nil then return end @@ -411,7 +422,7 @@ function M.complete(...) data.editor_options, data.other_documents, function(success, json) - if completions.request_id == request_id then + if completions and completions.request_id == request_id then completions.cancel = nil codeium_status = "idle" end From b91552e6d03b0eb3e4de7f5a2bf2dad2d038b0ea Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Sat, 12 Oct 2024 20:57:31 -1000 Subject: [PATCH 17/25] A bit more cleanup --- lua/codeium/virtual_text.lua | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lua/codeium/virtual_text.lua b/lua/codeium/virtual_text.lua index c6f68ad..5537240 100644 --- a/lua/codeium/virtual_text.lua +++ b/lua/codeium/virtual_text.lua @@ -8,6 +8,8 @@ local M = {} local hlgroup = "CodeiumSuggestion" local request_nonce = 0 local using_status_line = false + +--- @type "idle" | "waiting" | "completions" local codeium_status = "idle" --- @class Completions @@ -22,18 +24,18 @@ local completions local idle_timer local server = { + --- This will be replaced by the actual server when setup is called. is_healthy = function() return false end, } -local options -function M.setup(_server, _options) + +function M.setup(_server) server = _server - options = _options local augroup = vim.api.nvim_create_augroup("codeium_virtual_text", { clear = true }) - if not options.enabled then + if not config.options.virtual_text.enabled then return end @@ -458,7 +460,7 @@ function M.debounced_complete() return end local current_buf = vim.fn.bufnr("") - idle_timer = vim.fn.timer_start(options.idle_delay, function() + idle_timer = vim.fn.timer_start(config.options.virtual_text.idle_delay, function() M.complete(current_buf, idle_timer) end) end From 9332bd2826bd629ced71c1beb7348e7a600faee0 Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Sat, 12 Oct 2024 21:18:24 -1000 Subject: [PATCH 18/25] Convert from vim-style varargs to opts object --- lua/codeium/virtual_text.lua | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/lua/codeium/virtual_text.lua b/lua/codeium/virtual_text.lua index 5537240..b91d9b8 100644 --- a/lua/codeium/virtual_text.lua +++ b/lua/codeium/virtual_text.lua @@ -307,7 +307,7 @@ local function render_current_completion() end end -function M.clear(...) +function M.clear() codeium_status = "idle" M.redraw_status_line() if idle_timer then @@ -323,12 +323,11 @@ function M.clear(...) completions = nil end - if select("#", ...) == 0 then - render_current_completion() - end + render_current_completion() return "" end +--- @param n number function M.cycle_completions(n) if not completions or M.get_current_completion_item() == nil then return @@ -347,6 +346,10 @@ function M.cycle_completions(n) end local warn_filetype_missing = true +--- @param buf_id number +--- @param cur_line number +--- @param cur_col number +--- @return table local function get_document(buf_id, cur_line, cur_col) local lines = vim.api.nvim_buf_get_lines(buf_id, 0, -1, false) if vim.bo[buf_id].eol then @@ -375,17 +378,16 @@ local function get_document(buf_id, cur_line, cur_col) return doc end -function M.complete(...) - if select("#", ...) == 2 then - local bufnr, timer = ... - - if timer ~= idle_timer then +--- @param opts { bufnr: number, timer: any }? +function M.complete(opts) + if opts then + if opts.timer ~= idle_timer then return end idle_timer = nil - if vim.fn.mode() ~= "i" or bufnr ~= vim.fn.bufnr("") then + if vim.fn.mode() ~= "i" or opts.bufnr ~= vim.fn.bufnr("") then return end end @@ -460,8 +462,8 @@ function M.debounced_complete() return end local current_buf = vim.fn.bufnr("") - idle_timer = vim.fn.timer_start(config.options.virtual_text.idle_delay, function() - M.complete(current_buf, idle_timer) + idle_timer = vim.fn.timer_start(config.options.virtual_text.idle_delay, function(timer) + M.complete({ bufnr = current_buf, timer = timer }) end) end From 5df4dac0672c6909430a426e20660f72e93e0a2e Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Mon, 14 Oct 2024 09:07:03 -1000 Subject: [PATCH 19/25] Proper clear binding setup --- lua/codeium/virtual_text.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/codeium/virtual_text.lua b/lua/codeium/virtual_text.lua index b91d9b8..4eda8b1 100644 --- a/lua/codeium/virtual_text.lua +++ b/lua/codeium/virtual_text.lua @@ -74,7 +74,7 @@ function M.setup(_server) if config.options.virtual_text.map_keys then local bindings = config.options.virtual_text.key_bindings if bindings.clear and bindings.clear ~= "" then - vim.keymap.set("i", bindings.accept, function() + vim.keymap.set("i", bindings.clear, function() M.clear() end, { silent = true }) end From 0aaf908cbfe159795e5cbfbea9e3f2059fb60c2d Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Mon, 14 Oct 2024 09:11:07 -1000 Subject: [PATCH 20/25] Configure accept fallback through setup instead of global --- README.md | 5 +++++ lua/codeium/config.lua | 1 + lua/codeium/virtual_text.lua | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c266fa2..3a28bb0 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,8 @@ in your default browser using the xdg-open command. - `idle_delay`: defaults to `75`. Time in ms to wait before requesting completions after typing stops. - `virtual_text_priority`: defaults to `65535`. Priority of the virtual text - `map_keys`: defaults to `true`. Set `false` to not set any key bindings for completions + - `accept_fallback`: Emulate pressing this key when using the accept key binding but there is no completion. Defaults + to "\t" - `key_bindings`: key bindings for accepting and cycling through completions - `accept`: key binding for accepting a completion, default is `` - `accept_word`: key binding for accepting only the next word, default is not set @@ -170,6 +172,9 @@ require("codeium").setup({ virtual_text_priority = 65535, -- Set to false to disable all key bindings for managing completions. map_keys = true, + -- The key to press when hitting the accept keybinding but no completion is showing. + -- Defaults to \t normally or when a popup is showing. + accept_fallback = nil, -- Key bindings for managing completions in virtual text mode. key_bindings = { -- Accept the current completion. diff --git a/lua/codeium/config.lua b/lua/codeium/config.lua index 05fa48c..f4a58df 100644 --- a/lua/codeium/config.lua +++ b/lua/codeium/config.lua @@ -30,6 +30,7 @@ function M.defaults() idle_delay = 75, virtual_text_priority = 65535, map_keys = true, + accept_fallback = nil, key_bindings = { accept = "", accept_word = nil, diff --git a/lua/codeium/virtual_text.lua b/lua/codeium/virtual_text.lua index 4eda8b1..d9dd5fe 100644 --- a/lua/codeium/virtual_text.lua +++ b/lua/codeium/virtual_text.lua @@ -137,7 +137,7 @@ function M.get_completion_text() end local function completion_inserter(current_completion, insert_text) - local default = vim.g.codeium_tab_fallback or (vim.fn.pumvisible() == 1 and "" or "\t") + local default = config.options.virtual_text.accept_fallback or (vim.fn.pumvisible() == 1 and "" or "\t") if not (vim.fn.mode():match("^[iR]")) then return default From ac9aaa1fe04159e19d4599dd740a9a928bb9f8d3 Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Tue, 15 Oct 2024 09:00:58 -1000 Subject: [PATCH 21/25] Ignore buffers whose names are already URIs This indicates special buffers created by some plugins like oil.nvim, and the LS will return an error. --- lua/codeium/virtual_text.lua | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/lua/codeium/virtual_text.lua b/lua/codeium/virtual_text.lua index d9dd5fe..09602d0 100644 --- a/lua/codeium/virtual_text.lua +++ b/lua/codeium/virtual_text.lua @@ -349,7 +349,7 @@ local warn_filetype_missing = true --- @param buf_id number --- @param cur_line number --- @param cur_col number ---- @return table +--- @return table | nil local function get_document(buf_id, cur_line, cur_col) local lines = vim.api.nvim_buf_get_lines(buf_id, 0, -1, false) if vim.bo[buf_id].eol then @@ -364,6 +364,13 @@ local function get_document(buf_id, cur_line, cur_col) end local editor_language = vim.bo[buf_id].filetype == "" and "unspecified" or vim.bo[buf_id].filetype + local buf_name = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(buf_id), ":p") + -- If it's already any sort of URI, this might be a special buffer for some plugins, so we ignore it to + -- avoid an LS error. + if buf_name:match("^%w+://") ~= nil then + return nil + end + local line_ending = util.get_newline(buf_id) local doc = { text = table.concat(lines, line_ending), @@ -403,9 +410,14 @@ function M.complete(opts) end local bufnr = vim.fn.bufnr("") + local document = get_document(bufnr, vim.fn.line("."), vim.fn.col(".")) + if document == nil then + return + end + local other_documents = util.get_other_documents(bufnr) local data = { - document = get_document(bufnr, vim.fn.line("."), vim.fn.col(".")), + document = document, editor_options = util.get_editor_options(bufnr), other_documents = other_documents, } From bbb0d267bcea1ecd954949185cdb117116ab6f3f Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Tue, 15 Oct 2024 09:11:57 -1000 Subject: [PATCH 22/25] Allow enabling and disabling virtual text by filetype --- README.md | 25 +++++++++++++++++++++++++ lua/codeium/config.lua | 2 ++ lua/codeium/virtual_text.lua | 16 +++++++++++++++- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3a28bb0..71fc392 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,8 @@ in your default browser using the xdg-open command. - `enable_cmp_source`: defaults to true. Set `false` to disable registering a `cmp` source - `virtual_text`: configuration for showing completions in virtual text - `enabled`: defaults to `false`. Set `true` to enable the virtual text feature + - `filetypes`: A mapping of filetype to true or false, to enable virtual text + - `default_filetype_enabled`: Whether to enable virtual text of not for types not listed in `filetypes`. - `manual`: Set `true` to only trigger Codeium using a manual Lua function call - `idle_delay`: defaults to `75`. Time in ms to wait before requesting completions after typing stops. - `virtual_text_priority`: defaults to `65535`. Priority of the virtual text @@ -164,6 +166,10 @@ require("codeium").setup({ -- Set to true if you never want completions to be shown automatically. manual = false, + -- A mapping of filetype to true or false, to enable virtual text. + filetypes = {}, + -- Whether to enable virtual text of not for filetypes not specifically listed above. + default_filetype_enabled = true, -- How long to wait (in ms) before requesting completions after typing stops. idle_delay = 75, -- Priority of the virtual text. This usually ensures that the completions appear on top of @@ -194,6 +200,8 @@ require("codeium").setup({ }) ``` +#### Virtual Text Keybindings + The plugin defines a number of key bindings for managing completion in virtual text mode. You can override these by setting `virtual_text.key_bindings`. If you don't want any key bindings, set `virtual_text.map_keys` to `false`, or you can set specific bindings to `""`. Note that in Lua, setting a value to `nil` looks the same as not setting it at @@ -212,6 +220,23 @@ require('codeium.virtual_text').cycle_or_complete() require('codeium.virtual_text').debounced_complete() ``` +#### Virtual Text Filetypes + +You can se the `filetypes` and `deault_filetype_enabled` options in the `virtual_text` table to configure which filetypes +should use virtual text. + +```lua +require('codeium.virtual_text').setup({ + virtual_text = { + filetypes = { + "python" = true, + "markdown" = false + }, + default_filetype_enabled = true + } +}) +``` + ### Show Codeium status in statusline When using virtual text, Codeium status can be generated by calling `require('codeium.virtual_text').status_string()`. diff --git a/lua/codeium/config.lua b/lua/codeium/config.lua index f4a58df..11863f0 100644 --- a/lua/codeium/config.lua +++ b/lua/codeium/config.lua @@ -26,6 +26,8 @@ function M.defaults() enable_cmp_source = true, virtual_text = { enabled = false, + filetypes = {}, + default_filetype_enabled = true, manual = false, idle_delay = 75, virtual_text_priority = 65535, diff --git a/lua/codeium/virtual_text.lua b/lua/codeium/virtual_text.lua index 09602d0..8488146 100644 --- a/lua/codeium/virtual_text.lua +++ b/lua/codeium/virtual_text.lua @@ -410,6 +410,11 @@ function M.complete(opts) end local bufnr = vim.fn.bufnr("") + + if not M.filetype_enabled(bufnr) then + return + end + local document = get_document(bufnr, vim.fn.line("."), vim.fn.col(".")) if document == nil then return @@ -468,9 +473,18 @@ function M.handle_completions(completion_items) render_current_completion() end +function M.filetype_enabled(bufnr) + local filetype = vim.bo[bufnr].filetype + local enabled = config.options.virtual_text.filetypes[filetype] + if enabled == nil then + return config.options.virtual_text.default_filetype_enabled + end + return enabled +end + function M.debounced_complete() M.clear() - if config.options.virtual_text.manual or not server.is_healthy() then + if config.options.virtual_text.manual or not server.is_healthy() or not M.filetype_enabled(vim.fn.bufnr("")) then return end local current_buf = vim.fn.bufnr("") From 6a88a03e2673a88a7cc90d998f84669611ef4abe Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Tue, 15 Oct 2024 11:32:25 -1000 Subject: [PATCH 23/25] Fix README typos --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 71fc392..02f7c6c 100644 --- a/README.md +++ b/README.md @@ -222,15 +222,15 @@ require('codeium.virtual_text').debounced_complete() #### Virtual Text Filetypes -You can se the `filetypes` and `deault_filetype_enabled` options in the `virtual_text` table to configure which filetypes +You can set the `filetypes` and `default_filetype_enabled` options in the `virtual_text` table to configure which filetypes should use virtual text. ```lua require('codeium.virtual_text').setup({ virtual_text = { filetypes = { - "python" = true, - "markdown" = false + python = true, + markdown = false }, default_filetype_enabled = true } From 938a3df5ff8ba097beac4964290348e880686e65 Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Tue, 15 Oct 2024 21:06:05 -1000 Subject: [PATCH 24/25] Remove default clear binding since that is also Esc --- README.md | 2 +- lua/codeium/config.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 02f7c6c..669e8ca 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ in your default browser using the xdg-open command. - `accept`: key binding for accepting a completion, default is `` - `accept_word`: key binding for accepting only the next word, default is not set - `accept_line`: key binding for accepting only the next line, default is not set - - `clear`: key binding for clearing the virtual text, default is `` + - `clear`: key binding for clearing the virtual text, default is not set - `next`: key binding for cycling to the next completion, default is `` - `prev`: key binding for cycling to the previous completion, default is `` - `workspace_root`: diff --git a/lua/codeium/config.lua b/lua/codeium/config.lua index 11863f0..9f30bd2 100644 --- a/lua/codeium/config.lua +++ b/lua/codeium/config.lua @@ -37,7 +37,7 @@ function M.defaults() accept = "", accept_word = nil, accept_line = nil, - clear = "", + clear = nil, next = "", prev = "", }, From 2375ded0513ad619bdec45e2f6c68e4bcdeed9fa Mon Sep 17 00:00:00 2001 From: Daniel Imfeld Date: Fri, 18 Oct 2024 21:13:21 -1000 Subject: [PATCH 25/25] Suggest setting `false` instead of empty string to disable key bindings --- README.md | 9 ++++----- lua/codeium/config.lua | 6 +++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 669e8ca..2804a84 100644 --- a/README.md +++ b/README.md @@ -186,11 +186,11 @@ require("codeium").setup({ -- Accept the current completion. accept = "", -- Accept the next word. - accept_word = "", + accept_word = false, -- Accept the next line. - accept_line = "", + accept_line = false, -- Clear the virtual text. - clear = "", + clear = false, -- Cycle to the next completion. next = "", -- Cycle to the previous completion. @@ -204,8 +204,7 @@ require("codeium").setup({ The plugin defines a number of key bindings for managing completion in virtual text mode. You can override these by setting `virtual_text.key_bindings`. If you don't want any key bindings, set `virtual_text.map_keys` to `false`, or -you can set specific bindings to `""`. Note that in Lua, setting a value to `nil` looks the same as not setting it at -all, so the default key binding will be installed if you use `nil`. +you can set specific bindings to `false`. When `manual` mode is enabled, you can call any of these functions to show completions: diff --git a/lua/codeium/config.lua b/lua/codeium/config.lua index 9f30bd2..a1cc447 100644 --- a/lua/codeium/config.lua +++ b/lua/codeium/config.lua @@ -35,9 +35,9 @@ function M.defaults() accept_fallback = nil, key_bindings = { accept = "", - accept_word = nil, - accept_line = nil, - clear = nil, + accept_word = false, + accept_line = false, + clear = false, next = "", prev = "", },