use std::ops::RangeBounds;
use nvim_types::{
self as nvim,
conversion::FromObject,
Array,
Dictionary,
Integer,
};
use crate::choose;
use crate::ffi::extmark::*;
use crate::iterator::SuperIterator;
use crate::opts::*;
use crate::types::*;
use crate::utils;
use crate::Buffer;
use crate::{Error, Result};
impl Buffer {
pub fn add_highlight<R>(
&mut self,
ns_id: u32,
hl_group: &str,
line: usize,
byte_range: R,
) -> Result<i64>
where
R: RangeBounds<usize>,
{
let hl_group = nvim::String::from(hl_group);
let mut err = nvim::Error::new();
let (start, end) = utils::range_to_limits(byte_range);
let ns_id = unsafe {
nvim_buf_add_highlight(
self.0,
ns_id.into(),
hl_group.non_owning(),
line as Integer,
start,
end,
&mut err,
)
};
choose!(err, Ok(ns_id))
}
pub fn clear_namespace<R>(
&mut self,
ns_id: u32,
line_range: R,
) -> Result<()>
where
R: RangeBounds<usize>,
{
let mut err = nvim::Error::new();
let (start, end) = utils::range_to_limits(line_range);
unsafe {
nvim_buf_clear_namespace(
self.0,
ns_id as Integer,
start,
end,
&mut err,
)
};
choose!(err, ())
}
pub fn del_extmark(&mut self, ns_id: u32, extmark_id: u32) -> Result<()> {
let mut err = nvim::Error::new();
let was_found = unsafe {
nvim_buf_del_extmark(
self.0,
ns_id as Integer,
extmark_id as Integer,
&mut err,
)
};
choose!(
err,
match was_found {
true => Ok(()),
_ => Err(Error::custom(format!(
"No extmark with id {extmark_id} was found"
))),
}
)
}
pub fn get_extmark_by_id(
&self,
ns_id: u32,
extmark_id: u32,
opts: &GetExtmarkByIdOpts,
) -> Result<(usize, usize, Option<ExtmarkInfos>)> {
let opts = Dictionary::from(opts);
let mut err = nvim::Error::new();
let tuple = unsafe {
nvim_buf_get_extmark_by_id(
self.0,
ns_id as Integer,
extmark_id as Integer,
opts.non_owning(),
&mut err,
)
};
choose!(err, {
if tuple.is_empty() {
return Err(Error::custom(format!(
"No extmark with id {extmark_id} was found"
)));
}
let mut iter = tuple.into_iter();
let row =
usize::from_object(iter.next().expect("row is present"))?;
let col =
usize::from_object(iter.next().expect("col is present"))?;
let infos =
iter.next().map(ExtmarkInfos::from_object).transpose()?;
Ok((row, col, infos))
})
}
pub fn get_extmarks(
&self,
ns_id: u32,
start: ExtmarkPosition,
end: ExtmarkPosition,
opts: &GetExtmarksOpts,
) -> Result<impl SuperIterator<(u32, usize, usize, Option<ExtmarkInfos>)>>
{
let opts = Dictionary::from(opts);
let mut err = nvim::Error::new();
let extmarks = unsafe {
nvim_buf_get_extmarks(
self.0,
ns_id as Integer,
start.into(),
end.into(),
opts.non_owning(),
&mut err,
)
};
choose!(
err,
Ok({
extmarks.into_iter().map(|tuple| {
let mut iter =
Array::from_object(tuple).unwrap().into_iter();
let id =
u32::from_object(iter.next().expect("id is present"))
.unwrap();
let row = usize::from_object(
iter.next().expect("row is present"),
)
.unwrap();
let col = usize::from_object(
iter.next().expect("col is present"),
)
.unwrap();
let infos = iter
.next()
.map(ExtmarkInfos::from_object)
.transpose()
.unwrap();
(id, row, col, infos)
})
})
)
}
pub fn set_extmark(
&mut self,
ns_id: u32,
line: usize,
col: usize,
opts: &SetExtmarkOpts,
) -> Result<u32> {
let mut err = nvim::Error::new();
let id = unsafe {
nvim_buf_set_extmark(
self.0,
ns_id as Integer,
line as Integer,
col as Integer,
&opts.0,
&mut err,
)
};
choose!(err, Ok(id.try_into().expect("always positive")))
}
}
pub fn create_namespace(name: &str) -> u32 {
let name = nvim::String::from(name);
unsafe { nvim_create_namespace(name.non_owning()) }
.try_into()
.expect("always positive")
}
pub fn get_namespaces() -> impl SuperIterator<(String, u32)> {
unsafe { nvim_get_namespaces() }.into_iter().map(|(k, v)| {
let k = k.try_into().expect("namespace name is valid UTF-8");
let v = u32::from_object(v).expect("namespace id is positive");
(k, v)
})
}
pub fn set_decoration_provider(
ns_id: u32,
opts: &DecorationProviderOpts,
) -> Result<()> {
let opts = Dictionary::from(opts);
let mut err = nvim::Error::new();
unsafe {
nvim_set_decoration_provider(
ns_id as Integer,
opts.non_owning(),
&mut err,
)
};
choose!(err, ())
}