diff options
| -rw-r--r-- | lua/clever_f/acquisition_service.lua | 50 | ||||
| -rw-r--r-- | tests/run.lua | 42 |
2 files changed, 90 insertions, 2 deletions
diff --git a/lua/clever_f/acquisition_service.lua b/lua/clever_f/acquisition_service.lua index a8471f6..d632748 100644 --- a/lua/clever_f/acquisition_service.lua +++ b/lua/clever_f/acquisition_service.lua @@ -4,6 +4,7 @@ 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 target_plan_factory = require("clever_f.target_plan") local text_topology = require("clever_f.text_topology") local M = {} @@ -132,12 +133,16 @@ function AcquisitionResult.new(request, options) if target ~= nil and not domain.TargetValue.is(target) then fail("acquisition result target must be a TargetValue", 2) end + local target_plan = options.target_plan + if target_plan ~= nil and not domain.TargetPlan.is(target_plan) then + fail("acquisition result target_plan must be a TargetPlan", 2) + end local result = setmetatable({}, result_metatable) result_records[result] = { request = request, outcome = outcome, target = target, - target_plan = options.target_plan, + target_plan = target_plan, motion_plan = options.motion_plan, resolved_motion_plan = options.motion_plan, previous_input_trigger = options.previous_input_trigger, @@ -191,6 +196,8 @@ function TemporaryResourceScope.new(request, feedback) previous_target_source = nil, cached_target = nil, missing_previous_input = false, + text_view = nil, + target_plan = nil, outcome = nil, } return scope @@ -249,6 +256,20 @@ function TemporaryResourceScope:set_missing_previous_input(missing) return set_scope_resource(self, "missing_previous_input", missing) end +function TemporaryResourceScope:set_text_view(view) + if not text_topology.TextView.is(view) then + fail("temporary resource scope text must be a TextView", 2) + end + return set_scope_resource(self, "text_view", view) +end + +function TemporaryResourceScope:set_target_plan(target_plan) + if not domain.TargetPlan.is(target_plan) then + fail("temporary resource scope target plan must be a TargetPlan", 2) + end + return set_scope_resource(self, "target_plan", target_plan) +end + function TemporaryResourceScope:set_outcome(outcome) if not domain.ActionOutcome.is(outcome) then fail("temporary resource scope outcome must be an ActionOutcome", 2) @@ -299,6 +320,14 @@ local function require_direct_planner(planner) return planner end +local function require_target_factory(factory, policy_service) + factory = factory or target_plan_factory.new({ policy = policy_service }) + if type(factory) ~= "table" or type(factory.build) ~= "function" then + fail("AcquisitionService target factory must provide build", 3) + end + return factory +end + local function require_feedback(feedback, host, policy_service, transitions) feedback = feedback or feedback_service.new({ host = host, @@ -364,6 +393,10 @@ function AcquisitionService.new(options, dependencies) direct_planner = require_direct_planner( options.direct_planner or options.direct_preview_planner ), + target_factory = require_target_factory( + options.target_factory or options.target_plan_factory, + policy_service + ), window = options.window or options.current_window, last_scope = nil, started_scope_count = 0, @@ -613,7 +646,7 @@ function AcquisitionService:acquire(descriptor, context, position, count, macro_ end end if acquisition.mark_direct and not request.macro_state.executing then - local view = text_topology.from_host(record.host) + local view = scope:set_text_view(text_topology.from_host(record.host)) local positions = record.direct_planner:plan( view, request.position, @@ -679,8 +712,21 @@ function AcquisitionService:acquire(descriptor, context, position, count, macro_ target, acquisition_time_ms ) + local view = scope.text_view + or scope:set_text_view(text_topology.from_host(record.host)) + local target_plan = scope:set_target_plan(record.target_factory:build( + target, + nil, + { + text_view = view, + origin = request.position, + search_scope = record.policy:sample_search().search_scope, + effective_encoding = view.effective_encoding, + } + )) return AcquisitionResult.new(request, { target = target, + target_plan = target_plan, acquisition_time_ms = acquisition_time_ms, previous_input_trigger = trigger, previous_target_source = scope.previous_target_source, diff --git a/tests/run.lua b/tests/run.lua index fa9930e..959de66 100644 --- a/tests/run.lua +++ b/tests/run.lua @@ -5336,6 +5336,48 @@ test("Positive repeat timeout stores acquisition time", function() end end) +test("Acquisition builds one target plan from live matching policy", function() + fresh_sequence_state() + local host = MemoryHost.new({ + buffer_lines = { "aA" }, + configuration = { + mark_cursor = false, + ignore_case = false, + smart_case = false, + }, + input_packets = { { kind = "text", text = "a" } }, + }) + local policy_service = policy.new(host) + local underlying = target_plan.new({ policy = policy_service }) + local build_count = 0 + local factory = { + build = function(_, ...) + build_count = build_count + 1 + return underlying:build(...) + end, + } + local service = acquisition_service.new({ + host = host, + policy = policy_service, + target_factory = factory, + }) + host:set_configuration("ignore_case", true) + + local result = service:acquire( + "f", + "n", + domain.Position.new(1, 1), + nil, + nil + ) + same(1, build_count) + truthy(domain.TargetPlan.is(result.target_plan)) + same(domain.CaseMode.INSENSITIVE, result.target_plan.case_mode) + truthy(result.target_plan:matches("A")) + same(result.target, result.target_plan.target) + same(result.target_plan, service:last_temporary_scope().target_plan) +end) + for _, item in ipairs(tests) do local ok, failure = xpcall(item.body, debug.traceback) if not ok then |
