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`.
113 lines
2.9 KiB
Lua
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
|