Added completion

This commit is contained in:
Jonas Widen 2025-03-16 21:37:09 +01:00
parent a04835f90c
commit fb0213d77a
2 changed files with 92 additions and 49 deletions

View File

@ -1,45 +1,53 @@
local api = require("gemini.api")
local M = {}
-- Cache for completion items
local completion_cache = {}
-- State for managing current suggestion
local current_suggestion = {
text = nil,
start_col = nil,
namespace_id = vim.api.nvim_create_namespace('gemini_suggestion')
}
-- Helper function to create completion items from Gemini response
local function parse_completion_response(response)
if type(response) ~= "string" then
return {}
-- Helper function to clear current suggestion
local function clear_suggestion()
if current_suggestion.text then
vim.api.nvim_buf_clear_namespace(0, current_suggestion.namespace_id, 0, -1)
current_suggestion.text = nil
current_suggestion.start_col = nil
end
end
-- Split response into lines and filter out empty ones
local lines = vim.split(response, "\n")
local items = {}
-- Helper function to show suggestion
local function show_suggestion(suggestion, start_col)
clear_suggestion()
for _, line in ipairs(lines) do
if line and line:match("^%s*[^%s]") then -- Skip empty lines
table.insert(items, {
word = line:match("^%s*(.-)%s*$"), -- Trim whitespace
kind = vim.lsp.protocol.CompletionItemKind.Text,
menu = "[Gemini]",
info = line,
local line = vim.api.nvim_win_get_cursor(0)[1] - 1
current_suggestion.text = suggestion
current_suggestion.start_col = start_col
-- Show suggestion in a different color
vim.api.nvim_buf_add_highlight(0, current_suggestion.namespace_id, 'GeminiSuggestion', line, start_col, start_col + #suggestion)
vim.api.nvim_buf_set_text(0, line, start_col, line, start_col, {suggestion})
-- Make the text virtual (doesn't affect actual buffer content)
vim.api.nvim_buf_set_extmark(0, current_suggestion.namespace_id, line, start_col, {
virt_text = {{suggestion, 'GeminiSuggestion'}},
virt_text_pos = 'overlay',
})
end
-- Function to accept current suggestion
function M.accept_suggestion()
if current_suggestion.text and current_suggestion.start_col then
local line = vim.api.nvim_win_get_cursor(0)[1] - 1
vim.api.nvim_buf_set_text(0, line, current_suggestion.start_col, line, current_suggestion.start_col, {current_suggestion.text})
clear_suggestion()
return true
end
return false
end
-- Always return at least one item
if #items == 0 then
items = {
{
word = "No completions found",
kind = vim.lsp.protocol.CompletionItemKind.Text,
menu = "[Gemini]"
}
}
end
return items
end
function M.get_completion(params, callback)
function M.trigger_completion()
local cursor = vim.api.nvim_win_get_cursor(0)
local line = cursor[1]
local col = cursor[2]
@ -62,19 +70,44 @@ function M.get_completion(params, callback)
-- Get completion from Gemini
api.get_response(prompt, nil, function(response, error)
if error then
callback({
{
word = "Error: " .. error,
kind = vim.lsp.protocol.CompletionItemKind.Text,
menu = "[Gemini]"
}
})
vim.notify("Completion error: " .. error, vim.log.levels.ERROR)
return
end
local items = parse_completion_response(response)
callback(items)
if type(response) == "string" then
-- Get first non-empty line as suggestion
local suggestion = response:match("^%s*(.-)%s*$")
if suggestion and #suggestion > 0 then
vim.schedule(function()
show_suggestion(suggestion, col)
end)
end
end
end)
end
-- Setup function to create highlight group and keymaps
function M.setup()
-- Create highlight group for suggestions
vim.api.nvim_set_hl(0, 'GeminiSuggestion', {
fg = '#888888',
italic = true,
})
-- Map Tab to accept suggestion or behave normally
vim.keymap.set('i', '<Tab>', function()
if not M.accept_suggestion() then
-- If no suggestion to accept, send regular Tab key
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes('<Tab>', true, true, true), 'n', true)
end
end, { expr = false, noremap = true })
-- Clear suggestion on cursor move
vim.api.nvim_create_autocmd({'CursorMovedI', 'CursorMoved'}, {
callback = function()
clear_suggestion()
end
})
end
return M

View File

@ -43,12 +43,22 @@ function M.setup(opts)
config.setup(opts)
pcall(vim.treesitter.language.require_language, "markdown")
-- Set up omnifunc globally
vim.api.nvim_create_autocmd("FileType", {
pattern = "*",
-- Set up completion
require("gemini.completion").setup()
-- Auto-trigger completion after a short delay when typing
vim.api.nvim_create_autocmd("TextChangedI", {
callback = function()
vim.bo.omnifunc = "v:lua.require'gemini'.complete"
end,
-- Cancel any existing timer
if vim.b.completion_timer then
vim.fn.timer_stop(vim.b.completion_timer)
end
-- Start new timer
vim.b.completion_timer = vim.fn.timer_start(500, function()
require("gemini.completion").trigger_completion()
end)
end
})
vim.api.nvim_create_user_command("Gemini", function(opts)