summaryrefslogtreecommitdiff
path: root/lua
diff options
context:
space:
mode:
Diffstat (limited to 'lua')
-rw-r--r--lua/clever_f/motion_executor.lua6
-rw-r--r--lua/clever_f/testing/memory_host.lua142
2 files changed, 145 insertions, 3 deletions
diff --git a/lua/clever_f/motion_executor.lua b/lua/clever_f/motion_executor.lua
index 7a0755b..4e972cd 100644
--- a/lua/clever_f/motion_executor.lua
+++ b/lua/clever_f/motion_executor.lua
@@ -222,7 +222,11 @@ function MotionExecutor:_execute_command(request)
then
host:set_operator_inclusive(true)
end
- host:apply_cursor(outcome.endpoint)
+ host:apply_cursor(outcome.endpoint, {
+ context = request.context,
+ descriptor = request.plan.descriptor,
+ origin = origin,
+ })
end
if not outcome.complete then
return domain.ActionOutcome.from_search(outcome, request.plan.descriptor)
diff --git a/lua/clever_f/testing/memory_host.lua b/lua/clever_f/testing/memory_host.lua
index 57af1f1..8b473ad 100644
--- a/lua/clever_f/testing/memory_host.lua
+++ b/lua/clever_f/testing/memory_host.lua
@@ -1,5 +1,6 @@
local capabilities = require("clever_f.capabilities")
local domain = require("clever_f.domain")
+local text_topology = require("clever_f.text_topology")
local M = {}
local MemoryHost = {}
@@ -383,11 +384,148 @@ function MemoryHost:_emit_movement_event(previous)
end
end
-function MemoryHost:apply_cursor(position)
+local function motion_descriptor(motion)
+ if domain.Descriptor.is(motion) then
+ return motion
+ end
+ if type(motion) == "table" and motion.descriptor ~= nil then
+ return domain.Descriptor.from_string(motion.descriptor)
+ end
+ return nil
+end
+
+local function character_boundary(view, position)
+ if view:line_is_empty(position.line) then
+ return 1
+ end
+ return view:character_index_for_position(position)
+end
+
+local function character_lines(snapshot)
+ local result = {}
+ for line_number, line in ipairs(snapshot:lines()) do
+ result[line_number] = text_topology.split_editor_characters(line)
+ end
+ return result
+end
+
+local function joined_range(characters, first, last)
+ local result = {}
+ for index = first, last do
+ result[#result + 1] = characters[index]
+ end
+ return table.concat(result)
+end
+
+local function delete_character_range(
+ snapshot,
+ start_line,
+ start_index,
+ finish_line,
+ finish_index
+)
+ local source = character_lines(snapshot)
+ local lines = snapshot:lines()
+ local result = {}
+
+ for line_number = 1, start_line - 1 do
+ result[#result + 1] = lines[line_number]
+ end
+
+ local prefix = joined_range(source[start_line], 1, start_index - 1)
+ if start_line == finish_line then
+ result[#result + 1] = prefix
+ .. joined_range(
+ source[start_line],
+ finish_index,
+ #source[start_line]
+ )
+ else
+ result[#result + 1] = prefix
+ .. joined_range(
+ source[finish_line],
+ finish_index,
+ #source[finish_line]
+ )
+ end
+
+ for line_number = finish_line + 1, #lines do
+ result[#result + 1] = lines[line_number]
+ end
+ return domain.TextSnapshot.new(result)
+end
+
+local function normalized_cursor(snapshot, encoding, position)
+ local line_number = math.min(position.line, snapshot.line_count)
+ local view = text_topology.new(snapshot, encoding)
+ return view:normalize_endpoint(line_number, position.byte_column)
+end
+
+function MemoryHost:_apply_pending_delete(origin, destination, descriptor)
+ if self._pending_operator ~= "delete" and self._pending_operator ~= "d" then
+ return false
+ end
+
+ local view = text_topology.new(self._text, self._encoding)
+ local origin_index = character_boundary(view, origin)
+ local destination_index = character_boundary(view, destination)
+ local start_line
+ local start_index
+ local finish_line
+ local finish_index
+ local final_cursor
+
+ if descriptor.direction == domain.Direction.FORWARD then
+ start_line = origin.line
+ start_index = origin_index
+ finish_line = destination.line
+ finish_index = destination_index + (self._operator_inclusive and 1 or 0)
+ final_cursor = origin
+ elseif descriptor.family == domain.Family.FIND then
+ start_line = destination.line
+ start_index = destination_index + 1
+ finish_line = origin.line
+ finish_index = origin_index + 1
+ final_cursor = destination
+ else
+ start_line = destination.line
+ start_index = destination_index
+ finish_line = origin.line
+ finish_index = origin_index
+ final_cursor = view:predecessor(destination) or destination
+ end
+
+ self._text = delete_character_range(
+ self._text,
+ start_line,
+ start_index,
+ finish_line,
+ finish_index
+ )
+ self._cursor = normalized_cursor(self._text, self._encoding, final_cursor)
+ self:_record("apply_operator", {
+ operator = self._pending_operator,
+ descriptor = descriptor.value,
+ origin = origin,
+ endpoint = destination,
+ position = self._cursor,
+ })
+ return true
+end
+
+function MemoryHost:apply_cursor(position, motion)
position = domain.Position.coerce(position)
local previous = self._cursor
+ local descriptor = motion_descriptor(motion)
self._cursor = position
- self:_record("apply_cursor", { position = position })
+ self:_record("apply_cursor", {
+ position = position,
+ descriptor = descriptor and descriptor.value or nil,
+ })
+ if descriptor ~= nil then
+ local origin = type(motion) == "table" and motion.origin or previous
+ self:_apply_pending_delete(domain.Position.coerce(origin), position, descriptor)
+ end
self:_emit_movement_event(previous)
end