From 75879e3356685a145fab752c0b3365faa832f8d4 Mon Sep 17 00:00:00 2001 From: Jackson Moore Date: Fri, 4 Sep 2026 13:44:25 +0200 Subject: Refresh primary highlight timeout --- lua/clever_f/sequence_coordinator.lua | 40 ++++++++++++++++++++++++----------- tests/run.lua | 29 +++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 12 deletions(-) diff --git a/lua/clever_f/sequence_coordinator.lua b/lua/clever_f/sequence_coordinator.lua index ee50fbd..cb6bf80 100644 --- a/lua/clever_f/sequence_coordinator.lua +++ b/lua/clever_f/sequence_coordinator.lua @@ -424,6 +424,19 @@ function SequenceCoordinator:stored_primary_resolution( return resolution end +function SequenceCoordinator:refresh_primary_feedback(resolution) + if type(resolution) ~= "table" or not domain.TargetValue.is(resolution.target) then + fail("primary feedback refresh requires a resolved target", 2) + end + local record = coordinator_records[self] + if type(record.feedback.refresh_primary) ~= "function" then + fail("FeedbackService must refresh primary feedback", 2) + end + local window = resolution.timeout and resolution.timeout.window + or record.host:read_window() + return record.feedback:refresh_primary(resolution.target, window) +end + function SequenceCoordinator:execute_primary_resolution(resolution) if type(resolution) ~= "table" or not domain.ModeContext.is(resolution.invocation.context) @@ -433,20 +446,23 @@ function SequenceCoordinator:execute_primary_resolution(resolution) end local record = coordinator_records[self] record.last_primary_resolution = resolution + local outcome if resolution.skip_destination then - return domain.ActionOutcome.empty(resolution.invocation.position) - end - local view = resolution.text_view or text_topology.from_host(record.host) - local outcome = record.motion_executor:execute( - view, - resolution.invocation.context, - resolution.motion_plan, - resolution.invocation.count, - resolution.first_move - ) - if not domain.ActionOutcome.is(outcome) then - fail("MotionExecutor must return an ActionOutcome", 2) + outcome = domain.ActionOutcome.empty(resolution.invocation.position) + else + local view = resolution.text_view or text_topology.from_host(record.host) + outcome = record.motion_executor:execute( + view, + resolution.invocation.context, + resolution.motion_plan, + resolution.invocation.count, + resolution.first_move + ) + if not domain.ActionOutcome.is(outcome) then + fail("MotionExecutor must return an ActionOutcome", 2) + end end + resolution.highlight_timer = self:refresh_primary_feedback(resolution) return outcome end diff --git a/tests/run.lua b/tests/run.lua index cf7edb9..d0838e8 100644 --- a/tests/run.lua +++ b/tests/run.lua @@ -7605,6 +7605,35 @@ test("Primary coordination executes resolved movement through MotionExecutor", f ) end) +test("Fresh and repeated primary actions refresh highlight timeout", function() + local state = fresh_sequence_state() + local host = MemoryHost.new({ + buffer_lines = { "aaaa" }, + cursor = { line = 1, byte_column = 1 }, + input_packets = { { kind = "text", text = "a" } }, + configuration = { + mark_cursor = false, + mark_char = true, + highlight_timeout_ms = 25, + }, + emit_movement_events = false, + }) + local coordinator = sequence_coordinator.new({ host = host }) + + same(domain.ActionKind.MOVEMENT, coordinator:primary("f").kind) + local fresh_timer = state.highlight_timer + truthy(fresh_timer ~= nil) + same(fresh_timer, coordinator:last_primary_resolution().highlight_timer) + + same(domain.ActionKind.MOVEMENT, coordinator:primary("f").kind) + local repeated_timer = state.highlight_timer + truthy(repeated_timer ~= nil) + falsy(fresh_timer == repeated_timer) + falsy(host:timers()[fresh_timer].active) + truthy(host:timers()[repeated_timer].active) + same(repeated_timer, coordinator:last_primary_resolution().highlight_timer) +end) + for _, item in ipairs(tests) do local ok, failure = xpcall(item.body, debug.traceback) if not ok then -- cgit v1.2.3