diff options
| author | Jackson Moore <jacksonmoore@tuta.io> | 2026-09-04 14:42:49 +0200 |
|---|---|---|
| committer | Jackson Moore <jacksonmoore@tuta.io> | 2026-09-04 14:42:49 +0200 |
| commit | aa2c42761a91e8eca2d551fe14f1bc1dd3fc8593 (patch) | |
| tree | b9a4eb2cd465b14a7eb52e12fceea71d01589544 /lua | |
| parent | 7566197269a4a1767df1ce4d39f8fad6844ec587 (diff) | |
Fix native dot replay bridge
Diffstat (limited to 'lua')
| -rw-r--r-- | lua/clever_f/host_adapter.lua | 129 |
1 files changed, 128 insertions, 1 deletions
diff --git a/lua/clever_f/host_adapter.lua b/lua/clever_f/host_adapter.lua index 17c29ef..a81a44c 100644 --- a/lua/clever_f/host_adapter.lua +++ b/lua/clever_f/host_adapter.lua @@ -48,6 +48,7 @@ function HostAdapter.new(options) cursor_presentations = {}, events = {}, dot_repeat = nil, + dot_bridge = nil, event_order = {}, augroup = nil, } @@ -124,6 +125,8 @@ function HostAdapter:set_operator_inclusive(enabled) end end +local install_dot_bridge + function HostAdapter:register_dot_repeat(payload, callback) if not domain.DotPayload.is(payload) then fail("dot-repeat payload must be a DotPayload", 2) @@ -131,10 +134,18 @@ function HostAdapter:register_dot_repeat(payload, callback) if callback ~= nil and type(callback) ~= "function" then fail("dot-repeat callback must be a function", 2) end - adapter_records[self].dot_repeat = { + local record = adapter_records[self] + record.dot_repeat = { payload = payload, callback = callback, + operator = self:read_pending_operator(), } + if install_dot_bridge ~= nil then + install_dot_bridge(self) + end + if record.dot_bridge ~= nil then + record.dot_bridge.awaiting_change = true + end return payload end @@ -479,6 +490,122 @@ function HostAdapter:remove_event_registration(identity) return true end +local DOT_MOTION_MAPPING = "<Plug>(clever-f-dot-motion)" + +local function dot_bridge_supported(runtime) + return type(runtime.keymap) == "table" + and type(runtime.keymap.set) == "function" + and type(runtime.keymap.del) == "function" + and type(runtime.fn.maparg) == "function" + and type(runtime.fn.mapset) == "function" + and type(runtime.api.nvim_feedkeys) == "function" +end + +local function restore_dot_mapping(record) + local bridge = record.dot_bridge + if bridge == nil or not bridge.active then + return false + end + bridge.active = false + pcall(record.runtime.keymap.del, "n", ".") + if type(bridge.previous_mapping) == "table" + and next(bridge.previous_mapping) ~= nil + then + record.runtime.fn.mapset("n", false, bridge.previous_mapping) + end + return true +end + +local function dot_replay_keys(runtime, count, operator) + local prefix = count > 0 and tostring(count) or "" + local keys = prefix .. operator .. DOT_MOTION_MAPPING + if type(runtime.keycode) == "function" then + return runtime.keycode(keys) + end + return runtime.api.nvim_replace_termcodes(keys, true, false, true) +end + +install_dot_bridge = function(adapter) + local record = adapter_records[adapter] + local runtime = record.runtime + if not dot_bridge_supported(runtime) then + return nil + end + local bridge = record.dot_bridge + if bridge == nil then + bridge = { + active = false, + awaiting_change = false, + previous_mapping = nil, + } + record.dot_bridge = bridge + runtime.keymap.set("o", DOT_MOTION_MAPPING, function() + local registration = record.dot_repeat + if registration == nil or registration.callback == nil then + return + end + local count = runtime.v.count1 + if type(count) ~= "number" or count < 1 then + count = 1 + end + local outcome = registration.callback( + registration.payload, + domain.Count.new(count) + ) + if domain.ActionOutcome.is(outcome) then + adapter:translate_action_outcome(outcome) + end + end, { + silent = true, + remap = false, + desc = "clever-f dot motion", + }) + local has_cmd_atom = type(runtime.fn.exists) == "function" + and runtime.fn.exists("##CmdAtom") == 1 + local ownership_events = has_cmd_atom + and "CmdAtom" + or { "TextChanged", "TextChangedI", "TextChangedP" } + runtime.api.nvim_create_autocmd(ownership_events, { + group = event_augroup(record), + desc = "clever-f dot ownership", + callback = function(event) + if has_cmd_atom and not (event.data and event.data.changed) then + return + end + if bridge.awaiting_change then + bridge.awaiting_change = false + return + end + restore_dot_mapping(record) + end, + }) + end + if not bridge.active then + bridge.previous_mapping = runtime.fn.maparg(".", "n", false, true) + runtime.keymap.set("n", ".", function() + local registration = record.dot_repeat + if registration == nil or registration.operator == "" then + restore_dot_mapping(record) + runtime.api.nvim_feedkeys(".", "n", false) + return + end + bridge.awaiting_change = true + local count = runtime.v.count or 0 + runtime.api.nvim_feedkeys( + dot_replay_keys(runtime, count, registration.operator), + "n", + false + ) + end, { + silent = true, + remap = false, + desc = "clever-f dot repeat", + }) + bridge.active = true + end + return bridge +end + function HostAdapter:deliver_event(name, payload) if type(name) ~= "string" or name == "" then fail("event name must be a nonempty string", 2) |
