1

Regenerate nvim config

This commit is contained in:
2024-06-02 03:29:20 +02:00
parent 75eea0c030
commit ef2e28883d
5576 changed files with 604886 additions and 503 deletions

View File

@ -0,0 +1,510 @@
local actions = require "telescope.actions"
local action_set = require "telescope.actions.set"
local transform_mod = require("telescope.actions.mt").transform_mod
local eq = assert.are.same
describe("actions", function()
it("should allow creating custom actions", function()
local a = transform_mod {
x = function()
return 5
end,
}
eq(5, a.x())
end)
it("allows adding actions", function()
local a = transform_mod {
x = function()
return "x"
end,
y = function()
return "y"
end,
}
local x_plus_y = a.x + a.y
eq({ "x", "y" }, { x_plus_y() })
end)
it("ignores nils from added actions", function()
local a = transform_mod {
x = function()
return "x"
end,
y = function()
return "y"
end,
nil_maker = function()
return nil
end,
}
local x_plus_y = a.x + a.nil_maker + a.y
eq({ "x", "y" }, { x_plus_y() })
end)
it("allows overriding an action", function()
local a = transform_mod {
x = function()
return "x"
end,
y = function()
return "y"
end,
}
-- actions.file_goto_selection_edit:replace(...)
a.x:replace(function()
return "foo"
end)
eq("foo", a.x())
a._clear()
eq("x", a.x())
end)
it("allows overriding an action only in specific cases with if", function()
local a = transform_mod {
x = function(e)
return e * 10
end,
y = function()
return "y"
end,
}
-- actions.file_goto_selection_edit:replace(...)
a.x:replace_if(function(e)
return e > 0
end, function(e)
return (e / 10)
end)
eq(-100, a.x(-10))
eq(10, a.x(100))
eq(1, a.x(10))
a._clear()
eq(100, a.x(10))
end)
it("allows overriding an action only in specific cases with mod", function()
local a = transform_mod {
x = function(e)
return e * 10
end,
y = function()
return "y"
end,
}
-- actions.file_goto_selection_edit:replace(...)
a.x:replace_map {
[function(e)
return e > 0
end] = function(e)
return (e / 10)
end,
[function(e)
return e == 0
end] = function(e)
return (e + 10)
end,
}
eq(-100, a.x(-10))
eq(10, a.x(100))
eq(1, a.x(10))
eq(10, a.x(0))
a._clear()
eq(100, a.x(10))
end)
it("continuous replacement", function()
local a = transform_mod {
x = function()
return "cleared"
end,
y = function()
return "y"
end,
}
-- Replace original, which becomes new fallback
a.x:replace(function()
return "negative"
end)
-- actions.file_goto_selection_edit:replace(...)
a.x:replace_map {
[function(e)
return e > 0
end] = function(e)
return "positive"
end,
[function(e)
return e == 0
end] = function(e)
return "zero"
end,
}
eq("positive", a.x(10))
eq("zero", a.x(0))
eq("negative", a.x(-10))
a._clear()
eq("cleared", a.x(10))
end)
it("enhance.pre", function()
local a = transform_mod {
x = function()
return "x"
end,
y = function()
return "y"
end,
}
local called_pre = false
a.y:enhance {
pre = function()
called_pre = true
end,
}
eq("y", a.y())
eq(true, called_pre)
end)
it("enhance.post", function()
local a = transform_mod {
x = function()
return "x"
end,
y = function()
return "y"
end,
}
local called_post = false
a.y:enhance {
post = function()
called_post = true
end,
}
eq("y", a.y())
eq(true, called_post)
end)
it("static_pre static_post", function()
local called_pre = false
local called_post = false
local static_post = 0
local a = transform_mod {
x = {
pre = function()
called_pre = true
end,
action = function()
return "x"
end,
post = function()
called_post = true
end,
},
}
eq("x", a.x())
eq(true, called_pre)
eq(true, called_post)
end)
it("can call both", function()
local a = transform_mod {
x = function()
return "x"
end,
y = function()
return "y"
end,
}
local called_count = 0
local count_inc = function()
called_count = called_count + 1
end
a.y:enhance {
pre = count_inc,
post = count_inc,
}
eq("y", a.y())
eq(2, called_count)
end)
it("can call both even when combined", function()
local a = transform_mod {
x = function()
return "x"
end,
y = function()
return "y"
end,
}
local called_count = 0
local count_inc = function()
called_count = called_count + 1
end
a.y:enhance {
pre = count_inc,
post = count_inc,
}
a.x:enhance {
post = count_inc,
}
local x_plus_y = a.x + a.y
x_plus_y()
eq(3, called_count)
end)
it(
"can call replace fn even when combined before replace registered the fn (because that happens with mappings)",
function()
local a = transform_mod {
x = function()
return "x"
end,
y = function()
return "y"
end,
}
local called_count = 0
local count_inc = function()
called_count = called_count + 1
end
local x_plus_y = a.x + a.y
a.x:replace(function()
count_inc()
end)
a.y:replace(function()
count_inc()
end)
x_plus_y()
eq(2, called_count)
end
)
it(
"can call enhance fn even when combined before enhance registed fns (because that happens with mappings)",
function()
local a = transform_mod {
x = function()
return "x"
end,
y = function()
return "y"
end,
}
local called_count = 0
local count_inc = function()
called_count = called_count + 1
end
local x_plus_y = a.x + a.y
a.y:enhance {
pre = count_inc,
post = count_inc,
}
a.x:enhance {
post = count_inc,
}
x_plus_y()
eq(3, called_count)
end
)
it("clears enhance", function()
local a = transform_mod {
x = function()
return "x"
end,
y = function()
return "y"
end,
}
local called_post = false
a.y:enhance {
post = function()
called_post = true
end,
}
a._clear()
eq("y", a.y())
eq(false, called_post)
end)
it("handles passing arguments", function()
local a = transform_mod {
x = function(bufnr)
return string.format "bufnr: %s"
end,
}
a.x:replace(function(bufnr)
return string.format("modified: %s", bufnr)
end)
eq("modified: 5", a.x(5))
end)
it("handles add with two different tables", function()
local count_a = 0
local count_b = 0
local a = transform_mod {
x = function()
count_a = count_a + 1
end,
}
local b = transform_mod {
y = function()
count_b = count_b + 1
end,
}
local called_count = 0
local count_inc = function()
called_count = called_count + 1
end
a.x:enhance {
post = count_inc,
}
b.y:enhance {
post = count_inc,
}
local x_plus_y = a.x + b.y
x_plus_y()
eq(2, called_count)
eq(1, count_a)
eq(1, count_b)
end)
it("handles tripple concat with static pre post", function()
local count_a = 0
local count_b = 0
local count_c = 0
local static_pre = 0
local static_post = 0
local a = transform_mod {
x = {
pre = function()
static_pre = static_pre + 1
end,
action = function()
count_a = count_a + 1
end,
post = function()
static_post = static_post + 1
end,
},
}
local b = transform_mod {
y = {
pre = function()
static_pre = static_pre + 1
end,
action = function()
count_b = count_b + 1
end,
post = function()
static_post = static_post + 1
end,
},
}
local c = transform_mod {
z = {
pre = function()
static_pre = static_pre + 1
end,
action = function()
count_c = count_c + 1
end,
post = function()
static_post = static_post + 1
end,
},
}
local replace_count = 0
a.x:replace(function()
replace_count = replace_count + 1
end)
local x_plus_y_plus_z = a.x + b.y + c.z
x_plus_y_plus_z()
eq(0, count_a)
eq(1, count_b)
eq(1, count_c)
eq(1, replace_count)
eq(3, static_pre)
eq(3, static_post)
end)
describe("action_set", function()
it("can replace `action_set.edit`", function()
action_set.edit:replace(function(_, arg)
return "replaced:" .. arg
end)
eq("replaced:edit", actions.file_edit())
eq("replaced:vnew", actions.file_vsplit())
end)
pending("handles backwards compat with select and edit files", function()
-- Reproduce steps:
-- In config, we have { ["<CR>"] = actions.select, ... }
-- In caller, we have actions._goto:replace(...)
-- Person calls `select`, does not see update
action_set.edit:replace(function(_, arg)
return "default_to_edit:" .. arg
end)
eq("default_to_edit:edit", actions.select_default())
action_set.select:replace(function(_, arg)
return "override_with_select:" .. arg
end)
eq("override_with_select:default", actions.select_default())
-- Sometimes you might want to change the default selection...
-- but you don't want to prohibit the ability to edit the code...
end)
end)
end)

