summaryrefslogtreecommitdiff
path: root/lua/clever_f/destination_engine.lua
diff options
context:
space:
mode:
Diffstat (limited to 'lua/clever_f/destination_engine.lua')
-rw-r--r--lua/clever_f/destination_engine.lua83
1 files changed, 83 insertions, 0 deletions
diff --git a/lua/clever_f/destination_engine.lua b/lua/clever_f/destination_engine.lua
new file mode 100644
index 0000000..c7345d5
--- /dev/null
+++ b/lua/clever_f/destination_engine.lua
@@ -0,0 +1,83 @@
+local domain = require("clever_f.domain")
+local text_topology = require("clever_f.text_topology")
+
+local M = {}
+local DestinationEngine = {}
+M.DestinationEngine = DestinationEngine
+
+local engines = setmetatable({}, { __mode = "k" })
+
+local function fail(message, level)
+ error(message, (level or 1) + 1)
+end
+
+local engine_metatable = {
+ __index = DestinationEngine,
+ __newindex = function()
+ fail("DestinationEngine values are immutable", 2)
+ end,
+ __tostring = function()
+ return "destination-engine"
+ end,
+ __metatable = "clever_f.destination_engine.DestinationEngine",
+}
+
+function DestinationEngine.new()
+ local engine = setmetatable({}, engine_metatable)
+ engines[engine] = true
+ return engine
+end
+
+function DestinationEngine.is(value)
+ return type(value) == "table" and engines[value] == true
+end
+
+local function calculation_inputs(view, origin, plan, count, first_move)
+ if not text_topology.TextView.is(view) then
+ fail("destination calculation view must be a TextView", 3)
+ end
+
+ origin = domain.Position.coerce(origin)
+ if not view:is_valid_cursor_position(origin) then
+ fail("destination calculation origin must be a valid cursor position", 3)
+ end
+ if not domain.ResolvedMotionPlan.is(plan) then
+ fail("destination calculation plan must be a ResolvedMotionPlan", 3)
+ end
+ count = domain.Count.new(count)
+ if type(first_move) ~= "boolean" then
+ fail("destination calculation first_move must be a Boolean", 3)
+ end
+
+ return {
+ view = view,
+ origin = origin,
+ plan = plan,
+ count = count,
+ first_move = first_move,
+ }
+end
+
+function DestinationEngine:calculate(view, origin, plan, count, first_move)
+ local request = calculation_inputs(view, origin, plan, count, first_move)
+ return domain.SearchOutcome.boundary_before_any(request.origin)
+end
+
+function M.new()
+ return DestinationEngine.new()
+end
+
+function M.calculate(view, origin, plan, count, first_move)
+ return DestinationEngine.new():calculate(view, origin, plan, count, first_move)
+end
+
+M.resolve = M.calculate
+M.search = M.calculate
+
+setmetatable(M, {
+ __call = function()
+ return DestinationEngine.new()
+ end,
+})
+
+return M