Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

virtual text support #241

Merged
merged 25 commits into from
Oct 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3e29b1c
Start on virtual text support
dimfeld Oct 6, 2024
f939d4a
Working accept and clear
dimfeld Oct 6, 2024
ee2354c
Map keys. Rename functions as snake case
dimfeld Oct 6, 2024
3b0314b
Updates and fixes
dimfeld Oct 6, 2024
41b3136
some README updates for config
dimfeld Oct 6, 2024
128fc29
permit cmp to not be installed if not using cmp source
dimfeld Oct 7, 2024
c2c512a
More information on virtual text in README
dimfeld Oct 7, 2024
9003ea2
Better check for not setting key bindings
dimfeld Oct 7, 2024
a546100
Install highlight styles
dimfeld Oct 7, 2024
fa7bd85
Implement status line
dimfeld Oct 7, 2024
c1f6022
update language
dimfeld Oct 7, 2024
8e23f72
Fix virtual text priority
dimfeld Oct 7, 2024
69a5b76
change "unknown filetype" notify to debug
dimfeld Oct 8, 2024
0794afb
Use util.get_other_documents and util.get_newline instead of ported V…
dimfeld Oct 11, 2024
a7ab56f
Pass workspace_uri with completion doc, like Source:complete does
dimfeld Oct 11, 2024
3f3fd5b
some cleanup
dimfeld Oct 11, 2024
b91552e
A bit more cleanup
dimfeld Oct 13, 2024
9332bd2
Convert from vim-style varargs to opts object
dimfeld Oct 13, 2024
5df4dac
Proper clear binding setup
dimfeld Oct 14, 2024
0aaf908
Configure accept fallback through setup instead of global
dimfeld Oct 14, 2024
ac9aaa1
Ignore buffers whose names are already URIs
dimfeld Oct 15, 2024
bbb0d26
Allow enabling and disabling virtual text by filetype
dimfeld Oct 15, 2024
6a88a03
Fix README typos
dimfeld Oct 15, 2024
938a3df
Remove <c-[> default clear binding since that is also Esc
dimfeld Oct 16, 2024
2375ded
Suggest setting `false` instead of empty string to disable key bindings
dimfeld Oct 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 155 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,24 @@ 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 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
- `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 `<Tab>`
- `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 not set
- `next`: key binding for cycling to the next completion, default is `<M-]>`
- `prev`: key binding for cycling to the previous completion, default is `<M-[>`
- `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
Expand Down Expand Up @@ -133,6 +151,143 @@ 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,
-- 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
-- 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,
-- The key to press when hitting the accept keybinding but no completion is showing.
-- Defaults to \t normally or <c-n> when a popup is showing.
accept_fallback = nil,
-- Key bindings for managing completions in virtual text mode.
key_bindings = {
-- Accept the current completion.
accept = "<Tab>",
-- Accept the next word.
accept_word = false,
-- Accept the next line.
accept_line = false,
-- Clear the virtual text.
clear = false,
-- Cycle to the next completion.
next = "<M-]>",
-- Cycle to the previous completion.
prev = "<M-[>",
}
}
})
```

#### 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 `false`.

When `manual` mode is enabled, you can call any of these functions to show completions:

```lua
-- Request completions immediately.
require('codeium.virtual_text').complete()

-- 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().
require('codeium.virtual_text').debounced_complete()
```

#### Virtual Text 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
},
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()`.
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.
Expand Down Expand Up @@ -173,8 +328,6 @@ require('codeium').setup({
})
```



## Troubleshooting

The plugin log is written to `~/.cache/nvim/codeium.log`.
Expand Down
19 changes: 19 additions & 0 deletions lua/codeium/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,25 @@ 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,
filetypes = {},
default_filetype_enabled = true,
manual = false,
idle_delay = 75,
virtual_text_priority = 65535,
map_keys = true,
accept_fallback = nil,
key_bindings = {
accept = "<Tab>",
accept_word = false,
accept_line = false,
clear = false,
next = "<M-]>",
prev = "<M-[>",
},
},
workspace_root = {
use_lsp = true,
find_root = nil,
Expand Down
6 changes: 5 additions & 1 deletion lua/codeium/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
59 changes: 18 additions & 41 deletions lua/codeium/source.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand All @@ -120,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
Expand Down Expand Up @@ -178,7 +155,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(
{
Expand Down
27 changes: 27 additions & 0 deletions lua/codeium/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading
Loading