use libedit_sys::*;
use std::ffi::CString;
use crate::error::{Error, Result};
use crate::shim;
pub const DEFAULT_HISTORY_SIZE: usize = 100;
pub struct History {
inner: *mut libedit_sys::History,
}
impl std::fmt::Debug for History {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("History")
.field("inner", &self.inner)
.finish()
}
}
impl History {
pub fn new() -> Self {
Self::with_size(DEFAULT_HISTORY_SIZE)
}
pub fn with_size(size: usize) -> Self {
let inner = unsafe { history_init() };
assert!(!inner.is_null(), "history_init returned null");
unsafe { shim::history_setsize(inner, size as i32) };
History { inner }
}
pub fn set_size(&mut self, size: usize) {
unsafe { shim::history_setsize(self.inner, size as i32) }
}
pub fn set_unique(&mut self, unique: bool) {
unsafe { shim::history_setunique(self.inner, unique) }
}
pub fn add(&mut self, entry: impl AsRef<str>) -> Result<()> {
let c_entry = CString::new(entry.as_ref())?;
let ok = unsafe { shim::history_enter(self.inner, &c_entry) };
if ok {
Ok(())
} else {
Err(Error::operation(0, -1))
}
}
pub fn first(&self) -> Result<String> {
unsafe { shim::history_first(self.inner) }.ok_or(Error::NotFound)
}
pub fn len(&self) -> usize {
unsafe { shim::history_len(self.inner) }
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn clear(&mut self) {
unsafe { shim::history_clear_all(self.inner) }
}
pub fn load(&mut self, path: impl AsRef<std::path::Path>) -> Result<()> {
let c_path = path_to_cstring(path.as_ref())?;
let rc = unsafe { shim::history_load(self.inner, &c_path) };
if rc < 0 {
return Err(Error::operation(0, rc));
}
Ok(())
}
pub fn save(&self, path: impl AsRef<std::path::Path>) -> Result<()> {
let c_path = path_to_cstring(path.as_ref())?;
let rc = unsafe { shim::history_save(self.inner, &c_path) };
if rc < 0 {
return Err(Error::operation(0, rc));
}
Ok(())
}
pub(crate) fn as_mut_ptr(&mut self) -> *mut libedit_sys::History {
self.inner
}
pub unsafe fn as_ptr(&self) -> *mut libedit_sys::History {
self.inner
}
}
pub(crate) fn path_to_cstring(path: &std::path::Path) -> Result<CString> {
#[cfg(unix)]
{
use std::os::unix::ffi::OsStrExt;
Ok(CString::new(path.as_os_str().as_bytes())?)
}
#[cfg(not(unix))]
{
let s = path.to_str().ok_or(Error::NotFound)?;
Ok(CString::new(s)?)
}
}
impl Default for History {
fn default() -> Self {
Self::new()
}
}
impl Drop for History {
fn drop(&mut self) {
unsafe { history_end(self.inner) };
}
}