Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: (wip) Redesigned event publishing system #1076

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 6 additions & 11 deletions lua/neorg.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@

-- Require the most important modules
local neorg = require("neorg.core")
local config, log, modules = neorg.config, neorg.log, neorg.modules
local config, events, log, modules = neorg.config, neorg.events, neorg.log, neorg.modules

---@class event.core.neorg_started
Groctel marked this conversation as resolved.
Show resolved Hide resolved
---Informs all modules that all core Neorg modules have been loaded and Neorg
---has completed its setup process. It doesn't contain any fields.

--- This function takes in a user config, parses it, initializes everything and launches neorg if inside a .norg or .org file
---@param cfg table #A table that reflects the structure of config.user_config
Expand Down Expand Up @@ -106,16 +110,7 @@ function neorg.org_file_entered(manual, arguments)
config.started = true

-- Lets the entire Neorg environment know that Neorg has started!
modules.broadcast_event({
type = "core.started",
split_type = { "core", "started" },
filename = "",
filehead = "",
cursor_position = { 0, 0 },
referrer = "core",
line_content = "",
broadcast = true,
})
events.publish("neorg_started", nil --[[@as neorg.event.neorg_started]])

-- Sometimes external plugins prefer hooking in to an autocommand
vim.api.nvim_exec_autocmds("User", {
Expand Down
40 changes: 0 additions & 40 deletions lua/neorg/core/callbacks.lua

This file was deleted.

101 changes: 101 additions & 0 deletions lua/neorg/core/events.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
local modules = require("neorg.core.modules")
local api, fn = vim.api, vim.fn


---@class neorg.events
---# A simple interface to publish event samples.
---
---## Events and event samples
---An event is a point in the flow of Neorg's execution that one of its modules
---broadcasts so that other modules can react accordingly. Events follow a simple
---publish-subscribe model where publishers send the event to all loaded modules
---and those react to the event if they are subscribed to the event's topic.
---
---An event sample is an aggregation of data sent when an event is published, i.e.
---when the function `events.publish` is called by a module.
---
---## Topic names
---The topic name can be namespaced by prepending as many namespaces as desired
---separated by a dot (`.`). For example, you can namespace `"my_event"` as
---`"my_namespace.my_event"`. This namespacing scheme shall never be used to
---identify the publisher of the event. If the publisher should ever require
---identification, a discriminator should be included in the payload.
---
---## Payloads
---All samples contain a payload, whose type is identified by the sample's topic.
---A topic is a string that uniquely identifies the sample's type. When a module
---subscribes to a type of event, they subscribe to its topic. For example, a
---module can be subscribed to the topic `"module_loaded"` and not be subscribed
---to `"autocmd"`. When a module is subscribed to a topic, it knows exactly the
---fields that its corresponding sample's payload will have when it is received.
---This also implies that different topics can have the same type, but a topic's
---type must always be the same in every event sample.
---
---When you define your event's type with LuaLS, call it `neorg.event.<topic_name>`.
---For example, the event whose topic name is `"neorg_started"` should be of
---type `neorg.event.neorg_started`.
---
---### Making LuaLS aware of the type of the payload
---When you call `events.publish`, you can build the payload in-place as an
---argument for the function. If you do it this way, you can add an `@as` type
---hint after the table's closing bracket to enable completion and diagnostics:
---
---```lua
---events.publish("core.concealer.update_region", {
--- start = start_pos[1] - 1,
--- ["end"] = end_pos[1] + 2,
---} --[[@as neorg.event.core.concealer.update_region]])
---```
---
---## Notes on the publish-subscribe system
---When an event is published, it is published for every single loaded module.
---It is every module's responsibility to subscribe to the topics it is
---interested in and properly handle the samples it receives. This is integral to
---the correct functioning of the events system, since the responsibility also
---gives the subscribers the power to extend Neorg's functionality by
---implementing new behaviours based on the events published by different modules.
---
---If an event could be published but it shouldn't be received by any subscriber,
---it is the publisher's responsibility to prevent the publication of such event.
local events = {}


---@class neorg.event_sample
---@field public topic string #An unique name that identifies the event's payload type
---@field public payload any #The content of the event, identified by the `topic` discriminator field
---@field public cursor_position cursor_pos #The position of the cursor when the event was published
---@field public filename string #The name of the active file when the event was published
---@field public filehead string #The absolute path of the active file's directory when the event was published
---@field public line_content string #The content of the active line when the event was published
---@field public buffer integer #The active buffer descriptor when the event was published
---@field public window integer #The active window descriptor when the event was published
---@field public mode string #Vim's mode when the event was published


---Publish an event that is received by all modules. See the documentation for
---`neorg.events` for more information on the publishing and subscribing rules.
---@param topic string #See event_sample::topic
---@param payload any #See event_sample::payload
function events.publish(topic, payload)
local event --[[@as neorg.event_sample]] = {
topic = topic,
payload = payload,

-- Metadata members defining Vim's state when the event was published
-- TODO: Deprecate? These could be added to the payload on demand.
cursor_position = vim.api.nvim_win_get_cursor(0),
filename = fn.expand("%:t"),
filehead = fn.expand("%:p:h"),
line_content = api.nvim_get_current_line(),
buffer = api.nvim_get_current_buf(),
window = api.nvim_get_current_win(),
mode = api.nvim_get_mode().mode,
Comment on lines +86 to +92
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am happy to deprecate these! These used to be required when events were sent via vim.schedule, in which case you could get outdated information about the current buffer ID etc.

}

for _, module in pairs(modules.loaded_modules) do
module:on_event(event)
end
end


return events
2 changes: 1 addition & 1 deletion lua/neorg/core/init.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
local neorg = {
callbacks = require("neorg.core.callbacks"),
config = require("neorg.core.config"),
events = require("neorg.core.events"),
lib = require("neorg.core.lib"),
log = require("neorg.core.log"),
modules = require("neorg.core.modules"),
Expand Down
Loading
Loading