diff options
| author | Jackson Moore <jacksonmoore@tuta.io> | 2026-09-04 10:52:25 +0200 |
|---|---|---|
| committer | Jackson Moore <jacksonmoore@tuta.io> | 2026-09-04 10:52:25 +0200 |
| commit | 0668744a8f18edd1da4914f901bf6f108ab2fd81 (patch) | |
| tree | 724fdf2452718a9e96dad11dea9d0aaf8956e542 | |
| parent | 7c145a7e7369a2f02f32383603186ca1471794c0 (diff) | |
Toggle forward operator inclusivity
| -rw-r--r-- | lua/clever_f/motion_executor.lua | 6 | ||||
| -rw-r--r-- | tests/run.lua | 37 |
2 files changed, 43 insertions, 0 deletions
diff --git a/lua/clever_f/motion_executor.lua b/lua/clever_f/motion_executor.lua index f7722e8..7a0755b 100644 --- a/lua/clever_f/motion_executor.lua +++ b/lua/clever_f/motion_executor.lua @@ -77,6 +77,7 @@ local function require_host(host) or type(host.read_selection) ~= "function" or type(host.apply_cursor) ~= "function" or type(host.apply_selection) ~= "function" + or type(host.set_operator_inclusive) ~= "function" then fail("MotionExecutor host must provide movement state", 3) end @@ -216,6 +217,11 @@ function MotionExecutor:_execute_command(request) local origin = host:read_cursor() local outcome = calculate(self, request, origin) if outcome.successful_steps > 0 then + if request.context.operator + and request.plan.descriptor.direction == domain.Direction.FORWARD + then + host:set_operator_inclusive(true) + end host:apply_cursor(outcome.endpoint) end if not outcome.complete then diff --git a/tests/run.lua b/tests/run.lua index 2595224..393d51a 100644 --- a/tests/run.lua +++ b/tests/run.lua @@ -3500,6 +3500,43 @@ test("Visual execution preserves command direction and feedback anchor", functio same(domain.Position.new(2, 1), state:get_previous_landing("v")) end) +test("Forward operator motions toggle characterwise inclusivity", function() + for _, descriptor in ipairs({ "f", "t" }) do + fresh_sequence_state() + local host = MemoryHost.new({ + buffer_lines = { "hoge fuge" }, + cursor = { line = 1, byte_column = 1 }, + mode = "no", + pending_operator = "delete", + }) + local plan = motion_plan.build( + target_plan.build(target("e"), matching_policy()), + descriptor + ) + local view = text_topology.from_host(host) + host:clear_operations() + local outcome = motion_executor.new(host):execute( + view, + "no", + plan, + 1, + true + ) + + same(domain.ActionKind.MOVEMENT, outcome.kind, descriptor) + truthy(host:operator_inclusive(), descriptor) + local effect_operations = {} + for _, operation in ipairs(host:operations()) do + if operation.operation == "set_operator_inclusive" + or operation.operation == "apply_cursor" + then + effect_operations[#effect_operations + 1] = operation.operation + end + end + list_same({ "set_operator_inclusive", "apply_cursor" }, effect_operations) + end +end) + for _, item in ipairs(tests) do local ok, failure = xpcall(item.body, debug.traceback) if not ok then |
