Skip to content
Closed
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
43 changes: 43 additions & 0 deletions sable_ircd/src/command/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,41 @@ pub struct CommandRegistration {
pub(super) handler: CommandHandlerWrapper,
}

/// A free-form help topic not tied to a command handler.
///
/// Use this for topics that describe concepts rather than commands — for example
/// channel modes, user modes, or any other subject a user might query with `HELP`.
///
/// Register a topic at the call site with [`inventory::submit!`]:
///
/// ```rust,ignore
/// inventory::submit!(HelpTopic {
/// topic: "CMODE_SECRET",
/// lines: &[
/// "CMODE_SECRET (+s)",
/// "",
/// "Marks the channel as secret. Secret channels are hidden from /LIST",
/// "and /WHOIS for users who are not members.",
/// ],
/// });
/// ```
///
/// Topics are looked up case-insensitively via [`CommandDispatcher::get_help_topic`].
pub struct HelpTopic {
/// The name of the topic, matched case-insensitively against the argument to `HELP`.
pub topic: &'static str,
/// Lines of help text returned to the client.
pub lines: &'static [&'static str],
}

/// A command dispatcher. Collects registered command handlers and allows lookup by
/// command name.
pub struct CommandDispatcher {
handlers: HashMap<String, CommandHandlerWrapper>,
}

inventory::collect!(CommandRegistration);
inventory::collect!(HelpTopic);

impl CommandDispatcher {
/// Construct a default `CommandDispatcher`.
Expand Down Expand Up @@ -67,4 +95,19 @@ impl CommandDispatcher {
}
}
}

/// Look up a free-form [`HelpTopic`] by name (case-insensitive).
///
/// Returns the topic's lines of text, or `None` if no topic with that name was registered.
pub fn get_help_topic(&self, topic: &str) -> Option<&'static [&'static str]> {
inventory::iter::<HelpTopic>
.into_iter()
.find(|t| t.topic.eq_ignore_ascii_case(topic))
.map(|t| t.lines)
}

/// Iterate over all registered free-form [`HelpTopic`] entries.
pub fn iter_help_topics(&self) -> impl Iterator<Item = &'static HelpTopic> {
inventory::iter::<HelpTopic>.into_iter()
}
}
14 changes: 14 additions & 0 deletions sable_ircd/src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,20 @@ impl ClientServer {
&self.client_caps
}

/// Look up a free-form help topic by name (case-insensitive).
///
/// Returns the help lines registered via [`command::HelpTopic`], or `None` if no matching
/// topic was found. Command handlers that implement `HELP` should query this alongside
/// the command registry to cover both command docs and concept topics (modes, etc.).
pub fn get_help_topic(&self, topic: &str) -> Option<&'static [&'static str]> {
self.command_dispatcher.get_help_topic(topic)
}

/// Iterate over all free-form help topics registered via [`command::HelpTopic`].
pub fn iter_help_topics(&self) -> impl Iterator<Item = &'static command::HelpTopic> {
self.command_dispatcher.iter_help_topics()
}

/// Store a [`MessageSink`] to use when processing updates caused by the given event
pub(crate) fn store_response_sink(
&self,
Expand Down