summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lua/clever_f/direct_preview_planner.lua72
-rw-r--r--tests/run.lua27
2 files changed, 88 insertions, 11 deletions
diff --git a/lua/clever_f/direct_preview_planner.lua b/lua/clever_f/direct_preview_planner.lua
index 9a6b0d2..51d7b18 100644
--- a/lua/clever_f/direct_preview_planner.lua
+++ b/lua/clever_f/direct_preview_planner.lua
@@ -1,3 +1,4 @@
+local case_policy = require("clever_f.case_policy")
local domain = require("clever_f.domain")
local text_topology = require("clever_f.text_topology")
@@ -19,14 +20,37 @@ local function require_view(view)
return view
end
-function DirectPreviewPlanner.new()
+local function require_case_resolver(options)
+ options = options or {}
+ if type(options) == "function" then
+ options = { lowercase = options }
+ end
+ if type(options) ~= "table" then
+ fail("DirectPreviewPlanner options must be a table", 3)
+ end
+ local resolver = options.case_resolver
+ if resolver == nil then
+ resolver = case_policy.new({ lowercase = options.lowercase })
+ end
+ if type(resolver) ~= "table" or type(resolver.lowercase) ~= "function" then
+ fail("DirectPreviewPlanner case resolver must provide lowercase", 3)
+ end
+ return resolver
+end
+
+function DirectPreviewPlanner.new(options)
+ if DirectPreviewPlanner.is(options) then
+ return options
+ end
local planner = setmetatable({}, DirectPreviewPlanner)
- planner_records[planner] = true
+ planner_records[planner] = {
+ case_resolver = require_case_resolver(options),
+ }
return planner
end
function DirectPreviewPlanner.is(value)
- return type(value) == "table" and planner_records[value] == true
+ return type(value) == "table" and planner_records[value] ~= nil
end
function DirectPreviewPlanner:scan_current_line(view, origin, direction)
@@ -78,20 +102,40 @@ local function increment_counter(counters, character)
return value
end
-function DirectPreviewPlanner:plan(view, origin, descriptor, count)
+local function require_case_setting(settings, name)
+ local value = settings[name]
+ if value == nil then
+ return false
+ end
+ if type(value) ~= "boolean" then
+ fail("direct preview " .. name .. " must be a Boolean", 3)
+ end
+ return value
+end
+
+function DirectPreviewPlanner:plan(view, origin, descriptor, count, settings)
+ settings = settings or {}
+ if type(settings) ~= "table" then
+ fail("direct preview case settings must be a table", 2)
+ end
+ local ignore_case = require_case_setting(settings, "ignore_case")
local selected_occurrence = self:normalize_count(count)
local counters = {}
local positions = {}
+ local resolver = planner_records[self].case_resolver
for _, record in ipairs(self:scan_for_descriptor(view, origin, descriptor)) do
- if increment_counter(counters, record.character) == selected_occurrence then
+ local counter_key = ignore_case
+ and resolver:lowercase(record.character)
+ or record.character
+ if increment_counter(counters, counter_key) == selected_occurrence then
positions[#positions + 1] = record.position
end
end
return positions
end
-function M.new()
- return DirectPreviewPlanner.new()
+function M.new(options)
+ return DirectPreviewPlanner.new(options)
end
function M.scan_current_line(view, origin, direction)
@@ -102,13 +146,19 @@ function M.scan_for_descriptor(view, origin, descriptor)
return DirectPreviewPlanner.new():scan_for_descriptor(view, origin, descriptor)
end
-function M.plan(view, origin, descriptor, count)
- return DirectPreviewPlanner.new():plan(view, origin, descriptor, count)
+function M.plan(view, origin, descriptor, count, settings, options)
+ return DirectPreviewPlanner.new(options):plan(
+ view,
+ origin,
+ descriptor,
+ count,
+ settings
+ )
end
setmetatable(M, {
- __call = function()
- return DirectPreviewPlanner.new()
+ __call = function(_, options)
+ return DirectPreviewPlanner.new(options)
end,
})
diff --git a/tests/run.lua b/tests/run.lua
index 7ec0baf..3c2a077 100644
--- a/tests/run.lua
+++ b/tests/run.lua
@@ -4649,6 +4649,33 @@ test("Default direct previews count each exact character", function()
list_same({ 15 }, columns(planner:plan(view, origin, "f", 3)))
end)
+test("Ignore-case previews count editor-folded character classes", function()
+ local folded = {}
+ local planner = direct_preview_planner.new({
+ lowercase = function(character)
+ folded[#folded + 1] = character
+ return string.lower(character)
+ end,
+ })
+ local view = text_topology.new({ "xAaBbC" }, "utf-8")
+ local origin = domain.Position.new(1, 1)
+
+ local positions = planner:plan(view, origin, "f", 2, {
+ ignore_case = true,
+ smart_case = false,
+ })
+ same(2, #positions)
+ same(domain.Position.new(1, 3), positions[1])
+ same(domain.Position.new(1, 5), positions[2])
+ list_same({ "A", "a", "B", "b", "C" }, folded)
+
+ local exact = planner:plan(view, origin, "f", 2, {
+ ignore_case = false,
+ smart_case = false,
+ })
+ same(0, #exact)
+end)
+
for _, item in ipairs(tests) do
local ok, failure = xpcall(item.body, debug.traceback)
if not ok then