View File

@ -0,0 +1,102 @@
local command = require "telescope.command"
local eq = assert.are.same
describe("command_parser", function()
local test_parse = function(should, input, output)
it(should, function()
command.convert_user_opts(input)
eq(output, input)
end)
end
-- Strings
test_parse("should handle cwd", { cwd = "string" }, { cwd = "string" })
-- Find commands
test_parse(
"should handle find_command 1",
{ find_command = "rg,--ignore,--hidden,files" },
{ find_command = { "rg", "--ignore", "--hidden", "files" } }
)
test_parse(
"should handle find_command 2",
{ find_command = "fd,-t,f,-H" },
{ find_command = { "fd", "-t", "f", "-H" } }
)
test_parse(
"should handle find_command 3",
{ find_command = "fdfind,--type,f,--no-ignore" },
{ find_command = { "fdfind", "--type", "f", "--no-ignore" } }
)
-- Dictionaries/tables
test_parse(
"should handle layout_config viml 1",
{ layout_config = "{'prompt_position':'top'}" },
{ layout_config = { prompt_position = "top" } }
)
test_parse(
"should handle layout_config viml 2",
{ layout_config = "#{prompt_position:'bottom'}" },
{ layout_config = { prompt_position = "bottom" } }
)
test_parse(
"should handle layout_config viml 3",
{ layout_config = "{'mirror':v:true}" },
{ layout_config = { mirror = true } }
)
test_parse(
"should handle layout_config viml 4",
{ layout_config = "#{mirror:v:true}" },
{ layout_config = { mirror = true } }
)
test_parse(
"should handle layout_config lua 1",
{ layout_config = "{prompt_position='bottom'}" },
{ layout_config = { prompt_position = "bottom" } }
)
test_parse(
"should handle layout_config lua 2",
{ layout_config = "{mirror=true}" },
{ layout_config = { mirror = true } }
)
-- Lists/tables
test_parse(
"should handle symbols commas list",
{ symbols = "alpha,beta,gamma" },
{ symbols = { "alpha", "beta", "gamma" } }
)
test_parse(
"should handle symbols viml list",
{ symbols = "['alpha','beta','gamma']" },
{ symbols = { "alpha", "beta", "gamma" } }
)
test_parse(
"should handle symbols lua list",
{ symbols = "{'alpha','beta','gamma'}" },
{ symbols = { "alpha", "beta", "gamma" } }
)
-- Booleans
test_parse("should handle booleans 1", { hidden = "true" }, { hidden = true })
test_parse("should handle booleans 2", { no_ignore = "false" }, { no_ignore = false })
-- Numbers
test_parse("should handle numbers 1", { depth = "2" }, { depth = 2 })
test_parse("should handle numbers 2", { bufnr_width = "4" }, { bufnr_width = 4 })
test_parse("should handle numbers 3", { severity = "27" }, { severity = 27 })
-- Multiple options
test_parse(
"should handle multiple options 1",
{ layout_config = '{prompt_position="top"}', cwd = "/foobar", severity = "27" },
{ layout_config = { prompt_position = "top" }, cwd = "/foobar", severity = 27 }
)
test_parse(
"should handle multiple options 2",
{ symbols = "['alef','bet','gimel']", depth = "2", find_command = "rg,--ignore,files" },
{ symbols = { "alef", "bet", "gimel" }, depth = 2, find_command = { "rg", "--ignore", "files" } }
)
end)

View File

@ -0,0 +1,34 @@
local entry_display = require "telescope.pickers.entry_display"
describe("truncate", function()
for _, ambiwidth in ipairs { "single", "double" } do
for _, case in ipairs {
{ args = { "abcde", 6 }, expected = { single = "abcde", double = "abcde" } },
{ args = { "abcde", 5 }, expected = { single = "abcde", double = "abcde" } },
{ args = { "abcde", 4 }, expected = { single = "abc…", double = "ab…" } },
{ args = { "アイウエオ", 11 }, expected = { single = "アイウエオ", double = "アイウエオ" } },
{ args = { "アイウエオ", 10 }, expected = { single = "アイウエオ", double = "アイウエオ" } },
{ args = { "アイウエオ", 9 }, expected = { single = "アイウエ…", double = "アイウ…" } },
{ args = { "アイウエオ", 8 }, expected = { single = "アイウ…", double = "アイウ…" } },
{ args = { "├─┤", 7 }, expected = { single = "├─┤", double = "├─┤" } },
{ args = { "├─┤", 6 }, expected = { single = "├─┤", double = "├─┤" } },
{ args = { "├─┤", 5 }, expected = { single = "├─┤", double = "├…" } },
{ args = { "├─┤", 4 }, expected = { single = "├─┤", double = "├…" } },
{ args = { "├─┤", 3 }, expected = { single = "├─┤", double = "" } },
{ args = { "├─┤", 2 }, expected = { single = "├…", double = "" } },
} do
local msg = ("can truncate: ambiwidth = %s, [%s, %d] -> %s"):format(
ambiwidth,
case.args[1],
case.args[2],
case.expected[ambiwidth]
)
it(msg, function()
local original = vim.o.ambiwidth
vim.o.ambiwidth = ambiwidth
assert.are.same(case.expected[ambiwidth], entry_display.truncate(case.args[1], case.args[2]))
vim.o.ambiwidth = original
end)
end
end
end)

View File

