summaryrefslogtreecommitdiff
path: root/lua/clever_f/acquisition_service.lua
diff options
context:
space:
mode:
Diffstat (limited to 'lua/clever_f/acquisition_service.lua')
-rw-r--r--lua/clever_f/acquisition_service.lua101
1 files changed, 85 insertions, 16 deletions
diff --git a/lua/clever_f/acquisition_service.lua b/lua/clever_f/acquisition_service.lua
index d341414..45463e6 100644
--- a/lua/clever_f/acquisition_service.lua
+++ b/lua/clever_f/acquisition_service.lua
@@ -139,6 +139,7 @@ function AcquisitionResult.new(request, options)
target_plan = options.target_plan,
motion_plan = options.motion_plan,
resolved_motion_plan = options.motion_plan,
+ previous_input_trigger = options.previous_input_trigger,
completed = outcome ~= nil or target ~= nil,
}
return result
@@ -180,6 +181,7 @@ function TemporaryResourceScope.new(request, feedback)
cursor_presentation_lease = nil,
input_packet = nil,
acquired_target = nil,
+ previous_input_trigger = nil,
outcome = nil,
}
return scope
@@ -218,6 +220,10 @@ function TemporaryResourceScope:set_acquired_target(target)
return set_scope_resource(self, "acquired_target", target)
end
+function TemporaryResourceScope:set_previous_input_trigger(trigger)
+ return set_scope_resource(self, "previous_input_trigger", trigger)
+end
+
function TemporaryResourceScope:set_outcome(outcome)
if not domain.ActionOutcome.is(outcome) then
fail("temporary resource scope outcome must be an ActionOutcome", 2)
@@ -412,6 +418,18 @@ local function first_editor_character(text)
return characters[1]
end
+function M.editor_character_code(character)
+ character = first_editor_character(character)
+ local runtime = rawget(_G, "vim")
+ if type(runtime) == "table"
+ and type(runtime.fn) == "table"
+ and type(runtime.fn.char2nr) == "function"
+ then
+ return runtime.fn.char2nr(character)
+ end
+ return utf8_first_code(character)
+end
+
function M.normalize_ordinary_input(packet)
packet = domain.InputPacket.from_table(packet)
local text
@@ -428,17 +446,62 @@ function M.normalize_ordinary_input(packet)
fail("ordinary input packet must contain text or raw bytes", 2)
end
local character = first_editor_character(text)
- local runtime = rawget(_G, "vim")
- local first_code
- if type(runtime) == "table"
- and type(runtime.fn) == "table"
- and type(runtime.fn.char2nr) == "function"
- then
- first_code = runtime.fn.char2nr(character)
- else
- first_code = utf8_first_code(character)
+ return domain.TargetValue.character(
+ character,
+ M.editor_character_code(character)
+ )
+end
+
+local function encoded_packet_value(packet)
+ if packet.encoded ~= nil then
+ return packet.encoded
+ end
+ local bytes = packet:bytes()
+ if bytes == nil then
+ return nil
+ end
+ local characters = {}
+ for index = 1, #bytes do
+ characters[index] = string.char(bytes[index])
end
- return domain.TargetValue.character(character, first_code)
+ return table.concat(characters)
+end
+
+function M.normalize_input_packet(packet)
+ packet = domain.InputPacket.from_table(packet)
+ if packet.kind == domain.InputPacketKind.ERROR then
+ fail(packet.message, 2)
+ end
+ if packet.kind == domain.InputPacketKind.TEXT then
+ return M.normalize_ordinary_input(packet)
+ end
+
+ local encoded = encoded_packet_value(packet)
+ if encoded == nil then
+ return domain.TargetValue.code_fallback(0)
+ end
+ if string.byte(encoded, 1) == 0x80 then
+ return domain.TargetValue.special_key(encoded, 0x80)
+ end
+ return M.normalize_ordinary_input(domain.InputPacket.text(encoded))
+end
+
+function M.match_previous_input_trigger(first_code, triggers)
+ if type(first_code) ~= "number" or first_code < 0 then
+ fail("acquired first code must be nonnegative", 2)
+ end
+ if type(triggers) ~= "table" then
+ fail("previous-input triggers must be a list", 2)
+ end
+ for index, trigger in ipairs(triggers) do
+ if type(trigger) ~= "string" then
+ fail("previous-input triggers must contain strings", 2)
+ end
+ if trigger ~= "" and M.editor_character_code(trigger) == first_code then
+ return trigger, index
+ end
+ end
+ return nil
end
function M.is_escape(packet)
@@ -537,12 +600,18 @@ function AcquisitionService:acquire(descriptor, context, position, count, macro_
scope:release()
return AcquisitionResult.new(request, { outcome = outcome })
end
- if packet.kind == domain.InputPacketKind.TEXT
- or packet.kind == domain.InputPacketKind.RAW_BYTES
- then
- scope:set_acquired_target(M.normalize_ordinary_input(packet))
- end
- return AcquisitionResult.new(request, { target = scope.acquired_target })
+ local target = scope:set_acquired_target(M.normalize_input_packet(packet))
+ local previous_input = record.policy:sample_previous_input()
+ local trigger = scope:set_previous_input_trigger(
+ M.match_previous_input_trigger(
+ target.first_code,
+ previous_input.repeat_last_char_inputs
+ )
+ )
+ return AcquisitionResult.new(request, {
+ target = target,
+ previous_input_trigger = trigger,
+ })
end
function M.new(options, dependencies)