feat: add function completion, apply delay, and VimLeavePre cleanup

Major improvements to the event-driven prompt processing system:

Function Completion:
- Override intent to "complete" when prompt is inside function/method scope
- Use Tree-sitter to detect enclosing scope and replace entire function
- Special LLM prompt instructs to complete function body without duplicating
- Patch apply uses "replace" strategy for scope range instead of appending

Apply Delay:
- Add `apply_delay_ms` config option (default 5000ms) for code review time
- Log "Code ready. Applying in X seconds..." before applying patches
- Configurable wait time before removing tags and injecting code

VimLeavePre Cleanup:
- Logs panel and queue windows close automatically on Neovim exit
- Context modal closes on VimLeavePre
- Scheduler stops timer and cleans up augroup on exit
- Handle QuitPre for :qa, :wqa commands
- Force close with buffer deletion for robust cleanup

Response Cleaning:
- Remove LLM special tokens (deepseek, llama markers)
- Add blank line spacing before appended code
- Log full raw LLM response in logs panel for debugging

Documentation:
- Add required dependencies (plenary.nvim, nvim-treesitter)
- Add optional dependencies (nvim-treesitter-textobjects, nui.nvim)
- Document all intent types including "complete"
- Add Logs Panel section with features and keymaps
- Update lazy.nvim example with dependencies

Tests:
- Add tests for patch create_from_event with different strategies
- Fix assert.is_true to assert.is_truthy for string.match

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-13 23:40:13 -05:00
parent 0600144768
commit 46672f6f87
11 changed files with 469 additions and 47 deletions

View File

@@ -332,10 +332,7 @@ function M.check_for_closed_prompt()
-- Clean prompt content (strip file references)
local cleaned = parser.clean_prompt(parser.strip_file_references(prompt.content))
-- Detect intent from prompt
local intent = intent_mod.detect(cleaned)
-- Resolve scope in target file (use prompt position to find enclosing scope)
-- Resolve scope in target file FIRST (need it to adjust intent)
local target_bufnr = vim.fn.bufnr(target_path)
if target_bufnr == -1 then
target_bufnr = bufnr
@@ -354,6 +351,24 @@ function M.check_for_closed_prompt()
}
end
-- Detect intent from prompt
local intent = intent_mod.detect(cleaned)
-- IMPORTANT: If prompt is inside a function/method and intent is "add",
-- override to "complete" since we're completing the function body
if scope and (scope.type == "function" or scope.type == "method") then
if intent.type == "add" or intent.action == "insert" or intent.action == "append" then
-- Override to complete the function instead of adding new code
intent = {
type = "complete",
scope_hint = "function",
confidence = intent.confidence,
action = "replace",
keywords = intent.keywords,
}
end
end
-- Determine priority based on intent
local priority = 2 -- Normal
if intent.type == "fix" or intent.type == "complete" then
@@ -472,10 +487,7 @@ function M.check_all_prompts()
-- Clean prompt content (strip file references)
local cleaned = parser.clean_prompt(parser.strip_file_references(prompt.content))
-- Detect intent from prompt
local intent = intent_mod.detect(cleaned)
-- Resolve scope in target file
-- Resolve scope in target file FIRST (need it to adjust intent)
local target_bufnr = vim.fn.bufnr(target_path)
if target_bufnr == -1 then
target_bufnr = bufnr -- Use current buffer if target not loaded
@@ -494,6 +506,24 @@ function M.check_all_prompts()
}
end
-- Detect intent from prompt
local intent = intent_mod.detect(cleaned)
-- IMPORTANT: If prompt is inside a function/method and intent is "add",
-- override to "complete" since we're completing the function body
if scope and (scope.type == "function" or scope.type == "method") then
if intent.type == "add" or intent.action == "insert" or intent.action == "append" then
-- Override to complete the function instead of adding new code
intent = {
type = "complete",
scope_hint = "function",
confidence = intent.confidence,
action = "replace",
keywords = intent.keywords,
}
end
end
-- Determine priority based on intent
local priority = 2
if intent.type == "fix" or intent.type == "complete" then