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

@@ -16,7 +16,7 @@ describe("patch", function()
local id2 = patch.generate_id()
assert.is_not.equals(id1, id2)
assert.is_true(id1:match("^patch_"))
assert.is_truthy(id1:match("^patch_"))
end)
end)
@@ -302,4 +302,70 @@ describe("patch", function()
assert.equals(1, #patch.get_pending())
end)
end)
describe("create_from_event", function()
it("should create patch with replace strategy for complete intent", function()
local event = {
id = "evt_123",
target_path = "/tmp/test.lua",
bufnr = 1,
range = { start_line = 5, end_line = 10 },
scope_range = { start_line = 3, end_line = 12 },
scope = { type = "function", name = "test_fn" },
intent = {
type = "complete",
action = "replace",
confidence = 0.9,
keywords = {},
},
}
local p = patch.create_from_event(event, "function code", 0.9)
assert.equals("replace", p.injection_strategy)
assert.is_truthy(p.injection_range)
assert.equals(3, p.injection_range.start_line)
assert.equals(12, p.injection_range.end_line)
end)
it("should create patch with append strategy for add intent", function()
local event = {
id = "evt_456",
target_path = "/tmp/test.lua",
bufnr = 1,
range = { start_line = 5, end_line = 10 },
intent = {
type = "add",
action = "append",
confidence = 0.8,
keywords = {},
},
}
local p = patch.create_from_event(event, "new function", 0.8)
assert.equals("append", p.injection_strategy)
end)
it("should create patch with insert strategy for insert action", function()
local event = {
id = "evt_789",
target_path = "/tmp/test.lua",
bufnr = 1,
range = { start_line = 5, end_line = 10 },
intent = {
type = "add",
action = "insert",
confidence = 0.8,
keywords = {},
},
}
local p = patch.create_from_event(event, "inserted code", 0.8)
assert.equals("insert", p.injection_strategy)
assert.is_truthy(p.injection_range)
assert.equals(5, p.injection_range.start_line)
end)
end)
end)