console.lua: implement exact matching
Allow matching items exactly instead of fuzzily when prefixing the search with ' (like in fzf) or with --script-opt=console-exact_match=yes. This is mainly useful to filter history entries chronologically. You can also specify multiple search terms delimited by spaces. But ' makes every term an exact match, unlike fzf where you need to place it before every word, since we can't hook into fzy's algorithm. Closes #14587.
This commit is contained in:
1 parent
bff0d59cbe
commit
4cb5f7aa1f
4 files changed
+65
-4
No files matched your search
@@ -0,0 +1 @@
|
||||
add `console-exact_match` script-opt
|
||||
@@ -199,6 +199,12 @@ Configurable Options
|
||||
|
||||
The color of characters that match the searched string.
|
||||
|
||||
``exact_match``
|
||||
Default: no
|
||||
|
||||
Whether to match menu search queries exactly instead of fuzzily. Without
|
||||
this option, prefixing queries with ``'`` enables exact matching.
|
||||
|
||||
``case_sensitive``
|
||||
Default: no on Windows, yes on other platforms.
|
||||
|
||||
|
||||
+8
-3
@@ -10,9 +10,8 @@ console and do operations on the selected item. It can be disabled using the
|
||||
Key bindings
|
||||
------------
|
||||
|
||||
When using ``mp.input.select``, typing printable characters does a fuzzy search
|
||||
of the presented items, and key bindings listed in `CONSOLE`_ are extended with
|
||||
the following:
|
||||
When using ``mp.input.select``, the key bindings listed in `CONSOLE`_ are
|
||||
extended with the following:
|
||||
|
||||
ENTER, Ctrl+j and Ctrl+m
|
||||
Confirm the selection of the highlighted item.
|
||||
@@ -39,6 +38,12 @@ WHEEL_UP
|
||||
WHEEL_DOWN
|
||||
Scroll down.
|
||||
|
||||
Typing printable characters does a fuzzy search of the presented items.
|
||||
|
||||
If the query starts with ``'``, only exact matches are filtered. You can also
|
||||
specify multiple search terms delimited by spaces, and only items matching all
|
||||
terms are filtered.
|
||||
|
||||
Script bindings
|
||||
---------------
|
||||
|
||||
|
||||
+50
-1
@@ -43,6 +43,7 @@ local opts = {
|
||||
selected_color = "#222222",
|
||||
selected_back_color = "#FFFFFF",
|
||||
match_color = "#0088FF",
|
||||
exact_match = false,
|
||||
case_sensitive = platform ~= "windows" and true or false,
|
||||
history_dedup = true,
|
||||
font_hw_ratio = "auto",
|
||||
@@ -464,6 +465,54 @@ local function fuzzy_find(needle, haystacks, case_sensitive)
|
||||
return result
|
||||
end
|
||||
|
||||
local function find_matches(needle, haystacks)
|
||||
if not opts.exact_match and needle:sub(1, 1) ~= "'" then
|
||||
return fuzzy_find(needle, haystacks)
|
||||
end
|
||||
|
||||
if not opts.exact_match then
|
||||
needle = needle:sub(2)
|
||||
end
|
||||
|
||||
if not opts.case_sensitive then
|
||||
needle = needle:lower()
|
||||
end
|
||||
|
||||
local result = {}
|
||||
local needle_words = {}
|
||||
|
||||
for word in needle:gmatch("%S+") do
|
||||
needle_words[#needle_words + 1] = word
|
||||
end
|
||||
|
||||
for i, haystack in ipairs(haystacks) do
|
||||
if not opts.case_sensitive then
|
||||
haystack = haystack:lower()
|
||||
end
|
||||
|
||||
local matching_positions = {}
|
||||
for _, word in pairs(needle_words) do
|
||||
local start, e = haystack:find(word, 1, true)
|
||||
|
||||
if start then
|
||||
for j = start, e do
|
||||
matching_positions[#matching_positions + 1] = j
|
||||
end
|
||||
else
|
||||
matching_positions = nil
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if matching_positions then
|
||||
table.sort(matching_positions)
|
||||
result[#result + 1] = { i, matching_positions }
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
local function get_matches_to_print(terminal)
|
||||
if not selectable_items or selected_match == 0 then
|
||||
return {}
|
||||
@@ -886,7 +935,7 @@ local function handle_edit()
|
||||
end
|
||||
|
||||
matches = {}
|
||||
for i, match in ipairs(fuzzy_find(line, selectable_items)) do
|
||||
for i, match in ipairs(find_matches(line, selectable_items)) do
|
||||
matches[i] = {
|
||||
index = match[1],
|
||||
text = selectable_items[match[1]],
|
||||
|
||||
Reference in new issue
Block a user