@ -0,0 +1,189 @@
local EntryManager = require "telescope.entry_manager"
local eq = assert.are.same
describe("process_result", function()
it("works with one entry", function()
local manager = EntryManager:new(5, nil)
manager:add_entry(nil, 1, "hello", "")
eq(1, manager:get_score(1))
end)
it("works with two entries", function()
local manager = EntryManager:new(5, nil)
manager:add_entry(nil, 1, "hello", "")
manager:add_entry(nil, 2, "later", "")
eq(2, manager.linked_states.size)
eq("hello", manager:get_entry(1))
eq("later", manager:get_entry(2))
end)
it("calls functions when inserting", function()
local called_count = 0
local manager = EntryManager:new(5, function()
called_count = called_count + 1
end)
assert(called_count == 0)
manager:add_entry(nil, 1, "hello", "")
assert(called_count == 1)
end)
it("calls functions when inserting twice", function()
local called_count = 0
local manager = EntryManager:new(5, function()
called_count = called_count + 1
end)
assert(called_count == 0)
manager:add_entry(nil, 1, "hello", "")
manager:add_entry(nil, 2, "world", "")
assert(called_count == 2)
end)
it("correctly sorts lower scores", function()
local called_count = 0
local manager = EntryManager:new(5, function()
called_count = called_count + 1
end)
manager:add_entry(nil, 5, "worse result", "")
manager:add_entry(nil, 2, "better result", "")
eq("better result", manager:get_entry(1))
eq("worse result", manager:get_entry(2))
eq(2, called_count)
end)
it("respects max results", function()
local called_count = 0
local manager = EntryManager:new(1, function()
called_count = called_count + 1
end)
manager:add_entry(nil, 2, "better result", "")
manager:add_entry(nil, 5, "worse result", "")
eq("better result", manager:get_entry(1))
eq(1, called_count)
end)
it("should allow simple entries", function()
local manager = EntryManager:new(5)
local counts_executed = 0
manager:add_entry(
nil,
1,
setmetatable({}, {
__index = function(t, k)
local val = nil
if k == "ordinal" then
counts_executed = counts_executed + 1
-- This could be expensive, only call later
val = "wow"
end
rawset(t, k, val)
return val
end,
}),
""
)
eq("wow", manager:get_ordinal(1))
eq("wow", manager:get_ordinal(1))
eq("wow", manager:get_ordinal(1))
eq(1, counts_executed)
end)
it("should not loop a bunch", function()
local info = {}
local manager = EntryManager:new(5, nil, info)
manager:add_entry(nil, 4, "better result", "")
manager:add_entry(nil, 3, "better result", "")
manager:add_entry(nil, 2, "better result", "")
-- Loops once to find 3 < 4
-- Loops again to find 2 < 3
eq(2, info.looped)
end)
it("should not loop a bunch, part 2", function()
local info = {}
local manager = EntryManager:new(5, nil, info)
manager:add_entry(nil, 4, "better result", "")
manager:add_entry(nil, 2, "better result", "")
manager:add_entry(nil, 3, "better result", "")
-- Loops again to find 2 < 4
-- Loops once to find 3 > 2
-- but less than 4
eq(3, info.looped)
end)
it("should update worst score in all append case", function()
local manager = EntryManager:new(2, nil)
manager:add_entry(nil, 2, "result 2", "")
manager:add_entry(nil, 3, "result 3", "")
manager:add_entry(nil, 4, "result 4", "")
eq(3, manager.worst_acceptable_score)
end)
it("should update worst score in all prepend case", function()
local called_count = 0
local manager = EntryManager:new(2, function()
called_count = called_count + 1
end)
manager:add_entry(nil, 5, "worse result", "")
manager:add_entry(nil, 4, "less worse result", "")
manager:add_entry(nil, 2, "better result", "")
-- Once for insert 5
-- Once for prepend 4
-- Once for prepend 2
eq(3, called_count)
eq("better result", manager:get_entry(1))
eq(4, manager.worst_acceptable_score)
end)
it("should call tiebreaker if score is the same, sort length", function()
local manager = EntryManager:new(5, nil)
local picker = {
tiebreak = function(curr, prev, prompt)
eq("asdf", prompt)
return #curr < #prev
end,
}
manager:add_entry(picker, 0.5, "same same", "asdf")
manager:add_entry(picker, 0.5, "same", "asdf")
eq("same", manager:get_entry(1))
eq("same same", manager:get_entry(2))
end)
it("should call tiebreaker if score is the same, keep initial", function()
local manager = EntryManager:new(5, nil)
local picker = {
tiebreak = function(_, _, prompt)
eq("asdf", prompt)
return false
end,
}
manager:add_entry(picker, 0.5, "same same", "asdf")
manager:add_entry(picker, 0.5, "same", "asdf")
eq("same", manager:get_entry(2))
eq("same same", manager:get_entry(1))
end)
end)

View File

@ -0,0 +1,161 @@
local config = require "telescope.config"
local resolve = require "telescope.config.resolve"
local layout_strats = require "telescope.pickers.layout_strategies"
local validate_layout_config = layout_strats._validate_layout_config
local eq = assert.are.same
describe("layout_strategies", function()
it("should have validator", function()
assert(validate_layout_config, "Has validator")
end)
local test_height = function(should, output, input, opts)
opts = opts or {}
local max_columns, max_lines = opts.max_columns or 100, opts.max_lines or 100
it(should, function()
local layout_config = validate_layout_config("horizontal", { height = true }, { height = input })
eq(output, resolve.resolve_height(layout_config.height)({}, max_columns, max_lines))
end)
end
test_height("should handle numbers", 10, 10)
test_height("should handle percentage: 100", 10, 0.1, { max_lines = 100 })
test_height("should handle percentage: 110", 11, 0.1, { max_lines = 110 })
test_height("should call functions: simple", 5, function()
return 5
end)
test_height("should call functions: percentage", 15, function(_, _, lines)
return 0.1 * lines
end, {
max_lines = 150,
})
local test_defaults_key = function(should, key, strat, output, ours, theirs, override)
ours = ours or {}
theirs = theirs or {}
override = override or {}
it(should, function()
config.clear_defaults()
config.set_defaults({ layout_config = theirs }, { layout_config = { ours, "description" } })
local layout_config = validate_layout_config(strat, layout_strats._configurations[strat], override)
eq(output, layout_config[key])
end)
end
test_defaults_key(
"should use ours if theirs and override don't give the key",
"height",
"horizontal",
50,
{ height = 50 },
{ width = 100 },
{ width = 120 }
)
test_defaults_key(
"should use ours if theirs and override don't give the key for this strategy",
"height",
"horizontal",
50,
{ height = 50 },
{ vertical = { height = 100 } },
{ vertical = { height = 120 } }
)
test_defaults_key(
"should use theirs if override doesn't give the key",
"height",
"horizontal",
100,
{ height = 50 },
{ height = 100 },
{ width = 120 }
)
test_defaults_key(
"should use override if key given",
"height",
"horizontal",
120,
{ height = 50 },
{ height = 100 },
{ height = 120 }
)
test_defaults_key(
"should use override if key given for this strategy",
"height",
"horizontal",
120,
{ height = 50 },
{ height = 100 },
{ horizontal = { height = 120 } }
)
test_defaults_key(
"should use theirs if override doesn't give key (even if ours has strategy specific)",
"height",
"horizontal",
100,
{ horizontal = { height = 50 } },
{ height = 100 },
{ width = 120 }
)
test_defaults_key(
"should use override (even if ours has strategy specific)",
"height",
"horizontal",
120,
{ horizontal = { height = 50 } },
{ height = 100 },
{ height = 120 }
)
test_defaults_key(
"should use override (even if theirs has strategy specific)",
"height",
"horizontal",
120,
{ height = 50 },
{ horizontal = { height = 100 } },
{ height = 120 }
)
test_defaults_key(
"should use override (even if ours and theirs have strategy specific)",
"height",
"horizontal",
120,
{ horizontal = { height = 50 } },
{ horizontal = { height = 100 } },
{ height = 120 }
)
test_defaults_key(
"should handle user config overriding a table with a number",
"height",
"horizontal",
120,
{ height = { padding = 5 } },
{ height = 120 },
{}
)
test_defaults_key(
"should handle user oneshot overriding a table with a number",
"height",
"horizontal",
120,
{},
{ height = { padding = 5 } },
{ height = 120 }
)
end)

View File

