diff options
Diffstat (limited to 'lua/clever_f')
| -rw-r--r-- | lua/clever_f/feedback_service.lua | 100 |
1 files changed, 93 insertions, 7 deletions
diff --git a/lua/clever_f/feedback_service.lua b/lua/clever_f/feedback_service.lua index 9703502..037c7fd 100644 --- a/lua/clever_f/feedback_service.lua +++ b/lua/clever_f/feedback_service.lua @@ -1,6 +1,7 @@ local domain = require("clever_f.domain") local policy = require("clever_f.policy") local state_transitions = require("clever_f.state_transitions") +local text_topology = require("clever_f.text_topology") local M = {} local FeedbackService = {} @@ -307,6 +308,78 @@ function M.persistent_context_eligible(context) or context.key == "cvr" end +function M.persistent_destination( + view, + target_position, + descriptor, + endpoint_policy +) + if not text_topology.TextView.is(view) then + fail("persistent feedback requires a TextView", 2) + end + target_position = domain.Position.coerce(target_position) + descriptor = domain.Descriptor.from_string(descriptor) + endpoint_policy = domain.EndpointPolicy.from_string(endpoint_policy) + + if endpoint_policy == domain.EndpointPolicy.VISUAL_EXCLUSIVE + and descriptor.direction == domain.Direction.FORWARD + then + if descriptor.family == domain.Family.FIND then + return view:successor(target_position) + end + return target_position + end + if descriptor.family == domain.Family.FIND then + return target_position + end + if descriptor.direction == domain.Direction.FORWARD then + return view:predecessor(target_position) + end + return view:successor(target_position) +end + +function M.persistent_match_positions( + view, + match_start_line, + target_plan, + descriptor, + endpoint_policy +) + if not text_topology.TextView.is(view) then + fail("persistent feedback requires a TextView", 2) + end + if not domain.TargetPlan.is(target_plan) then + fail("persistent feedback requires a TargetPlan", 2) + end + local positions = {} + local seen = {} + local candidates = view:iter_line_forward(match_start_line) + while true do + local position, character = candidates() + if position == nil then + break + end + if target_plan:matches(character, position, view) then + local destination = M.persistent_destination( + view, + position, + descriptor, + endpoint_policy + ) + if destination ~= nil then + local key = tostring(destination.line) + .. ":" + .. tostring(destination.byte_column) + if not seen[key] then + seen[key] = true + positions[#positions + 1] = destination + end + end + end + end + return positions +end + function FeedbackService:build_persistent(specification) if type(specification) ~= "table" then fail("persistent feedback request must be a table", 2) @@ -324,17 +397,30 @@ function FeedbackService:build_persistent(specification) if specification.motion_plan.target_plan ~= specification.target_plan then fail("persistent feedback must reuse the movement TargetPlan", 2) end - local descriptor = specification.descriptor - or specification.motion_plan.descriptor - local endpoint_policy = specification.endpoint_policy - or specification.motion_plan.endpoint_policy + local descriptor = domain.Descriptor.from_string( + specification.descriptor or specification.motion_plan.descriptor + ) + local endpoint_policy = domain.EndpointPolicy.from_string( + specification.endpoint_policy or specification.motion_plan.endpoint_policy + ) + local anchor = domain.Position.coerce(specification.anchor) + local view = specification.text_view + or text_topology.from_host(service_records[self].host) return { context = context, - anchor = domain.Position.coerce(specification.anchor), + anchor = anchor, target_plan = specification.target_plan, motion_plan = specification.motion_plan, - descriptor = domain.Descriptor.from_string(descriptor), - endpoint_policy = domain.EndpointPolicy.from_string(endpoint_policy), + descriptor = descriptor, + endpoint_policy = endpoint_policy, + positions = M.persistent_match_positions( + view, + anchor.line, + specification.target_plan, + descriptor, + endpoint_policy + ), + text_view = view, window = specification.window, } end |
