diff options
| -rw-r--r-- | lua/clever_f/host_adapter.lua | 70 | ||||
| -rw-r--r-- | tests/run.lua | 56 |
2 files changed, 126 insertions, 0 deletions
diff --git a/lua/clever_f/host_adapter.lua b/lua/clever_f/host_adapter.lua index 7a71fb8..17c29ef 100644 --- a/lua/clever_f/host_adapter.lua +++ b/lua/clever_f/host_adapter.lua @@ -47,6 +47,7 @@ function HostAdapter.new(options) timers = {}, cursor_presentations = {}, events = {}, + dot_repeat = nil, event_order = {}, augroup = nil, } @@ -84,6 +85,75 @@ function HostAdapter:lowercase(value) return result end +function HostAdapter:read_pending_operator() + local operator = self:runtime().v.operator + if operator == nil then + return "" + end + return operator +end + +function HostAdapter:apply_cursor(position) + position = domain.Position.coerce(position) + self:runtime().api.nvim_win_set_cursor( + 0, + { position.line, position.byte_column - 1 } + ) +end + +function HostAdapter:apply_selection(position) + if domain.Selection.is(position) then + if not position.active then + fail("selection movement requires an active selection", 2) + end + position = position.focus + end + return self:apply_cursor(position) +end + +function HostAdapter:set_operator_inclusive(enabled) + if type(enabled) ~= "boolean" then + fail("operator inclusivity must be a Boolean", 2) + end + if enabled then + self:runtime().api.nvim_cmd({ + cmd = "normal", + bang = true, + args = { "v" }, + }, {}) + end +end + +function HostAdapter:register_dot_repeat(payload, callback) + if not domain.DotPayload.is(payload) then + fail("dot-repeat payload must be a DotPayload", 2) + end + if callback ~= nil and type(callback) ~= "function" then + fail("dot-repeat callback must be a function", 2) + end + adapter_records[self].dot_repeat = { + payload = payload, + callback = callback, + } + return payload +end + +function HostAdapter:dot_repeat_payload() + local registration = adapter_records[self].dot_repeat + return registration and registration.payload or nil +end + +function HostAdapter:replay_dot(count) + local registration = adapter_records[self].dot_repeat + if registration == nil or registration.callback == nil then + fail("dot repeat is not executable", 2) + end + return registration.callback( + registration.payload, + domain.Count.new(count) + ) +end + local function next_identity(adapter, prefix) local record = adapter_records[adapter] local identity = prefix .. "-" .. tostring(record.next_identity) diff --git a/tests/run.lua b/tests/run.lua index 871d977..e00f694 100644 --- a/tests/run.lua +++ b/tests/run.lua @@ -361,6 +361,62 @@ test("ActionOutcome and DotPayload retain resolved result data", function() same("problem", domain.ActionOutcome.error(destination, "problem").diagnostic) end) +test("Host adapter connects motion endpoints and dot payloads", function() + local cursor + local commands = {} + local runtime = { + api = { + nvim_win_set_cursor = function(window, position) + same(0, window) + cursor = position + end, + nvim_cmd = function(command, options) + commands[#commands + 1] = command + truthy(vim.tbl_isempty(options)) + end, + }, + v = { operator = "d" }, + } + local adapter = host_adapter.new({ runtime = runtime }) + + same("d", adapter:read_pending_operator()) + adapter:apply_cursor(domain.Position.new(3, 5), { + descriptor = domain.Descriptor.FIND_FORWARD, + }) + list_same({ 3, 4 }, cursor) + adapter:apply_selection(domain.Selection.active( + domain.SelectionKind.CHARACTER, + domain.Position.new(3, 1), + domain.Position.new(4, 2), + domain.SelectionOption.INCLUSIVE + )) + list_same({ 4, 1 }, cursor) + + adapter:set_operator_inclusive(false) + same(0, #commands) + adapter:set_operator_inclusive(true) + same(1, #commands) + same("normal", commands[1].cmd) + truthy(commands[1].bang) + list_same({ "v" }, commands[1].args) + + local payload = domain.DotPayload.new( + "t", + domain.TargetValue.character("x", string.byte("x")) + ) + local replayed_payload + local replayed_count + same(payload, adapter:register_dot_repeat(payload, function(value, count) + replayed_payload = value + replayed_count = count + return "replayed" + end)) + same(payload, adapter:dot_repeat_payload()) + same("replayed", adapter:replay_dot(3)) + same(payload, replayed_payload) + same(3, replayed_count.value) +end) + test("Host adapter reads encoding and uses Nvim case conversion", function() local lowered = {} local runtime = { |
