diff options
Diffstat (limited to 'loaders/lua5.1/peas-lua-internal.lua')
-rw-r--r-- | loaders/lua5.1/peas-lua-internal.lua | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/loaders/lua5.1/peas-lua-internal.lua b/loaders/lua5.1/peas-lua-internal.lua new file mode 100644 index 0000000..8f4e60d --- /dev/null +++ b/loaders/lua5.1/peas-lua-internal.lua @@ -0,0 +1,162 @@ +-- +-- Copyright (C) 2015 - Garrett Regier +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU Library General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU Library General Public License for more details. +-- +-- You should have received a copy of the GNU Library General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street, Fifth Floor, +-- Boston, MA 02110-1301, USA. + +local debug = require 'debug' +local package = require 'package' + +local lgi = require 'lgi' +local GObject = lgi.GObject +local Peas = lgi.Peas + + +local Hooks = {} +Hooks.__index = Hooks + +function Hooks.new() + local self = { priv = {} } + setmetatable(self, Hooks) + + self.priv.module_cache = {} + self.priv.extension_cache = {} + return self +end + +function Hooks:failed(msg) + -- This is implemented by the plugin loader + error('Hooks:failed() was not implemented!') +end + +local function add_package_path(package_path) + local paths = (';%s/?.lua;%s/?/init.lua'):format(package_path, + package_path) + + if not package.path:find(paths, 1, true) then + package.path = package.path .. paths + end +end + +local function format_plugin_exception(err) + -- Format the error even if given a userdata + local formatted = debug.traceback(tostring(err), 2) + + if type(formatted) ~= 'string' then + return formatted + end + + -- Remove all mentions of this file + local lines = {} + for line in formatted:gmatch('([^\n]+\n?)') do + if line:find('peas-lua-internal.lua', 1, true) then + break + end + + table.insert(lines, line) + end + + return table.concat(lines, '') +end + +function Hooks:load(filename, module_dir, module_name) + local module = self.priv.module_cache[filename] + + if module ~= nil then + return module ~= false + end + + if package.loaded[module_name] ~= nil then + local msg = ("Error loading plugin '%s': " .. + "module name '%s' has already been used") + self:failed(msg:format(filename, module_name)) + end + + add_package_path(module_dir) + + local success, result = xpcall(function() + return require(module_name) + end, format_plugin_exception) + + if not success then + local msg = "Error loading plugin '%s':\n%s" + self:failed(msg:format(module_name, tostring(result))) + end + + if type(result) ~= 'table' then + self.priv.module_cache[filename] = false + + local msg = "Error loading plugin '%s': expected table, got: %s (%s)" + self:failed(msg:format(module_name, type(result), tostring(result))) + end + + self.priv.module_cache[filename] = result + self.priv.extension_cache[filename] = {} + return true +end + +function Hooks:find_extension_type(filename, gtype) + local module_gtypes = self.priv.extension_cache[filename] + local extension_type = module_gtypes[gtype] + + if extension_type ~= nil then + if extension_type == false then + return nil + end + + return extension_type + end + + for _, value in pairs(self.priv.module_cache[filename]) do + local value_gtype = value._gtype + + if value_gtype ~= nil then + if GObject.type_is_a(value_gtype, gtype) then + module_gtypes[gtype] = value_gtype + return value_gtype + end + end + end + + module_gtypes[gtype] = false + return nil +end + +local function check_native(native, wrapped, typename) + local msg = ('Invalid wrapper for %s: %s'):format(typename, + tostring(wrapped)) + + -- Cannot compare userdata directly! + assert(wrapped ~= nil, msg) + assert(tostring(native) == tostring(wrapped._native), msg) +end + +function Hooks:setup_extension(exten, info) + local wrapped_exten = GObject.Object(exten, false) + check_native(exten, wrapped_exten, 'extension') + + local wrapped_info = Peas.PluginInfo(info, false) + check_native(info, wrapped_info, 'PeasPluginInfo') + + wrapped_exten.priv.plugin_info = wrapped_info +end + +function Hooks:garbage_collect() + collectgarbage() +end + +return Hooks.new() + +-- ex:set ts=4 et sw=4 ai: |