summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lua/clever_f/sequence_coordinator.lua49
-rw-r--r--tests/run.lua42
2 files changed, 90 insertions, 1 deletions
diff --git a/lua/clever_f/sequence_coordinator.lua b/lua/clever_f/sequence_coordinator.lua
index d1316e6..334e058 100644
--- a/lua/clever_f/sequence_coordinator.lua
+++ b/lua/clever_f/sequence_coordinator.lua
@@ -1,4 +1,8 @@
local domain = require("clever_f.domain")
+local policy = require("clever_f.policy")
+local repeat_resolver_factory = require("clever_f.repeat_resolver")
+local sequence_state = require("clever_f.sequence_state")
+local state_transitions = require("clever_f.state_transitions")
local M = {}
local SequenceCoordinator = {}
@@ -33,9 +37,36 @@ function SequenceCoordinator.new(options)
if type(options) ~= "table" then
fail("SequenceCoordinator options must be a table", 2)
end
+ local host = options.host or options
+ local state = options.state or sequence_state.get()
+ if not sequence_state.is(state) then
+ fail("SequenceCoordinator state must be the plugin-global SequenceState", 2)
+ end
+ local transitions = options.transitions
+ or options.state_transitions
+ or state_transitions.new(state)
+ local policy_service = options.policy
+ or options.policy_service
+ or policy.new(host)
+ local resolver = options.repeat_resolver
+ or options.resolver
+ or repeat_resolver_factory.new({
+ state = state,
+ transitions = transitions,
+ policy = policy_service,
+ clock = host,
+ })
+ if type(resolver) ~= "table" or type(resolver.decide) ~= "function" then
+ fail("SequenceCoordinator repeat resolver must provide decide", 2)
+ end
+
local coordinator = setmetatable({}, SequenceCoordinator)
coordinator_records[coordinator] = {
- host = options.host or options,
+ host = host,
+ state = state,
+ transitions = transitions,
+ policy = policy_service,
+ repeat_resolver = resolver,
}
return coordinator
end
@@ -120,6 +151,21 @@ function SequenceCoordinator:open_enclosing_folds(invocation, fold_state)
return opened
end
+function SequenceCoordinator:decide_primary(invocation)
+ if type(invocation) ~= "table"
+ or not domain.ModeContext.is(invocation.context)
+ or not domain.Position.is(invocation.position)
+ or not domain.MacroState.is(invocation.macro_state)
+ then
+ fail("primary decision requires invocation state", 2)
+ end
+ return coordinator_records[self].repeat_resolver:decide(
+ invocation.context,
+ invocation.position,
+ invocation.macro_state
+ )
+end
+
function SequenceCoordinator:primary(value)
local descriptor = self:validate_primary_descriptor(value)
local invocation = self:read_primary_invocation()
@@ -128,6 +174,7 @@ function SequenceCoordinator:primary(value)
invocation,
invocation.fold_state
)
+ invocation.repeat_decision = self:decide_primary(invocation)
return descriptor
end
diff --git a/tests/run.lua b/tests/run.lua
index 1906c6d..e72114d 100644
--- a/tests/run.lua
+++ b/tests/run.lua
@@ -7153,6 +7153,48 @@ test("Primary preflight repeats fold opening until the line is visible", functio
same(0, host:read_fold_state().closed_levels)
end)
+test("Primary coordination asks RepeatResolver for acquisition or repetition", function()
+ local state, transitions = fresh_sequence_state()
+ local landing = domain.Position.new(1, 2)
+ local host = MemoryHost.new({
+ buffer_lines = { "aba" },
+ cursor = landing,
+ })
+ local coordinator = sequence_coordinator.new({
+ host = host,
+ state = state,
+ transitions = transitions,
+ })
+ local invocation = coordinator:read_primary_invocation()
+
+ same(repeat_resolver.Decision.ACQUIRE, coordinator:decide_primary(invocation))
+ transitions:CommitCommandSuccess("n", landing, true)
+ same(repeat_resolver.Decision.REPEAT, coordinator:decide_primary(invocation))
+ host:set_macro_state("q")
+ invocation = coordinator:read_primary_invocation()
+ same(repeat_resolver.Decision.ACQUIRE, coordinator:decide_primary(invocation))
+end)
+
+test("Primary repetition guard runs after fold preflight", function()
+ fresh_sequence_state()
+ local host = MemoryHost.new({
+ fold_open_policy = { "all" },
+ closed_fold_levels = 2,
+ })
+ local observed_levels
+ local resolver = {
+ decide = function()
+ observed_levels = host:read_fold_state().closed_levels
+ return repeat_resolver.Decision.ACQUIRE
+ end,
+ }
+ sequence_coordinator.new({
+ host = host,
+ repeat_resolver = resolver,
+ }):primary("f")
+ same(0, observed_levels)
+end)
+
for _, item in ipairs(tests) do
local ok, failure = xpcall(item.body, debug.traceback)
if not ok then