diff options
| -rw-r--r-- | lua/clever_f/repeat_resolver.lua | 72 | ||||
| -rw-r--r-- | tests/run.lua | 17 |
2 files changed, 89 insertions, 0 deletions
diff --git a/lua/clever_f/repeat_resolver.lua b/lua/clever_f/repeat_resolver.lua new file mode 100644 index 0000000..1b74420 --- /dev/null +++ b/lua/clever_f/repeat_resolver.lua @@ -0,0 +1,72 @@ +local domain = require("clever_f.domain") +local sequence_state = require("clever_f.sequence_state") + +local M = {} +local RepeatResolver = {} +M.RepeatResolver = RepeatResolver + +local resolver_records = setmetatable({}, { __mode = "k" }) + +local function fail(message, level) + error(message, (level or 1) + 1) +end + +local resolver_metatable = { + __index = RepeatResolver, + __newindex = function() + fail("RepeatResolver values are immutable", 2) + end, + __tostring = function() + return "repeat-resolver" + end, + __metatable = "clever_f.repeat_resolver.RepeatResolver", +} + +function RepeatResolver.new(options) + if RepeatResolver.is(options) then + return options + end + if options == nil then + options = {} + elseif sequence_state.is(options) then + options = { state = options } + elseif type(options) ~= "table" then + fail("RepeatResolver options must be a table", 2) + end + + local state = options.state or sequence_state.get() + if not sequence_state.is(state) then + fail("RepeatResolver state must be the plugin-global SequenceState", 2) + end + + local resolver = setmetatable({}, resolver_metatable) + resolver_records[resolver] = { + state = state, + } + return resolver +end + +function RepeatResolver.is(value) + return type(value) == "table" and resolver_records[value] ~= nil +end + +function RepeatResolver:previous_landing(context) + context = domain.ModeContext.from_full_mode(context) + return resolver_records[self].state:get_previous_landing(context) +end + +function M.new(options) + return RepeatResolver.new(options) +end + +M.landing = function(context, options) + return RepeatResolver.new(options):previous_landing(context) +end + +setmetatable(M, { + __call = function(_, options) + return RepeatResolver.new(options) + end, +}) + +return M diff --git a/tests/run.lua b/tests/run.lua index 48928e7..3095e6d 100644 --- a/tests/run.lua +++ b/tests/run.lua @@ -11,6 +11,7 @@ local capabilities = require("clever_f.capabilities") local destination_engine = require("clever_f.destination_engine") local case_policy = require("clever_f.case_policy") local policy = require("clever_f.policy") +local repeat_resolver = require("clever_f.repeat_resolver") local migemo_catalog = require("clever_f.migemo_catalog") local motion_plan = require("clever_f.motion_plan") local motion_executor = require("clever_f.motion_executor") @@ -3786,6 +3787,22 @@ test("Select contexts execute through the command path", function() same(0, applied_selection) end) +test("RepeatResolver reads the normalized contextual landing", function() + local _, transitions = fresh_sequence_state() + local landing = domain.Position.new(3, 7) + transitions:BeginAcquisition("nov", "f") + transitions:CommitCommandSuccess("noV", landing, true) + + local resolver = repeat_resolver.new() + same(landing, resolver:previous_landing("no" .. string.char(0x16))) + same(nil, resolver:previous_landing("n")) + truthy(repeat_resolver.RepeatResolver.is(resolver)) + same(resolver, repeat_resolver.new(resolver)) + fails(function() + resolver.extra = true + end, "immutable") +end) + for _, item in ipairs(tests) do local ok, failure = xpcall(item.body, debug.traceback) if not ok then |
