summaryrefslogtreecommitdiff
path: root/lua/clever_f
diff options
context:
space:
mode:
authorJackson Moore <jacksonmoore@tuta.io>2026-09-04 13:48:22 +0200
committerJackson Moore <jacksonmoore@tuta.io>2026-09-04 13:48:22 +0200
commit6c87eb3b6103c638cf76c7509ab2da6bcea67ec8 (patch)
treebc83e928dc48ff5aa41bc1ebf3ca435c90d68871 /lua/clever_f
parent7ec26094fee806bf53f3eb253b57f3a06025c70d (diff)
Execute explicit repeat motions
Diffstat (limited to 'lua/clever_f')
-rw-r--r--lua/clever_f/action_facade.lua20
-rw-r--r--lua/clever_f/sequence_coordinator.lua63
2 files changed, 63 insertions, 20 deletions
diff --git a/lua/clever_f/action_facade.lua b/lua/clever_f/action_facade.lua
index 5d8da67..1dd5052 100644
--- a/lua/clever_f/action_facade.lua
+++ b/lua/clever_f/action_facade.lua
@@ -54,6 +54,26 @@ end
ActionFacade.invoke_primary = ActionFacade.primary
ActionFacade.start = ActionFacade.primary
+local function explicit_outcome(facade, method_name)
+ local coordinator = facade:coordinator()
+ local outcome = coordinator[method_name](coordinator)
+ if not domain.ActionOutcome.is(outcome) then
+ fail("SequenceCoordinator must return an ActionOutcome", 3)
+ end
+ return outcome
+end
+
+function ActionFacade:repeat_same_direction()
+ return explicit_outcome(self, "repeat_same_direction")
+end
+
+function ActionFacade:repeat_opposite_direction()
+ return explicit_outcome(self, "repeat_opposite_direction")
+end
+
+ActionFacade.RepeatSameDirection = ActionFacade.repeat_same_direction
+ActionFacade.RepeatOppositeDirection = ActionFacade.repeat_opposite_direction
+
function M.new(options)
return ActionFacade.new(options)
end
diff --git a/lua/clever_f/sequence_coordinator.lua b/lua/clever_f/sequence_coordinator.lua
index 4d64e51..59dc332 100644
--- a/lua/clever_f/sequence_coordinator.lua
+++ b/lua/clever_f/sequence_coordinator.lua
@@ -126,6 +126,7 @@ function SequenceCoordinator.new(options)
acquisition = acquisition,
motion_executor = executor,
last_primary_resolution = nil,
+ last_explicit_resolution = nil,
}
return coordinator
end
@@ -437,31 +438,36 @@ function SequenceCoordinator:refresh_primary_feedback(resolution)
return record.feedback:refresh_primary(resolution.target, window)
end
-function SequenceCoordinator:execute_primary_resolution(resolution)
+function SequenceCoordinator:execute_resolved_motion(resolution, execution_options)
if type(resolution) ~= "table"
or not domain.ModeContext.is(resolution.invocation.context)
or not domain.ResolvedMotionPlan.is(resolution.motion_plan)
then
- fail("primary execution requires a resolved motion", 2)
+ fail("motion execution requires a resolved motion", 2)
end
- local record = coordinator_records[self]
- record.last_primary_resolution = resolution
- local outcome
if resolution.skip_destination then
- 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
+ return domain.ActionOutcome.empty(resolution.invocation.position)
end
+ local record = coordinator_records[self]
+ 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,
+ execution_options
+ )
+ if not domain.ActionOutcome.is(outcome) then
+ fail("MotionExecutor must return an ActionOutcome", 2)
+ end
+ return outcome
+end
+
+function SequenceCoordinator:execute_primary_resolution(resolution)
+ local record = coordinator_records[self]
+ record.last_primary_resolution = resolution
+ local outcome = self:execute_resolved_motion(resolution)
resolution.highlight_timer = self:refresh_primary_feedback(resolution)
return outcome
end
@@ -470,6 +476,10 @@ function SequenceCoordinator:last_primary_resolution()
return coordinator_records[self].last_primary_resolution
end
+function SequenceCoordinator:last_explicit_resolution()
+ return coordinator_records[self].last_explicit_resolution
+end
+
function SequenceCoordinator:read_explicit_invocation()
local host = coordinator_records[self].host
if type(host) ~= "table"
@@ -579,15 +589,28 @@ function SequenceCoordinator:primary(value)
)
end
+function SequenceCoordinator:execute_explicit_resolution(resolution)
+ if type(resolution) ~= "table"
+ or not domain.ExplicitRepeatRequest.is(resolution.request)
+ then
+ fail("explicit execution requires a resolved repeat request", 2)
+ end
+ coordinator_records[self].last_explicit_resolution = resolution
+ if resolution.request.neutral then
+ return domain.ActionOutcome.empty(resolution.invocation.position)
+ end
+ return self:execute_resolved_motion(resolution)
+end
+
function SequenceCoordinator:repeat_same_direction()
- return self:resolve_explicit_same()
+ return self:execute_explicit_resolution(self:resolve_explicit_same())
end
SequenceCoordinator.RepeatSameDirection =
SequenceCoordinator.repeat_same_direction
function SequenceCoordinator:repeat_opposite_direction()
- return self:resolve_explicit_opposite()
+ return self:execute_explicit_resolution(self:resolve_explicit_opposite())
end
SequenceCoordinator.RepeatOppositeDirection =