From 6d1d45776b231304b0ff41b5e6098f07931ec44e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Andr=C3=A9=20Tanner?= Date: Thu, 8 Dec 2016 09:06:01 +0100 Subject: lua: add simple event multiplexing mechanism The editor core calls into the functions registered in the `vis.events` table which then multiplex the events to all registered event handlers. The first handler which returns a non `nil` value terminates event propagation. --- lua/vis.lua | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 2 deletions(-) (limited to 'lua/vis.lua') diff --git a/lua/vis.lua b/lua/vis.lua index 5a4af8d..c5ab47e 100644 --- a/lua/vis.lua +++ b/lua/vis.lua @@ -14,8 +14,6 @@ if not ok then vis:info('WARNING: could not load lexer module, is lpeg installed?') end -vis.events = {} - --- Map a new motion. -- -- Sets up a mapping in normal, visual and operator pending mode. @@ -71,4 +69,104 @@ vis.textobject_new = function(vis, key, textobject) return true end +--- Events. +-- +-- User scripts can subscribe Lua functions to certain events. Multiple functions +-- can be associated with the same event. They will be called in the order they were +-- registered. The first function which returns a non `nil` value terminates event +-- propagation. The remaining event handler will not be called. +-- +-- Keep in mind that the editor is blocked while the event handlers +-- are being executed, avoid long running tasks. +-- +-- @section Events + +--- Event names. +--- @table events +local events = { + FILE_CLOSE = "Event::FILE_CLOSE", -- see @{file_close} + FILE_OPEN = "Event::FILE_OPEN", -- see @{file_open} + FILE_SAVE_POST = "Event::FILE_SAVE_POST", -- see @{file_save_post} + FILE_SAVE_PRE = "Event::FILE_SAVE_PRE", -- see @{file_save_pre} + QUIT = "Event::QUIT", -- see @{quit} + START = "Event::START", -- see @{start} + THEME_CHANGE = "Event::THEME_CHANGE", -- see @{theme_change} + WIN_CLOSE = "Event::WIN_CLOSE", -- see @{win_close} + WIN_HIGHLIGHT = "Event::WIN_HIGHLIGHT", -- see @{win_highlight} + WIN_OPEN = "Event::WIN_OPEN", -- see @{win_open} + WIN_STATUS = "Event::WIN_STATUS", -- see @{win_status} + WIN_SYNTAX = "Event::WIN_SYNTAX", -- see @{win_syntax} +} + +events.file_close = function(...) events.emit(events.FILE_CLOSE, ...) end +events.file_open = function(...) events.emit(events.FILE_OPEN, ...) end +events.file_save_post = function(...) events.emit(events.FILE_SAVE_POST, ...) end +events.file_save_pre = function(...) return events.emit(events.FILE_SAVE_PRE, ...) end +events.quit = function(...) events.emit(events.QUIT, ...) end +events.start = function(...) events.emit(events.START, ...) end +events.theme_change = function(...) events.emit(events.THEME_CHANGE, ...) end +events.win_close = function(...) events.emit(events.WIN_CLOSE, ...) end +events.win_highlight = function(...) events.emit(events.WIN_HIGHLIGHT, ...) end +events.win_open = function(...) events.emit(events.WIN_OPEN, ...) end +events.win_status = function(...) events.emit(events.WIN_STATUS, ...) end +events.win_syntax = function(...) return events.emit(events.WIN_SYNTAX, ...) end + +local handlers = {} + +--- Subscribe to an event. +-- +-- Register an event handler. +-- @tparam string event the event name +-- @tparam function handler the event handler +-- @tparam[opt] int index the index at which to insert the handler (1 is the highest priority) +-- @usage +-- vis.events.subscribe(vis.events.FILE_SAVE_PRE, function(file, path) +-- -- do something useful +-- return true +-- end) +events.subscribe = function(event, handler, index) + if not event then error("Invalid event name") end + if type(handler) ~= 'function' then error("Invalid event handler") end + if not handlers[event] then handlers[event] = {} end + events.unsubscribe(event, handler) + table.insert(handlers[event], index or #handlers[event]+1, handler) +end + +--- Unsubscribe from an event. +-- +-- Remove a registered event handler. +-- @tparamm string event the event name +-- @tparam function handler the event handler to unsubscribe +-- @treturn bool whether the handler was successfully removed +events.unsubscribe = function(event, handler) + local h = handlers[event] + if not h then return end + for i = 1, #h do + if h[i] == handler then + table.remove(h, i) + return true + end + end + return false +end + +--- Generate event. +-- +-- Invokes all event handlers in the order they were registered. +-- Passes all arguments to the handler. The first handler which returns a non `nil` +-- value terminates the event propagation. The other handlers will not be called. +-- +-- @tparam string event the event name +-- @tparam ... ... the remaining paramters are passed on to the handler +events.emit = function(event, ...) + local h = handlers[event] + if not h then return end + for i = 1, #h do + local ret = h[i](...) + if type(ret) ~= 'nil' then return ret end + end +end + +vis.events = events + require('vis-std') -- cgit v1.2.3