summaryrefslogtreecommitdiff
path: root/lua/clever_f/destination_engine.lua
blob: c7345d5488f464485e412c087467a0e846be1517 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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