Widget Loading¶
Bootstrap begins in runtime.lua.
Flow¶
- resolve widget directory
- load runtime modules
- call
loader.load_widgets(...)
Before loader.lua executes widget entrypoints, it prepends these user-library paths to Lua's standard module search path:
<widgets_dir>/lib/?.lua
<widgets_dir>/lib/?/init.lua
Inside loader.lua:
- configure the widget
lib/module paths - create an isolated environment per top-level widget file
- inject the scoped
easybarAPI - execute the widget file
Important details¶
- each widget has isolated defaults
- all widgets share one runtime registry
- only regular top-level
*.luafiles are loaded as widget entrypoints - modules below
lib/run only through standardrequire(...)calls - required modules use Lua's process-wide
package.loadedcache - reload is a full reset
- widget environments fall back to
_G, so isolation is about local state, not security
Trust model¶
EasyBar widget files are trusted local scripts.
loader.lua gives each file its own table so widget-local variables and defaults do not leak into
other widget files, but that table uses _G as a fallback. In practice that means widgets still
have broad access to standard Lua globals and whatever the host process exposes through the normal
Lua environment.
This is not a sandbox. Do not treat third-party widget files as untrusted code.
Public widget API shape¶
Lua widget authors use node handles.
easybar.add(...) creates one node and returns its handle:
local clock = easybar.add(easybar.kind.item, "clock", {
position = "right",
order = 10,
label = os.date("%H:%M"),
})
The returned handle owns node operations:
node.idnode.namenode:set(props)node:get()node:remove()node:subscribe(events, handler)
Example:
clock:subscribe(easybar.events.minute_tick, function()
clock:set({
label = os.date("%H:%M"),
})
end)
Internally, api.lua still delegates to the registry and subscription modules by id.
The id-based functions are internal implementation details, not the public widget-author API.