local dbg = require 'std.dbg' local proxy_cache = {} local function printStackTrace() local level = 2 while true do local info = debug.getinfo( level, 'nSl' ) if not info then break end dbg( '%s:%d in function %s', info.short_src, info.currentline, info.name or '' ) level = level + 1 end end ---Require one or more modules gracefully. ---Calls `require` in protected mode. ---@example --- local want = require 'std.prequire' --- prequire 'foo'.setup {} --- prequire('foo', 'bar', function(foo, bar) --- foo.setup{arg = bar} --- end) ---@see pcall ---@param ... ... or more module names. The last argument may optionally be a function, consuming all modules ---previously given. ---@return any module The first module, when loaded successfully. Otherwise a proxy object, that does nothing when called or ---indexed into. This prevents nil dereferencing errors when using the pattern `require('std.prequire')('this mod does ---not exist').setup()`. return function ( ... ) local args = { ..., } local mods = {} local first_mod for _, arg in ipairs( args ) do if type( arg ) == 'function' then arg( unpack( mods ) ) break end local ok, mod = pcall( require, arg ) if ok then if not first_mod then first_mod = mod end table.insert( mods, mod ) else printStackTrace() vim.notify_once( string.format( 'Prequire is missing a module: %s', arg ), vim.log.levels.WARN ) if not proxy_cache[arg] then proxy_cache[arg] = setmetatable( {}, { __call = function () return proxy_cache[arg] end, __index = function () return proxy_cache[arg] end, } ) end return proxy_cache[arg] end end return first_mod end