1use std::ops::RangeBounds;
2
3use nvim_types::{
4 self as nvim,
5 conversion::FromObject,
6 Array,
7 Dictionary,
8 Integer,
9};
10
11use crate::choose;
12use crate::ffi::extmark::*;
13use crate::iterator::SuperIterator;
14use crate::opts::*;
15use crate::types::*;
16use crate::utils;
17use crate::Buffer;
18use crate::{Error, Result};
19
20impl Buffer {
21 pub fn add_highlight<R>(
26 &mut self,
27 ns_id: u32,
28 hl_group: &str,
29 line: usize,
30 byte_range: R,
31 ) -> Result<i64>
32 where
33 R: RangeBounds<usize>,
34 {
35 let hl_group = nvim::String::from(hl_group);
36 let mut err = nvim::Error::new();
37 let (start, end) = utils::range_to_limits(byte_range);
38 let ns_id = unsafe {
39 nvim_buf_add_highlight(
40 self.0,
41 ns_id.into(),
42 hl_group.non_owning(),
43 line as Integer,
44 start,
45 end,
46 &mut err,
47 )
48 };
49 choose!(err, Ok(ns_id))
50 }
51
52 pub fn clear_namespace<R>(
59 &mut self,
60 ns_id: u32,
61 line_range: R,
62 ) -> Result<()>
63 where
64 R: RangeBounds<usize>,
65 {
66 let mut err = nvim::Error::new();
67 let (start, end) = utils::range_to_limits(line_range);
68 unsafe {
69 nvim_buf_clear_namespace(
70 self.0,
71 ns_id as Integer,
72 start,
73 end,
74 &mut err,
75 )
76 };
77 choose!(err, ())
78 }
79
80 pub fn del_extmark(&mut self, ns_id: u32, extmark_id: u32) -> Result<()> {
86 let mut err = nvim::Error::new();
87 let was_found = unsafe {
88 nvim_buf_del_extmark(
89 self.0,
90 ns_id as Integer,
91 extmark_id as Integer,
92 &mut err,
93 )
94 };
95 choose!(
96 err,
97 match was_found {
98 true => Ok(()),
99 _ => Err(Error::custom(format!(
100 "No extmark with id {extmark_id} was found"
101 ))),
102 }
103 )
104 }
105
106 pub fn get_extmark_by_id(
115 &self,
116 ns_id: u32,
117 extmark_id: u32,
118 opts: &GetExtmarkByIdOpts,
119 ) -> Result<(usize, usize, Option<ExtmarkInfos>)> {
120 let opts = Dictionary::from(opts);
121 let mut err = nvim::Error::new();
122 let tuple = unsafe {
123 nvim_buf_get_extmark_by_id(
124 self.0,
125 ns_id as Integer,
126 extmark_id as Integer,
127 opts.non_owning(),
128 &mut err,
129 )
130 };
131 choose!(err, {
132 if tuple.is_empty() {
133 return Err(Error::custom(format!(
134 "No extmark with id {extmark_id} was found"
135 )));
136 }
137
138 let mut iter = tuple.into_iter();
139 let row =
140 usize::from_object(iter.next().expect("row is present"))?;
141 let col =
142 usize::from_object(iter.next().expect("col is present"))?;
143 let infos =
144 iter.next().map(ExtmarkInfos::from_object).transpose()?;
145 Ok((row, col, infos))
146 })
147 }
148
149 pub fn get_extmarks(
160 &self,
161 ns_id: u32,
162 start: ExtmarkPosition,
163 end: ExtmarkPosition,
164 opts: &GetExtmarksOpts,
165 ) -> Result<impl SuperIterator<(u32, usize, usize, Option<ExtmarkInfos>)>>
166 {
167 let opts = Dictionary::from(opts);
168 let mut err = nvim::Error::new();
169 let extmarks = unsafe {
170 nvim_buf_get_extmarks(
171 self.0,
172 ns_id as Integer,
173 start.into(),
174 end.into(),
175 opts.non_owning(),
176 &mut err,
177 )
178 };
179 choose!(
180 err,
181 Ok({
182 extmarks.into_iter().map(|tuple| {
183 let mut iter =
184 Array::from_object(tuple).unwrap().into_iter();
185 let id =
186 u32::from_object(iter.next().expect("id is present"))
187 .unwrap();
188 let row = usize::from_object(
189 iter.next().expect("row is present"),
190 )
191 .unwrap();
192 let col = usize::from_object(
193 iter.next().expect("col is present"),
194 )
195 .unwrap();
196 let infos = iter
197 .next()
198 .map(ExtmarkInfos::from_object)
199 .transpose()
200 .unwrap();
201 (id, row, col, infos)
202 })
203 })
204 )
205 }
206
207 pub fn set_extmark(
212 &mut self,
213 ns_id: u32,
214 line: usize,
215 col: usize,
216 opts: &SetExtmarkOpts,
217 ) -> Result<u32> {
218 let mut err = nvim::Error::new();
219 let id = unsafe {
220 nvim_buf_set_extmark(
221 self.0,
222 ns_id as Integer,
223 line as Integer,
224 col as Integer,
225 &opts.0,
226 &mut err,
227 )
228 };
229 choose!(err, Ok(id.try_into().expect("always positive")))
230 }
231}
232
233pub fn create_namespace(name: &str) -> u32 {
238 let name = nvim::String::from(name);
239 unsafe { nvim_create_namespace(name.non_owning()) }
240 .try_into()
241 .expect("always positive")
242}
243
244pub fn get_namespaces() -> impl SuperIterator<(String, u32)> {
249 unsafe { nvim_get_namespaces() }.into_iter().map(|(k, v)| {
250 let k = k.try_into().expect("namespace name is valid UTF-8");
251 let v = u32::from_object(v).expect("namespace id is positive");
252 (k, v)
253 })
254}
255
256pub fn set_decoration_provider(
260 ns_id: u32,
261 opts: &DecorationProviderOpts,
262) -> Result<()> {
263 let opts = Dictionary::from(opts);
264 let mut err = nvim::Error::new();
265 unsafe {
266 nvim_set_decoration_provider(
267 ns_id as Integer,
268 opts.non_owning(),
269 &mut err,
270 )
271 };
272 choose!(err, ())
273}