dotfiles/mpv/scripts/pickshader.lua
2025-03-24 04:38:41 +11:00

200 lines
5.6 KiB
Lua
Executable file

-- This script provides an easy interface for setting/appending to
-- --glsl-shaders.
--
-- Ctrl+r is the default keybind, but if desired this can be changed in
-- input.conf, for example:
--
-- Ctrl+t script-binding pickshader
--
-- The interface is similar to ^R from Unix shells. Once it's open, simply type
-- a query to narrow down the results.
--
-- These keybinds can be used within the interface:
--
-- ESC or Ctrl+c will close the interface
--
-- ENTER will ADD the selected shader to --glsl-shaders
--
-- Ctrl+ENTER will SET --glsl-shaders to the selected shader
--
-- UP, DOWN, Ctrl+n, Ctrl+p will move the cursor up/down
--
-- This script assumes shaders are installed under ~~/shaders/ (~~ being the
-- directory where mpv.conf is). If they aren't located there, either relocate
-- them or make a symlink.
local utils = require 'mp.utils'
local options = require 'mp.options'
-- If you really don't want to use ~~/shaders for some reason this can be
-- changed in ~~/script-opts/pickshader.conf
local o = {
shader_dir = "~~/shaders"
}
options.read_options(o)
local function recursive_ls(dir)
local result = {}
local ls = utils.readdir(dir)
for i,child in pairs(ls) do
local info = utils.file_info(dir.."/"..child);
if info.is_dir then
for _,grandchild in pairs(recursive_ls(dir.."/"..child)) do
result[#result + 1] = grandchild
end
elseif string.match(child, "%.glsl$") or string.match(child, "%.hook$") then
result[#result + 1] = dir.."/"..child
end
end
return result
end
shaders = nil
local function init_shaders()
if shaders ~= nil then
return
end
local shader_dir = mp.command_native({"expand-path", o.shader_dir})
shaders = recursive_ls(shader_dir)
for i,shader in pairs(shaders) do -- basename
shaders[i] = shaders[i]:sub(shader_dir:len() + 2)
end
table.sort(shaders)
end
grepped_arr = {}
grepped_pattern = ""
cursor = 1
local function draw()
if current_pattern == "" then
grepped_arr = shaders
grepped_pattern = current_pattern
elseif grepped_pattern ~= current_pattern then
grepped_arr = {}
grepped_pattern = current_pattern
cursor = 1
for i,shader in pairs(shaders) do
-- XXX maybe split by space and interpret each part as a separate pattern
local e, match = pcall(string.match, shader:lower(), current_pattern:lower())
if match and e then
grepped_arr[#grepped_arr + 1] = shader
elseif not e then
break
end
end
end
local results_str = ""
for i,shader in pairs(grepped_arr) do
if i == cursor then
results_str = results_str .. "\n> " .. shader
elseif math.abs(i - cursor) < 3 then
results_str = results_str .. "\n" .. shader
end
end
results_str = results_str:sub(2) -- trim leading newline
-- lazy underlining, lua doesn't support case insensitive matching
if current_pattern ~= "" then
local e, underlined = pcall(string.gsub, results_str, current_pattern, "{\\u1}%0{\\u0}")
if e then results_str = underlined end
local e, underlined = pcall(string.gsub, results_str, current_pattern:upper(), "{\\u1}%0{\\u0}")
if e then results_str = underlined end
end
if results_str == "" then
results_str = "> " .. current_pattern
end
overlay.data = results_str
overlay:update()
end
local function incr_cursor()
cursor = math.min(cursor + 1, #grepped_arr)
draw()
end
local function decr_cursor()
cursor = math.max(cursor - 1, 1)
draw()
end
local function mode_off()
mode_on = false
grepped_arr = {}
cursor = 1
grepped_pattern = ""
current_pattern = ""
overlay.data = ""
overlay:remove()
overlay:update()
local binds = { "mode_off1", "mode_off2", "mode_off3", "incr1", "decr1", "incr2", "decr2", "backspace", "clear", "pick_add", "pick_set", "handle_input" }
for k,v in pairs(binds) do
mp.remove_key_binding(v)
end
end
local function backspace()
current_pattern = current_pattern:sub(1, -2)
draw()
end
local function clear()
current_pattern = ""
draw()
end
local function pick(op)
local shader = grepped_arr[cursor]
if op == nil then op = "add" end
mp.commandv("change-list", "glsl-shaders", op, o.shader_dir.."/"..shader)
mode_off()
mp.commandv("show-text", op.." "..shader)
end
current_pattern = ""
local function handle_input(input)
if input.event == "press"
or input.event == "down"
or input.event == "repeat" then
current_pattern = current_pattern .. input.key_text
draw()
end
end
mode_on = false
local function pickshader()
if not mode_on then
mode_on = true
overlay = mp.create_osd_overlay("ass-events")
init_shaders()
mp.add_forced_key_binding("ESC", "mode_off1", mode_off)
mp.add_forced_key_binding("Ctrl+[", "mode_off2", mode_off)
mp.add_forced_key_binding("Ctrl+c", "mode_off3", mode_off)
mp.add_forced_key_binding("Ctrl+n", "incr1", incr_cursor,
{ repeatable = true })
mp.add_forced_key_binding("Ctrl+p", "decr1", decr_cursor,
{ repeatable = true })
mp.add_forced_key_binding("DOWN", "incr2", incr_cursor,
{ repeatable = true })
mp.add_forced_key_binding("UP", "decr2", decr_cursor,
{ repeatable = true })
mp.add_forced_key_binding("BS", "backspace", backspace,
{ repeatable = true })
mp.add_forced_key_binding("Ctrl+u", "clear", clear)
mp.add_forced_key_binding("ENTER", "pick_add", pick)
mp.add_forced_key_binding("Ctrl+ENTER", "pick_set", function() pick("set") end)
mp.add_forced_key_binding("any_unicode", "handle_input", handle_input,
{ repeatable = true, complex = true })
draw()
else
incr_cursor()
end
end
mp.add_key_binding("Ctrl+r", "pickshader", pickshader,
{ repeatable = true })