Files
deb-lite-xl/data/core/command.lua
T
Guldoman cf29a6a45f Allow command predicates to manage parameters passed to the commands
When a command is performed with parameters, those are now passed to the
predicate.
The predicate can then return, after the validity boolean, any other
value that will then be passed to the actual command.
If the predicate only returns the validity boolean, the original
parameters are passed through to the actual command.

This allows predicates to manipulate the received parameters, and allows
them to pass the result of an expensive computation to the actual
command, which won't have to recalculate it.

String and table predicates will now also return `core.active_view`.
2022-08-16 22:13:16 +02:00

113 lines
2.9 KiB
Lua

local core = require "core"
local command = {}
command.map = {}
local always_true = function() return true end
---Used iternally by command.add, statusview, and contextmenu to generate a
---function with a condition to evaluate returning the boolean result of this
---evaluation.
---
---If a string predicate is given it is treated as a require import that should
---return a valid object which is checked against the current active view,
---eg: "core.docview" will match any view that inherits from DocView. Appending
---a `!` at the end of the string means we want to match the given object
---from the import strcitly eg: "core.docview!" only DocView is matched.
---A function that returns a boolean can be used instead to perform a custom
---evaluation, setting to nil means always evaluates to true.
---
---@param predicate string | table | function
---@return function
function command.generate_predicate(predicate)
predicate = predicate or always_true
local strict = false
if type(predicate) == "string" then
if predicate:match("!$") then
strict = true
predicate = predicate:gsub("!$", "")
end
predicate = require(predicate)
end
if type(predicate) == "table" then
local class = predicate
if not strict then
predicate = function(...) return core.active_view:extends(class), core.active_view, ... end
else
predicate = function(...) return core.active_view:is(class), core.active_view, ... end
end
end
return predicate
end
function command.add(predicate, map)
predicate = command.generate_predicate(predicate)
for name, fn in pairs(map) do
assert(not command.map[name], "command already exists: " .. name)
command.map[name] = { predicate = predicate, perform = fn }
end
end
local function capitalize_first(str)
return str:sub(1, 1):upper() .. str:sub(2)
end
function command.prettify_name(name)
return name:gsub(":", ": "):gsub("-", " "):gsub("%S+", capitalize_first)
end
function command.get_all_valid()
local res = {}
for name, cmd in pairs(command.map) do
if cmd.predicate() then
table.insert(res, name)
end
end
return res
end
function command.is_valid(name, ...)
return command.map[name] and command.map[name].predicate(...)
end
local function perform(name, ...)
local cmd = command.map[name]
if not cmd then return false end
local res = { cmd.predicate(...) }
if table.remove(res, 1) then
if #res > 0 then
-- send values returned from predicate
cmd.perform(table.unpack(res))
else
-- send original parameters
cmd.perform(...)
end
return true
end
return false
end
function command.perform(...)
local ok, res = core.try(perform, ...)
return not ok or res
end
function command.add_defaults()
local reg = {
"core", "root", "command", "doc", "findreplace",
"files", "drawwhitespace", "dialog", "log", "statusbar"
}
for _, name in ipairs(reg) do
require("core.commands." .. name)
end
end
return command