summaryrefslogtreecommitdiff
path: root/lua/clever_f/state_transitions.lua
diff options
context:
space:
mode:
Diffstat (limited to 'lua/clever_f/state_transitions.lua')
-rw-r--r--lua/clever_f/state_transitions.lua493
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