Subscribe to host events. Built-in events cannot be emitted from
Lua; use hollow.events.emit(name, payload) only for custom events
that you also register handlers for.
For the LuaLS schema see
types/hollow.lua (HollowEventName,
HollowEventListener).
handle = hollow.events.on(name, handler) -- returns a handle (integer)
hollow.events.off(handle) -- unsubscribe
hollow.events.once(name, handler) -- unsubscribe after first call
hollow.events.emit(name, payload?) -- dispatch a custom eventhandler(payload) is called on the host thread with a payload table.
| Event | Payload |
|---|---|
config:reloaded |
(empty) |
config:ready |
(empty) — emitted once after config loading completes (including deferred defaults) |
workspace:new |
{ workspace, index } |
workspace:changed |
{ workspace, index } |
workspace:closed |
{ name } — emitted when a workspace becomes empty and is auto-closed |
selection:begin |
(empty) |
selection:cleared |
(empty) |
term:title_changed |
{ pane, old_title, new_title } |
term:tab_activated |
{ tab } |
term:tab_closed |
{ tab_id } |
term:pane_focused |
{ pane } |
term:pane_layout_changed |
{ pane } |
term:cwd_changed |
{ pane, old_cwd, new_cwd } |
term:foreground_process_changed |
{ pane, old_process, new_process } |
term:bell |
{ pane } (pane.has_bell is true until focus) |
key:unhandled |
{ key, mods } |
window:resized |
{ size } (size has rows, cols, width, height) |
window:files_dropped |
{ paths, pane, pane_id, x, y, text } |
window:focused |
(empty) |
window:blurred |
(empty) |
copy_mode:changed |
{ active, query?, match_count?, match_index?, selecting?, block? } |
copy_mode:search_requested |
(empty; open a search prompt) |
topbar:hover |
{ id } |
topbar:leave |
(empty) |
topbar:click |
{ id } |
bottombar:hover |
{ id } |
bottombar:leave |
(empty) |
bottombar:click |
{ id } |
The term:bell event fires once per BEL (\a) received by a pane.
The pane snapshot's has_bell field stays true until the pane
receives focus.
Use hollow.on_file_drop to customize what happens after a file drop.
The handler receives the same payload as window:files_dropped.
hollow.on_file_drop(function(e)
local paths = {}
for i, path in ipairs(e.paths) do
paths[i] = path:gsub("^([A-Za-z]):\\", "/mnt/%1/"):gsub("\\", "/")
end
return table.concat(paths, " ")
end)Return nil or true to use default insertion, false to consume
the drop, or a string to replace inserted text. The default handler
quotes paths containing spaces and inserts them into pane under drop.
Default insertion is skipped for remote panes, but handler can transfer
files and return replacement text (or send its own text to pane_id).
window:files_dropped is observational; use hollow.on_file_drop
when handler must replace or suppress default insertion.
React to config reloads:
hollow.events.on("config:reloaded", function()
hollow.ui.notify.info("Config reloaded", { ttl = 1200 })
end)Track cwd changes to update a custom widget:
hollow.events.on("term:cwd_changed", function(e)
-- e.pane is a HollowPane snapshot
-- e.new_cwd is the new directory
end)React to copy mode transitions:
hollow.events.on("copy_mode:changed", function(e)
if e.active and e.query ~= "" then
-- show "match_index / match_count" in a custom widget
end
end)
hollow.events.on("copy_mode:search_requested", function()
hollow.ui.input.open({
prompt = "Search",
on_confirm = function(value)
require("hollow.state").get().host_api.copy_mode_search_set_query(value)
end,
})
end)One-shot subscription:
hollow.events.once("workspace:new", function(e)
print("first workspace:", e.workspace.name)
end)-- emit
hollow.events.on("build_started", function(e)
hollow.ui.notify.info("build: " .. e.target)
end)
hollow.events.emit("build_started", { target = "release" })Custom event names are plain strings. The host does not interpret them; they are a local bus between Lua modules in the same Hollow process.
hollow.ui— widgets react to eventshollow.keymap— bind keys to actions- Copy mode — uses
copy_mode:*events