From fd7e224c16fa53a04084bff1009cea1e4c6d30b1 Mon Sep 17 00:00:00 2001 From: poire-z Date: Wed, 22 May 2024 21:25:26 +0200 Subject: [PATCH] userpatch: add a few helpers that can be used in userpatches Make the few tricks we discovered readily available, which should make user patches simpler. --- frontend/userpatch.lua | 69 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/frontend/userpatch.lua b/frontend/userpatch.lua index c405dc0ac..6d992eff8 100644 --- a/frontend/userpatch.lua +++ b/frontend/userpatch.lua @@ -103,4 +103,73 @@ function userpatch.applyPatches(priority) end end + +-- Helper functions that can be used in userpatches + +--[[ +-- For replacing/extending some object method, one just has to do in his user patch: + +local TheModule = require("themodule") +local orig_TheModule_theMethod = TheModule.theMethod +TheModule.theMethod = function(self, arg1, arg2) + -- do your stuff here + -- and call the original method if needed + return orig_TheModule_theMethod(self, arg1, arg2) +end + +-- (Tried to make use of util.wrapMethod(), but it doesn't make anything simpler +-- than doing it manually.) +]]-- + +-- Module local variables aren't directly reachable when we require() a module. +-- The only way to possibly reach them is thru an exported function that uses +-- these local variables, by looking at its referenced upvalues +function userpatch.getUpValue(func_obj, up_value_name) + local upvalue + local up_value_idx = 1 + while true do + local name, value = debug.getupvalue(func_obj, up_value_idx) + if not name then break end + if name == up_value_name then + upvalue = value + break + end + up_value_idx = up_value_idx + 1 + end + return upvalue, up_value_idx +end + +-- Replace an upvalue: func_obj should be the same as given to userpatch.getUpValue(), +-- and up_value_idx the one we got when calling it +function userpatch.replaceUpValue(func_obj, up_value_idx, replacement_obj) + debug.setupvalue(func_obj, up_value_idx, replacement_obj) +end + +-- On each new Reader/FileManager, plugins are dofile()d, and then +-- instantiated through createPluginInstance. We need to catch and +-- patch them each time they are instantiated. +local orig_PluginLoader_createPluginInstance +local patch_plugin_funcs = {} +function userpatch.registerPatchPluginFunc(plugin_name, patch_func) + if not orig_PluginLoader_createPluginInstance then + local PluginLoader = require("pluginloader") + orig_PluginLoader_createPluginInstance = PluginLoader.createPluginInstance + PluginLoader.createPluginInstance = function(this, plugin, attr) + local ok, plugin_or_err = orig_PluginLoader_createPluginInstance(this, plugin, attr) + if ok and patch_plugin_funcs[plugin.name] then + for _, patchfunc in ipairs(patch_plugin_funcs[plugin.name]) do + patchfunc(plugin) + logger.dbg("userpatch applied to plugin", plugin.name) + end + end + return ok, plugin_or_err + end + end + if not patch_plugin_funcs[plugin_name] then + patch_plugin_funcs[plugin_name] = {} -- array (to allow more than one patch_func per plugin) + end + table.insert(patch_plugin_funcs[plugin_name], patch_func) + logger.dbg("userpatch registered for plugin", plugin_name) +end + return userpatch