summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lua/clever_f/acquisition_service.lua50
-rw-r--r--tests/run.lua42
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