local domain = require("clever_f.domain") local M = {} local SequenceCoordinator = {} SequenceCoordinator.__index = SequenceCoordinator M.SequenceCoordinator = SequenceCoordinator local coordinator_records = setmetatable({}, { __mode = "k" }) local function fail(message, level) error(message, (level or 1) + 1) end local function descriptor_text(value) if domain.Descriptor.is(value) then return value.value end return tostring(value) end function M.validate_primary_descriptor(value) local descriptor = domain.Descriptor.try_from_string(value) if descriptor == nil then fail("clever-f: Invalid mapping '" .. descriptor_text(value) .. "'", 2) end return descriptor end function SequenceCoordinator.new(options) if SequenceCoordinator.is(options) then return options end if type(options) ~= "table" then fail("SequenceCoordinator options must be a table", 2) end local coordinator = setmetatable({}, SequenceCoordinator) coordinator_records[coordinator] = { host = options.host or options, } return coordinator end function SequenceCoordinator.is(value) return type(value) == "table" and coordinator_records[value] ~= nil end function SequenceCoordinator:validate_primary_descriptor(value) return M.validate_primary_descriptor(value) end local function require_primary_reader(host) if type(host) ~= "table" or type(host.read_mode) ~= "function" or type(host.read_cursor) ~= "function" or type(host.read_count) ~= "function" or type(host.read_macro_state) ~= "function" then fail("SequenceCoordinator host must provide primary action state", 3) end return host end function SequenceCoordinator:read_primary_invocation() local host = require_primary_reader(coordinator_records[self].host) local context = domain.ModeContext.from_full_mode(host:read_mode()) local position = domain.Position.coerce(host:read_cursor()) local count = domain.Count.new(host:read_count()) local macro_state = domain.MacroState.new(host:read_macro_state()) return { context = context, position = position, origin = position, count = count, macro_state = macro_state, } end function SequenceCoordinator:primary(value) return self:validate_primary_descriptor(value) end function M.new(options) return SequenceCoordinator.new(options) end setmetatable(M, { __call = function(_, options) return SequenceCoordinator.new(options) end, }) return M