@ -0,0 +1,133 @@
local LinkedList = require "telescope.algos.linked_list"
describe("LinkedList", function()
it("can create a list", function()
local l = LinkedList:new()
assert.are.same(0, l.size)
end)
it("can add a single entry to the list", function()
local l = LinkedList:new()
l:append "hello"
assert.are.same(1, l.size)
end)
it("can iterate over one item", function()
local l = LinkedList:new()
l:append "hello"
for val in l:iter() do
assert.are.same("hello", val)
end
end)
it("iterates in order", function()
local l = LinkedList:new()
l:append "hello"
l:append "world"
local x = {}
for val in l:iter() do
table.insert(x, val)
end
assert.are.same({ "hello", "world" }, x)
end)
it("iterates in order, for prepend", function()
local l = LinkedList:new()
l:prepend "world"
l:prepend "hello"
local x = {}
for val in l:iter() do
table.insert(x, val)
end
assert.are.same({ "hello", "world" }, x)
end)
it("iterates in order, for combo", function()
local l = LinkedList:new()
l:prepend "world"
l:prepend "hello"
l:append "last"
l:prepend "first"
local x = {}
for val in l:iter() do
table.insert(x, val)
end
assert.are.same({ "first", "hello", "world", "last" }, x)
assert.are.same(#x, l.size)
end)
it("has ipairs", function()
local l = LinkedList:new()
l:prepend "world"
l:prepend "hello"
l:append "last"
l:prepend "first"
local x = {}
for v in l:iter() do
table.insert(x, v)
end
assert.are.same({ "first", "hello", "world", "last" }, x)
local expected = {}
for i, v in ipairs(x) do
table.insert(expected, { i, v })
end
local actual = {}
for i, v in l:ipairs() do
table.insert(actual, { i, v })
end
assert.are.same(expected, actual)
end)
describe("track_at", function()
it("should update tracked when only appending", function()
local l = LinkedList:new { track_at = 2 }
l:append "first"
l:append "second"
l:append "third"
assert.are.same("second", l.tracked)
end)
it("should update tracked when first some prepend and then append", function()
local l = LinkedList:new { track_at = 2 }
l:prepend "first"
l:append "second"
l:append "third"
assert.are.same("second", l.tracked)
end)
it("should update when only prepending", function()
local l = LinkedList:new { track_at = 2 }
l:prepend "third"
l:prepend "second"
l:prepend "first"
assert.are.same("second", l.tracked)
end)
it("should update when lots of prepend and append", function()
local l = LinkedList:new { track_at = 2 }
l:prepend "third"
l:prepend "second"
l:prepend "first"
l:append "fourth"
l:prepend "zeroth"
assert.are.same("first", l.tracked)
end)
end)
end)

View File

@ -0,0 +1,143 @@
-- Just skip on mac, it has flaky CI for some reason
if vim.fn.has "mac" == 1 or require("telescope.utils").iswin then
return
end
local tester = require "telescope.testharness"
local disp = function(val)
return vim.inspect(val, { newline = " ", indent = "" })
end
describe("builtin.find_files", function()
it("should find the readme", function()
tester.run_file "find_files__readme"
end)
it("should handle cycling for full list", function()
tester.run_file "find_files__scrolling_descending_cycle"
end)
for _, configuration in ipairs {
{ sorting_strategy = "descending" },
{ sorting_strategy = "ascending" },
} do
it("should not display devicons when disabled: " .. disp(configuration), function()
tester.run_string(string.format(
[[
local max_results = 5
runner.picker('find_files', 'README.md', {
post_typed = {
{ "> README.md", GetPrompt },
{ "> README.md", GetBestResult },
},
post_close = {
{ 'README.md', GetFile },
{ 'README.md', GetFile },
}
}, vim.tbl_extend("force", {
disable_devicons = true,
sorter = require('telescope.sorters').get_fzy_sorter(),
layout_strategy = 'center',
layout_config = {
height = max_results + 1,
width = 0.9,
},
}, vim.json.decode([==[%s]==])))
]],
vim.json.encode(configuration)
))
end)
pending("use devicons, if it has it when enabled", function()
if not pcall(require, "nvim-web-devicons") then
return
end
local md = require("nvim-web-devicons").get_icon "md"
tester.run_string(string.format(
[[
runner.picker('find_files', 'README.md', {
post_typed = {
{ "> README.md", GetPrompt },
{ "> %s README.md", GetBestResult }
},
post_close = {
{ 'README.md', GetFile },
{ 'README.md', GetFile },
}
}, vim.tbl_extend("force", {
disable_devicons = false,
sorter = require('telescope.sorters').get_fzy_sorter(),
}, vim.json.decode([==[%s]==])))
]],
md,
vim.json.encode(configuration)
))
end)
end
it("should find the readme, using lowercase", function()
tester.run_string [[
runner.picker('find_files', 'readme.md', {
post_close = {
{ 'README.md', GetFile },
}
})
]]
end)
it("should find the pickers.lua, using lowercase", function()
tester.run_string [[
runner.picker('find_files', 'pickers.lua', {
post_close = {
{ 'pickers.lua', GetFile },
}
})
]]
end)
it("should find the pickers.lua", function()
tester.run_string [[
runner.picker('find_files', 'pickers.lua', {
post_close = {
{ 'pickers.lua', GetFile },
{ 'pickers.lua', GetFile },
}
})
]]
end)
it("should be able to c-n the items", function()
tester.run_string [[
runner.picker('find_files', 'fixtures/find_files/file<c-n>', {
post_typed = {
{
{
" lua/tests/fixtures/find_files/file_a.txt",
"> lua/tests/fixtures/find_files/file_abc.txt",
}, GetResults
},
},
post_close = {
{ 'file_abc.txt', GetFile },
},
}, {
sorter = require('telescope.sorters').get_fzy_sorter(),
sorting_strategy = "ascending",
disable_devicons = true,
})
]]
end)
it("should be able to get the current selection", function()
tester.run_string [[
runner.picker('find_files', 'fixtures/find_files/file_abc', {
post_typed = {
{ 'lua/tests/fixtures/find_files/file_abc.txt', GetSelectionValue },
}
})
]]
end)
end)

View File

@ -0,0 +1,208 @@
local eq = function(a, b)
assert.are.same(a, b)
end
local resolve = require "telescope.config.resolve"
describe("telescope.config.resolve", function()
describe("win_option", function()
it("should resolve for percentages", function()
local height_config = 0.8
local opt = resolve.win_option(height_config)
eq(height_config, opt.preview)
eq(height_config, opt.prompt)
eq(height_config, opt.results)
end)
it("should resolve for percentages with default", function()
local height_config = 0.8
local opt = resolve.win_option(nil, height_config)
eq(height_config, opt.preview)
eq(height_config, opt.prompt)
eq(height_config, opt.results)
end)
it("should resolve table values", function()
local table_val = { "a" }
local opt = resolve.win_option(nil, table_val)
eq(table_val, opt.preview)
eq(table_val, opt.prompt)
eq(table_val, opt.results)
end)
it("should allow overrides for different wins", function()
local prompt_override = { "a", prompt = "b" }
local opt = resolve.win_option(prompt_override)
eq("a", opt.preview)
eq("a", opt.results)
eq("b", opt.prompt)
end)
it("should allow overrides for all wins", function()
local all_specified = { preview = "a", prompt = "b", results = "c" }
local opt = resolve.win_option(all_specified)
eq("a", opt.preview)
eq("b", opt.prompt)
eq("c", opt.results)
end)
it("should allow some specified with a simple default", function()
local some_specified = { prompt = "b", results = "c" }
local opt = resolve.win_option(some_specified, "a")
eq("a", opt.preview)
eq("b", opt.prompt)
eq("c", opt.results)
end)
end)
describe("resolve_height/width", function()
local test_sizes = {
{ 24, 100 },
{ 35, 125 },
{ 60, 59 },
{ 100, 40 },
}
it("should handle percentages", function()
local percentages = { 0.1, 0.33333, 0.5, 0.99 }
for _, s in ipairs(test_sizes) do
for _, p in ipairs(percentages) do
eq(math.floor(s[1] * p), resolve.resolve_width(p)(nil, unpack(s)))
eq(math.floor(s[2] * p), resolve.resolve_height(p)(nil, unpack(s)))
end
end
end)
it("should handle percentages with min/max boundary", function()
eq(20, resolve.resolve_width { 0.1, min = 20 }(nil, 40, 120))
eq(30, resolve.resolve_height { 0.1, min = 20 }(nil, 40, 300))
eq(24, resolve.resolve_width { 0.4, max = 80 }(nil, 60, 60))
eq(80, resolve.resolve_height { 0.4, max = 80 }(nil, 60, 300))
end)
it("should handle fixed size", function()
local fixed = { 5, 8, 13, 21, 34 }
for _, s in ipairs(test_sizes) do
for _, f in ipairs(fixed) do
eq(math.min(f, s[1]), resolve.resolve_width(f)(nil, unpack(s)))
eq(math.min(f, s[2]), resolve.resolve_height(f)(nil, unpack(s)))
end
end
end)
it("should handle functions", function()
local func = function(_, max_columns, max_lines)
if max_columns < 45 then
return math.min(max_columns, max_lines)
elseif max_columns < max_lines then
return max_columns * 0.8
else
return math.min(max_columns, max_lines) * 0.5
end
end
for _, s in ipairs(test_sizes) do
eq(func(nil, unpack(s)), resolve.resolve_height(func)(nil, unpack(s)))
end
end)
it("should handle padding", function()
local func = function(_, max_columns, max_lines)
return math.floor(math.min(max_columns * 0.6, max_lines * 0.8))
end
local pads = { 0.1, 5, func }
for _, s in ipairs(test_sizes) do
for _, p in ipairs(pads) do
eq(s[1] - 2 * resolve.resolve_width(p)(nil, unpack(s)), resolve.resolve_width { padding = p }(nil, unpack(s)))
eq(
s[2] - 2 * resolve.resolve_height(p)(nil, unpack(s)),
resolve.resolve_height { padding = p }(nil, unpack(s))
)
end
end
end)
end)
describe("resolve_anchor_pos", function()
local test_sizes = {
{ 6, 7, 8, 9 },
{ 10, 20, 30, 40 },
{ 15, 15, 16, 16 },
{ 17, 19, 23, 31 },
{ 21, 18, 26, 24 },
{ 50, 100, 150, 200 },
}
it([[should not adjust when "CENTER" or "" is the anchor]], function()
for _, s in ipairs(test_sizes) do
eq({ 0, 0 }, resolve.resolve_anchor_pos("", unpack(s)))
eq({ 0, 0 }, resolve.resolve_anchor_pos("center", unpack(s)))
eq({ 0, 0 }, resolve.resolve_anchor_pos("CENTER", unpack(s)))
end
end)
it([[should end up at top when "N" in the anchor]], function()
local top_test = function(anchor, p_width, p_height, max_columns, max_lines)
local pos = resolve.resolve_anchor_pos(anchor, p_width, p_height, max_columns, max_lines)
eq(1, pos[2] + math.floor((max_lines - p_height) / 2))
end
for _, s in ipairs(test_sizes) do
top_test("NW", unpack(s))
top_test("N", unpack(s))
top_test("NE", unpack(s))
end
end)
it([[should end up at left when "W" in the anchor]], function()
local left_test = function(anchor, p_width, p_height, max_columns, max_lines)
local pos = resolve.resolve_anchor_pos(anchor, p_width, p_height, max_columns, max_lines)
eq(1, pos[1] + math.floor((max_columns - p_width) / 2))
end
for _, s in ipairs(test_sizes) do
left_test("NW", unpack(s))
left_test("W", unpack(s))
left_test("SW", unpack(s))
end
end)
it([[should end up at bottom when "S" in the anchor]], function()
local bot_test = function(anchor, p_width, p_height, max_columns, max_lines)
local pos = resolve.resolve_anchor_pos(anchor, p_width, p_height, max_columns, max_lines)
eq(max_lines - 1, pos[2] + p_height + math.floor((max_lines - p_height) / 2))
end
for _, s in ipairs(test_sizes) do
bot_test("SW", unpack(s))
bot_test("S", unpack(s))
bot_test("SE", unpack(s))
end
end)
it([[should end up at right when "E" in the anchor]], function()
local right_test = function(anchor, p_width, p_height, max_columns, max_lines)
local pos = resolve.resolve_anchor_pos(anchor, p_width, p_height, max_columns, max_lines)
eq(max_columns - 1, pos[1] + p_width + math.floor((max_columns - p_width) / 2))
end
for _, s in ipairs(test_sizes) do
right_test("NE", unpack(s))
right_test("E", unpack(s))
right_test("SE", unpack(s))
end
end)
it([[should ignore casing of the anchor]], function()
local case_test = function(a1, a2, p_width, p_height, max_columns, max_lines)
local pos1 = resolve.resolve_anchor_pos(a1, p_width, p_height, max_columns, max_lines)
local pos2 = resolve.resolve_anchor_pos(a2, p_width, p_height, max_columns, max_lines)
eq(pos1, pos2)
end
for _, s in ipairs(test_sizes) do
case_test("ne", "NE", unpack(s))
case_test("w", "W", unpack(s))
case_test("sW", "sw", unpack(s))
case_test("cEnTeR", "CeNtEr", unpack(s))
end
end)
end)
end)

View File

@ -0,0 +1,143 @@
local p_scroller = require "telescope.pickers.scroller"
local log = require "telescope.log"
log.use_console = false
local eq = assert.are.same
describe("scroller", function()
local max_results = 10
describe("ascending cycle", function()
local cycle_scroller = p_scroller.create("cycle", "ascending")
it("should return values within the max results", function()
eq(5, cycle_scroller(max_results, max_results, 5))
end)
it("should return 0 at 0", function()
eq(0, cycle_scroller(max_results, max_results, 0))
end)
it("should cycle you to the top when you go below 0", function()
eq(max_results - 1, cycle_scroller(max_results, max_results, -1))
end)
it("should cycle you to 0 when you go past the results", function()
eq(0, cycle_scroller(max_results, max_results, max_results + 1))
end)
it("should cycle when current results is less than max_results", function()
eq(0, cycle_scroller(max_results, 5, 7))
end)
end)
describe("ascending limit", function()
local limit_scroller = p_scroller.create("limit", "ascending")
it("should return values within the max results", function()
eq(5, limit_scroller(max_results, max_results, 5))
end)
it("should return 0 at 0", function()
eq(0, limit_scroller(max_results, max_results, 0))
end)
it("should not cycle", function()
eq(0, limit_scroller(max_results, max_results, -1))
end)
it("should not cycle you to 0 when you go past the results", function()
eq(max_results - 1, limit_scroller(max_results, max_results, max_results + 1))
end)
it("should stay at current results when current results is less than max_results", function()
local current = 5
eq(current - 1, limit_scroller(max_results, current, 7))
end)
end)
describe("descending cycle", function()
local cycle_scroller = p_scroller.create("cycle", "descending")
it("should return values within the max results", function()
eq(5, cycle_scroller(max_results, max_results, 5))
end)
it("should return max_results - 1 at 0", function()
eq(0, cycle_scroller(max_results, max_results, 0))
end)
it("should cycle you to the bot when you go below 0", function()
eq(max_results - 1, cycle_scroller(max_results, max_results, -1))
end)
it("should cycle you to 0 when you go past the results", function()
eq(0, cycle_scroller(max_results, max_results, max_results + 1))
end)
it("should cycle when current results is less than max_results", function()
eq(9, cycle_scroller(max_results, 5, 4))
end)
end)
describe("descending limit", function()
local limit_scroller = p_scroller.create("limit", "descending")
it("should return values within the max results", function()
eq(5, limit_scroller(max_results, max_results, 5))
end)
it("should return 0 at 0", function()
eq(0, limit_scroller(max_results, max_results, 0))
end)
it("should not cycle", function()
eq(0, limit_scroller(max_results, max_results, -1))
end)
it("should not cycle you to 0 when you go past the results", function()
eq(max_results - 1, limit_scroller(max_results, max_results, max_results + 1))
end)
it("should stay at current results when current results is less than max_results", function()
local current = 5
eq(max_results - current, limit_scroller(max_results, current, 4))
end)
end)
describe("https://github.com/nvim-telescope/telescope.nvim/pull/293#issuecomment-751463224", function()
it("should handle having many more results than necessary", function()
local scroller = p_scroller.create("cycle", "descending")
-- 23 112 23
eq(0, scroller(23, 112, 23))
end)
end)
describe("should give top, middle and bottom index", function()
it("should handle ascending", function()
eq(0, p_scroller.top("ascending", 20, 1000))
eq(19, p_scroller.bottom("ascending", 20, 1000))
eq(0, p_scroller.top("ascending", 20, 10))
eq(9, p_scroller.bottom("ascending", 20, 10))
eq(5, p_scroller.middle("ascending", 11, 100))
eq(10, p_scroller.middle("ascending", 20, 100))
eq(12, p_scroller.middle("ascending", 25, 100))
end)
it("should handle descending", function()
eq(0, p_scroller.top("descending", 20, 1000))
eq(19, p_scroller.bottom("descending", 20, 1000))
eq(10, p_scroller.top("descending", 20, 10))
eq(19, p_scroller.bottom("descending", 20, 10))
eq(25, p_scroller.middle("descending", 30, 10))
eq(50, p_scroller.middle("descending", 60, 20))
eq(105, p_scroller.middle("descending", 120, 30))
end)
end)
end)

View File

@ -0,0 +1,84 @@
local sorters = require "telescope.sorters"
describe("get_substr_matcher", function()
local function with_smartcase(smartcase, case)
local original = vim.o.smartcase
vim.o.smartcase = smartcase
describe("scoring_function", function()
it(case.msg, function()
local matcher = sorters.get_substr_matcher()
assert.are.same(case.expected_score, matcher.scoring_function(_, case.prompt, _, case.entry))
end)
end)
describe("highlighter", function()
it("returns valid highlights", function()
local matcher = sorters.get_substr_matcher()
local highlights = matcher.highlighter(_, case.prompt, case.entry.ordinal)
table.sort(highlights, function(a, b)
return a.start < b.start
end)
assert.are.same(case.expected_highlights, highlights)
end)
end)
vim.o.smartcase = original
end
describe("when smartcase=OFF", function()
for _, case in ipairs {
{
msg = "doesn't match",
prompt = "abc def",
entry = { index = 3, ordinal = "abc d" },
expected_score = -1,
expected_highlights = { { start = 1, finish = 3 } },
},
{
msg = "matches with lower case letters only",
prompt = "abc def",
entry = { index = 3, ordinal = "abc def ghi" },
expected_score = 3,
expected_highlights = { { start = 1, finish = 3 }, { start = 5, finish = 7 } },
},
{
msg = "doesn't match with upper case letters",
prompt = "ABC def",
entry = { index = 3, ordinal = "ABC def ghi" },
expected_score = -1,
expected_highlights = { { start = 5, finish = 7 } },
},
} do
with_smartcase(false, case)
end
end)
describe("when smartcase=OFF", function()
for _, case in ipairs {
{
msg = "doesn't match",
prompt = "abc def",
entry = { index = 3, ordinal = "abc d" },
expected_score = -1,
expected_highlights = { { start = 1, finish = 3 } },
},
{
msg = "matches with lower case letters only",
prompt = "abc def",
entry = { index = 3, ordinal = "abc def ghi" },
expected_score = 3,
expected_highlights = { { start = 1, finish = 3 }, { start = 5, finish = 7 } },
},
{
msg = "matches with upper case letters",
prompt = "ABC def",
entry = { index = 3, ordinal = "ABC def ghi" },
expected_score = 3,
expected_highlights = { { start = 1, finish = 3 }, { start = 5, finish = 7 } },
},
} do
with_smartcase(true, case)
end
end)
end)

View File

@ -0,0 +1,218 @@
local picker = require "telescope.pickers"
local Path = require "plenary.path"
local eq = assert.are.same
local function new_path(unix_path)
return Path:new(unpack(vim.split(unix_path, "/"))).filename
end
describe("telescope", function()
describe("Picker", function()
describe("window_dimensions", function()
it("", function()
assert(true)
end)
end)
describe("attach_mappings", function()
local new_picker = function(a, b)
a.finder = true
return picker.new(a, b)
end
it("should allow for passing in a function", function()
local p = new_picker({}, {
attach_mappings = function()
return 1
end,
})
eq(1, p.attach_mappings())
end)
it("should override an attach mappings passed in by opts", function()
local called_order = {}
local p = new_picker({
attach_mappings = function()
table.insert(called_order, "opts")
end,
}, {
attach_mappings = function()
table.insert(called_order, "default")
end,
})
p.attach_mappings()
eq({ "default", "opts" }, called_order)
end)
end)
end)
describe("Sorters", function()
describe("generic_fuzzy_sorter", function()
it("sort matches well", function()
local sorter = require("telescope.sorters").get_generic_fuzzy_sorter()
local exact_match = sorter:score("hello", { ordinal = "hello" })
local no_match = sorter:score("abcdef", { ordinal = "ghijkl" })
local ok_match = sorter:score("abcdef", { ordinal = "ab" })
assert(exact_match < no_match, "exact match better than no match")
assert(exact_match < ok_match, "exact match better than ok match")
assert(ok_match < no_match, "ok match better than no match")
end)
it("sorts multiple finds better", function()
local sorter = require("telescope.sorters").get_generic_fuzzy_sorter()
local multi_match = sorter:score("generics", "exercises/generics/generics2.rs")
local one_match = sorter:score("abcdef", "exercises/generics/README.md")
-- assert(multi_match < one_match)
end)
end)
describe("fuzzy_file", function()
it("sort matches well", function()
local sorter = require("telescope.sorters").get_fuzzy_file()
local exact_match = sorter:score("abcdef", { ordinal = "abcdef" })
local no_match = sorter:score("abcdef", { ordinal = "ghijkl" })
local ok_match = sorter:score("abcdef", { ordinal = "ab" })
assert(exact_match < no_match, string.format("Exact match better than no match: %s %s", exact_match, no_match))
assert(exact_match < ok_match, string.format("Exact match better than OK match: %s %s", exact_match, ok_match))
assert(ok_match < no_match, "OK match better than no match")
end)
it("sorts matches after last os sep better", function()
local sorter = require("telescope.sorters").get_fuzzy_file()
local better_match = sorter:score("aaa", { ordinal = new_path "bbb/aaa" })
local worse_match = sorter:score("aaa", { ordinal = new_path "aaa/bbb" })
assert(better_match < worse_match, "Final match should be stronger")
end)
pending("sorts multiple finds better", function()
local sorter = require("telescope.sorters").get_fuzzy_file()
local multi_match = sorter:score("generics", { ordinal = "exercises/generics/generics2.rs" })
local one_match = sorter:score("abcdef", { ordinal = "exercises/generics/README.md" })
assert(multi_match < one_match)
end)
end)
describe("fzy", function()
local sorter = require("telescope.sorters").get_fzy_sorter()
local function score(prompt, line)
line = new_path(line)
return sorter:score(prompt, { ordinal = line }, function(val)
return val
end, function()
return -1
end)
end
describe("matches", function()
it("exact matches", function()
assert.True(score("a", "a") >= 0)
assert.True(score("a.bb", "a.bb") >= 0)
end)
it("ignore case", function()
assert.True(score("AbB", "abb") >= 0)
assert.True(score("abb", "ABB") >= 0)
end)
it("partial matches", function()
assert.True(score("a", "ab") >= 0)
assert.True(score("a", "ba") >= 0)
assert.True(score("aba", "baabbaab") >= 0)
end)
it("with delimiters between", function()
assert.True(score("abc", "a|b|c") >= 0)
end)
it("with empty query", function()
assert.True(score("", "") >= 0)
assert.True(score("", "a") >= 0)
end)
it("rejects non-matches", function()
assert.True(score("a", "") < 0)
assert.True(score("a", "b") < 0)
assert.True(score("aa", "a") < 0)
assert.True(score("ba", "a") < 0)
assert.True(score("ab", "a") < 0)
end)
end)
describe("scoring", function()
it("prefers beginnings of words", function()
assert.True(score("amor", "app/models/order") < score("amor", "app/models/zrder"))
end)
it("prefers consecutive letters", function()
assert.True(score("amo", "app/models/foo") < score("amo", "app/m/foo"))
assert.True(score("erf", "perfect") < score("erf", "terrific"))
end)
it("prefers contiguous over letter following period", function()
assert.True(score("gemfil", "Gemfile") < score("gemfil", "Gemfile.lock"))
end)
it("prefers shorter matches", function()
assert.True(score("abce", "abcdef") < score("abce", "abc de"))
assert.True(score("abc", " a b c ") < score("abc", " a b c "))
assert.True(score("abc", " a b c ") < score("abc", " a b c "))
end)
it("prefers shorter candidates", function()
assert.True(score("test", "tests") < score("test", "testing"))
end)
it("prefers matches at the beginning", function()
assert.True(score("ab", "abbb") < score("ab", "babb"))
assert.True(score("test", "testing") < score("test", "/testing"))
end)
it("prefers matches at some locations", function()
assert.True(score("a", "/a") < score("a", "ba"))
assert.True(score("a", "bA") < score("a", "ba"))
assert.True(score("a", ".a") < score("a", "ba"))
end)
end)
local function positions(prompt, line)
return sorter:highlighter(prompt, new_path(line))
end
describe("positioning", function()
it("favors consecutive positions", function()
assert.same({ 1, 5, 6 }, positions("amo", "app/models/foo"))
end)
it("favors word beginnings", function()
assert.same({ 1, 5, 12, 13 }, positions("amor", "app/models/order"))
end)
it("works when there are no bonuses", function()
assert.same({ 2, 4 }, positions("as", "tags"))
assert.same({ 3, 8 }, positions("as", "examples.txt"))
end)
it("favors smaller groupings of positions", function()
assert.same({ 3, 5, 7 }, positions("abc", "a/a/b/c/c"))
assert.same({ 3, 5 }, positions("ab", "caacbbc"))
end)
it("handles exact matches", function()
assert.same({ 1, 2, 3 }, positions("foo", "foo"))
end)
it("ignores empty requests", function()
assert.same({}, positions("", ""))
assert.same({}, positions("", "foo"))
assert.same({}, positions("foo", ""))
end)
end)
end)
describe("layout_strategies", function()
describe("center", function()
it("should handle large terminals", function()
-- TODO: This could call layout_strategies.center w/ some weird edge case.
-- and then assert stuff about the dimensions.
end)
end)
end)
end)
end)

View File

@ -0,0 +1,309 @@
local Path = require "plenary.path"
local utils = require "telescope.utils"
local eq = assert.are.equal
describe("path_expand()", function()
it("removes trailing os_sep", function()
if utils.iswin then
eq([[C:\Users\a\b]], utils.path_expand [[C:\Users\a\b\]])
else
eq("/home/user", utils.path_expand "/home/user/")
end
end)
it("works with root dir", function()
if utils.iswin then
eq([[C:\]], utils.path_expand [[C:\]])
else
eq("/", utils.path_expand "/")
end
end)
it("works with ~", function()
eq(vim.loop.os_homedir() .. "/src/foo", utils.path_expand "~/src/foo")
end)
it("handles duplicate os_sep", function()
if utils.iswin then
eq([[C:\Users\a]], utils.path_expand [[C:\\\Users\\a]])
else
eq("/home/user", utils.path_expand "/home///user")
end
end)
it("preserves fake whitespace characters and whitespace", function()
local path_space = "/home/user/hello world"
eq(path_space, utils.path_expand(path_space))
local path_newline = [[/home/user/hello\nworld]]
eq(path_newline, utils.path_expand(path_newline))
end)
describe("early return for uri", function()
local uris = {
[[https://www.example.com/index.html]],
[[ftp://ftp.example.com/files/document.pdf]],
[[mailto:user@example.com]],
[[tel:+1234567890]],
[[file:///home/user/documents/report.docx]],
[[news:comp.lang.python]],
[[ldap://ldap.example.com:389/dc=example,dc=com]],
[[git://github.com/user/repo.git]],
[[steam://run/123456]],
[[magnet:?xt=urn:btih:6B4C3343E1C63A1BC36AEB8A3D1F52C4EDEEB096]],
}
for _, uri in ipairs(uris) do
it(uri, function()
eq(uri, utils.path_expand(uri))
end)
end
end)
end)
describe("is_uri", function()
describe("detects valid uris", function()
local uris = {
[[https://www.example.com/index.html]],
[[ftp://ftp.example.com/files/document.pdf]],
[[mailto:user@example.com]],
[[tel:+1234567890]],
[[file:///home/user/documents/report.docx]],
[[news:comp.lang.python]],
[[ldap://ldap.example.com:389/dc=example,dc=com]],
[[git://github.com/user/repo.git]],
[[steam://run/123456]],
[[magnet:?xt=urn:btih:6B4C3343E1C63A1BC36AEB8A3D1F52C4EDEEB096]],
}
for _, uri in ipairs(uris) do
it(uri, function()
assert.True(utils.is_uri(uri))
end)
end
end)
describe("detects invalid uris/paths", function()
local inputs = {
"hello",
"hello:",
"123",
"",
}
for _, input in ipairs(inputs) do
it(input, function()
assert.False(utils.is_uri(input))
end)
end
end)
describe("handles windows paths", function()
local paths = {
[[C:\Users\Usuario\Documents\archivo.txt]],
[[D:\Projects\project_folder\source_code.py]],
[[E:\Music\song.mp3]],
}
for _, uri in ipairs(paths) do
it(uri, function()
assert.False(utils.is_uri(uri))
end)
end
end)
describe("handles linux paths", function()
local paths = {
[[/home/usuario/documents/archivo.txt]],
[[/var/www/html/index.html]],
[[/mnt/backup/backup_file.tar.gz]],
}
for _, path in ipairs(paths) do
it(path, function()
assert.False(utils.is_uri(path))
end)
end
end)
describe("handles macos paths", function()
local paths = {
[[/Users/Usuario/Documents/archivo.txt]],
[[/Applications/App.app/Contents/MacOS/app_executable]],
[[/Volumes/ExternalDrive/Data/file.xlsx]],
}
for _, path in ipairs(paths) do
it(path, function()
assert.False(utils.is_uri(path))
end)
end
end)
end)
describe("__separates_file_path_location", function()
local suites = {
{
input = "file.txt:12:4",
file = "file.txt",
row = 12,
col = 4,
},
{
input = "file.txt:12",
file = "file.txt",
row = 12,
col = 0,
},
{
input = "file:12:4",
file = "file",
row = 12,
col = 4,
},
{
input = "file:12:",
file = "file",
row = 12,
col = 0,
},
{
input = "file:",
file = "file",
},
}
for _, suite in ipairs(suites) do
it("separtates file path for " .. suite.input, function()
local file, row, col = utils.__separate_file_path_location(suite.input)
eq(file, suite.file)
eq(row, suite.row)
eq(col, suite.col)
end)
end
end)
describe("transform_path", function()
local cwd = (function()
if utils.iswin then
return [[C:\Users\user\projects\telescope.nvim]]
else
return "/home/user/projects/telescope.nvim"
end
end)()
local function new_relpath(unix_path)
return Path:new(unpack(vim.split(unix_path, "/"))).filename
end
local function assert_path(path_display, path, expect)
local opts = { cwd = cwd, __length = 15 }
if type(path_display) == "string" then
opts.path_display = { path_display }
eq(expect, utils.transform_path(opts, path))
opts.path_display = { [path_display] = true }
eq(expect, utils.transform_path(opts, path))
elseif type(path_display) == "table" then
opts.path_display = path_display
eq(expect, utils.transform_path(opts, path))
elseif type(path_display) == "function" then
opts.path_display = path_display
eq(expect, utils.transform_path(opts, path))
elseif path_display == nil then
eq(expect, utils.transform_path(opts, path))
end
end
it("handles nil path", function()
assert_path(nil, nil, "")
end)
it("returns back uri", function()
local uri = [[https://www.example.com/index.html]]
assert_path(nil, uri, uri)
end)
it("handles 'hidden' path_display", function()
eq("", utils.transform_path({ cwd = cwd, path_display = "hidden" }, "foobar"))
assert_path("hidden", "foobar", "")
end)
it("returns relative path for default opts", function()
local relative = Path:new { "lua", "telescope", "init.lua" }
local absolute = Path:new { cwd, relative }
assert_path(nil, absolute.filename, relative.filename)
assert_path(nil, relative.filename, relative.filename)
end)
it("handles 'tail' path_display", function()
local path = new_relpath "lua/telescope/init.lua"
assert_path("tail", path, "init.lua")
end)
it("handles 'smart' path_display", function()
local path1 = new_relpath "lua/telescope/init.lua"
local path2 = new_relpath "lua/telescope/finders.lua"
local path3 = new_relpath "lua/telescope/finders/async_job_finder.lua"
local path4 = new_relpath "plugin/telescope.lua"
assert_path("smart", path1, path1)
assert_path("smart", path2, new_relpath "../telescope/finders.lua")
assert_path("smart", path3, new_relpath "../telescope/finders/async_job_finder.lua")
assert_path("smart", path4, path4)
end)
it("handles 'absolute' path_display", function()
local relative = Path:new { "lua", "telescope", "init.lua" }
local absolute = Path:new { cwd, relative }
-- TODO: feels like 'absolute' should turn relative paths to absolute
-- assert_path("absolute", relative.filename, absolute.filename)
assert_path("absolute", absolute.filename, absolute.filename)
end)
it("handles default 'shorten' path_display", function()
assert_path("shorten", new_relpath "lua/telescope/init.lua", new_relpath "l/t/init.lua")
end)
it("handles 'shorten' with number", function()
assert_path({ shorten = 2 }, new_relpath "lua/telescope/init.lua", new_relpath "lu/te/init.lua")
end)
it("handles 'shorten' with option table", function()
assert_path({ shorten = { len = 2 } }, new_relpath "lua/telescope/init.lua", new_relpath "lu/te/init.lua")
assert_path(
{ shorten = { len = 2, exclude = { 1, 3, -1 } } },
new_relpath "lua/telescope/builtin/init.lua",
new_relpath "lua/te/builtin/init.lua"
)
end)
it("handles default 'truncate' path_display", function()
assert_path({ "truncate" }, new_relpath "lua/telescope/init.lua", new_relpath "…scope/init.lua")
end)
it("handles 'filename_first' path_display", function()
assert_path("filename_first", new_relpath "init.lua", new_relpath "init.lua")
assert_path("filename_first", new_relpath "lua/telescope/init.lua", new_relpath "init.lua lua/telescope")
end)
it("handles 'filename_first' path_display with the option to reverse directories", function()
assert_path({ filename_first = { reverse_directories = true } }, new_relpath "init.lua", new_relpath "init.lua")
assert_path(
{ filename_first = { reverse_directories = true } },
new_relpath "lua/telescope/init.lua",
new_relpath "init.lua telescope/lua"
)
assert_path({ filename_first = { reverse_directories = false } }, new_relpath "init.lua", new_relpath "init.lua")
assert_path(
{ filename_first = { reverse_directories = false } },
new_relpath "lua/telescope/init.lua",
new_relpath "init.lua lua/telescope"
)
end)
it("handles function passed to path_display", function()
assert_path(function(_, path)
return string.gsub(path, "^doc", "d")
end, new_relpath "doc/mydoc.md", new_relpath "d/mydoc.md")
end)
end)

View File

@ -0,0 +1,87 @@
local finders = require "telescope.finders"
local make_entry = require "telescope.make_entry"
local previewers = require "telescope.previewers"
local pickers = require "telescope.pickers"
local sorters = require "telescope.sorters"
local utils = require "telescope.utils"
local helpers = {}
-- TODO: We should do something with builtins to get those easily.
helpers.auto_find_files = function(opts)
opts = opts or {}
opts.prompt_prefix = ""
local find_command = opts.find_command
if not find_command then
if 1 == vim.fn.executable "fd" then
find_command = { "fd", "--type", "f" }
elseif 1 == vim.fn.executable "fdfind" then
find_command = { "fdfind", "--type", "f" }
elseif 1 == vim.fn.executable "rg" then
find_command = { "rg", "--files" }
end
end
if opts.cwd then
opts.cwd = utils.path_expand(opts.cwd)
end
opts.entry_maker = opts.entry_maker or make_entry.gen_from_file(opts)
local p = pickers.new(opts, {
prompt = "Find Files",
finder = finders.new_oneshot_job(find_command, opts),
previewer = previewers.cat.new(opts),
sorter = sorters.get_fuzzy_file(),
track = true,
})
local count = 0
p:register_completion_callback(function(s)
print(
count,
vim.inspect(s.stats, {
process = function(item)
if type(item) == "string" and item:sub(1, 1) == "_" then
return nil
end
return item
end,
})
)
count = count + 1
end)
local feed = function(text, feed_opts)
feed_opts = feed_opts or "n"
vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(text, true, false, true), feed_opts, true)
end
p:register_completion_callback(coroutine.wrap(function()
local input = opts.input
for i = 1, #input do
feed(input:sub(i, i))
coroutine.yield()
end
vim.wait(300, function() end)
feed("<CR>", "")
vim.defer_fn(function()
PASSED = opts.condition()
COMPLETED = true
end, 500)
coroutine.yield()
end))
p:find()
end
return helpers

View File

@ -0,0 +1,8 @@
local helper = require "telescope.testharness.helpers"
local runner = require "telescope.testharness.runner"
runner.picker("find_files", "README.md", {
post_close = {
{ "README.md", helper.get_file },
},
})

View File

@ -0,0 +1,12 @@
local tester = require "telescope.testharness"
local helper = require "telescope.testharness.helpers"
local runner = require "telescope.testharness.runner"
runner.picker("find_files", "telescope<c-n>", {
post_close = {
tester.not_ { "plugin/telescope.vim", helper.get_file },
},
}, {
sorting_strategy = "descending",
scroll_strategy = "cycle",
})