nvim_oxi_api/
extmark.rs

1use std::ops::RangeBounds;
2
3use types::{self as nvim, conversion::FromObject, Array, Integer};
4
5use crate::choose;
6use crate::ffi::extmark::*;
7use crate::opts::*;
8use crate::types::*;
9use crate::utils;
10use crate::Buffer;
11use crate::SuperIterator;
12use crate::{Error, Result};
13
14/// Binding to [`nvim_create_namespace()`][1].
15///
16/// Creates a new namespace or gets the id of an existing one. If `name`
17/// matches an existing namespace the associated id is returned.
18///
19/// [1]: https://neovim.io/doc/user/api.html#nvim_create_namespace()
20pub fn create_namespace(name: &str) -> u32 {
21    let name = nvim::String::from(name);
22    unsafe { nvim_create_namespace(name.non_owning()) }
23        .try_into()
24        .expect("always positive")
25}
26
27/// Binding to [`nvim_get_namespaces()`][1].
28///
29/// Returns an iterator over all the existing, non-anonymous namespace names
30/// and ids tuples `(name, id)`.
31///
32/// [1]: https://neovim.io/doc/user/api.html#nvim_get_namespaces()
33pub fn get_namespaces() -> impl SuperIterator<(String, u32)> {
34    unsafe {
35        nvim_get_namespaces(
36            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
37            types::arena(),
38        )
39    }
40    .into_iter()
41    .map(|(k, v)| {
42        let k = k.to_string_lossy().into();
43        let v = u32::from_object(v).expect("namespace id is positive");
44        (k, v)
45    })
46}
47
48/// Binding to [`nvim_set_decoration_provider()`][1].
49///
50/// Sets or changes a decoration provider for a namespace.
51///
52/// [1]: https://neovim.io/doc/user/api.html#nvim_set_decoration_provider()
53pub fn set_decoration_provider(
54    ns_id: u32,
55    opts: &DecorationProviderOpts,
56) -> Result<()> {
57    let mut err = nvim::Error::new();
58    unsafe { nvim_set_decoration_provider(ns_id as Integer, opts, &mut err) };
59    choose!(err, ())
60}
61
62impl Buffer {
63    /// Binding to [`nvim_buf_add_highlight()`][1].
64    ///
65    /// Adds a highlight to the buffer. Both `line` and `byte_range` are
66    /// 0-indexed.
67    ///
68    /// [1]: https://neovim.io/doc/user/api.html#nvim_buf_add_highlight()
69    pub fn add_highlight<R>(
70        &mut self,
71        ns_id: u32,
72        hl_group: &str,
73        line: usize,
74        byte_range: R,
75    ) -> Result<i64>
76    where
77        R: RangeBounds<usize>,
78    {
79        let hl_group = nvim::String::from(hl_group);
80        let mut err = nvim::Error::new();
81        let (start, end) = utils::range_to_limits(byte_range);
82        let ns_id = unsafe {
83            nvim_buf_add_highlight(
84                self.0,
85                ns_id.into(),
86                hl_group.non_owning(),
87                line as Integer,
88                start,
89                end,
90                &mut err,
91            )
92        };
93        choose!(err, Ok(ns_id))
94    }
95
96    /// Binding to [`nvim_buf_clear_namespace()`][1].
97    ///
98    /// Clears namespaced objects like highlights, extmarks, or virtual text
99    /// from a region.
100    ///
101    /// The line range is 0-indexed.
102    ///
103    /// [1]: https://neovim.io/doc/user/api.html#nvim_buf_clear_namespace()
104    pub fn clear_namespace<R>(
105        &mut self,
106        ns_id: u32,
107        line_range: R,
108    ) -> Result<()>
109    where
110        R: RangeBounds<usize>,
111    {
112        let mut err = nvim::Error::new();
113        let (start, end) = utils::range_to_limits(line_range);
114        unsafe {
115            nvim_buf_clear_namespace(
116                self.0,
117                ns_id as Integer,
118                start,
119                end,
120                &mut err,
121            )
122        };
123        choose!(err, ())
124    }
125
126    /// Binding to [`nvim_buf_del_extmark()`][1].
127    ///
128    /// Removes an extmark from the buffer.
129    ///
130    /// [1]: https://neovim.io/doc/user/api.html#nvim_buf_del_extmark()
131    pub fn del_extmark(&mut self, ns_id: u32, extmark_id: u32) -> Result<()> {
132        let mut err = nvim::Error::new();
133        let was_found = unsafe {
134            nvim_buf_del_extmark(
135                self.0,
136                ns_id as Integer,
137                extmark_id as Integer,
138                &mut err,
139            )
140        };
141        choose!(
142            err,
143            match was_found {
144                true => Ok(()),
145                _ => Err(Error::custom(format!(
146                    "No extmark with id {extmark_id} was found"
147                ))),
148            }
149        )
150    }
151
152    /// Binding to [`nvim_buf_get_extmark_by_id()`][1].
153    ///
154    /// The first two elements of the returned tuple represent the 0-indexed
155    /// `row, col` position of the extmark. The last element is only present if
156    /// the [`details`](crate::opts::GetExtmarkByIdOptsBuilder::details) option
157    /// field was set to `true`.
158    ///
159    /// [1]: https://neovim.io/doc/user/api.html#nvim_buf_get_extmark_by_id()
160    pub fn get_extmark_by_id(
161        &self,
162        ns_id: u32,
163        extmark_id: u32,
164        opts: &GetExtmarkByIdOpts,
165    ) -> Result<(usize, usize, Option<ExtmarkInfos>)> {
166        #[cfg(not(feature = "neovim-0-10"))] // 0nly on 0.9.
167        let opts = types::Dictionary::from(opts);
168        let mut err = nvim::Error::new();
169        let tuple = unsafe {
170            nvim_buf_get_extmark_by_id(
171                self.0,
172                ns_id as Integer,
173                extmark_id as Integer,
174                #[cfg(not(feature = "neovim-0-10"))] // 0nly on 0.9.
175                opts.non_owning(),
176                #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
177                opts,
178                #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
179                types::arena(),
180                &mut err,
181            )
182        };
183        choose!(err, {
184            if tuple.is_empty() {
185                return Err(Error::custom(format!(
186                    "No extmark with id {extmark_id} was found"
187                )));
188            }
189
190            let mut iter = tuple.into_iter();
191            let row =
192                usize::from_object(iter.next().expect("row is present"))?;
193            let col =
194                usize::from_object(iter.next().expect("col is present"))?;
195            let infos =
196                iter.next().map(ExtmarkInfos::from_object).transpose()?;
197            Ok((row, col, infos))
198        })
199    }
200
201    /// Bindings to [`nvim_buf_get_extmarks`][1].
202    ///
203    /// Gets all the extmarks in a buffer region specified by start and end
204    /// positions. Returns an iterator over `(extmark_id, row, col, infos)`
205    /// tuples in "traversal order". Like for [`Buffer::get_extmark_by_id`],
206    /// the `infos` are present only if the
207    /// [`details`](crate::opts::GetExtmarksOptsBuilder::details) option field
208    /// was set to `true`.
209    ///
210    /// [1]: https://neovim.io/doc/user/api.html#nvim_buf_get_extmarks()
211    pub fn get_extmarks(
212        &self,
213        ns_id: u32,
214        start: ExtmarkPosition,
215        end: ExtmarkPosition,
216        opts: &GetExtmarksOpts,
217    ) -> Result<impl SuperIterator<(u32, usize, usize, Option<ExtmarkInfos>)>>
218    {
219        #[cfg(not(feature = "neovim-0-10"))] // 0nly on 0.9.
220        let opts = types::Dictionary::from(opts);
221        let mut err = nvim::Error::new();
222        let extmarks = unsafe {
223            nvim_buf_get_extmarks(
224                self.0,
225                ns_id as Integer,
226                start.into(),
227                end.into(),
228                #[cfg(not(feature = "neovim-0-10"))] // 0nly on 0.9.
229                opts.non_owning(),
230                #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
231                opts,
232                #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
233                types::arena(),
234                &mut err,
235            )
236        };
237        choose!(
238            err,
239            Ok({
240                extmarks.into_iter().map(|tuple| {
241                    let mut iter =
242                        Array::from_object(tuple).unwrap().into_iter();
243                    let id =
244                        u32::from_object(iter.next().expect("id is present"))
245                            .unwrap();
246                    let row = usize::from_object(
247                        iter.next().expect("row is present"),
248                    )
249                    .unwrap();
250                    let col = usize::from_object(
251                        iter.next().expect("col is present"),
252                    )
253                    .unwrap();
254                    let infos = iter
255                        .next()
256                        .map(ExtmarkInfos::from_object)
257                        .transpose()
258                        .unwrap();
259                    (id, row, col, infos)
260                })
261            })
262        )
263    }
264
265    /// Binding to [`nvim_buf_set_extmark()`][1].
266    ///
267    /// Creates or updates an extmark. Both `line` and `col` are 0-indexed.
268    /// Returns the id of the created/updated extmark.
269    ///
270    /// [1]: https://neovim.io/doc/user/api.html#nvim_buf_set_extmark()
271    pub fn set_extmark(
272        &mut self,
273        ns_id: u32,
274        line: usize,
275        col: usize,
276        opts: &SetExtmarkOpts,
277    ) -> Result<u32> {
278        let mut err = nvim::Error::new();
279        let id = unsafe {
280            nvim_buf_set_extmark(
281                self.0,
282                ns_id as Integer,
283                line as Integer,
284                col as Integer,
285                opts,
286                &mut err,
287            )
288        };
289        choose!(err, Ok(id.try_into().expect("always positive")))
290    }
291}