use crate::{config::OptionChanged, LossyCString, Weechat};
use std::{borrow::Cow, convert::TryFrom, ffi::CStr};
use weechat_sys::{t_config_option, t_weechat_plugin};
#[derive(Debug, PartialEq, Clone)]
#[allow(missing_docs)]
pub enum OptionType {
Boolean,
Integer,
String,
Color,
}
impl TryFrom<&str> for OptionType {
type Error = &'static str;
fn try_from(value: &str) -> Result<Self, Self::Error> {
let ret = match value {
"boolean" => OptionType::Boolean,
"integer" => OptionType::Integer,
"string" => OptionType::String,
"color" => OptionType::Color,
_ => return Err("Invalid option type"),
};
Ok(ret)
}
}
impl OptionType {
pub(crate) fn as_str(&self) -> &'static str {
match self {
OptionType::Boolean => "boolean",
OptionType::Integer => "integer",
OptionType::String => "string",
OptionType::Color => "color",
}
}
}
impl Default for OptionType {
fn default() -> Self {
OptionType::String
}
}
pub trait FromPtrs {
fn from_ptrs(option_ptr: *mut t_config_option, weechat_ptr: *mut t_weechat_plugin) -> Self;
}
pub trait HidenConfigOptionT {
fn get_ptr(&self) -> *mut t_config_option;
fn get_weechat(&self) -> Weechat;
fn get_string(&self, property: &str) -> Option<Cow<str>> {
let weechat = self.get_weechat();
let get_string = weechat.get().config_option_get_string.unwrap();
let property = LossyCString::new(property);
unsafe {
let string = get_string(self.get_ptr(), property.as_ptr());
if string.is_null() {
None
} else {
Some(CStr::from_ptr(string).to_string_lossy())
}
}
}
}
pub trait BaseConfigOption: HidenConfigOptionT {
fn name(&self) -> Cow<str> {
self.get_string("name")
.expect("Can't get the name of the option")
}
fn description(&self) -> Cow<str> {
self.get_string("description")
.expect("Can't get the description of the option")
}
fn section_name(&self) -> Cow<str> {
self.get_string("section_name")
.expect("Can't get the section name of the option")
}
fn config_name(&self) -> Cow<str> {
self.get_string("config_name")
.expect("Can't get the config name of the option")
}
fn option_type(&self) -> OptionType {
let option_type = self
.get_string("type")
.expect("Can't get the config name of the option");
OptionType::try_from(option_type.as_ref()).unwrap()
}
fn reset(&self, run_callback: bool) -> OptionChanged {
let weechat = self.get_weechat();
let option_reset = weechat.get().config_option_reset.unwrap();
let ret = unsafe { option_reset(self.get_ptr(), run_callback as i32) };
OptionChanged::from_int(ret)
}
fn set(&self, value: &str, run_callback: bool) -> OptionChanged {
let value = LossyCString::new(value);
let weechat = self.get_weechat();
let option_set = weechat.get().config_option_set.unwrap();
let ret = unsafe { option_set(self.get_ptr(), value.as_ptr(), run_callback as i32) };
OptionChanged::from_int(ret)
}
fn is_null(&self) -> bool {
let weechat = self.get_weechat();
let is_null = weechat.get().config_option_is_null.unwrap();
let ret = unsafe { is_null(self.get_ptr()) };
ret != 0
}
}
pub trait ConfigOptions: BaseConfigOption + FromPtrs {}
pub(crate) type CheckCB<T> = dyn FnMut(&Weechat, &T, Cow<str>) -> bool;
pub(crate) struct OptionPointers<T> {
pub(crate) weechat_ptr: *mut t_weechat_plugin,
pub(crate) check_cb: Option<Box<CheckCB<T>>>,
pub(crate) change_cb: Option<Box<dyn FnMut(&Weechat, &T)>>,
pub(crate) delete_cb: Option<Box<dyn FnMut(&Weechat, &T)>>,
}