1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 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
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
//! # `rust-weechat`
//!
//! rust-weechat implements high level bindings for the Weechat plugin API.
//!
//! The bindings make it possible to create powerful Weechat plugins using rust.
//!
//! ```no_run
//! use std::borrow::Cow;
//! use weechat::buffer::{Buffer, BufferSettings, NickSettings};
//! use weechat::hooks::{CommandSettings, Command};
//! use weechat::{weechat_plugin, ArgsWeechat, Weechat, WeechatPlugin};
//!
//! struct SamplePlugin {
//!     _command: Command,
//! }
//!
//! impl SamplePlugin {
//!     fn input_cb(
//!         _weechat: &Weechat,
//!         buffer: &Buffer,
//!         input: Cow<str>,
//!     ) -> Result<(), ()> {
//!         buffer.print(&input);
//!         Ok(())
//!     }
//!
//!     fn close_cb(_weechat: &Weechat, _buffer: &Buffer) -> Result<(), ()> {
//!         Weechat::print("Closing buffer");
//!         Ok(())
//!     }
//!
//!     fn rust_command_cb(_weechat: &Weechat, buffer: &Buffer, args: ArgsWeechat) {
//!        buffer.print("Hello world");
//!
//!        for arg in args {
//!            buffer.print(&arg)
//!        }
//!    }
//! }
//!
//! impl WeechatPlugin for SamplePlugin {
//!     fn init(weechat: &Weechat, _args: ArgsWeechat) -> Result<Self, ()> {
//!         Weechat::print("Hello Rust!");
//!
//!         let buffer_settings = BufferSettings::new("Test buffer")
//!             .input_callback(SamplePlugin::input_cb)
//!             .close_callback(SamplePlugin::close_cb);
//!
//!         let buffer_handle =
//!             Weechat::buffer_new(buffer_settings).expect("Can't create buffer");
//!
//!         let buffer = buffer_handle.upgrade().expect("Buffer already closed?");
//!
//!         let op_group = buffer
//!             .add_nicklist_group("operators", "blue", true, None)
//!             .expect("Can't create nick group");
//!         let emma = op_group
//!             .add_nick(
//!                 NickSettings::new("Emma")
//!                     .set_color("magenta")
//!                     .set_prefix("&")
//!                     .set_prefix_color("green"),
//!             )
//!             .expect("Can't add nick to group");
//!
//!         let sample_command = CommandSettings::new("rustcommand");
//!
//!         let command = Command::new(
//!             sample_command,
//!             SamplePlugin::rust_command_cb,
//!         );
//!
//!         Ok(SamplePlugin {
//!             _command: command.unwrap(),
//!         })
//!     }
//! }
//!
//! impl Drop for SamplePlugin {
//!     fn drop(&mut self) {
//!         Weechat::print("Bye rust");
//!     }
//! }
//! ```
//!
//! The above plugin implementation still needs to be registered as a Weechat
//! plugin:
//!
//! ```ignore
//! weechat_plugin!(
//!     SamplePlugin,
//!     name: "rust_sample",
//!     author: "poljar",
//!     description: "",
//!     version: "0.1.0",
//!     license: "MIT"
//! );
//! ```

#![deny(missing_docs)]

use std::ffi::CString;

#[cfg(feature = "async-executor")]
mod executor;
mod hashtable;
mod hdata;
mod weechat;

#[cfg(feature = "config-macro")]
#[macro_use]
mod config_macros;

#[cfg(feature = "config-macro")]
pub use paste;
#[cfg(feature = "config-macro")]
pub use strum;

pub mod buffer;
pub mod config;
pub mod hooks;
pub mod infolist;

pub use crate::weechat::{ArgsWeechat, Weechat};

pub use libc;
pub use weechat_macro::weechat_plugin;
pub use weechat_sys;

/// Weechat plugin trait.
///
/// Implement this trait over your struct to implement a Weechat plugin. The
/// init method will get called when Weechat loads the plugin, while the
/// Drop method will be called when Weechat unloads the plugin.
pub trait WeechatPlugin: Sized {
    /// Initialize the plugin.
    ///
    /// # Arguments
    ///
    /// * `weechat` - A borrow to a Weechat object that will be valid during the
    ///     duration of the init callback.
    ///
    /// * `args` - Arguments passed to the plugin when it is loaded.
    fn init(weechat: &Weechat, args: ArgsWeechat) -> Result<Self, ()>;
}

#[cfg(feature = "async-executor")]
pub use executor::JoinHandle;

/// Status values for Weechat callbacks
pub enum ReturnCode {
    /// The callback returned successfully.
    Ok = weechat_sys::WEECHAT_RC_OK as isize,
    /// The callback returned successfully and the command will not be executed
    /// after the callback.
    OkEat = weechat_sys::WEECHAT_RC_OK_EAT as isize,
    /// The callback returned with an error.
    Error = weechat_sys::WEECHAT_RC_ERROR as isize,
}

pub(crate) struct LossyCString;

impl LossyCString {
    #[allow(clippy::new_ret_no_self)]
    pub(crate) fn new<T: AsRef<str>>(t: T) -> CString {
        match CString::new(t.as_ref()) {
            Ok(cstr) => cstr,
            Err(_) => CString::new(t.as_ref().replace('\0', ""))
                .expect("string has no nulls"),
        }
    }
}