mod lines;
mod nick;
mod nickgroup;
use std::{
borrow::Cow,
cmp::{Ord, Ordering},
ffi::{c_void, CStr},
marker::PhantomData,
ptr,
};
use std::{cell::Cell, rc::Rc};
#[cfg(feature = "async")]
use async_trait::async_trait;
#[cfg(feature = "async")]
use futures::future::LocalBoxFuture;
use crate::{LossyCString, Weechat};
use libc::{c_char, c_int};
use weechat_sys::{
t_gui_buffer, t_gui_nick, t_hdata, t_weechat_plugin, WEECHAT_RC_ERROR, WEECHAT_RC_OK,
};
pub use crate::buffer::{
lines::{BufferLine, BufferLines, LineData},
nick::{Nick, NickSettings},
nickgroup::NickGroup,
};
pub struct Buffer<'a> {
pub(crate) inner: InnerBuffers<'a>,
}
impl<'a> std::fmt::Debug for Buffer<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Buffer")
.field("full_name", &self.full_name())
.finish()
}
}
pub(crate) enum InnerBuffers<'a> {
BorrowedBuffer(InnerBuffer<'a>),
OwnedBuffer(InnerOwnedBuffer<'a>),
}
impl<'a> InnerBuffers<'a> {
fn is_closing(&self) -> bool {
match self {
InnerBuffers::BorrowedBuffer(b) => b.closing.get(),
InnerBuffers::OwnedBuffer(b) => b.closing.get(),
}
}
fn mark_as_closing(&self) {
match self {
InnerBuffers::BorrowedBuffer(b) => b.closing.as_ref().replace(true),
InnerBuffers::OwnedBuffer(b) => b.closing.as_ref().replace(true),
};
}
}
impl<'a> InnerBuffers<'a> {
pub(crate) fn weechat_ptr(&self) -> *mut t_weechat_plugin {
match self {
InnerBuffers::BorrowedBuffer(b) => b.weechat,
InnerBuffers::OwnedBuffer(b) => b.weechat,
}
}
}
pub(crate) struct InnerOwnedBuffer<'a> {
pub(crate) weechat: *mut t_weechat_plugin,
pub(crate) buffer_handle: &'a BufferHandle,
closing: Rc<Cell<bool>>,
}
pub(crate) struct InnerBuffer<'a> {
pub(crate) weechat: *mut t_weechat_plugin,
pub(crate) ptr: *mut t_gui_buffer,
pub(crate) weechat_phantom: PhantomData<&'a Weechat>,
pub(crate) closing: Rc<Cell<bool>>,
}
impl PartialEq for Buffer<'_> {
fn eq(&self, other: &Buffer) -> bool {
self.ptr() == other.ptr()
}
}
impl PartialOrd for Buffer<'_> {
fn partial_cmp(&self, other: &Buffer) -> Option<Ordering> {
self.number().partial_cmp(&other.number())
}
}
impl Eq for Buffer<'_> {}
impl Ord for Buffer<'_> {
fn cmp(&self, other: &Self) -> Ordering {
self.number().cmp(&other.number())
}
}
#[derive(Clone)]
pub struct BufferHandle {
buffer_name: Rc<String>,
weechat: *mut t_weechat_plugin,
buffer_ptr: Rc<Cell<*mut t_gui_buffer>>,
closing: Rc<Cell<bool>>,
}
impl BufferHandle {
pub fn upgrade(&self) -> Result<Buffer<'_>, ()> {
let ptr = self.buffer_ptr.get();
if ptr.is_null() {
Err(())
} else {
let buffer = Buffer {
inner: InnerBuffers::OwnedBuffer(InnerOwnedBuffer {
weechat: self.weechat,
buffer_handle: self,
closing: self.closing.clone(),
}),
};
Ok(buffer)
}
}
}
#[cfg(feature = "async")]
pub(crate) struct BufferPointersAsync {
pub(crate) weechat: *mut t_weechat_plugin,
pub(crate) input_cb: Option<Box<dyn BufferInputCallbackAsync>>,
pub(crate) close_cb: Option<Box<dyn BufferCloseCallback>>,
pub(crate) buffer_cell: Option<Rc<Cell<*mut t_gui_buffer>>>,
}
pub(crate) struct BufferPointers {
pub(crate) weechat: *mut t_weechat_plugin,
pub(crate) input_cb: Option<Box<dyn BufferInputCallback>>,
pub(crate) close_cb: Option<Box<dyn BufferCloseCallback>>,
pub(crate) buffer_cell: Option<Rc<Cell<*mut t_gui_buffer>>>,
}
pub trait BufferInputCallback: 'static {
fn callback(&mut self, weechat: &Weechat, buffer: &Buffer, input: Cow<str>) -> Result<(), ()>;
}
impl<T: FnMut(&Weechat, &Buffer, Cow<str>) -> Result<(), ()> + 'static> BufferInputCallback for T {
fn callback(&mut self, weechat: &Weechat, buffer: &Buffer, input: Cow<str>) -> Result<(), ()> {
self(weechat, buffer, input)
}
}
pub trait BufferCloseCallback {
fn callback(&mut self, weechat: &Weechat, buffer: &Buffer) -> Result<(), ()>;
}
impl<T: FnMut(&Weechat, &Buffer) -> Result<(), ()> + 'static> BufferCloseCallback for T {
fn callback(&mut self, weechat: &Weechat, buffer: &Buffer) -> Result<(), ()> {
self(weechat, buffer)
}
}
#[cfg(feature = "async")]
#[cfg_attr(feature = "docs", doc(cfg(r#async)))]
#[async_trait(?Send)]
pub trait BufferInputCallbackAsync: 'static {
async fn callback(&mut self, buffer: BufferHandle, input: String);
}
#[cfg(feature = "async")]
#[async_trait(?Send)]
impl<T: FnMut(BufferHandle, String) -> LocalBoxFuture<'static, ()> + 'static>
BufferInputCallbackAsync for T
{
async fn callback(&mut self, buffer: BufferHandle, input: String) {
self(buffer, input).await
}
}
#[cfg(feature = "async")]
#[cfg_attr(feature = "docs", doc(cfg(r#async)))]
pub struct BufferBuilderAsync {
pub(crate) name: String,
pub(crate) input_callback: Option<Box<dyn BufferInputCallbackAsync>>,
pub(crate) close_callback: Option<Box<dyn BufferCloseCallback>>,
}
pub struct BufferBuilder {
pub(crate) name: String,
pub(crate) input_callback: Option<Box<dyn BufferInputCallback>>,
pub(crate) close_callback: Option<Box<dyn BufferCloseCallback>>,
}
#[cfg(feature = "async")]
impl BufferBuilderAsync {
pub fn new(name: &str) -> Self {
BufferBuilderAsync {
name: name.to_owned(),
input_callback: None,
close_callback: None,
}
}
pub fn input_callback(mut self, callback: impl BufferInputCallbackAsync) -> Self {
self.input_callback = Some(Box::new(callback));
self
}
pub fn close_callback(mut self, callback: impl BufferCloseCallback + 'static) -> Self {
self.close_callback = Some(Box::new(callback));
self
}
pub fn build(self) -> Result<BufferHandle, ()> {
Weechat::buffer_new_with_async(self)
}
}
impl BufferBuilder {
pub fn new(name: &str) -> Self {
BufferBuilder {
name: name.to_owned(),
input_callback: None,
close_callback: None,
}
}
pub fn input_callback(mut self, callback: impl BufferInputCallback + 'static) -> Self {
self.input_callback = Some(Box::new(callback));
self
}
pub fn close_callback(mut self, callback: impl BufferCloseCallback + 'static) -> Self {
self.close_callback = Some(Box::new(callback));
self
}
pub fn build(self) -> Result<BufferHandle, ()> {
Weechat::buffer_new(self)
}
}
impl Weechat {
pub fn buffer_search(&self, plugin_name: &str, buffer_name: &str) -> Option<Buffer> {
let buffer_search = self.get().buffer_search.unwrap();
let plugin_name = LossyCString::new(plugin_name);
let buffer_name = LossyCString::new(buffer_name);
let buf_ptr = unsafe { buffer_search(plugin_name.as_ptr(), buffer_name.as_ptr()) };
if buf_ptr.is_null() {
None
} else {
Some(self.buffer_from_ptr(buf_ptr))
}
}
pub(crate) fn buffer_from_ptr(&self, buffer_ptr: *mut t_gui_buffer) -> Buffer {
Buffer {
inner: InnerBuffers::BorrowedBuffer(InnerBuffer {
weechat: self.ptr,
ptr: buffer_ptr,
weechat_phantom: PhantomData,
closing: Rc::new(Cell::new(false)),
}),
}
}
pub fn current_buffer(&self) -> Buffer {
let buffer_search = self.get().buffer_search.unwrap();
let buf_ptr = unsafe { buffer_search(ptr::null(), ptr::null()) };
if buf_ptr.is_null() {
panic!("No open buffer found");
} else {
self.buffer_from_ptr(buf_ptr)
}
}
#[cfg(feature = "async")]
#[cfg_attr(feature = "docs", doc(cfg(r#async)))]
fn buffer_new_with_async(builder: BufferBuilderAsync) -> Result<BufferHandle, ()> {
unsafe extern "C" fn c_input_cb(
pointer: *const c_void,
_data: *mut c_void,
buffer: *mut t_gui_buffer,
input_data: *const c_char,
) -> c_int {
let input_data = CStr::from_ptr(input_data).to_string_lossy();
let pointers: &mut BufferPointersAsync =
{ &mut *(pointer as *mut BufferPointersAsync) };
let weechat = Weechat::from_ptr(pointers.weechat);
let buffer = weechat.buffer_from_ptr(buffer);
let buffer_cell = pointers
.buffer_cell
.as_ref()
.expect("Buffer cell wasn't initialized properly")
.clone();
let buffer_handle = BufferHandle {
buffer_name: Rc::new(buffer.full_name().to_string()),
weechat: pointers.weechat,
buffer_ptr: buffer_cell,
closing: Rc::new(Cell::new(false)),
};
if let Some(cb) = pointers.input_cb.as_mut() {
let future = cb.callback(buffer_handle, input_data.to_string());
Weechat::spawn_buffer_cb(buffer.full_name().to_string(), future).detach();
}
WEECHAT_RC_OK
}
unsafe extern "C" fn c_close_cb(
pointer: *const c_void,
_data: *mut c_void,
buffer: *mut t_gui_buffer,
) -> c_int {
let pointers = Box::from_raw(pointer as *mut BufferPointersAsync);
let weechat = Weechat::from_ptr(pointers.weechat);
let buffer = weechat.buffer_from_ptr(buffer);
buffer.mark_as_closing();
let ret = if let Some(mut cb) = pointers.close_cb {
cb.callback(&weechat, &buffer).is_ok()
} else {
true
};
pointers
.buffer_cell
.as_ref()
.expect("Buffer cell wasn't initialized properly")
.replace(ptr::null_mut());
if ret {
WEECHAT_RC_OK
} else {
WEECHAT_RC_ERROR
}
}
Weechat::check_thread();
let weechat = unsafe { Weechat::weechat() };
let c_input_cb: Option<WeechatInputCbT> = match builder.input_callback {
Some(_) => Some(c_input_cb),
None => None,
};
let buffer_pointers = Box::new(BufferPointersAsync {
weechat: weechat.ptr,
input_cb: builder.input_callback,
close_cb: builder.close_callback,
buffer_cell: None,
});
let buffer_pointers_ref = Box::leak(buffer_pointers);
let buf_new = weechat.get().buffer_new.unwrap();
let c_name = LossyCString::new(builder.name);
let buf_ptr = unsafe {
buf_new(
weechat.ptr,
c_name.as_ptr(),
c_input_cb,
buffer_pointers_ref as *const _ as *const c_void,
ptr::null_mut(),
Some(c_close_cb),
buffer_pointers_ref as *const _ as *const c_void,
ptr::null_mut(),
)
};
if buf_ptr.is_null() {
unsafe { Box::from_raw(buffer_pointers_ref) };
return Err(());
}
let pointers: &mut BufferPointersAsync =
unsafe { &mut *(buffer_pointers_ref as *mut BufferPointersAsync) };
let buffer = weechat.buffer_from_ptr(buf_ptr);
let buffer_cell = Rc::new(Cell::new(buf_ptr));
pointers.buffer_cell = Some(buffer_cell.clone());
Ok(BufferHandle {
buffer_name: Rc::new(buffer.full_name().to_string()),
weechat: weechat.ptr,
buffer_ptr: buffer_cell,
closing: Rc::new(Cell::new(false)),
})
}
fn buffer_new(builder: BufferBuilder) -> Result<BufferHandle, ()> {
unsafe extern "C" fn c_input_cb(
pointer: *const c_void,
_data: *mut c_void,
buffer: *mut t_gui_buffer,
input_data: *const c_char,
) -> c_int {
let input_data = CStr::from_ptr(input_data).to_string_lossy();
let pointers: &mut BufferPointers = { &mut *(pointer as *mut BufferPointers) };
let weechat = Weechat::from_ptr(pointers.weechat);
let buffer = weechat.buffer_from_ptr(buffer);
let ret = if let Some(ref mut cb) = pointers.input_cb.as_mut() {
cb.callback(&weechat, &buffer, input_data).is_ok()
} else {
true
};
if ret {
WEECHAT_RC_OK
} else {
WEECHAT_RC_ERROR
}
}
unsafe extern "C" fn c_close_cb(
pointer: *const c_void,
_data: *mut c_void,
buffer: *mut t_gui_buffer,
) -> c_int {
let pointers = Box::from_raw(pointer as *mut BufferPointers);
let weechat = Weechat::from_ptr(pointers.weechat);
let buffer = weechat.buffer_from_ptr(buffer);
buffer.mark_as_closing();
let ret = if let Some(mut cb) = pointers.close_cb {
cb.callback(&weechat, &buffer).is_ok()
} else {
true
};
pointers
.buffer_cell
.as_ref()
.expect("Buffer cell wasn't initialized properly")
.replace(ptr::null_mut());
if ret {
WEECHAT_RC_OK
} else {
WEECHAT_RC_ERROR
}
}
Weechat::check_thread();
let weechat = unsafe { Weechat::weechat() };
let c_input_cb: Option<WeechatInputCbT> = match builder.input_callback {
Some(_) => Some(c_input_cb),
None => None,
};
let buffer_pointers = Box::new(BufferPointers {
weechat: weechat.ptr,
input_cb: builder.input_callback,
close_cb: builder.close_callback,
buffer_cell: None,
});
let buffer_pointers_ref = Box::leak(buffer_pointers);
let buf_new = weechat.get().buffer_new.unwrap();
let c_name = LossyCString::new(builder.name);
let buf_ptr = unsafe {
buf_new(
weechat.ptr,
c_name.as_ptr(),
c_input_cb,
buffer_pointers_ref as *const _ as *const c_void,
ptr::null_mut(),
Some(c_close_cb),
buffer_pointers_ref as *const _ as *const c_void,
ptr::null_mut(),
)
};
if buf_ptr.is_null() {
unsafe { Box::from_raw(buffer_pointers_ref) };
return Err(());
}
let pointers: &mut BufferPointers =
unsafe { &mut *(buffer_pointers_ref as *mut BufferPointers) };
let buffer = weechat.buffer_from_ptr(buf_ptr);
let buffer_cell = Rc::new(Cell::new(buf_ptr));
pointers.buffer_cell = Some(buffer_cell.clone());
Ok(BufferHandle {
buffer_name: Rc::new(buffer.full_name().to_string()),
weechat: weechat.ptr,
buffer_ptr: buffer_cell,
closing: Rc::new(Cell::new(false)),
})
}
}
pub(crate) type WeechatInputCbT = unsafe extern "C" fn(
pointer: *const c_void,
data: *mut c_void,
buffer: *mut t_gui_buffer,
input_data: *const c_char,
) -> c_int;
impl Buffer<'_> {
fn weechat(&self) -> Weechat {
let ptr = match &self.inner {
InnerBuffers::BorrowedBuffer(b) => b.weechat,
InnerBuffers::OwnedBuffer(b) => b.weechat,
};
Weechat::from_ptr(ptr)
}
pub(crate) fn ptr(&self) -> *mut t_gui_buffer {
match &self.inner {
InnerBuffers::BorrowedBuffer(b) => b.ptr,
InnerBuffers::OwnedBuffer(b) => {
let ptr = b.buffer_handle.buffer_ptr.get();
if ptr.is_null() {
panic!("Buffer {} has been closed.", b.buffer_handle.buffer_name)
} else {
ptr
}
}
}
}
fn is_closing(&self) -> bool {
self.inner.is_closing()
}
fn mark_as_closing(&self) {
self.inner.mark_as_closing()
}
pub fn print(&self, message: &str) {
let weechat = self.weechat();
let printf_date_tags = weechat.get().printf_date_tags.unwrap();
let fmt_str = LossyCString::new("%s");
let c_message = LossyCString::new(message);
unsafe {
printf_date_tags(
self.ptr(),
0,
ptr::null(),
fmt_str.as_ptr(),
c_message.as_ptr(),
)
}
}
pub fn print_date_tags(&self, date: i64, tags: &[&str], message: &str) {
let weechat = self.weechat();
let printf_date_tags = weechat.get().printf_date_tags.unwrap();
let fmt_str = LossyCString::new("%s");
let tags = tags.join(",");
let tags = LossyCString::new(tags);
let message = LossyCString::new(message);
unsafe {
printf_date_tags(
self.ptr(),
date,
tags.as_ptr(),
fmt_str.as_ptr(),
message.as_ptr(),
)
}
}
pub fn search_nicklist_group(&self, name: &str) -> Option<NickGroup> {
let weechat = self.weechat();
let nicklist_search_group = weechat.get().nicklist_search_group.unwrap();
let name = LossyCString::new(name);
let group = unsafe { nicklist_search_group(self.ptr(), ptr::null_mut(), name.as_ptr()) };
if group.is_null() {
None
} else {
Some(NickGroup {
ptr: group,
buf_ptr: self.ptr(),
weechat_ptr: self.weechat().ptr,
buffer: PhantomData,
})
}
}
pub fn search_nick(&self, nick: &str) -> Option<Nick> {
let weechat = self.weechat();
let nick = Buffer::search_nick_helper(&weechat, self.ptr(), nick, None);
if nick.is_null() {
None
} else {
Some(Nick {
ptr: nick,
buf_ptr: self.ptr(),
weechat_ptr: weechat.ptr,
buffer: PhantomData,
})
}
}
fn search_nick_helper(
weechat: &Weechat,
buffer_ptr: *mut t_gui_buffer,
nick: &str,
group: Option<&NickGroup>,
) -> *mut t_gui_nick {
let nicklist_search_nick = weechat.get().nicklist_search_nick.unwrap();
let nick = LossyCString::new(nick);
let group_ptr = group.map(|g| g.ptr).unwrap_or(ptr::null_mut());
unsafe { nicklist_search_nick(buffer_ptr, group_ptr, nick.as_ptr()) }
}
pub fn add_nick(&self, nick_settings: NickSettings) -> Result<Nick, ()> {
let weechat = self.weechat();
let nick_ptr = Buffer::add_nick_helper(&weechat, self.ptr(), nick_settings, None);
if nick_ptr.is_null() {
return Err(());
}
Ok(Nick {
ptr: nick_ptr,
buf_ptr: self.ptr(),
weechat_ptr: self.weechat().ptr,
buffer: PhantomData,
})
}
pub fn remove_nicklist_group(&self, group_name: &str) -> bool {
let weechat = self.weechat();
let group = self.search_nicklist_group(group_name);
match group {
Some(group) => {
let nicklist_remove_group = weechat.get().nicklist_remove_group.unwrap();
unsafe {
nicklist_remove_group(self.ptr(), group.ptr);
}
true
}
None => false,
}
}
pub fn remove_nick(&self, nick: &str) -> bool {
let weechat = self.weechat();
let nick = self.search_nick(nick);
match nick {
Some(nick) => {
let nicklist_remove_nick = weechat.get().nicklist_remove_nick.unwrap();
unsafe {
nicklist_remove_nick(self.ptr(), nick.ptr);
}
true
}
None => false,
}
}
fn add_nick_helper(
weechat: &Weechat,
buffer_ptr: *mut t_gui_buffer,
nick_settings: NickSettings,
group: Option<&NickGroup>,
) -> *mut t_gui_nick {
let c_nick = LossyCString::new(nick_settings.name);
let color = LossyCString::new(nick_settings.color);
let prefix = LossyCString::new(nick_settings.prefix);
let prefix_color = LossyCString::new(nick_settings.prefix_color);
let add_nick = weechat.get().nicklist_add_nick.unwrap();
let group_ptr = match group {
Some(g) => g.ptr,
None => ptr::null_mut(),
};
unsafe {
add_nick(
buffer_ptr,
group_ptr,
c_nick.as_ptr(),
color.as_ptr(),
prefix.as_ptr(),
prefix_color.as_ptr(),
nick_settings.visible as i32,
)
}
}
pub fn add_nicklist_group(
&self,
name: &str,
color: &str,
visible: bool,
parent_group: Option<&NickGroup>,
) -> Result<NickGroup, ()> {
let weechat = self.weechat();
let add_group = weechat.get().nicklist_add_group.unwrap();
let c_name = LossyCString::new(name);
let c_color = LossyCString::new(color);
let group_ptr = match parent_group {
Some(g) => g.ptr,
None => ptr::null_mut(),
};
let group_ptr = unsafe {
add_group(
self.ptr(),
group_ptr,
c_name.as_ptr(),
c_color.as_ptr(),
visible as i32,
)
};
if group_ptr.is_null() {
return Err(());
}
Ok(NickGroup {
ptr: group_ptr,
buf_ptr: self.ptr(),
weechat_ptr: self.weechat().ptr,
buffer: PhantomData,
})
}
fn set(&self, property: &str, value: &str) {
let weechat = self.weechat();
let buffer_set = weechat.get().buffer_set.unwrap();
let option = LossyCString::new(property);
let value = LossyCString::new(value);
unsafe { buffer_set(self.ptr(), option.as_ptr(), value.as_ptr()) };
}
fn get_string(&self, property: &str) -> Option<Cow<str>> {
let weechat = self.weechat();
let buffer_get = weechat.get().buffer_get_string.unwrap();
let property = LossyCString::new(property);
unsafe {
let value = buffer_get(self.ptr(), property.as_ptr());
if value.is_null() {
None
} else {
Some(CStr::from_ptr(value).to_string_lossy())
}
}
}
fn get_integer(&self, property: &str) -> i32 {
let weechat = self.weechat();
let buffer_get = weechat.get().buffer_get_integer.unwrap();
let property = LossyCString::new(property);
unsafe { buffer_get(self.ptr(), property.as_ptr()) }
}
pub fn get_localvar(&self, property: &str) -> Option<Cow<str>> {
self.get_string(&format!("localvar_{}", property))
}
pub fn set_localvar(&self, property: &str, value: &str) {
self.set(&format!("localvar_set_{}", property), value)
}
pub fn full_name(&self) -> Cow<str> {
self.get_string("full_name").unwrap()
}
pub fn set_full_name(&self, name: &str) {
self.set("full_name", name);
}
pub fn name(&self) -> Cow<str> {
self.get_string("name").unwrap()
}
pub fn set_name(&self, name: &str) {
self.set("name", name);
}
pub fn short_name(&self) -> Cow<str> {
self.get_string("short_name").unwrap()
}
pub fn set_short_name(&self, name: &str) {
self.set("short_name", name);
}
pub fn plugin_name(&self) -> Cow<str> {
self.get_string("plugin").unwrap()
}
pub fn disable_time_for_each_line(&self) {
self.set("time_for_each_line", "0");
}
pub fn disable_nicklist(&self) {
self.set("nicklist", "0")
}
pub fn enable_nicklist(&self) {
self.set("nicklist", "1")
}
pub fn title(&self) {
self.get_string("title");
}
pub fn set_title(&self, title: &str) {
self.set("title", title);
}
pub fn disable_log(&self) {
self.set("localvar_set_no_log", "1");
}
pub fn clear(&self) {
let weechat = self.weechat();
let buffer_clear = weechat.get().buffer_clear.unwrap();
unsafe { buffer_clear(self.ptr()) }
}
pub fn close(&self) {
if !self.is_closing() {
let weechat = self.weechat();
let buffer_close = weechat.get().buffer_close.unwrap();
unsafe { buffer_close(self.ptr()) };
self.mark_as_closing();
}
}
pub fn input(&self) -> Cow<str> {
self.get_string("input").unwrap()
}
pub fn set_input(&self, input: &str) {
self.set("input", input)
}
pub fn input_position(&self) -> i32 {
self.get_integer("input_pos")
}
pub fn set_input_position(&self, position: i32) {
self.set("input_pos", &position.to_string())
}
pub fn number(&self) -> i32 {
self.get_integer("number")
}
pub fn switch_to(&self) {
self.set("display", "1");
}
pub fn run_command(&self, command: &str) -> Result<(), ()> {
let command = LossyCString::new(command);
let weechat = self.weechat();
let run_command = weechat.get().command.unwrap();
let ret = unsafe { run_command(weechat.ptr, self.ptr(), command.as_ptr()) };
match ret {
WEECHAT_RC_OK => Ok(()),
WEECHAT_RC_ERROR => Err(()),
_ => unreachable!(),
}
}
fn hdata_pointer(&self) -> *mut t_hdata {
let weechat = self.weechat();
unsafe { weechat.hdata_get("buffer") }
}
fn own_lines(&self) -> *mut c_void {
let weechat = self.weechat();
let hdata = self.hdata_pointer();
unsafe { weechat.hdata_pointer(hdata, self.ptr() as *mut c_void, "own_lines") }
}
pub fn num_lines(&self) -> i32 {
let weechat = self.weechat();
let own_lines = self.own_lines();
unsafe {
let lines = weechat.hdata_get("lines");
weechat.hdata_integer(lines, own_lines, "lines_count")
}
}
pub fn lines(&self) -> BufferLines {
let weechat = self.weechat();
let own_lines = self.own_lines();
let (first_line, last_line) = unsafe {
let lines = weechat.hdata_get("lines");
(
weechat.hdata_pointer(lines, own_lines, "first_line"),
weechat.hdata_pointer(lines, own_lines, "last_line"),
)
};
BufferLines {
weechat_ptr: self.weechat().ptr,
first_line,
last_line,
buffer: PhantomData,
done: false,
}
}
}