diff options
| author | Jackson Moore <jacksonmoore@tuta.io> | 2026-09-04 11:59:20 +0200 |
|---|---|---|
| committer | Jackson Moore <jacksonmoore@tuta.io> | 2026-09-04 11:59:20 +0200 |
| commit | 4005e0311f4dc951d3e9464ddf2f8f309d9b9a24 (patch) | |
| tree | 32f60693b6af227db048d8220a58ac4e3473eaee | |
| parent | 61233d0cfb09f6d5a42c48eb31df5edf1d91c12f (diff) | |
Create enabled direct acquisition previews
| -rw-r--r-- | lua/clever_f/acquisition_service.lua | 65 | ||||
| -rw-r--r-- | lua/clever_f/policy.lua | 7 | ||||
| -rw-r--r-- | tests/run.lua | 42 |
3 files changed, 108 insertions, 6 deletions
diff --git a/lua/clever_f/acquisition_service.lua b/lua/clever_f/acquisition_service.lua index 3c7cc14..0cfd843 100644 --- a/lua/clever_f/acquisition_service.lua +++ b/lua/clever_f/acquisition_service.lua @@ -1,8 +1,10 @@ local domain = require("clever_f.domain") +local direct_preview_planner = require("clever_f.direct_preview_planner") local feedback_service = require("clever_f.feedback_service") local policy = require("clever_f.policy") local sequence_state = require("clever_f.sequence_state") local state_transitions = require("clever_f.state_transitions") +local text_topology = require("clever_f.text_topology") local M = {} local AcquisitionRequest = {} @@ -112,6 +114,7 @@ function TemporaryResourceScope.new(request, feedback) feedback = feedback, active = true, cursor_marker = nil, + direct_marker = nil, } return scope end @@ -120,13 +123,21 @@ function TemporaryResourceScope.is(value) return type(value) == "table" and scope_records[value] ~= nil end -function TemporaryResourceScope:set_cursor_marker(marker) - local record = scope_records[self] +local function set_scope_resource(scope, field, resource) + local record = scope_records[scope] if record == nil or not record.active then - fail("temporary resource scope must be active", 2) + fail("temporary resource scope must be active", 3) end - record.cursor_marker = marker - return marker + record[field] = resource + return resource +end + +function TemporaryResourceScope:set_cursor_marker(marker) + return set_scope_resource(self, "cursor_marker", marker) +end + +function TemporaryResourceScope:set_direct_marker(marker) + return set_scope_resource(self, "direct_marker", marker) end function TemporaryResourceScope:release() @@ -161,6 +172,14 @@ local function require_transitions(transitions, state) return transitions end +local function require_direct_planner(planner) + planner = planner or direct_preview_planner.new() + if type(planner) ~= "table" or type(planner.plan) ~= "function" then + fail("AcquisitionService direct planner must provide plan", 3) + end + return planner +end + local function require_feedback(feedback, host, policy_service, transitions) feedback = feedback or feedback_service.new({ host = host, @@ -222,6 +241,9 @@ function AcquisitionService.new(options, dependencies) policy_service, transitions ), + direct_planner = require_direct_planner( + options.direct_planner or options.direct_preview_planner + ), window = options.window or options.current_window, last_scope = nil, started_scope_count = 0, @@ -268,11 +290,25 @@ function AcquisitionService:started_scope_count() return service_records[self].started_scope_count end +local function direct_preview_settings(policy_service) + if type(policy_service.sample_direct_preview) == "function" then + return policy_service:sample_direct_preview() + end + if type(policy_service.get_boolean) == "function" then + return { + ignore_case = policy_service:get_boolean("ignore_case"), + smart_case = policy_service:get_boolean("smart_case"), + } + end + fail("AcquisitionService policy must sample direct preview settings", 3) +end + function AcquisitionService:acquire(descriptor, context, position, count, macro_state) local request = self:request(descriptor, context, position, count, macro_state) local scope = self:start_temporary_scope(request) local record = service_records[self] - if record.policy:sample_acquisition().mark_cursor then + local acquisition = record.policy:sample_acquisition() + if acquisition.mark_cursor then scope:set_cursor_marker(record.feedback:create_cursor_marker( request.position, current_window(record) @@ -281,6 +317,23 @@ function AcquisitionService:acquire(descriptor, context, position, count, macro_ record.host:redraw("screen") end end + if acquisition.mark_direct and not request.macro_state.executing then + local view = text_topology.from_host(record.host) + local positions = record.direct_planner:plan( + view, + request.position, + request.descriptor, + request.count, + direct_preview_settings(record.policy) + ) + local window = scope.cursor_marker + and scope.cursor_marker.window + or current_window(record) + scope:set_direct_marker(record.feedback:create_direct_markers( + positions, + window + )) + end return request end diff --git a/lua/clever_f/policy.lua b/lua/clever_f/policy.lua index 3dbffa8..df9fb7a 100644 --- a/lua/clever_f/policy.lua +++ b/lua/clever_f/policy.lua @@ -453,6 +453,13 @@ function PolicyService:sample_acquisition() } end +function PolicyService:sample_direct_preview() + return { + ignore_case = self:get_boolean("ignore_case"), + smart_case = self:get_boolean("smart_case"), + } +end + function PolicyService:sample_markers() return { mark_cursor = self:get_boolean("mark_cursor"), diff --git a/tests/run.lua b/tests/run.lua index 9de914f..80294bb 100644 --- a/tests/run.lua +++ b/tests/run.lua @@ -4976,6 +4976,48 @@ test("Interactive acquisition redraws after cursor marker creation", function() same(0, #macro_host:redraws()) end) +test("Interactive acquisition creates enabled direct previews", function() + local state, transitions = fresh_sequence_state() + local host = MemoryHost.new({ + buffer_lines = { "xaxa" }, + cursor = { line = 1, byte_column = 1 }, + count = 2, + configuration = { + mark_cursor = false, + mark_direct = true, + ignore_case = false, + smart_case = false, + }, + }) + local service = acquisition_service.new({ + host = host, + transitions = transitions, + }) + + service:acquire("t", "n", host:read_cursor(), host:read_count(), nil) + local marker = service:last_temporary_scope().direct_marker + truthy(marker ~= nil) + same("CleverFDirect", marker.group) + same(1, #marker.positions) + same(domain.Position.new(1, 4), marker.positions[1]) + same(marker.identity, state:temporary_overlay_identities()[1]) + + fresh_sequence_state() + local macro_host = MemoryHost.new({ + buffer_lines = { "xaxa" }, + configuration = { mark_cursor = false, mark_direct = true }, + }) + local macro_service = acquisition_service.new(macro_host) + macro_service:acquire( + "f", + "n", + domain.Position.new(1, 1), + nil, + "q" + ) + same(nil, macro_service:last_temporary_scope().direct_marker) +end) + for _, item in ipairs(tests) do local ok, failure = xpcall(item.body, debug.traceback) if not ok then |
