diff options
| author | Jackson Moore <jacksonmoore@tuta.io> | 2026-09-04 18:44:32 +0200 |
|---|---|---|
| committer | Jackson Moore <jacksonmoore@tuta.io> | 2026-09-04 18:44:32 +0200 |
| commit | c7b14ffb6d14969c9c41864e827f33f8e80fc24e (patch) | |
| tree | c7c0ac23dc93a4a8b75449d2be4d0e05c4f05f9e /lua/clever_f/state_transitions.lua | |
| parent | 9013636a57144e1f57c9339e7888d588430aae6a (diff) | |
Rename plugin to clever-tee
Diffstat (limited to 'lua/clever_f/state_transitions.lua')
| -rw-r--r-- | lua/clever_f/state_transitions.lua | 493 |
1 files changed, 0 insertions, 493 deletions
diff --git a/lua/clever_f/state_transitions.lua b/lua/clever_f/state_transitions.lua deleted file mode 100644 index 426bddb..0000000 --- a/lua/clever_f/state_transitions.lua +++ /dev/null @@ -1,493 +0,0 @@ -local domain = require("clever_f.domain") -local sequence_state = require("clever_f.sequence_state") - -local M = {} -local StateTransitions = {} -StateTransitions.__index = StateTransitions -M.StateTransitions = StateTransitions - -local function fail(message, level) - error(message, (level or 1) + 1) -end - -local function is_integer(value) - return type(value) == "number" - and value > -math.huge - and value < math.huge - and value == math.floor(value) -end - -local function require_time(value, name) - if type(value) ~= "number" - or value ~= value - or value <= -math.huge - or value >= math.huge - then - fail((name or "time") .. " must be a finite number", 2) - end - return value -end - -local function require_identity(identity, name) - if identity == nil then - fail((name or "resource identity") .. " must be active", 2) - end - return identity -end - -local function require_location(location, name) - if location == nil then - fail((name or "resource location") .. " must identify its host location", 2) - end - return location -end - -local function require_target(target) - if not domain.TargetValue.is(target) then - fail("acquired target must be a TargetValue", 2) - end - return target -end - -local function require_position(position) - return domain.Position.coerce(position) -end - -local function moved_forward_value(direction) - if type(direction) == "boolean" then - return direction - end - if domain.Direction.is(direction) then - return direction == domain.Direction.FORWARD - end - if domain.Descriptor.is(direction) then - return direction.direction == domain.Direction.FORWARD - end - if direction == "forward" or direction == "backward" then - return direction == "forward" - end - fail("movement direction must be a Boolean, Direction, or Descriptor", 2) -end - -local function copy_resource(resource) - local result = {} - for key, value in pairs(resource) do - result[key] = value - end - return result -end - -local function resource_matches(resource, identity, location_field, location) - return resource.identity == identity - and (location == nil or resource[location_field] == location) -end - -local function add_unique_resource(resources, resource, location_field, field_name) - for _, active in ipairs(resources) do - if resource_matches( - active, - resource.identity, - location_field, - resource[location_field] - ) then - fail(field_name .. " resource is already active at this host location", 3) - end - end - resources[#resources + 1] = resource - return copy_resource(resource) -end - -local function remove_resources(data, field, predicate) - local removed = {} - local retained = {} - for _, resource in ipairs(data[field]) do - if predicate(resource) then - removed[#removed + 1] = copy_resource(resource) - else - retained[#retained + 1] = resource - end - end - data[field] = retained - return removed -end - -local function clear_target_overlays(data, window) - return remove_resources(data, "target_overlays", function(resource) - return window == nil or resource.window == window - end) -end - -local function clear_temporary_overlays(data, window) - return remove_resources(data, "temporary_overlays", function(resource) - return window == nil or resource.window == window - end) -end - -local function clear_finalizers(data, buffer) - return remove_resources(data, "finalizers", function(resource) - return buffer == nil or resource.buffer == buffer - end) -end - -local function clear_highlight_timer(data) - local identity = data.highlight_timer - data.highlight_timer = nil - return identity -end - -local function clear_all_landings_and_direction(data) - data.previous_landing = {} - data.moved_forward = false -end - -local function public_reset(data, current_window) - local cleanup = { - highlight_timer = clear_highlight_timer(data), - target_overlays = clear_target_overlays(data, current_window), - finalizers = {}, - temporary_overlays = {}, - } - data.previous_descriptor = {} - data.previous_landing = {} - data.first_move = {} - data.migemo_cache = {} - data.repeat_timestamp_ms = 0 - return cleanup -end - -function StateTransitions.new(state) - state = state or sequence_state.get() - if not sequence_state.is(state) then - fail("StateTransitions requires the plugin-global SequenceState", 2) - end - return setmetatable({ _state = state }, StateTransitions) -end - -function M.new(state) - return StateTransitions.new(state) -end - -setmetatable(M, { - __call = function(_, state) - return StateTransitions.new(state) - end, -}) - -function StateTransitions:state() - return self._state -end - -function StateTransitions:_mutate(mutation) - return sequence_state._mutate(self._state, mutation) -end - -function StateTransitions:BeginAcquisition(context, descriptor) - context = sequence_state._normalize_context(context) - descriptor = domain.Descriptor.from_string(descriptor) - return self:_mutate(function(state) - state.known_contexts[context] = true - state.previous_descriptor[context] = descriptor - state.first_move[context] = true - return self._state:get_context(context) - end) -end - -function StateTransitions:CommitAcquiredTarget(context, target, time_ms) - context = sequence_state._normalize_context(context) - target = require_target(target) - if time_ms ~= nil then - time_ms = require_time(time_ms, "acquisition time") - end - return self:_mutate(function(state) - state.known_contexts[context] = true - state.previous_target[context] = target - state.last_input_context = context - if time_ms ~= nil then - state.repeat_timestamp_ms = time_ms - end - return self._state:get_context(context) - end) -end - -function StateTransitions:CommitCommandSuccess(context, destination, direction) - context = sequence_state._normalize_context(context) - destination = require_position(destination) - local forward = moved_forward_value(direction) - return self:_mutate(function(state) - state.known_contexts[context] = true - state.moved_forward = forward - state.moved_forward_initialized = true - state.previous_landing[context] = destination - state.first_move[context] = false - return self._state:get_context(context) - end) -end - -function StateTransitions:CommitVisualSuccess(context, destination) - context = sequence_state._normalize_context(context) - destination = require_position(destination) - return self:_mutate(function(state) - state.known_contexts[context] = true - state.previous_landing[context] = destination - state.first_move[context] = false - return self._state:get_context(context) - end) -end - -function StateTransitions:ClearAllLandingsAndDirection() - return self:_mutate(function(state) - clear_all_landings_and_direction(state) - end) -end - -function StateTransitions:SetRepeatTimestamp(time_ms) - time_ms = require_time(time_ms, "repeat timestamp") - return self:_mutate(function(state) - local previous = state.repeat_timestamp_ms - state.repeat_timestamp_ms = time_ms - return previous - end) -end - -function StateTransitions:CacheMigemo(encoding, dictionary) - if type(encoding) ~= "string" or encoding == "" then - fail("Migemo cache encoding must be a nonempty string", 2) - end - if dictionary == nil then - fail("Migemo cache dictionary must be present", 2) - end - return self:_mutate(function(state) - local previous = state.migemo_cache[encoding] - state.migemo_cache[encoding] = dictionary - return previous - end) -end - -function StateTransitions:RemoveMigemo(encoding) - if type(encoding) ~= "string" or encoding == "" then - fail("Migemo cache encoding must be a nonempty string", 2) - end - return self:_mutate(function(state) - local previous = state.migemo_cache[encoding] - state.migemo_cache[encoding] = nil - return previous - end) -end - -function StateTransitions:ClearMigemoCache() - return self:_mutate(function(state) - local previous = state.migemo_cache - state.migemo_cache = {} - return previous - end) -end - -function StateTransitions:SetHighlightTimer(identity) - return self:_mutate(function(state) - local previous = state.highlight_timer - state.highlight_timer = identity - return previous - end) -end - -function StateTransitions:ClearHighlightTimer(expected_identity) - return self:_mutate(function(state) - local current = state.highlight_timer - if current == nil then - return nil, false - end - if expected_identity ~= nil and current ~= expected_identity then - return nil, false - end - state.highlight_timer = nil - return current, true - end) -end - -function StateTransitions:AddTargetOverlay(identity, window, anchor_line) - if type(identity) == "table" and window == nil and identity.identity ~= nil then - local resource = identity - identity = resource.identity - window = resource.window - anchor_line = resource.anchor_line - end - require_identity(identity, "target overlay identity") - require_location(window, "target overlay window") - if anchor_line ~= nil and (not is_integer(anchor_line) or anchor_line < 1) then - fail("target overlay anchor_line must be a positive integer", 2) - end - local resource = { - identity = identity, - window = window, - group = "CleverFChar", - anchor_line = anchor_line, - } - return self:_mutate(function(state) - return add_unique_resource( - state.target_overlays, - resource, - "window", - "target overlay" - ) - end) -end - -function StateTransitions:RemoveTargetOverlay(identity, window) - require_identity(identity, "target overlay identity") - return self:_mutate(function(state) - return remove_resources(state, "target_overlays", function(resource) - return resource_matches(resource, identity, "window", window) - end) - end) -end - -function StateTransitions:ClearTargetOverlays(window) - return self:_mutate(function(state) - return clear_target_overlays(state, window) - end) -end - -function StateTransitions:AddTemporaryOverlay(identity, window, group) - if type(identity) == "table" and window == nil and identity.identity ~= nil then - local resource = identity - identity = resource.identity - window = resource.window - group = resource.group - end - require_identity(identity, "temporary overlay identity") - require_location(window, "temporary overlay window") - group = group or "CleverFCursor" - if group ~= "CleverFCursor" and group ~= "CleverFDirect" then - fail("temporary overlay group must be CleverFCursor or CleverFDirect", 2) - end - local resource = { - identity = identity, - window = window, - group = group, - } - return self:_mutate(function(state) - return add_unique_resource( - state.temporary_overlays, - resource, - "window", - "temporary overlay" - ) - end) -end - -function StateTransitions:RemoveTemporaryOverlay(identity, window) - require_identity(identity, "temporary overlay identity") - return self:_mutate(function(state) - return remove_resources(state, "temporary_overlays", function(resource) - return resource_matches(resource, identity, "window", window) - end) - end) -end - -function StateTransitions:ClearTemporaryOverlays(window) - return self:_mutate(function(state) - return clear_temporary_overlays(state, window) - end) -end - -function StateTransitions:AddFinalizer(identity, buffer) - if type(identity) == "table" and buffer == nil and identity.identity ~= nil then - local resource = identity - identity = resource.identity - buffer = resource.buffer - end - require_identity(identity, "finalizer identity") - require_location(buffer, "finalizer buffer") - local resource = { - identity = identity, - buffer = buffer, - } - return self:_mutate(function(state) - return add_unique_resource(state.finalizers, resource, "buffer", "finalizer") - end) -end - -function StateTransitions:RemoveFinalizer(identity, buffer) - require_identity(identity, "finalizer identity") - return self:_mutate(function(state) - return remove_resources(state, "finalizers", function(resource) - return resource_matches(resource, identity, "buffer", buffer) - end) - end) -end - -function StateTransitions:ClearFinalizers(buffer) - return self:_mutate(function(state) - return clear_finalizers(state, buffer) - end) -end - -function StateTransitions:ClearTargetFeedback(current_window) - return self:_mutate(function(state) - return { - highlight_timer = clear_highlight_timer(state), - target_overlays = clear_target_overlays(state, current_window), - finalizers = {}, - temporary_overlays = {}, - } - end) -end - -function StateTransitions:FullFinalization(current_window) - return self:_mutate(function(state) - local cleanup = { - highlight_timer = clear_highlight_timer(state), - target_overlays = clear_target_overlays(state, current_window), - finalizers = clear_finalizers(state), - temporary_overlays = {}, - } - clear_all_landings_and_direction(state) - return cleanup - end) -end - -function StateTransitions:PublicReset(current_window) - return self:_mutate(function(state) - return public_reset(state, current_window) - end) -end - -function StateTransitions:DiagnosticFullReset(current_window) - return self:_mutate(function(state) - local cleanup = public_reset(state, current_window) - cleanup.finalizers = clear_finalizers(state) - state.previous_target = {} - state.last_input_context = nil - state.moved_forward = false - state.moved_forward_initialized = false - return cleanup - end) -end - -StateTransitions.begin_acquisition = StateTransitions.BeginAcquisition -StateTransitions.commit_acquired_target = StateTransitions.CommitAcquiredTarget -StateTransitions.commit_command_success = StateTransitions.CommitCommandSuccess -StateTransitions.commit_visual_success = StateTransitions.CommitVisualSuccess -StateTransitions.clear_all_landings_and_direction = - StateTransitions.ClearAllLandingsAndDirection -StateTransitions.set_repeat_timestamp = StateTransitions.SetRepeatTimestamp -StateTransitions.cache_migemo = StateTransitions.CacheMigemo -StateTransitions.remove_migemo = StateTransitions.RemoveMigemo -StateTransitions.clear_migemo_cache = StateTransitions.ClearMigemoCache -StateTransitions.set_highlight_timer = StateTransitions.SetHighlightTimer -StateTransitions.clear_highlight_timer = StateTransitions.ClearHighlightTimer -StateTransitions.add_target_overlay = StateTransitions.AddTargetOverlay -StateTransitions.remove_target_overlay = StateTransitions.RemoveTargetOverlay -StateTransitions.clear_target_overlays = StateTransitions.ClearTargetOverlays -StateTransitions.add_temporary_overlay = StateTransitions.AddTemporaryOverlay -StateTransitions.remove_temporary_overlay = StateTransitions.RemoveTemporaryOverlay -StateTransitions.clear_temporary_overlays = StateTransitions.ClearTemporaryOverlays -StateTransitions.add_finalizer = StateTransitions.AddFinalizer -StateTransitions.remove_finalizer = StateTransitions.RemoveFinalizer -StateTransitions.clear_finalizers = StateTransitions.ClearFinalizers -StateTransitions.clear_target_feedback = StateTransitions.ClearTargetFeedback -StateTransitions.full_finalization = StateTransitions.FullFinalization -StateTransitions.public_reset = StateTransitions.PublicReset -StateTransitions.diagnostic_full_reset = StateTransitions.DiagnosticFullReset - -return M |
