Review and cleanup
This commit is contained in:
parent
81c200df66
commit
2c641faf11
@ -14,6 +14,26 @@ local current_suggestion = {
|
||||
max_context_lines = 10, -- Maximum number of context lines to send
|
||||
}
|
||||
|
||||
-- Helper function to get visible lines around cursor
|
||||
local function get_visible_lines()
|
||||
local win = vim.api.nvim_get_current_win()
|
||||
local cursor_line = vim.api.nvim_win_get_cursor(0)[1]
|
||||
local top_line = vim.fn.line('w0')
|
||||
local bottom_line = vim.fn.line('w$')
|
||||
|
||||
-- Get all visible lines
|
||||
local lines = vim.api.nvim_buf_get_lines(0, top_line - 1, bottom_line, false)
|
||||
local relative_cursor = cursor_line - top_line + 1
|
||||
|
||||
return lines, relative_cursor
|
||||
end
|
||||
|
||||
-- Helper function to get current line indent
|
||||
local function get_line_indent(line)
|
||||
local indent = line:match("^%s+") or ""
|
||||
return indent
|
||||
end
|
||||
|
||||
-- Debug function
|
||||
local function debug_print(...)
|
||||
vim.notify(string.format(...), vim.log.levels.INFO)
|
||||
@ -52,44 +72,27 @@ end
|
||||
local function show_suggestion(suggestion, start_col)
|
||||
clear_suggestion()
|
||||
|
||||
-- Split suggestion into lines
|
||||
local cursor = vim.api.nvim_win_get_cursor(0)
|
||||
local line = cursor[1] - 1
|
||||
local current_line = vim.api.nvim_get_current_line()
|
||||
|
||||
-- Get current line indent
|
||||
local indent = get_line_indent(current_line)
|
||||
|
||||
-- Split suggestion into lines and apply indent to all lines except first
|
||||
local suggestion_lines = vim.split(suggestion, "\n")
|
||||
for i = 2, #suggestion_lines do
|
||||
suggestion_lines[i] = indent .. suggestion_lines[i]
|
||||
end
|
||||
|
||||
if #suggestion_lines == 0 then return end
|
||||
|
||||
-- Get current line info
|
||||
local line = vim.api.nvim_win_get_cursor(0)[1] - 1
|
||||
local line_text = vim.api.nvim_buf_get_lines(0, line, line + 1, true)[1]
|
||||
|
||||
-- Validate start_col
|
||||
if not line_text then return end
|
||||
start_col = math.min(start_col, #line_text)
|
||||
if start_col < 0 then start_col = 0 end
|
||||
|
||||
-- Get text before cursor on current line
|
||||
local input_before_cursor = string.sub(line_text, 1, start_col)
|
||||
local first_line = suggestion_lines[1]
|
||||
|
||||
-- If the suggestion starts with what's already typed, remove that part
|
||||
if vim.startswith(first_line, input_before_cursor) then
|
||||
first_line = string.sub(first_line, #input_before_cursor + 1)
|
||||
end
|
||||
|
||||
if first_line == "" and #suggestion_lines == 1 then return end
|
||||
|
||||
current_suggestion.text = suggestion
|
||||
current_suggestion.start_col = start_col
|
||||
|
||||
-- Show first line as virtual text
|
||||
if first_line ~= "" then
|
||||
-- Ensure we're not exceeding line length
|
||||
local safe_col = math.min(start_col, #line_text)
|
||||
|
||||
vim.api.nvim_buf_set_extmark(0, current_suggestion.namespace_id, line, safe_col, {
|
||||
virt_text = {{first_line, 'GeminiSuggestion'}},
|
||||
virt_text_pos = 'inline',
|
||||
virt_text_hide = true,
|
||||
-- Show ghost text
|
||||
vim.api.nvim_buf_set_extmark(0, current_suggestion.namespace_id, line, start_col, {
|
||||
virt_text = {{suggestion_lines[1], 'GeminiSuggestion'}},
|
||||
virt_text_pos = 'overlay',
|
||||
hl_mode = 'combine',
|
||||
})
|
||||
end
|
||||
|
||||
-- Show remaining lines as virtual lines
|
||||
if #suggestion_lines > 1 then
|
||||
@ -98,16 +101,14 @@ local function show_suggestion(suggestion, start_col)
|
||||
table.insert(virt_lines, {{suggestion_lines[i], 'GeminiSuggestion'}})
|
||||
end
|
||||
|
||||
-- Use safe column position for virtual lines
|
||||
local safe_col = math.min(start_col, #line_text)
|
||||
|
||||
vim.api.nvim_buf_set_extmark(0, current_suggestion.namespace_id, line, safe_col, {
|
||||
vim.api.nvim_buf_set_extmark(0, current_suggestion.namespace_id, line, start_col, {
|
||||
virt_lines = virt_lines,
|
||||
virt_lines_above = false,
|
||||
})
|
||||
end
|
||||
|
||||
debug_print("Showing suggestion: '%s'", first_line)
|
||||
current_suggestion.text = table.concat(suggestion_lines, "\n")
|
||||
current_suggestion.start_col = start_col
|
||||
end
|
||||
|
||||
function M.accept_suggestion()
|
||||
@ -206,66 +207,45 @@ local function get_context_around_cursor(lines, current_line, max_lines)
|
||||
end
|
||||
|
||||
function M.trigger_completion()
|
||||
debug_print("Triggering completion...")
|
||||
|
||||
-- Clear any existing timer
|
||||
if current_suggestion.timer then
|
||||
vim.fn.timer_stop(current_suggestion.timer)
|
||||
end
|
||||
|
||||
-- Set up debounce timer
|
||||
current_suggestion.timer = vim.fn.timer_start(150, function()
|
||||
local cursor = vim.api.nvim_win_get_cursor(0)
|
||||
local line = cursor[1]
|
||||
local line = cursor[1] - 1
|
||||
local col = cursor[2]
|
||||
local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false)
|
||||
local current_line = lines[line]
|
||||
|
||||
-- Don't trigger if at end of file or empty line
|
||||
-- Get visible context
|
||||
local visible_lines, relative_cursor = get_visible_lines()
|
||||
local current_line = visible_lines[relative_cursor]
|
||||
|
||||
if not current_line or current_line == "" then
|
||||
clear_suggestion()
|
||||
return
|
||||
end
|
||||
|
||||
-- Get text before cursor
|
||||
local prefix = string.sub(current_line, 1, col)
|
||||
|
||||
-- Don't trigger if we're in comments or strings
|
||||
local syntax_group = vim.fn.synIDattr(vim.fn.synID(line, col, 1), "name")
|
||||
-- Don't trigger in comments or strings
|
||||
local syntax_group = vim.fn.synIDattr(vim.fn.synID(cursor[1], col, 1), "name")
|
||||
if syntax_group:match("Comment") or syntax_group:match("String") then
|
||||
debug_print("Skipping: in comment or string")
|
||||
clear_suggestion()
|
||||
return
|
||||
end
|
||||
|
||||
-- Check minimum character threshold
|
||||
local trimmed_prefix = vim.trim(prefix)
|
||||
if #trimmed_prefix < current_suggestion.min_chars then
|
||||
debug_print("Skipping: not enough characters")
|
||||
clear_suggestion()
|
||||
return
|
||||
end
|
||||
|
||||
-- Get focused context around cursor
|
||||
local context = get_context_around_cursor(lines, line, current_suggestion.max_context_lines)
|
||||
|
||||
-- Add cursor position marker
|
||||
local cursor_marker = string.rep(" ", col) .. "^"
|
||||
table.insert(context, string.format("L%d (current): %s", line, current_line))
|
||||
table.insert(context, cursor_marker)
|
||||
|
||||
local full_context = table.concat(context, "\n")
|
||||
-- Prepare context for AI
|
||||
local context = table.concat(visible_lines, "\n")
|
||||
local file_type = vim.bo.filetype
|
||||
|
||||
-- Improved prompt for better completions
|
||||
local prompt = string.format([[In this %s file, complete the code at the cursor (^) position:
|
||||
local prompt = string.format([[
|
||||
In this %s file, complete the code at line %d, column %d:
|
||||
|
||||
%s
|
||||
|
||||
Return ONLY the completion text that would naturally continue from the cursor position.
|
||||
Focus on completing the current statement or block.
|
||||
Consider the syntax, style, and patterns in the surrounding code.
|
||||
Do not repeat any text that appears before the cursor.]], file_type, full_context)
|
||||
Consider the visible context, syntax, and code style.
|
||||
Do not repeat any text that appears before the cursor.]],
|
||||
file_type, cursor[1], col + 1, context)
|
||||
|
||||
-- Check cache and rate limiting
|
||||
local cache_key = get_cache_key(prompt)
|
||||
@ -274,28 +254,19 @@ Do not repeat any text that appears before the cursor.]], file_type, full_contex
|
||||
return
|
||||
end
|
||||
|
||||
if should_rate_limit() then
|
||||
debug_print("Rate limited")
|
||||
return
|
||||
end
|
||||
if should_rate_limit() then return end
|
||||
|
||||
-- Get completion from Gemini
|
||||
api.get_response(prompt, nil, function(response, error)
|
||||
if error then
|
||||
debug_print("Completion error: %s", error)
|
||||
return
|
||||
end
|
||||
if error then return end
|
||||
|
||||
if type(response) == "string" and #response > 0 then
|
||||
-- Clean up response and remove any leading whitespace/indentation
|
||||
response = vim.trim(response)
|
||||
response = response:gsub("^%s+", "")
|
||||
current_suggestion.cache[cache_key] = response
|
||||
|
||||
vim.schedule(function()
|
||||
-- Verify cursor position hasn't changed significantly
|
||||
local new_cursor = vim.api.nvim_win_get_cursor(0)
|
||||
if new_cursor[1] == line and math.abs(new_cursor[2] - col) <= 1 then
|
||||
if new_cursor[1] == cursor[1] and math.abs(new_cursor[2] - col) <= 1 then
|
||||
show_suggestion(response, col)
|
||||
end
|
||||
end)
|
||||
@ -310,12 +281,12 @@ function M.setup()
|
||||
vim.api.nvim_set_hl(0, 'GeminiSuggestion', {
|
||||
fg = '#666666',
|
||||
italic = true,
|
||||
blend = 15 -- Makes the ghost text slightly transparent
|
||||
})
|
||||
|
||||
-- Map Tab to accept suggestion or behave normally
|
||||
-- Map Tab to accept suggestion
|
||||
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 })
|
||||
@ -324,7 +295,6 @@ function M.setup()
|
||||
vim.api.nvim_create_autocmd("TextChangedI", {
|
||||
pattern = "*",
|
||||
callback = function()
|
||||
-- Only trigger if enabled
|
||||
if vim.b.gemini_completion_enabled then
|
||||
M.trigger_completion()
|
||||
end
|
||||
@ -338,8 +308,6 @@ function M.setup()
|
||||
clear_suggestion()
|
||||
end
|
||||
})
|
||||
|
||||
debug_print("Gemini completion setup complete")
|
||||
end
|
||||
|
||||
return M
|
||||
|
Loading…
x
Reference in New Issue
Block a user