From 0a670e606d7467d62dbd31fde199159c46c54ee9 Mon Sep 17 00:00:00 2001 From: Jackson Moore Date: Fri, 4 Sep 2026 12:36:12 +0200 Subject: Register buffer feedback finalizers --- lua/clever_f/capabilities.lua | 1 + lua/clever_f/feedback_service.lua | 29 +++++++++++++++++++++++++++++ lua/clever_f/testing/memory_host.lua | 13 +++++++++++++ tests/run.lua | 28 ++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+) diff --git a/lua/clever_f/capabilities.lua b/lua/clever_f/capabilities.lua index 7478fb2..79013b5 100644 --- a/lua/clever_f/capabilities.lua +++ b/lua/clever_f/capabilities.lua @@ -2,6 +2,7 @@ local M = {} M.read_methods = { text = { "read_text" }, + buffer = { "read_buffer" }, cursor = { "read_cursor" }, mode = { "read_mode", "read_pending_operator" }, selection = { "read_selection" }, diff --git a/lua/clever_f/feedback_service.lua b/lua/clever_f/feedback_service.lua index 39ae527..492eda6 100644 --- a/lua/clever_f/feedback_service.lua +++ b/lua/clever_f/feedback_service.lua @@ -15,6 +15,11 @@ M.Priority = { HIGH = "high", ORDINARY = "ordinary", } +M.FINALIZER_EVENTS = { + "CursorMoved", + "InsertEnter", + "TextChanged", +} local OVERLAY_PRIORITIES = { CleverFCursor = M.Priority.HIGH, @@ -95,6 +100,8 @@ local function require_host(host) or type(host.define_highlight_group) ~= "function" or type(host.create_highlight) ~= "function" or type(host.remove_highlight) ~= "function" + or type(host.read_buffer) ~= "function" + or type(host.register_events) ~= "function" or type(host.supports_cursor_presentation) ~= "function" or type(host.suppress_cursor_presentation) ~= "function" or type(host.restore_cursor_presentation) ~= "function" @@ -111,6 +118,7 @@ local function require_transitions(transitions, state) or type(transitions.RemoveTemporaryOverlay) ~= "function" or type(transitions.AddTargetOverlay) ~= "function" or type(transitions.ClearTargetOverlays) ~= "function" + or type(transitions.AddFinalizer) ~= "function" then fail("FeedbackService transitions must manage overlay resources", 3) end @@ -447,6 +455,26 @@ function FeedbackService:remove_character_overlays(window) return remove_target_overlays(service_records[self], window) end +function FeedbackService:handle_finalizer_event() + return false +end + +local function register_finalizers(service, record) + local buffer = record.host:read_buffer() + local identity = record.host:register_events( + M.FINALIZER_EVENTS, + function(name, payload) + service:handle_finalizer_event(name, payload) + end, + { buffer = buffer } + ) + record.transitions:AddFinalizer(identity, buffer) + return { + identity = identity, + buffer = buffer, + } +end + function FeedbackService:request_persistent(specification) local request = self:build_persistent(specification) if request.window == nil then @@ -471,6 +499,7 @@ function FeedbackService:request_persistent(specification) request.window, request.anchor.line ) + request.finalizers = register_finalizers(self, record) local requests = record.persistent_requests requests[#requests + 1] = request return request diff --git a/lua/clever_f/testing/memory_host.lua b/lua/clever_f/testing/memory_host.lua index b815c2f..8d92697 100644 --- a/lua/clever_f/testing/memory_host.lua +++ b/lua/clever_f/testing/memory_host.lua @@ -138,6 +138,7 @@ function MemoryHost.new(options) local self = setmetatable({ _text = text_snapshot(options.text or options.buffer_lines or { "" }), + _buffer = options.buffer or "buffer-1", _cursor = domain.Position.coerce(options.cursor or { line = 1, byte_column = 1 }), _window = options.window or "window-1", _mode = raw_mode, @@ -229,6 +230,11 @@ function MemoryHost:read_cursor() return self._cursor end +function MemoryHost:read_buffer() + self:_record("read_buffer", { buffer = self._buffer }) + return self._buffer +end + function MemoryHost:read_window() self:_record("read_window", { window = self._window }) return self._window @@ -322,6 +328,13 @@ function MemoryHost:set_cursor(position) self._cursor = domain.Position.coerce(position) end +function MemoryHost:set_buffer(buffer) + if buffer == nil then + error("buffer identity must be present", 2) + end + self._buffer = buffer +end + function MemoryHost:set_window(window) if window == nil then error("window identity must be present", 2) diff --git a/tests/run.lua b/tests/run.lua index 2b54ff1..2da1855 100644 --- a/tests/run.lua +++ b/tests/run.lua @@ -6069,6 +6069,34 @@ test("Persistent feedback stores overlay identity and anchor", function() same(2, resource.anchor_line) end) +test("Persistent creation registers current-buffer finalizers", function() + local state, transitions = fresh_sequence_state() + local host = MemoryHost.new({ + buffer = "buffer-finalized", + buffer_lines = { "aba" }, + }) + local feedback = feedback_service.new({ + host = host, + transitions = transitions, + }) + local shared_target = target_plan.build(target("a"), matching_policy()) + local movement = motion_plan.build(shared_target, "f") + local persistent = feedback:request_persistent({ + context = "n", + anchor = domain.Position.new(1, 1), + target_plan = shared_target, + motion_plan = movement, + window = "window-1", + }) + local registration = host:event_registrations()[persistent.finalizers.identity] + + same("buffer-finalized", persistent.finalizers.buffer) + same("buffer-finalized", state.finalizers[1].buffer) + list_same(feedback_service.FINALIZER_EVENTS, registration.names) + same("buffer-finalized", registration.options.buffer) + truthy(registration.active) +end) + for _, item in ipairs(tests) do local ok, failure = xpcall(item.body, debug.traceback) if not ok then -- cgit v1.2.3