summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJackson Moore <jacksonmoore@tuta.io>2026-09-04 13:36:23 +0200
committerJackson Moore <jacksonmoore@tuta.io>2026-09-04 13:36:23 +0200
commit614eb6bd3f7059d297b4c940af5de154214091b3 (patch)
tree3280e586797c96d8ed58caaa14e0cbe4bf090700
parent1ed91850daac2c4960e0bf316818de20341143fd (diff)
Acquire pressed primary targets
-rw-r--r--lua/clever_f/sequence_coordinator.lua41
-rw-r--r--tests/run.lua34
2 files changed, 72 insertions, 3 deletions
diff --git a/lua/clever_f/sequence_coordinator.lua b/lua/clever_f/sequence_coordinator.lua
index 334e058..d391eec 100644
--- a/lua/clever_f/sequence_coordinator.lua
+++ b/lua/clever_f/sequence_coordinator.lua
@@ -1,4 +1,6 @@
+local acquisition_service_factory = require("clever_f.acquisition_service")
local domain = require("clever_f.domain")
+local feedback_service_factory = require("clever_f.feedback_service")
local policy = require("clever_f.policy")
local repeat_resolver_factory = require("clever_f.repeat_resolver")
local sequence_state = require("clever_f.sequence_state")
@@ -59,6 +61,26 @@ function SequenceCoordinator.new(options)
if type(resolver) ~= "table" or type(resolver.decide) ~= "function" then
fail("SequenceCoordinator repeat resolver must provide decide", 2)
end
+ local feedback = options.feedback
+ or options.feedback_service
+ or feedback_service_factory.new({
+ host = host,
+ state = state,
+ transitions = transitions,
+ policy = policy_service,
+ })
+ local acquisition = options.acquisition
+ or options.acquisition_service
+ or acquisition_service_factory.new({
+ host = host,
+ state = state,
+ transitions = transitions,
+ policy = policy_service,
+ feedback = feedback,
+ })
+ if type(acquisition) ~= "table" or type(acquisition.acquire) ~= "function" then
+ fail("SequenceCoordinator acquisition service must provide acquire", 2)
+ end
local coordinator = setmetatable({}, SequenceCoordinator)
coordinator_records[coordinator] = {
@@ -67,6 +89,8 @@ function SequenceCoordinator.new(options)
transitions = transitions,
policy = policy_service,
repeat_resolver = resolver,
+ feedback = feedback,
+ acquisition = acquisition,
}
return coordinator
end
@@ -166,6 +190,20 @@ function SequenceCoordinator:decide_primary(invocation)
)
end
+function SequenceCoordinator:acquire_primary(descriptor, invocation)
+ descriptor = self:validate_primary_descriptor(descriptor)
+ if type(invocation) ~= "table" then
+ fail("primary acquisition requires invocation state", 2)
+ end
+ return coordinator_records[self].acquisition:acquire(
+ descriptor,
+ invocation.context,
+ invocation.position,
+ invocation.count,
+ invocation.macro_state
+ )
+end
+
function SequenceCoordinator:primary(value)
local descriptor = self:validate_primary_descriptor(value)
local invocation = self:read_primary_invocation()
@@ -175,6 +213,9 @@ function SequenceCoordinator:primary(value)
invocation.fold_state
)
invocation.repeat_decision = self:decide_primary(invocation)
+ if invocation.repeat_decision == repeat_resolver_factory.Decision.ACQUIRE then
+ return self:acquire_primary(descriptor, invocation)
+ end
return descriptor
end
diff --git a/tests/run.lua b/tests/run.lua
index e72114d..f004a23 100644
--- a/tests/run.lua
+++ b/tests/run.lua
@@ -7072,7 +7072,10 @@ end)
test("Primary coordination accepts only the four motion descriptors", function()
local coordinator = sequence_coordinator.new({ host = MemoryHost.new() })
for _, value in ipairs({ "f", "F", "t", "T" }) do
- same(domain.Descriptor.from_string(value), coordinator:primary(value))
+ same(
+ domain.Descriptor.from_string(value),
+ coordinator:validate_primary_descriptor(value)
+ )
end
fails(function()
coordinator:primary("x")
@@ -7104,11 +7107,12 @@ test("Primary coordination inspects fold policy during preflight", function()
closed_fold_levels = 1,
})
local coordinator = sequence_coordinator.new({ host = host })
+ local invocation = coordinator:read_primary_invocation()
- same(domain.Descriptor.FIND_FORWARD, coordinator:primary("f"))
+ local folds = coordinator:inspect_fold_open_policy(invocation)
local operations = host:operations()
same("read_fold_state", operations[#operations].operation)
- truthy(host:read_fold_state():opens("horizontal"))
+ truthy(folds:opens("horizontal"))
end)
test("Primary preflight opens folds for horizontal and all policies", function()
@@ -7195,6 +7199,30 @@ test("Primary repetition guard runs after fold preflight", function()
same(0, observed_levels)
end)
+test("Acquiring primary coordination passes the pressed descriptor", function()
+ local state, transitions = fresh_sequence_state()
+ local host = MemoryHost.new({
+ buffer_lines = { "aba" },
+ cursor = { line = 1, byte_column = 1 },
+ input_packets = { { kind = "text", text = "a" } },
+ configuration = {
+ mark_cursor = false,
+ mark_char = false,
+ },
+ })
+ local result = sequence_coordinator.new({
+ host = host,
+ state = state,
+ transitions = transitions,
+ }):primary("t")
+
+ truthy(acquisition_service.AcquisitionResult.is(result))
+ truthy(result.resolved)
+ same(domain.Descriptor.TILL_FORWARD, result.request.descriptor)
+ same(domain.Descriptor.TILL_FORWARD, state:get_previous_descriptor("n"))
+ same("a", result.target.value)
+end)
+
for _, item in ipairs(tests) do
local ok, failure = xpcall(item.body, debug.traceback)
if not ok then