summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJackson Moore <jacksonmoore@tuta.io>2026-09-04 12:11:58 +0200
committerJackson Moore <jacksonmoore@tuta.io>2026-09-04 12:11:58 +0200
commitba6df9a71fcbcb3520e162284fe72ff60ff34c2a (patch)
tree36e2df2ff5cb288e86b943119438f9a3bc5eb9dc
parent0b7341d3363ce56995f8a28c03b8444c1f7718ff (diff)
Redraw completed interactive prompt
-rw-r--r--lua/clever_f/acquisition_service.lua35
-rw-r--r--tests/run.lua55
2 files changed, 86 insertions, 4 deletions
diff --git a/lua/clever_f/acquisition_service.lua b/lua/clever_f/acquisition_service.lua
index e86bd73..3708ca4 100644
--- a/lua/clever_f/acquisition_service.lua
+++ b/lua/clever_f/acquisition_service.lua
@@ -191,7 +191,7 @@ local scope_metatable = {
__metatable = "clever_f.acquisition_service.TemporaryResourceScope",
}
-function TemporaryResourceScope.new(request, feedback)
+function TemporaryResourceScope.new(request, feedback, host)
if not AcquisitionRequest.is(request) then
fail("temporary resource scope requires an AcquisitionRequest", 2)
end
@@ -199,7 +199,12 @@ function TemporaryResourceScope.new(request, feedback)
scope_records[scope] = {
request = request,
feedback = feedback,
+ host = host,
active = true,
+ interactive = not request.macro_state.executing,
+ prompt_shown = false,
+ input_completed = false,
+ acquisition_completed = false,
cursor_marker = nil,
direct_marker = nil,
cursor_presentation_lease = nil,
@@ -247,6 +252,18 @@ function TemporaryResourceScope:set_input_packet(packet)
return set_scope_resource(self, "input_packet", packet)
end
+function TemporaryResourceScope:mark_prompt_shown()
+ return set_scope_resource(self, "prompt_shown", true)
+end
+
+function TemporaryResourceScope:mark_input_completed()
+ return set_scope_resource(self, "input_completed", true)
+end
+
+function TemporaryResourceScope:mark_acquisition_completed()
+ return set_scope_resource(self, "acquisition_completed", true)
+end
+
function TemporaryResourceScope:set_acquired_target(target)
return set_scope_resource(self, "acquired_target", target)
end
@@ -304,6 +321,13 @@ function TemporaryResourceScope:release()
if record == nil then
fail("temporary resource scope is invalid", 2)
end
+ if record.interactive
+ and record.prompt_shown
+ and record.input_completed
+ and record.acquisition_completed
+ then
+ record.host:redraw("full")
+ end
record.active = false
end
@@ -466,7 +490,7 @@ end
function AcquisitionService:start_temporary_scope(request)
request = AcquisitionRequest.new(request)
local record = service_records[self]
- local scope = TemporaryResourceScope.new(request, record.feedback)
+ local scope = TemporaryResourceScope.new(request, record.feedback, record.host)
record.last_scope = scope
record.started_scope_count = record.started_scope_count + 1
return scope
@@ -702,9 +726,11 @@ function AcquisitionService:acquire(descriptor, context, position, count, macro_
end
if acquisition.show_prompt and not request.macro_state.executing then
record.host:show_prompt(M.PROMPT)
+ scope:mark_prompt_shown()
end
record.transitions:BeginAcquisition(request.context, request.descriptor)
local packet = scope:set_input_packet(read_input_packet(record.host))
+ scope:mark_input_completed()
if M.is_escape(packet) then
local outcome = scope:set_outcome(domain.ActionOutcome.escape(request.position))
scope:release()
@@ -789,7 +815,7 @@ function AcquisitionService:acquire(descriptor, context, position, count, macro_
window = window,
})
end
- return AcquisitionResult.new(request, {
+ local result = AcquisitionResult.new(request, {
target = target,
target_plan = target_plan,
motion_plan = motion_plan,
@@ -800,6 +826,9 @@ function AcquisitionService:acquire(descriptor, context, position, count, macro_
cached_target = scope.cached_target,
missing_previous_input = scope.missing_previous_input,
})
+ scope:mark_acquisition_completed()
+ scope:release()
+ return result
end
function M.new(options, dependencies)
diff --git a/tests/run.lua b/tests/run.lua
index 78789c6..42ebe89 100644
--- a/tests/run.lua
+++ b/tests/run.lua
@@ -4914,7 +4914,7 @@ test("Acquisition starts one temporary resource scope", function()
truthy(acquisition_service.AcquisitionRequest.is(result.request))
truthy(acquisition_service.TemporaryResourceScope.is(scope))
same(result.request, scope.request)
- truthy(scope.active)
+ falsy(scope.active)
same(1, service:started_scope_count())
end)
@@ -5057,6 +5057,7 @@ test("Acquisition emits the exact enabled prompt", function()
)
same("clever-f: ", acquisition_service.PROMPT)
list_same({ "clever-f: " }, host:prompts())
+ list_same({ "full" }, host:redraws())
fresh_sequence_state()
local macro_host = MemoryHost.new({
@@ -5459,6 +5460,58 @@ test("Acquisition requests eligible persistent target feedback", function()
falsy(feedback_service.persistent_context_eligible("no"))
end)
+test("Completed interactive prompt input requests a full redraw", function()
+ fresh_sequence_state()
+ local host = MemoryHost.new({
+ buffer_lines = { "ab" },
+ configuration = {
+ mark_cursor = false,
+ mark_direct = false,
+ mark_char = false,
+ show_prompt = true,
+ },
+ input_packets = { { kind = "text", text = "b" } },
+ })
+ acquisition_service.new(host):acquire(
+ "f",
+ "n",
+ domain.Position.new(1, 1),
+ nil,
+ nil
+ )
+ list_same({ "full" }, host:redraws())
+
+ local input_index
+ local redraw_index
+ for index, operation in ipairs(host:operations()) do
+ if operation.operation == "read_input" then
+ input_index = index
+ elseif operation.operation == "redraw" and operation.kind == "full" then
+ redraw_index = index
+ end
+ end
+ truthy(redraw_index > input_index)
+
+ fresh_sequence_state()
+ local escape_host = MemoryHost.new({
+ configuration = {
+ mark_cursor = false,
+ show_prompt = true,
+ },
+ input_packets = {
+ { kind = "special_key", name = "Escape", bytes = { 27 } },
+ },
+ })
+ acquisition_service.new(escape_host):acquire(
+ "f",
+ "n",
+ domain.Position.new(1, 1),
+ nil,
+ nil
+ )
+ same(0, #escape_host:redraws())
+end)
+
for _, item in ipairs(tests) do
local ok, failure = xpcall(item.body, debug.traceback)
if not ok then