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