nvim_oxi_api/
extmark.rs

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