Struct hexavalent::PluginHandle
source · pub struct PluginHandle<'ph, P: 'static> { /* private fields */ }
Expand description
Interacts with HexChat’s plugin API.
Passed into Plugin::init
, Plugin::deinit
, and hook callbacks such as PluginHandle::hook_command
.
Most of HexChat’s functions are available as associated functions,
without the hexchat_
prefix.
Implementations§
source§impl<'ph, P> PluginHandle<'ph, P>
impl<'ph, P> PluginHandle<'ph, P>
General functions allow printing text, running commands, creating events, and other miscellaneous operations.
sourcepub fn print(self, text: impl IntoCStr)
pub fn print(self, text: impl IntoCStr)
Prints text to the current context. Text may contain mIRC color codes and formatting.
Analogous to hexchat_print
.
§Examples
use hexavalent::PluginHandle;
fn say_hello<P>(ph: PluginHandle<'_, P>) {
ph.print(c"hello!");
}
Examples found in repository?
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
fn init(&self, ph: PluginHandle<'_, Self>) {
ph.hook_print(ChannelMessage, Priority::Normal, Self::message_cb);
ph.hook_command(
c"count",
c"Usage: COUNT, print message count",
Priority::Normal,
|plugin, ph, _words| {
let count = plugin.count.get();
let nicks = plugin.nicks.borrow().len();
ph.print(format!(
"Received {} messages from {} unique nicks.",
count, nicks
));
Eat::All
},
);
ph.print(c"Plugin loaded successfully!");
}
fn deinit(&self, ph: PluginHandle<'_, Self>) {
ph.print(c"Unloading plugin...");
}
More examples
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
fn proxy_and_adjust_timestamp<E, const N: usize>(&self, ph: PluginHandle<'_, Self>, event: E)
where
E: PrintEvent<N>,
{
ph.hook_print_attrs(event, Priority::Highest, |plugin, ph, attrs, args| {
if plugin.inside_hook.get() {
// Already inside hook, don't reprocess this event.
return Eat::None;
}
let offset = plugin.offset_seconds.get();
let new_time = if offset < 0 {
attrs.time() - Duration::from_secs(offset.abs_diff(0))
} else {
attrs.time() + Duration::from_secs(offset.abs_diff(0))
};
let new_attrs = attrs.with_time(new_time);
plugin.inside_hook.set(true);
if let Err(()) = ph.emit_print_attrs(E::default(), new_attrs, args) {
ph.print(c"Failed to emit event.");
}
plugin.inside_hook.set(false);
Eat::All
});
}
}
impl Plugin for TimeShiftPlugin {
fn init(&self, ph: PluginHandle<'_, Self>) {
ph.hook_command(
c"timeshift",
c"Usage: TIMESHIFT <seconds>, adjust timestamps of future messages",
Priority::Normal,
|plugin, ph, words| {
match words[1].parse() {
Ok(offset) => {
plugin.offset_seconds.set(offset);
ph.print(format!("Timestamps will be shifted by {} seconds.", offset));
}
Err(e) => {
ph.print(format!("Invalid number of seconds: {}", e));
}
}
Eat::All
},
);
self.proxy_and_adjust_timestamp(ph, ChannelMessage);
self.proxy_and_adjust_timestamp(ph, MessageSend);
self.proxy_and_adjust_timestamp(ph, PrivateMessage);
ph.print(c"Time shift plugin loaded successfully!");
}
fn deinit(&self, ph: PluginHandle<'_, Self>) {
ph.print(c"Unloading time shift plugin...");
}
sourcepub fn command(self, cmd: impl IntoCStr)
pub fn command(self, cmd: impl IntoCStr)
Executes a command in the current context as if it were typed into HexChat’s input box after a /
.
Analogous to hexchat_command
.
§Examples
use hexavalent::PluginHandle;
use hexavalent::str::HexStr;
fn op_user<P>(ph: PluginHandle<'_, P>, username: &HexStr) {
// do not include the leading slash
ph.command(format!("OP {}", username));
}
sourcepub fn emit_print<E: PrintEvent<N>, const N: usize>(
self,
event: E,
args: impl IntoCStrArray<N>
) -> Result<(), ()>
pub fn emit_print<E: PrintEvent<N>, const N: usize>( self, event: E, args: impl IntoCStrArray<N> ) -> Result<(), ()>
Emits a print event in the current context.
See the event::print
submodule for a list of print events.
Note that this triggers any print hooks registered for the event, so be careful to avoid infinite recursion
when calling this function from hook callbacks such as PluginHandle::hook_print
.
Analogous to hexchat_emit_print
.
§Examples
use hexavalent::PluginHandle;
use hexavalent::event::print::ChannelMessage;
use hexavalent::str::HexStr;
fn print_fake_message<P>(ph: PluginHandle<'_, P>, user: &HexStr, text: &str) -> Result<(), ()> {
ph.emit_print(ChannelMessage, (user, text, c"@", c"$"))
}
sourcepub fn emit_print_attrs<E: PrintEvent<N>, const N: usize>(
self,
event: E,
attrs: EventAttrs<'_>,
args: impl IntoCStrArray<N>
) -> Result<(), ()>
pub fn emit_print_attrs<E: PrintEvent<N>, const N: usize>( self, event: E, attrs: EventAttrs<'_>, args: impl IntoCStrArray<N> ) -> Result<(), ()>
Emits a print event in the current context, specifying its attributes.
See the event::print
submodule for a list of print events.
Note that this triggers any print hooks registered for the event, so be careful to avoid infinite recursion
when calling this function from hook callbacks such as PluginHandle::hook_print_attrs
.
Analogous to hexchat_emit_print_attrs
.
§Examples
use hexavalent::PluginHandle;
use hexavalent::event::EventAttrs;
use hexavalent::event::print::ChannelMessage;
use time::OffsetDateTime;
fn print_fake_message_like_its_1979<P>(ph: PluginHandle<'_, P>, user: &str, text: &str) -> Result<(), ()> {
let attrs = EventAttrs::new(OffsetDateTime::from_unix_timestamp(86400 * 365 * 10).unwrap());
ph.emit_print_attrs(ChannelMessage, attrs, (user, text, c"@", c"$"))
}
Examples found in repository?
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
fn proxy_and_adjust_timestamp<E, const N: usize>(&self, ph: PluginHandle<'_, Self>, event: E)
where
E: PrintEvent<N>,
{
ph.hook_print_attrs(event, Priority::Highest, |plugin, ph, attrs, args| {
if plugin.inside_hook.get() {
// Already inside hook, don't reprocess this event.
return Eat::None;
}
let offset = plugin.offset_seconds.get();
let new_time = if offset < 0 {
attrs.time() - Duration::from_secs(offset.abs_diff(0))
} else {
attrs.time() + Duration::from_secs(offset.abs_diff(0))
};
let new_attrs = attrs.with_time(new_time);
plugin.inside_hook.set(true);
if let Err(()) = ph.emit_print_attrs(E::default(), new_attrs, args) {
ph.print(c"Failed to emit event.");
}
plugin.inside_hook.set(false);
Eat::All
});
}
sourcepub fn send_modes(
self,
targets: impl IntoIterator<Item = impl IntoCStr>,
sign: Sign,
mode_char: u8
)
pub fn send_modes( self, targets: impl IntoIterator<Item = impl IntoCStr>, sign: Sign, mode_char: u8 )
Sends channel mode changes to targets in the current context.
Analogous to hexchat_send_modes
.
§Examples
use hexavalent::PluginHandle;
use hexavalent::mode::Sign;
fn op_users<P>(ph: PluginHandle<'_, P>, users: &[&str]) {
// sends `MODE <users> +o`
ph.send_modes(users.into_iter().copied(), Sign::Add, b'o');
}
sourcepub fn send_mode(self, target: impl IntoCStr, sign: Sign, mode_char: u8)
pub fn send_mode(self, target: impl IntoCStr, sign: Sign, mode_char: u8)
Sends channel mode changes to a target in the current context.
Behaves the same as PluginHandle::send_modes
,
but is more efficient when you only need to send mode changes to one target.
Analogous to hexchat_send_modes
.
§Examples
use hexavalent::PluginHandle;
use hexavalent::mode::Sign;
fn unban_user<P>(ph: PluginHandle<'_, P>, user: &str) {
// sends `MODE <user> -b`
ph.send_mode(user, Sign::Remove, b'b');
}
sourcepub fn nickcmp(self, s1: impl IntoCStr, s2: impl IntoCStr) -> Ordering
pub fn nickcmp(self, s1: impl IntoCStr, s2: impl IntoCStr) -> Ordering
Performs a comparison of nicknames or channel names, compliant with RFC1459.
Because of IRC’s scandanavian origin, the characters {}| are considered to be the lower case equivalents of the characters []\, respectively. This is a critical issue when determining the equivalence of two nicknames.
Analogous to hexchat_nickcmp
.
§Examples
use hexavalent::PluginHandle;
use hexavalent::str::HexStr;
fn sort_nicknames<P>(ph: PluginHandle<'_, P>, nicks: &mut [&HexStr]) {
nicks.sort_by(|n1, n2| ph.nickcmp(*n1, *n2));
}
sourcepub fn strip(
self,
str: impl IntoCStr,
mirc: MircColors,
attrs: TextAttrs
) -> Result<StrippedStr<'ph>, ()>
pub fn strip( self, str: impl IntoCStr, mirc: MircColors, attrs: TextAttrs ) -> Result<StrippedStr<'ph>, ()>
Strips mIRC colors and/or text attributes (bold, underline, etc.) from a string.
Analogous to hexchat_strip
.
§Examples
use hexavalent::PluginHandle;
use hexavalent::strip::{MircColors, TextAttrs};
fn strip_example<P>(ph: PluginHandle<'_, P>) {
let orig = "\x0312Blue\x03 \x02Bold!\x02";
let strip_all = ph.strip(orig, MircColors::Remove, TextAttrs::Remove);
assert_eq!(strip_all.unwrap().as_str(), "Blue Bold!");
let strip_colors = ph.strip(orig, MircColors::Remove, TextAttrs::Keep);
assert_eq!(strip_colors.unwrap().as_str(), "Blue \x02Bold!\x02");
}
source§impl<'ph, P> PluginHandle<'ph, P>
impl<'ph, P> PluginHandle<'ph, P>
Allows you get information about the current context or HexChat’s settings.
sourcepub fn get_info<I: Info>(self, info: I) -> <I as Info>::Type
pub fn get_info<I: Info>(self, info: I) -> <I as Info>::Type
Gets information based on the current context.
See the info
submodule for a list of info types.
Analogous to hexchat_get_info
.
§Example
use hexavalent::PluginHandle;
use hexavalent::info::{AwayReason, Channel};
use hexavalent::str::HexString;
fn current_channel<P>(ph: PluginHandle<'_, P>) -> HexString {
ph.get_info(Channel)
}
fn current_away_reason<P>(ph: PluginHandle<'_, P>) -> Option<HexString> {
ph.get_info(AwayReason)
}
sourcepub fn get_pref<Pr: Pref>(self, pref: Pr) -> Result<<Pr as Pref>::Type, ()>
pub fn get_pref<Pr: Pref>(self, pref: Pr) -> Result<<Pr as Pref>::Type, ()>
Gets settings information from HexChat, as available with /set
.
See the pref
submodule for a list of preferences.
Analogous to hexchat_get_prefs
.
§Example
use hexavalent::PluginHandle;
use hexavalent::pref::IrcNick1;
fn print_nick_setting<P>(ph: PluginHandle<'_, P>) {
match ph.get_pref(IrcNick1) {
Ok(nick) => ph.print(format!("Current nickname setting is: {}", nick)),
Err(()) => ph.print(c"Failed to get nickname!"),
}
}
sourcepub fn get_list<L: List>(
self,
list: L
) -> Result<impl Iterator<Item = <L as List>::Elem> + 'ph, ()>
pub fn get_list<L: List>( self, list: L ) -> Result<impl Iterator<Item = <L as List>::Elem> + 'ph, ()>
Gets a list of information, possibly specific to the current context.
See the list
submodule for a list of lists.
Analogous to hexchat_list_get
and related functions.
§Examples
use hexavalent::PluginHandle;
use hexavalent::context::Context;
use hexavalent::list::{Channels, Users};
fn print_all_users_in_all_channels<P>(ph: PluginHandle<'_, P>) {
let channels = match ph.get_list(Channels) {
Ok(channels) => channels,
Err(()) => return ph.print(c"Failed to get channels!"),
};
for channel in channels {
let ctxt = match ph.find_context(Context::fully_qualified(channel.servname(), channel.name())) {
Some(ctxt) => ctxt,
None => {
ph.print(format!("Failed to find channel {} on server {}, skipping.", channel.name(), channel.servname()));
continue;
}
};
let users = match ph.with_context(ctxt, || ph.get_list(Users)) {
Ok(users) => users,
Err(()) => {
ph.print(format!("Failed to find users in {} on server {}, skipping.", channel.name(), channel.servname()));
continue;
}
};
ph.print(format!("Users in {} on {}:", channel.name(), channel.servname()));
for user in users {
ph.print(format!(" {}{}", user.prefix().unwrap_or(' '), user.nick()));
}
}
}
source§impl<'ph, P> PluginHandle<'ph, P>
impl<'ph, P> PluginHandle<'ph, P>
Hook functions register hook callbacks with HexChat. You can execute code when the user runs a command, when print or server events happen, or on a timer interval.
§Examples
The callback
passed into each hook function is a function pointer (fn(X) -> Y
)
and not a type implementing a function trait (impl Fn(X) -> Y
), unlike most higher-order functions in Rust.
This means that no allocation is required to register a hook, so the plugin cannot leak memory on unload.
However, it also means that you cannot capture local variables in hook callbacks.
For example, the following does not compile, because count
is captured by the closure.
use hexavalent::{Plugin, PluginHandle};
use hexavalent::hook::{Eat, HookHandle, Priority};
struct MyPlugin;
fn add_counting_command(ph: PluginHandle<'_, MyPlugin>) {
let mut count = 0;
ph.hook_command(
c"count",
c"Usage: COUNT, counts the number of times this command was used",
Priority::Normal,
|plugin, ph, words| {
count += 1;
ph.print(format!("Called {} time(s)!", count));
Eat::All
}
);
}
Instead, store state on the plugin struct. Each hook callback gets a shared reference to the plugin.
Use Cell
to store simple Copy
types, as in the following (working) example of a count command.
Also use Cell
when a non-Copy
type should be moved in and out of the state without mutation,
as in PluginHandle::unhook
’s example, where a (non-Copy
) HookHandle
is stored.
use std::cell::Cell;
use hexavalent::{Plugin, PluginHandle};
use hexavalent::hook::{Eat, HookHandle, Priority};
struct MyPlugin {
count: Cell<u32>,
}
fn add_counting_command(ph: PluginHandle<'_, MyPlugin>) {
ph.hook_command(
c"count",
c"Usage: COUNT, counts the number of times this command was used",
Priority::Normal,
|plugin, ph, words| {
plugin.count.set(plugin.count.get() + 1);
ph.print(format!("Called {} time(s)!", plugin.count.get()));
Eat::All
}
);
}
Use RefCell
to store values which are mutated while in the state, as in the following example of a map.
use std::cell::RefCell;
use std::collections::HashMap;
use hexavalent::{Plugin, PluginHandle};
use hexavalent::hook::{Eat, HookHandle, Priority};
use hexavalent::str::HexString;
struct MyPlugin {
map: RefCell<HashMap<HexString, HexString>>,
}
fn add_map_command(ph: PluginHandle<'_, MyPlugin>) {
ph.hook_command(c"map_set", c"Usage: MAP_SET <k> <v>", Priority::Normal, |plugin, ph, words| {
let key = words[1].to_owned();
let val = words[2].to_owned();
plugin.map.borrow_mut().insert(key, val);
Eat::All
});
ph.hook_command(c"map_del", c"Usage: MAP_DEL <k>", Priority::Normal, |plugin, ph, words| {
let key = words[1];
plugin.map.borrow_mut().remove(key);
Eat::All
});
ph.hook_command(c"map_get", c"Usage: MAP_GET <k>", Priority::Normal, |plugin, ph, words| {
let key = words[1];
match plugin.map.borrow().get(key) {
Some(val) => ph.print(format!("map['{}']: '{}'", key, val)),
None => ph.print(format!("map['{}']: <not found>", key)),
}
Eat::All
});
}
sourcepub fn hook_command(
self,
name: impl IntoCStr,
help_text: impl IntoCStr,
priority: Priority,
callback: fn(plugin: &P, ph: PluginHandle<'_, P>, words: &[&HexStr]) -> Eat
) -> HookHandle
pub fn hook_command( self, name: impl IntoCStr, help_text: impl IntoCStr, priority: Priority, callback: fn(plugin: &P, ph: PluginHandle<'_, P>, words: &[&HexStr]) -> Eat ) -> HookHandle
Registers a command hook with HexChat.
The command is usable by typing /command <words...>
.
Command names starting with .
are hidden in /help
.
Hooking the special command ""
(empty string) captures non-commands, i.e. input without a /
at the beginning.
Each element of words
is an argument to the command.
words[0]
is the name of the command, so words[1]
is the first user-provided argument.
words
is limited to 32 elements, and HexChat may provide excess elements, so the length of words
is not meaningful.
Note that callback
is a function pointer, so it cannot capture any variables.
Analogous to hexchat_hook_command
.
§Example
use hexavalent::{Plugin, PluginHandle};
use hexavalent::hook::{Eat, HookHandle, Priority};
struct MyPlugin;
fn add_greeting_command(ph: PluginHandle<'_, MyPlugin>) {
ph.hook_command(
c"greet",
c"Usage: GREET <name>, prints a greeting locally",
Priority::Normal,
|plugin, ph, words| {
ph.print(format!("Hello {}!", words[1]));
Eat::All
}
);
}
Examples found in repository?
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
fn init(&self, ph: PluginHandle<'_, Self>) {
ph.hook_print(ChannelMessage, Priority::Normal, Self::message_cb);
ph.hook_command(
c"count",
c"Usage: COUNT, print message count",
Priority::Normal,
|plugin, ph, _words| {
let count = plugin.count.get();
let nicks = plugin.nicks.borrow().len();
ph.print(format!(
"Received {} messages from {} unique nicks.",
count, nicks
));
Eat::All
},
);
ph.print(c"Plugin loaded successfully!");
}
More examples
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
fn init(&self, ph: PluginHandle<'_, Self>) {
ph.hook_command(
c"timeshift",
c"Usage: TIMESHIFT <seconds>, adjust timestamps of future messages",
Priority::Normal,
|plugin, ph, words| {
match words[1].parse() {
Ok(offset) => {
plugin.offset_seconds.set(offset);
ph.print(format!("Timestamps will be shifted by {} seconds.", offset));
}
Err(e) => {
ph.print(format!("Invalid number of seconds: {}", e));
}
}
Eat::All
},
);
self.proxy_and_adjust_timestamp(ph, ChannelMessage);
self.proxy_and_adjust_timestamp(ph, MessageSend);
self.proxy_and_adjust_timestamp(ph, PrivateMessage);
ph.print(c"Time shift plugin loaded successfully!");
}
sourcepub fn hook_print<E: PrintEvent<N>, const N: usize>(
self,
event: E,
priority: Priority,
callback: fn(plugin: &P, ph: PluginHandle<'_, P>, args: [&HexStr; N]) -> Eat
) -> HookHandle
pub fn hook_print<E: PrintEvent<N>, const N: usize>( self, event: E, priority: Priority, callback: fn(plugin: &P, ph: PluginHandle<'_, P>, args: [&HexStr; N]) -> Eat ) -> HookHandle
Registers a print event hook with HexChat.
See the event::print
submodule for a list of print events.
Note that callback
is a function pointer, so it cannot capture any variables.
Analogous to hexchat_hook_print
.
§Examples
use hexavalent::PluginHandle;
use hexavalent::event::print::YouPartWithReason;
use hexavalent::hook::{Eat, Priority};
struct MyPlugin;
fn hook_you_part(ph: PluginHandle<'_, MyPlugin>) {
ph.hook_print(YouPartWithReason, Priority::Normal, |plugin, ph, args| {
let [your_nick, your_host, channel, reason] = args;
ph.print(format!("You left channel {}: {}.", channel, reason));
Eat::HexChat
});
}
Examples found in repository?
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
fn init(&self, ph: PluginHandle<'_, Self>) {
ph.hook_print(ChannelMessage, Priority::Normal, Self::message_cb);
ph.hook_command(
c"count",
c"Usage: COUNT, print message count",
Priority::Normal,
|plugin, ph, _words| {
let count = plugin.count.get();
let nicks = plugin.nicks.borrow().len();
ph.print(format!(
"Received {} messages from {} unique nicks.",
count, nicks
));
Eat::All
},
);
ph.print(c"Plugin loaded successfully!");
}
sourcepub fn hook_print_attrs<E: PrintEvent<N>, const N: usize>(
self,
event: E,
priority: Priority,
callback: fn(plugin: &P, ph: PluginHandle<'_, P>, attrs: EventAttrs<'_>, args: [&HexStr; N]) -> Eat
) -> HookHandle
pub fn hook_print_attrs<E: PrintEvent<N>, const N: usize>( self, event: E, priority: Priority, callback: fn(plugin: &P, ph: PluginHandle<'_, P>, attrs: EventAttrs<'_>, args: [&HexStr; N]) -> Eat ) -> HookHandle
Registers a print event hook with HexChat, capturing the event’s attributes.
See the event::print
submodule for a list of print events.
Note that callback
is a function pointer, so it cannot capture any variables.
Analogous to hexchat_hook_print_attrs
.
§Examples
use hexavalent::PluginHandle;
use hexavalent::event::print::YouPartWithReason;
use hexavalent::hook::{Eat, Priority};
struct MyPlugin;
fn hook_you_part(ph: PluginHandle<'_, MyPlugin>) {
ph.hook_print_attrs(YouPartWithReason, Priority::Normal, |plugin, ph, attrs, args| {
let [your_nick, your_host, channel, reason] = args;
ph.print(format!("You left channel {} at {}: {}.", channel, attrs.time(), reason));
Eat::HexChat
});
}
Examples found in repository?
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
fn proxy_and_adjust_timestamp<E, const N: usize>(&self, ph: PluginHandle<'_, Self>, event: E)
where
E: PrintEvent<N>,
{
ph.hook_print_attrs(event, Priority::Highest, |plugin, ph, attrs, args| {
if plugin.inside_hook.get() {
// Already inside hook, don't reprocess this event.
return Eat::None;
}
let offset = plugin.offset_seconds.get();
let new_time = if offset < 0 {
attrs.time() - Duration::from_secs(offset.abs_diff(0))
} else {
attrs.time() + Duration::from_secs(offset.abs_diff(0))
};
let new_attrs = attrs.with_time(new_time);
plugin.inside_hook.set(true);
if let Err(()) = ph.emit_print_attrs(E::default(), new_attrs, args) {
ph.print(c"Failed to emit event.");
}
plugin.inside_hook.set(false);
Eat::All
});
}
sourcepub fn hook_server<E: ServerEvent<N>, const N: usize>(
self,
event: E,
priority: Priority,
callback: fn(plugin: &P, ph: PluginHandle<'_, P>, args: [&HexStr; N]) -> Eat
) -> HookHandle
pub fn hook_server<E: ServerEvent<N>, const N: usize>( self, event: E, priority: Priority, callback: fn(plugin: &P, ph: PluginHandle<'_, P>, args: [&HexStr; N]) -> Eat ) -> HookHandle
Registers a server event hook with HexChat.
See the event::server
submodule for a list of server events.
Note that callback
is a function pointer, so it cannot capture any variables.
Analogous to hexchat_hook_server
.
§Examples
use hexavalent::PluginHandle;
use hexavalent::event::server::Part;
use hexavalent::hook::{Eat, Priority};
struct MyPlugin;
fn hook_part(ph: PluginHandle<'_, MyPlugin>) {
ph.hook_server(Part, Priority::Normal, |plugin, ph, args| {
let [sender, _, channel, reason] = args;
ph.print(format!("{} left channel {}: {}.", sender, channel, reason));
Eat::None
});
}
sourcepub fn hook_server_attrs<E: ServerEvent<N>, const N: usize>(
self,
event: E,
priority: Priority,
callback: fn(plugin: &P, ph: PluginHandle<'_, P>, attrs: EventAttrs<'_>, args: [&HexStr; N]) -> Eat
) -> HookHandle
pub fn hook_server_attrs<E: ServerEvent<N>, const N: usize>( self, event: E, priority: Priority, callback: fn(plugin: &P, ph: PluginHandle<'_, P>, attrs: EventAttrs<'_>, args: [&HexStr; N]) -> Eat ) -> HookHandle
Registers a server event hook with HexChat, capturing the event’s attributes.
See the event::server
submodule for a list of server events.
Note that callback
is a function pointer, so it cannot capture any variables.
Analogous to hexchat_hook_server_attrs
.
§Examples
use hexavalent::PluginHandle;
use hexavalent::event::server::Part;
use hexavalent::hook::{Eat, Priority};
struct MyPlugin;
fn hook_part(ph: PluginHandle<'_, MyPlugin>) {
ph.hook_server_attrs(Part, Priority::Normal, |plugin, ph, attrs, args| {
let [sender, _, channel, reason] = args;
ph.print(format!("{} left channel {} at {}: {}.", sender, channel, attrs.time(), reason));
Eat::None
});
}
sourcepub fn hook_timer(
self,
timeout: Duration,
callback: fn(plugin: &P, ph: PluginHandle<'_, P>) -> Timer
) -> HookHandle
pub fn hook_timer( self, timeout: Duration, callback: fn(plugin: &P, ph: PluginHandle<'_, P>) -> Timer ) -> HookHandle
Registers a timer hook with HexChat.
callback
will be called at the interval specified by timeout
, with a resolution of 1 millisecond.
Note that callback
is a function pointer, so it cannot capture any variables.
Analogous to hexchat_hook_timer
.
§Panics
If timeout
is more than i32::MAX
milliseconds.
§Examples
use std::cell::Cell;
use std::time::Duration;
use hexavalent::{Plugin, PluginHandle};
use hexavalent::hook::{Eat, HookHandle, Priority, Timer};
struct MyPlugin {
should_run: Cell<bool>,
}
fn add_annoying_command(plugin: &MyPlugin, ph: PluginHandle<'_, MyPlugin>) {
plugin.should_run.set(true);
ph.hook_timer(Duration::from_secs(5), |plugin, ph| {
if plugin.should_run.get() {
ph.print(c"Annoying message! Type /stop to stop.");
Timer::Continue
} else {
ph.print(c"This is the last annoying message!");
Timer::Stop
}
});
ph.hook_command(
c"stop",
c"Usage: STOP, stops being annoying",
Priority::Normal,
|plugin, ph, words| {
if plugin.should_run.get() {
// Instead of using this `Cell<bool>` flag,
// it would make more sense to store a `HookHandle`
// and call `ph.unhook(hook)` here,
// but this demonstrates the use of `Timer::Stop`.
plugin.should_run.set(false);
}
Eat::All
}
);
}
sourcepub fn unhook(self, hook: HookHandle)
pub fn unhook(self, hook: HookHandle)
Unregisters a hook from HexChat.
Used with hook registrations functions such as PluginHandle::hook_command
.
HexChat automatically unhooks any remaining hooks after your plugin finishes unloading, so this function is only useful if you need to unhook a hook while your plugin is running.
§Example
use std::cell::Cell;
use hexavalent::{Plugin, PluginHandle};
use hexavalent::hook::{Eat, HookHandle, Priority};
#[derive(Default)]
struct MyPlugin {
cmd_handle: Cell<Option<HookHandle>>,
}
impl Plugin for MyPlugin {
fn init(&self, ph: PluginHandle<'_, Self>) {
let hook = ph.hook_command(
c"thisCommandOnlyWorksOnce",
c"Usage: THISCOMMANDONLYWORKSONCE <args...>, this command only works once",
Priority::Normal,
|plugin, ph, words| {
let all_words = words.into_iter().fold(String::new(), |acc, w| acc + "|" + w);
ph.print(format!("You'll only see this once: {}", all_words));
if let Some(hook) = plugin.cmd_handle.take() {
ph.unhook(hook);
}
Eat::All
}
);
self.cmd_handle.set(Some(hook));
}
}
source§impl<'ph, P> PluginHandle<'ph, P>
impl<'ph, P> PluginHandle<'ph, P>
Allows you to work with server/channel contexts.
It is not always necessary to change context, as hook callbacks usually execute in a context related to the event. For example:
PluginHandle::hook_command
callbacks run in the context where the command was executed.PluginHandle::hook_print
callbacks run in the context where the print event was emitted.PluginHandle::hook_server
callbacks run in the server (but not channel) context where the server event was received.
sourcepub fn find_context<S>(self, find: Context<S>) -> Option<ContextHandle<'ph>>where
S: IntoCStr,
pub fn find_context<S>(self, find: Context<S>) -> Option<ContextHandle<'ph>>where
S: IntoCStr,
Finds a server/channel context based on various criteria.
See Context
for available criteria.
These include: the currently-focused tab, a specified channel, or the frontmost tab in a server.
Returns a ContextHandle
which should be passed to
PluginHandle::with_context
to enter the context.
Analogous to hexchat_find_context
.
§Examples
use hexavalent::PluginHandle;
use hexavalent::context::Context;
fn find_context_example<P>(ph: PluginHandle<'_, P>) {
if let Some(ctxt) = ph.find_context(Context::focused()) {
ph.with_context(ctxt, || ph.print(c"This tab is focused!"));
}
if let Some(ctxt) = ph.find_context(Context::channel(c"#help")) {
ph.with_context(ctxt, || ph.print(c"This tab is #help!"));
}
if let Some(ctxt) = ph.find_context(Context::frontmost("Snoonet")) {
ph.with_context(ctxt, || ph.print("This tab is frontmost on snoonet!"));
}
}
sourcepub fn with_context<R>(
self,
context: ContextHandle<'_>,
f: impl FnOnce() -> R
) -> R
pub fn with_context<R>( self, context: ContextHandle<'_>, f: impl FnOnce() -> R ) -> R
Executes a function in a different server/channel context.
Used with PluginHandle::find_context
.
Analogous to hexchat_get_context
and
hexchat_set_context
.
§Examples
use hexavalent::PluginHandle;
use hexavalent::context::Context;
use hexavalent::str::HexStr;
fn send_message_to_channel<P>(
ph: PluginHandle<'_, P>,
channel: &HexStr,
message: &str,
) -> Result<(), ()> {
let ctxt = match ph.find_context(Context::channel(channel)) {
Some(ctxt) => ctxt,
None => return Err(()),
};
ph.with_context(ctxt, || {
ph.print(message);
Ok(())
})
}
source§impl<'ph, P> PluginHandle<'ph, P>
impl<'ph, P> PluginHandle<'ph, P>
Allows you to get and set preferences associated with your plugin.
sourcepub fn pluginpref_set_str(
self,
name: impl IntoCStr,
value: impl IntoCStr
) -> Result<(), ()>
pub fn pluginpref_set_str( self, name: impl IntoCStr, value: impl IntoCStr ) -> Result<(), ()>
Sets a plugin-specific string preference.
Fails if value
exceeds 511 bytes in length.
Analogous to hexchat_pluginpref_set_str
.
§Examples
use hexavalent::PluginHandle;
fn save_str<P>(ph: PluginHandle<'_, P>) -> Result<(), ()> {
ph.pluginpref_set_str(c"myvar1", c"something important")
}
sourcepub fn pluginpref_get_str(self, name: impl IntoCStr) -> Result<HexString, ()>
pub fn pluginpref_get_str(self, name: impl IntoCStr) -> Result<HexString, ()>
Gets a plugin-specific string preference.
Note that int preferences can be successfully loaded as strings.
Analogous to hexchat_pluginpref_get_str
.
§Examples
use hexavalent::PluginHandle;
fn load_str<P>(ph: PluginHandle<'_, P>) {
let pref = ph.pluginpref_get_str(c"myvar1");
assert_eq!(pref.unwrap().as_str(), "something important");
}
sourcepub fn pluginpref_get_str_with<R>(
self,
name: impl IntoCStr,
f: impl FnOnce(Result<&HexStr, ()>) -> R
) -> R
pub fn pluginpref_get_str_with<R>( self, name: impl IntoCStr, f: impl FnOnce(Result<&HexStr, ()>) -> R ) -> R
Gets a plugin-specific string preference, passing the result to a closure.
Note that int preferences can be successfully loaded as strings.
Behaves the same as PluginHandle::pluginpref_get_str
,
but avoids allocating a String
to hold the preference value.
Analogous to hexchat_pluginpref_get_str
.
§Examples
use hexavalent::PluginHandle;
fn load_str<P>(ph: PluginHandle<'_, P>) {
ph.pluginpref_get_str_with(c"myvar1", |pref| {
assert_eq!(pref.unwrap().as_str(), "something important");
});
}
sourcepub fn pluginpref_set_int(
self,
name: impl IntoCStr,
value: i32
) -> Result<(), ()>
pub fn pluginpref_set_int( self, name: impl IntoCStr, value: i32 ) -> Result<(), ()>
Sets a plugin-specific int preference.
-1
is a reserved value and cannot be used.
Analogous to hexchat_pluginpref_set_int
.
§Examples
use hexavalent::PluginHandle;
fn save_int<P>(ph: PluginHandle<'_, P>) -> Result<(), ()> {
ph.pluginpref_set_int(c"answer", 42)
}
sourcepub fn pluginpref_get_int(self, name: impl IntoCStr) -> Result<i32, ()>
pub fn pluginpref_get_int(self, name: impl IntoCStr) -> Result<i32, ()>
Gets a plugin-specific int preference.
Analogous to hexchat_pluginpref_get_int
.
§Examples
use hexavalent::PluginHandle;
fn load_int<P>(ph: PluginHandle<'_, P>) {
let pref = ph.pluginpref_get_int(c"answer");
assert_eq!(pref, Ok(42));
}
sourcepub fn pluginpref_delete(self, name: impl IntoCStr) -> Result<(), ()>
pub fn pluginpref_delete(self, name: impl IntoCStr) -> Result<(), ()>
Deletes a plugin-specific preference.
Returns Ok(())
both when an existing preference is deleted and when no preference with name
exists.
Analogous to hexchat_pluginpref_delete
.
§Examples
use hexavalent::PluginHandle;
fn remove_answer<P>(ph: PluginHandle<'_, P>) -> Result<(), ()> {
ph.pluginpref_delete(c"answer")
}
sourcepub fn pluginpref_list(self) -> Result<Vec<String>, ()>
pub fn pluginpref_list(self) -> Result<Vec<String>, ()>
Lists the names of all plugin-specific preferences.
Note that the total length of all preference names is limited to about 4095 bytes.
Analogous to hexchat_pluginpref_list
.
§Examples
use hexavalent::PluginHandle;
fn print_all_prefs<P>(ph: PluginHandle<'_, P>) {
let prefs = match ph.pluginpref_list() {
Ok(prefs) => prefs,
Err(()) => return ph.print(c"Failed to list plugin preferences!"),
};
ph.print(c"All plugin preferences:");
for pref in prefs {
let val = ph.pluginpref_get_str(pref.as_str());
let val = match &val {
Ok(v) => v,
Err(()) => "<not found>",
};
ph.print(format!("{} = {}", pref, val));
}
}
sourcepub fn pluginpref_list_with<R>(
self,
f: impl FnOnce(Result<&mut dyn Iterator<Item = &str>, ()>) -> R
) -> R
pub fn pluginpref_list_with<R>( self, f: impl FnOnce(Result<&mut dyn Iterator<Item = &str>, ()>) -> R ) -> R
Lists the names of all plugin-specific preferences, passing the result to a closure.
Note that the total length of all preference names is limited to about 4095 bytes.
Behaves the same as PluginHandle::pluginpref_list
,
but avoids allocating a Vec
and String
s to hold each preference name.
Analogous to hexchat_pluginpref_list
.
§Examples
use hexavalent::PluginHandle;
fn print_all_prefs<P>(ph: PluginHandle<'_, P>) {
ph.pluginpref_list_with(|prefs| {
let prefs = match prefs {
Ok(prefs) => prefs,
Err(()) => return ph.print(c"Failed to list plugin preferences!"),
};
ph.print(c"All plugin preferences:");
for pref in prefs {
ph.pluginpref_get_str_with(pref, |val| {
let val = match val {
Ok(v) => v,
Err(()) => "<not found>",
};
ph.print(format!("{} = {}", pref, val));
});
}
});
}
source§impl<'ph, P> PluginHandle<'ph, P>
impl<'ph, P> PluginHandle<'ph, P>
Allows you to add and remove fake plugins from the plugin GUI.
sourcepub fn plugingui_add(
self,
filename: impl IntoCStr,
name: impl IntoCStr,
desc: impl IntoCStr,
version: impl IntoCStr
) -> FakePluginHandle
pub fn plugingui_add( self, filename: impl IntoCStr, name: impl IntoCStr, desc: impl IntoCStr, version: impl IntoCStr ) -> FakePluginHandle
Adds a fake plugin to the plugin GUI.
Only useful if your plugin loads other plugins.
Do not call this function with the same arguments you pass to export_plugin
.
Returns a FakePluginHandle
which must be passed to
PluginHandle::plugingui_remove
to remove the fake plugin.
Analogous to hexchat_plugingui_add
.
sourcepub fn plugingui_remove(self, gui: FakePluginHandle)
pub fn plugingui_remove(self, gui: FakePluginHandle)
Removes a fake plugin from the plugin GUI.
Used with PluginHandle::plugingui_add
.
Analogous to hexchat_plugingui_remove
.