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>

General Functions

General functions allow printing text, running commands, creating events, and other miscellaneous operations.

source

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?
examples/simple.rs (lines 40-43)
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
Hide additional examples
examples/time_shift.rs (line 37)
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...");
    }
source

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));
}
source

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"$"))
}
source

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?
examples/time_shift.rs (line 36)
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
        });
    }
source

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');
}
source

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');
}
source

pub fn nickcmp(self, s1: impl IntoCStr, s2: impl IntoCStr) -> Ordering

Performs a comparison of nicknames or channel names, compliant with RFC1459.

RFC1459 says:

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));
}
source

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>

Getting Information

Allows you get information about the current context or HexChat’s settings.

source

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)
}
source

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!"),
    }
}
source

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>

Hook Functions

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
    });
}
source

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?
examples/simple.rs (lines 32-47)
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
Hide additional examples
examples/time_shift.rs (lines 48-64)
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!");
    }
source

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?
examples/simple.rs (line 30)
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!");
    }
source

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?
examples/time_shift.rs (lines 21-42)
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
        });
    }
source

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
    });
}
source

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
    });
}
source

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
        }
    );
}
source

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>

Context Functions

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:

source

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!"));
    }
}
source

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>

Plugin Preferences

Allows you to get and set preferences associated with your plugin.

source

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")
}
source

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");
}
source

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");
    });
}
source

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)
}
source

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));
}
source

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")
}
source

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));
    }
}
source

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 Strings 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>

Plugin GUI

Allows you to add and remove fake plugins from the plugin GUI.

source

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.

source

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.

Trait Implementations§

source§

impl<'ph, P> Clone for PluginHandle<'ph, P>

source§

fn clone(&self) -> Self

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<'ph, P: Debug + 'static> Debug for PluginHandle<'ph, P>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<'ph, P> Copy for PluginHandle<'ph, P>

Auto Trait Implementations§

§

impl<'ph, P> Freeze for PluginHandle<'ph, P>

§

impl<'ph, P> RefUnwindSafe for PluginHandle<'ph, P>
where P: RefUnwindSafe,

§

impl<'ph, P> !Send for PluginHandle<'ph, P>

§

impl<'ph, P> !Sync for PluginHandle<'ph, P>

§

impl<'ph, P> Unpin for PluginHandle<'ph, P>
where P: Unpin,

§

impl<'ph, P> UnwindSafe for PluginHandle<'ph, P>
where P: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.