aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2016-12-08 09:06:01 +0100
committerMarc André Tanner <mat@brain-dump.org>2016-12-08 09:11:59 +0100
commit6d1d45776b231304b0ff41b5e6098f07931ec44e (patch)
tree2f7f41170491200d5da92bf4cd570a3e268fbed2
parent065a804d282ac99dd93e9ebaf7bc986ccf53e75b (diff)
downloadvis-6d1d45776b231304b0ff41b5e6098f07931ec44e.tar.gz
vis-6d1d45776b231304b0ff41b5e6098f07931ec44e.tar.xz
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.
-rw-r--r--lua/doc/config.ld1
-rw-r--r--lua/plugins/filetype.lua4
-rw-r--r--lua/vis-std.lua16
-rw-r--r--lua/vis.lua102
-rw-r--r--lua/visrc.lua11
-rw-r--r--vis-lua.c11
6 files changed, 121 insertions, 24 deletions
diff --git a/lua/doc/config.ld b/lua/doc/config.ld
index a955b38..a979f83 100644
--- a/lua/doc/config.ld
+++ b/lua/doc/config.ld
@@ -7,6 +7,7 @@ dir="."
sort=true
merge=true
no_space_before_args=true
+not_luadoc=true
file={
"../../vis-lua.c",
"../vis.lua",
diff --git a/lua/plugins/filetype.lua b/lua/plugins/filetype.lua
index e308ac0..7101e4c 100644
--- a/lua/plugins/filetype.lua
+++ b/lua/plugins/filetype.lua
@@ -356,7 +356,7 @@ vis.ftdetect.filetypes = {
},
}
-vis.filetype_detect = function(win)
+vis.events.subscribe(vis.events.WIN_OPEN, function(win)
local name = win.file.name
-- remove ignored suffixes from filename
local sanitizedfn = name
@@ -425,5 +425,5 @@ vis.filetype_detect = function(win)
end
win.syntax = nil
-end
+end)
diff --git a/lua/vis-std.lua b/lua/vis-std.lua
index d8a32ad..a46896a 100644
--- a/lua/vis-std.lua
+++ b/lua/vis-std.lua
@@ -1,6 +1,6 @@
-- standard vis event handlers
-vis.events.theme_change = function(name)
+vis.events.subscribe(vis.events.THEME_CHANGE, function(name)
if name ~= nil then
local theme = 'themes/'..name
package.loaded[theme] = nil
@@ -12,9 +12,9 @@ vis.events.theme_change = function(name)
for win in vis:windows() do
win.syntax = win.syntax;
end
-end
+end)
-vis.events.win_syntax = function(win, name)
+vis.events.subscribe(vis.events.WIN_SYNTAX, function(win, name)
local lexers = vis.lexers
if not lexers.load then return false end
@@ -37,9 +37,9 @@ vis.events.win_syntax = function(win, name)
end
return true
-end
+end)
-vis.events.win_highlight = function(win, horizon_max)
+vis.events.subscribe(vis.events.WIN_HIGHLIGHT, function(win, horizon_max)
if win.syntax == nil or vis.lexers == nil then return end
local lexer = vis.lexers.load(win.syntax)
if lexer == nil then return end
@@ -67,7 +67,7 @@ vis.events.win_highlight = function(win, horizon_max)
end
token_start = token_end
end
-end
+end)
local modes = {
[vis.MODE_NORMAL] = '',
@@ -78,7 +78,7 @@ local modes = {
[vis.MODE_REPLACE] = 'REPLACE',
}
-vis.events.win_status = function(win)
+vis.events.subscribe(vis.events.WIN_STATUS, function(win)
local left_parts = {}
local right_parts = {}
local file = win.file
@@ -114,6 +114,6 @@ vis.events.win_status = function(win)
local left = ' ' .. table.concat(left_parts, " » ") .. ' '
local right = ' ' .. table.concat(right_parts, " « ") .. ' '
win:status(left, right);
-end
+end)
vis:command("set theme ".. (vis.ui.colors <= 16 and "default-16" or "default-256"))
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')
diff --git a/lua/visrc.lua b/lua/visrc.lua
index 4c44f6a..1a304b4 100644
--- a/lua/visrc.lua
+++ b/lua/visrc.lua
@@ -3,15 +3,12 @@ require('vis')
require('plugins/filetype')
require('plugins/textobject-lexer')
-vis.events.start = function()
+vis.events.subscribe(vis.events.START, function()
-- Your global configuration options e.g.
-- vis:command('map! normal j gj')
-end
-
-vis.events.win_open = function(win)
- -- enable syntax highlighting for known file types
- vis.filetype_detect(win)
+end)
+vis.events.subscribe(vis.events.WIN_OPEN, function(win)
-- Your per window configuration options e.g.
-- vis:command('set number')
-end
+end)
diff --git a/vis-lua.c b/vis-lua.c
index f3b0114..29f3103 100644
--- a/vis-lua.c
+++ b/vis-lua.c
@@ -1733,13 +1733,14 @@ static const struct luaL_Reg file_lines_funcs[] = {
*/
/***
- * Events.
+ * Core Events.
*
* These events are invoked from the editor core.
- * The following functions are looked up in the `vis.events` table.
- * Keep in mind that the editor is blocked while the event handlers
- * are being executed, avoid long running tasks.
- * @section Events
+ * The following functions are invoked if they are registered in the
+ * `vis.events` table. Users scripts should generally use the [Events](#events)
+ * mechanism instead which multiplexes these core events.
+ *
+ * @section Core Events
*/
static void vis_lua_event_get(lua_State *L, const char *name) {