Files
mpv-config/scripts/file-browser/modules/addons/find.lua
T
2026-03-27 07:06:16 +01:00

124 lines
3.4 KiB
Lua

--[[
This file is an internal file-browser addon.
It should not be imported like a normal module.
Allows searching the current directory.
]]--
local msg = require "mp.msg"
local fb = require "file-browser"
local input_loaded, input = pcall(require, "mp.input")
local user_input_loaded, user_input = pcall(require, "user-input-module")
---@type ParserConfig
local find = {
api_version = "1.3.0"
}
---@type thread|nil
local latest_coroutine = nil
---@type State
local global_fb_state = getmetatable(fb.get_state()).__original
---@param name string
---@param query string
---@return boolean
local function compare(name, query)
if name:find(query) then return true end
if name:lower():find(query) then return true end
if name:upper():find(query) then return true end
return false
end
---@async
---@param key Keybind
---@param state State
---@param co thread
---@return boolean?
local function main(key, state, co)
if not state.list then return false end
---@type string
local text
if key.name == "find/find" then text = "Find: enter search string"
else text = "Find: enter advanced search string" end
if input_loaded then
input.get({
prompt = text .. "\n>",
id = "file-browser/find",
submit = fb.coroutine.callback(),
})
elseif user_input_loaded then
user_input.get_user_input( fb.coroutine.callback(), { text = text, id = "find", replace = true } )
end
local query, error = coroutine.yield()
if input_loaded then input.terminate() end
if not query then return msg.debug(error) end
-- allow the directory to be changed before this point
local list = fb.get_list()
local parse_id = global_fb_state.co
if key.name == "find/find" then
query = fb.pattern_escape(query)
end
local results = {}
for index, item in ipairs(list) do
if compare(item.label or item.name, query) then
table.insert(results, index)
end
end
if (#results < 1) then
msg.warn("No matching items for '"..query.."'")
return
end
--keep cycling through the search results if any are found
--putting this into a separate coroutine removes any passthrough ambiguity
--the final return statement should return to `step_find` not any other function
---@async
fb.coroutine.run(function()
latest_coroutine = coroutine.running()
---@type number
local rindex = 1
while (true) do
if rindex == 0 then rindex = #results
elseif rindex == #results + 1 then rindex = 1 end
fb.set_selected_index(results[rindex])
local direction = coroutine.yield(true) --[[@as number]]
rindex = rindex + direction
if parse_id ~= global_fb_state.co then
latest_coroutine = nil
return
end
end
end)
end
local function step_find(key)
if not latest_coroutine then return false end
---@type number
local direction = 0
if key.name == "find/next" then direction = 1
elseif key.name == "find/prev" then direction = -1 end
return fb.coroutine.resume_err(latest_coroutine, direction)
end
find.keybinds = {
{"Ctrl+f", "find", main, {}},
{"Ctrl+F", "find_advanced", main, {}},
{"n", "next", step_find, {}},
{"N", "prev", step_find, {}},
}
return find