nvim_oxi_api/
vim.rs

1use std::path::{Path, PathBuf};
2
3use types::{
4    self as nvim,
5    conversion::{FromObject, ToObject},
6    Array,
7    Dictionary,
8    Integer,
9    Object,
10};
11
12use crate::choose;
13use crate::ffi::vim::*;
14use crate::opts::*;
15use crate::types::*;
16use crate::SuperIterator;
17use crate::LUA_INTERNAL_CALL;
18use crate::{Buffer, TabPage, Window};
19use crate::{Error, Result};
20
21/// Binding to [`nvim_chan_send()`][1].
22///
23/// Sends data to a channel.
24///
25/// [1]: https://neovim.io/doc/user/api.html#nvim_chan_send()
26pub fn chan_send(channel_id: u32, data: &str) -> Result<()> {
27    let mut err = nvim::Error::new();
28    let data = nvim::String::from(data);
29    unsafe { nvim_chan_send(channel_id.into(), data.non_owning(), &mut err) };
30    choose!(err, ())
31}
32
33/// Binding to [`nvim_create_buf()`][1].
34///
35/// Creates a new, empty, unnamed buffer.
36///
37/// [1]: https://neovim.io/doc/user/api.html#nvim_create_buf()
38pub fn create_buf(is_listed: bool, is_scratch: bool) -> Result<Buffer> {
39    let mut err = nvim::Error::new();
40    let handle = unsafe { nvim_create_buf(is_listed, is_scratch, &mut err) };
41    choose!(err, Ok(handle.into()))
42}
43
44/// Binding to [`nvim_del_current_line()`][1].
45///
46/// Deletes the current line.
47///
48/// [1]: https://neovim.io/doc/user/api.html#nvim_del_current_line()
49pub fn del_current_line() -> Result<()> {
50    let mut err = nvim::Error::new();
51    unsafe {
52        nvim_del_current_line(
53            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
54            types::arena(),
55            &mut err,
56        )
57    };
58    choose!(err, ())
59}
60
61/// Binding to [`nvim_del_keymap()`][1].
62///
63/// Unmaps a global mapping for the given mode. To unmap a buffer-local mapping
64/// use [`Buffer::del_keymap`] instead.
65///
66/// [1]: https://neovim.io/doc/user/api.html#nvim_del_keymap()
67pub fn del_keymap(mode: Mode, lhs: &str) -> Result<()> {
68    let mode = nvim::String::from(mode);
69    let lhs = nvim::String::from(lhs);
70    let mut err = nvim::Error::new();
71    unsafe {
72        nvim_del_keymap(
73            LUA_INTERNAL_CALL,
74            mode.non_owning(),
75            lhs.non_owning(),
76            &mut err,
77        )
78    };
79    choose!(err, ())
80}
81
82/// Binding to [`nvim_del_mark()`][1].
83///
84/// Deletes an uppercase/file named mark. Returns an error if a lowercase or
85/// buffer-local named mark is used. Use [`Buffer::del_mark`] to delete a
86/// buffer-local mark.
87///
88/// [1]: https://neovim.io/doc/user/api.html#nvim_del_mark()
89pub fn del_mark(name: char) -> Result<()> {
90    let name = nvim::String::from(name);
91    let mut err = nvim::Error::new();
92    let was_deleted = unsafe { nvim_del_mark(name.non_owning(), &mut err) };
93    choose!(
94        err,
95        match was_deleted {
96            true => Ok(()),
97            _ => Err(Error::custom("Couldn't delete mark")),
98        }
99    )
100}
101
102/// Binding to [`nvim_del_var()`][1].
103///
104/// Removes a global (`g:`) variable.
105///
106/// [1]: https://neovim.io/doc/user/api.html#nvim_del_var()
107pub fn del_var(name: &str) -> Result<()> {
108    let name = nvim::String::from(name);
109    let mut err = nvim::Error::new();
110    unsafe { nvim_del_var(name.non_owning(), &mut err) };
111    choose!(err, ())
112}
113
114/// Binding to [`nvim_echo()`][1].
115///
116/// Echoes a message to the Neovim message area.
117///
118/// [1]: https://neovim.io/doc/user/api.html#nvim_echo()
119pub fn echo<'hl, Text, Chunks>(
120    chunks: Chunks,
121    history: bool,
122    opts: &EchoOpts,
123) -> Result<()>
124where
125    Chunks: IntoIterator<Item = (Text, Option<&'hl str>)>,
126    Text: Into<nvim::String>,
127{
128    let chunks = chunks
129        .into_iter()
130        .map(|(text, hlgroup)| {
131            Array::from_iter([
132                Object::from(text.into()),
133                Object::from(hlgroup.map(|hl| hl.to_owned())),
134            ])
135        })
136        .collect::<Array>();
137
138    let mut err = nvim::Error::new();
139    unsafe { nvim_echo(chunks.non_owning(), history, opts, &mut err) };
140    choose!(err, ())
141}
142
143/// Binding to [`nvim_err_write()`][1].
144///
145/// Writes a message to the Neovim error buffer. Does not append a newline
146/// (`"\n"`); the message gets buffered and won't be displayed until a linefeed
147/// is written.
148///
149/// [1]: https://neovim.io/doc/user/api.html#nvim_err_write()
150pub fn err_write(str: &str) {
151    unsafe { nvim_err_write(nvim::String::from(str).non_owning()) }
152}
153
154/// Binding to [`nvim_err_writeln()`][1].
155///
156/// Writes a message to the Neovim error buffer. Appends a newline (`"\n"`), so
157/// the buffer is flushed and displayed.
158///
159/// [1]: https://neovim.io/doc/user/api.html#nvim_err_writeln()
160pub fn err_writeln(str: &str) {
161    unsafe { nvim_err_writeln(nvim::String::from(str).non_owning()) }
162}
163
164/// Binding to [`nvim_eval_statusline()`][1].
165///
166/// Evaluates a string to be displayed in the statusline.
167///
168/// [1]: https://neovim.io/doc/user/api.html#nvim_eval_statusline()
169pub fn eval_statusline(
170    str: &str,
171    opts: &EvalStatuslineOpts,
172) -> Result<StatuslineInfos> {
173    let str = nvim::String::from(str);
174    let mut err = nvim::Error::new();
175    let dict = unsafe {
176        nvim_eval_statusline(
177            str.non_owning(),
178            opts,
179            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
180            types::arena(),
181            &mut err,
182        )
183    };
184    choose!(err, Ok(StatuslineInfos::from_object(dict.into())?))
185}
186
187/// Binding to [`nvim_feedkeys()`][1].
188///
189/// [1]: https://neovim.io/doc/user/api.html#nvim_feedkeys()
190pub fn feedkeys(keys: &str, mode: Mode, escape_ks: bool) {
191    let keys = nvim::String::from(keys);
192    let mode = nvim::String::from(mode);
193    unsafe { nvim_feedkeys(keys.non_owning(), mode.non_owning(), escape_ks) }
194}
195
196/// Binding to [`nvim_get_chan_info()`][1].
197///
198/// Gets information about a channel.
199///
200/// [1]: https://neovim.io/doc/user/api.html#nvim_get_chan_info()
201pub fn get_chan_info(channel_id: u32) -> Result<ChannelInfos> {
202    let mut err = nvim::Error::new();
203    let infos = unsafe { nvim_get_chan_info(channel_id.into(), &mut err) };
204    choose!(err, Ok(ChannelInfos::from_object(infos.into())?))
205}
206
207/// Binding to [`nvim_get_color_by_name()`][1].
208///
209/// Returns the 24-bit RGB value of a `crate::api::get_color_map` color name or
210/// "#rrggbb" hexadecimal string.
211///
212/// [1]: https://neovim.io/doc/user/api.html#nvim_get_color_by_name()
213pub fn get_color_by_name(name: &str) -> Result<u32> {
214    let name = nvim::String::from(name);
215    let color = unsafe { nvim_get_color_by_name(name.non_owning()) };
216    (color != -1).then(|| color.try_into().unwrap()).ok_or_else(|| {
217        Error::custom(format!("{name:?} is not a valid color name"))
218    })
219}
220
221/// Binding to [`nvim_get_color_map()`][1].
222///
223/// Returns an iterator over tuples representing color names and 24-bit RGB
224/// values (e.g. 65535).
225///
226/// [1]: https://neovim.io/doc/user/api.html#nvim_get_color_map()
227pub fn get_color_map() -> impl SuperIterator<(String, u32)> {
228    unsafe {
229        nvim_get_color_map(
230            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
231            types::arena(),
232        )
233    }
234    .into_iter()
235    .map(|(k, v)| (k.to_string_lossy().into(), u32::from_object(v).unwrap()))
236}
237
238/// Binding to [`nvim_get_context()`][1].
239///
240/// Returns a snapshot of the current editor state.
241///
242/// [1]: https://neovim.io/doc/user/api.html#nvim_get_context()
243pub fn get_context(opts: &GetContextOpts) -> Result<EditorContext> {
244    let mut err = nvim::Error::new();
245    let ctx = unsafe {
246        nvim_get_context(
247            opts,
248            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
249            types::arena(),
250            &mut err,
251        )
252    };
253    choose!(err, Ok(EditorContext::from_object(ctx.into())?))
254}
255
256/// Binding to [`nvim_get_current_buf()`][1].
257///
258/// Gets the current buffer.
259///
260/// [1]: https://neovim.io/doc/user/api.html#nvim_get_current_buf()
261pub fn get_current_buf() -> Buffer {
262    unsafe { nvim_get_current_buf() }.into()
263}
264
265/// Binding to [`nvim_get_current_line()`][1].
266///
267/// Gets the current line in the current bufferr.
268///
269/// [1]: https://neovim.io/doc/user/api.html#nvim_get_current_line()
270pub fn get_current_line() -> Result<String> {
271    let mut err = nvim::Error::new();
272    let s = unsafe {
273        nvim_get_current_line(
274            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
275            types::arena(),
276            &mut err,
277        )
278    };
279    choose!(err, Ok(s.to_string_lossy().into()))
280}
281
282/// Binding to [`nvim_get_current_tabpage()`][1].
283///
284/// Gets the current tabpage.
285///
286/// [1]: https://neovim.io/doc/user/api.html#nvim_get_current_tabpage()
287pub fn get_current_tabpage() -> TabPage {
288    unsafe { nvim_get_current_tabpage() }.into()
289}
290
291/// Binding to [`nvim_get_current_win()`][1].
292///
293/// Gets the current window.
294///
295/// [1]: https://neovim.io/doc/user/api.html#nvim_get_current_win()
296pub fn get_current_win() -> Window {
297    unsafe { nvim_get_current_win() }.into()
298}
299
300/// Binding to [`nvim_get_hl()`][1].
301///
302/// Gets all or specific highlight groups in a namespace.
303///
304/// [1]: https://neovim.io/doc/user/api.html#nvim_get_hl()
305#[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
306#[cfg_attr(
307    docsrs,
308    doc(cfg(any(feature = "neovim-0-10", feature = "neovim-nightly")))
309)]
310pub fn get_hl(
311    ns_id: u32,
312    opts: &GetHighlightOpts,
313) -> Result<GetHlInfos<impl SuperIterator<(types::String, HighlightInfos)>>> {
314    let mut err = nvim::Error::new();
315    let dict = unsafe {
316        nvim_get_hl(ns_id as Integer, opts, types::arena(), &mut err)
317    };
318    if err.is_err() {
319        return Err(err.into());
320    }
321
322    let is_map = dict
323        .iter()
324        .next()
325        .map(|(_, hl_infos)| {
326            let d = types::serde::Deserializer::new(hl_infos.clone());
327            <HighlightInfos as serde::Deserialize>::deserialize(d).is_ok()
328        })
329        .unwrap_or(false);
330
331    if is_map {
332        let iter = dict.into_iter().map(|(hl_name, hl_infos)| {
333            let infos = HighlightInfos::from_object(hl_infos).unwrap();
334            (hl_name, infos)
335        });
336        Ok(GetHlInfos::Map(iter))
337    } else {
338        HighlightInfos::from_object(dict.into())
339            .map(GetHlInfos::Single)
340            .map_err(Into::into)
341    }
342}
343
344/// Binding to [`nvim_get_hl_id_by_name()`][1].
345///
346/// Gets a highlight definition by name.
347///
348/// [1]: https://neovim.io/doc/user/api.html#nvim_get_hl_id_by_name()
349pub fn get_hl_id_by_name(name: &str) -> Result<u32> {
350    let name = nvim::String::from(name);
351    let id = unsafe { nvim_get_hl_id_by_name(name.non_owning()) };
352    id.try_into().map_err(Into::into)
353}
354
355/// Binding to [`nvim_get_hl_ns()`][1].
356///
357/// Gets the active highlight namespace.
358///
359/// [1]: https://neovim.io/doc/user/api.html#nvim_get_hl_ns()
360#[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
361#[cfg_attr(
362    docsrs,
363    doc(cfg(any(feature = "neovim-0-10", feature = "neovim-nightly")))
364)]
365pub fn get_hl_ns(opts: &GetNamespaceOpts) -> Result<i64> {
366    let mut err = nvim::Error::new();
367    let res = unsafe { nvim_get_hl_ns(opts, &mut err) };
368    choose!(err, Ok(res))
369}
370
371/// Binding to [`nvim_get_keymap()`][1].
372///
373/// Returns an iterator over the global mapping definitions.
374///
375/// [1]: https://neovim.io/doc/user/api.html#nvim_get_keymap()
376pub fn get_keymap(mode: Mode) -> impl SuperIterator<KeymapInfos> {
377    let mode = nvim::String::from(mode);
378    let keymaps = unsafe {
379        nvim_get_keymap(
380            mode.non_owning(),
381            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
382            types::arena(),
383        )
384    };
385    keymaps.into_iter().map(|obj| KeymapInfos::from_object(obj).unwrap())
386}
387
388/// Binding to [`nvim_get_mark()`][1].
389///
390/// Returns a tuple `(row, col, buffer, buffername)` representing the position
391/// of the named mark. Marks are (1,0)-indexed.
392///
393/// [1]: https://neovim.io/doc/user/api.html#nvim_get_mark()
394pub fn get_mark(
395    name: char,
396    opts: &GetMarkOpts,
397) -> Result<(usize, usize, Buffer, String)> {
398    let name = nvim::String::from(name);
399    #[cfg(not(feature = "neovim-0-10"))] // 0nly on 0.9.
400    let opts = Dictionary::from(opts);
401    let mut err = nvim::Error::new();
402    let mark = unsafe {
403        nvim_get_mark(
404            name.non_owning(),
405            #[cfg(not(feature = "neovim-0-10"))] // 0nly on 0.9.
406            opts.non_owning(),
407            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
408            opts,
409            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
410            types::arena(),
411            &mut err,
412        )
413    };
414    choose!(err, {
415        let mut iter = mark.into_iter();
416        let row = usize::from_object(iter.next().expect("row is present"))?;
417        let col = usize::from_object(iter.next().expect("col is present"))?;
418        let buffer =
419            Buffer::from_object(iter.next().expect("buffer is present"))?;
420        let buffername =
421            String::from_object(iter.next().expect("buffername is present"))?;
422        Ok((row, col, buffer, buffername))
423    })
424}
425
426/// Binding to [`nvim_get_mode()`][1].
427///
428/// Gets the current mode. The [`blocking`](GotMode::blocking) field of
429/// [`GotMode`] is `true` if Neovim is waiting for input.
430///
431/// [1]: https://neovim.io/doc/user/api.html#nvim_get_mode()
432pub fn get_mode() -> Result<GotMode> {
433    Ok(GotMode::from_object(
434        unsafe {
435            nvim_get_mode(
436                #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
437                types::arena(),
438            )
439        }
440        .into(),
441    )?)
442}
443
444/// Binding to [`nvim_get_proc()`][1].
445///
446/// Gets informations about a process with a given `pid`.
447///
448/// [1]: https://neovim.io/doc/user/api.html#nvim_get_proc()
449pub fn get_proc(pid: u32) -> Result<ProcInfos> {
450    let mut err = nvim::Error::new();
451    let obj = unsafe {
452        nvim_get_proc(
453            pid.into(),
454            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
455            types::arena(),
456            &mut err,
457        )
458    };
459    choose!(err, Ok(ProcInfos::from_object(obj)?))
460}
461
462/// Binding to [`nvim_get_proc_children()`][1].
463///
464/// Gets the immediate children of process `pid`.
465///
466/// [1]: https://neovim.io/doc/user/api.html#nvim_get_proc_children()
467pub fn get_proc_children(pid: u32) -> Result<impl SuperIterator<u32>> {
468    let mut err = nvim::Error::new();
469    let procs = unsafe {
470        nvim_get_proc_children(
471            pid.into(),
472            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
473            types::arena(),
474            &mut err,
475        )
476    };
477    choose!(
478        err,
479        Ok(procs.into_iter().map(|obj| u32::from_object(obj).unwrap()))
480    )
481}
482
483/// Binding to [`nvim_get_runtime_file()`][1].
484///
485/// Returns an iterator over all the files matching `name` in the runtime path.
486///
487/// [1]: https://neovim.io/doc/user/api.html#nvim_get_runtime_file()
488pub fn get_runtime_file(
489    name: impl AsRef<Path>,
490    get_all: bool,
491) -> Result<impl SuperIterator<PathBuf>> {
492    let name = nvim::String::from(name.as_ref());
493    let mut err = nvim::Error::new();
494    let files = unsafe {
495        nvim_get_runtime_file(
496            name.non_owning(),
497            get_all,
498            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
499            types::arena(),
500            &mut err,
501        )
502    };
503    choose!(
504        err,
505        Ok({
506            files.into_iter().map(|obj| {
507                PathBuf::from(nvim::String::from_object(obj).unwrap())
508            })
509        })
510    )
511}
512
513/// Binding to [`nvim_get_var()`][1].
514///
515/// Gets a global (`g:`) variable.
516///
517/// [1]: https://neovim.io/doc/user/api.html#nvim_get_var()
518pub fn get_var<Var>(name: &str) -> Result<Var>
519where
520    Var: FromObject,
521{
522    let mut err = nvim::Error::new();
523    let name = nvim::String::from(name);
524    let obj = unsafe {
525        nvim_get_var(
526            name.non_owning(),
527            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
528            types::arena(),
529            &mut err,
530        )
531    };
532    choose!(err, Ok(Var::from_object(obj)?))
533}
534
535/// Binding to [`nvim_get_vvar()`][1].
536///
537/// Gets a `v:` variable.
538///
539/// [1]: https://neovim.io/doc/user/api.html#nvim_get_vvar()
540pub fn get_vvar<Var>(name: &str) -> Result<Var>
541where
542    Var: FromObject,
543{
544    let name = nvim::String::from(name);
545    let mut err = nvim::Error::new();
546    let obj = unsafe {
547        nvim_get_vvar(
548            name.non_owning(),
549            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
550            types::arena(),
551            &mut err,
552        )
553    };
554    choose!(err, Ok(Var::from_object(obj)?))
555}
556
557/// Binding to [`nvim_input()`][1].
558///
559/// Queues raw user-input. Unlike [`api::feedkeys`](feedkeys) this uses a
560/// low-level input buffer and the call is non-blocking.
561///
562/// Returns the number of bytes written to the buffer.
563///
564/// [1]: https://neovim.io/doc/user/api.html#nvim_input()
565pub fn input<Input>(keys: Input) -> Result<usize>
566where
567    Input: Into<nvim::String>,
568{
569    unsafe { nvim_input(keys.into().non_owning()) }
570        .try_into()
571        .map_err(From::from)
572}
573
574/// Binding to [`nvim_input_mouse()`][1].
575///
576/// Send mouse event from GUI. The call is non-blocking.
577///
578/// [1]: https://neovim.io/doc/user/api.html#nvim_input_mouse()
579pub fn input_mouse(
580    button: MouseButton,
581    action: MouseAction,
582    modifier: &str,
583    grid: u32,
584    row: usize,
585    col: usize,
586) -> Result<()> {
587    let button = nvim::String::from(button);
588    let action = nvim::String::from(action);
589    let modifier = nvim::String::from(modifier);
590    let mut err = nvim::Error::new();
591    unsafe {
592        nvim_input_mouse(
593            button.non_owning(),
594            action.non_owning(),
595            modifier.non_owning(),
596            grid.into(),
597            row.try_into()?,
598            col.try_into()?,
599            &mut err,
600        )
601    };
602    choose!(err, ())
603}
604
605/// Binding to [`nvim_list_bufs()`][1].
606///
607/// Gets the current list of [`Buffer`]s, including unlisted [1]
608/// buffers (like `:ls!`). Use [`Buffer::is_loaded`] to check if a
609/// buffer is loaded.
610///
611/// [1]: https://neovim.io/doc/user/api.html#nvim_list_bufs()
612///
613/// [1]: unloaded/deleted
614pub fn list_bufs() -> impl SuperIterator<Buffer> {
615    let bufs = unsafe {
616        nvim_list_bufs(
617            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
618            types::arena(),
619        )
620    };
621    bufs.into_iter().map(|obj| Buffer::from_object(obj).unwrap())
622}
623
624/// Binding to [`nvim_list_chans()`][1].
625///
626/// Returns an iterator over the informations about all the open channels.
627///
628/// [1]: https://neovim.io/doc/user/api.html#nvim_list_chans()
629pub fn list_chans() -> impl SuperIterator<ChannelInfos> {
630    unsafe { nvim_list_chans() }
631        .into_iter()
632        .map(|obj| ChannelInfos::from_object(obj).unwrap())
633}
634
635/// Binding to [`nvim_list_runtime_paths()`][1].
636///
637/// Gets the paths contained in https://neovim's runtimepath.
638///
639/// [1]: https://neovim.io/doc/user/api.html#nvim_list_runtime_paths()
640pub fn list_runtime_paths() -> Result<impl SuperIterator<PathBuf>> {
641    let mut err = nvim::Error::new();
642    let paths = unsafe {
643        nvim_list_runtime_paths(
644            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
645            types::arena(),
646            &mut err,
647        )
648    };
649    choose!(
650        err,
651        Ok({
652            paths.into_iter().map(|obj| {
653                PathBuf::from(nvim::String::from_object(obj).unwrap())
654            })
655        })
656    )
657}
658
659/// Binding to [`nvim_list_bufs()`][1].
660///
661/// Gets the current list of `Tabpage`s.
662///
663/// [1]: https://neovim.io/doc/user/api.html#nvim_list_bufs()
664pub fn list_tabpages() -> impl SuperIterator<TabPage> {
665    unsafe { nvim_list_tabpages() }
666        .into_iter()
667        .map(|obj| TabPage::from_object(obj).unwrap())
668}
669
670/// Binding to [`nvim_list_uis()`][1].
671///
672/// Returns an iterator over the informations about all the attached UIs.
673///
674/// [1]: https://neovim.io/doc/user/api.html#nvim_list_uis()
675pub fn list_uis() -> impl SuperIterator<UiInfos> {
676    unsafe {
677        nvim_list_uis(
678            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
679            types::arena(),
680        )
681    }
682    .into_iter()
683    .map(|obj| UiInfos::from_object(obj).unwrap())
684}
685
686/// Binding to [`nvim_list_wins()`][1].
687///
688/// Gets the current list of `Window`s.
689///
690/// [1]: https://neovim.io/doc/user/api.html#nvim_list_wins()
691pub fn list_wins() -> impl SuperIterator<Window> {
692    unsafe {
693        nvim_list_wins(
694            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
695            types::arena(),
696        )
697    }
698    .into_iter()
699    .map(|obj| Window::from_object(obj).unwrap())
700}
701
702/// Binding to [`nvim_load_context()`][1].
703///
704/// Sets the current editor state from the given [`EditorContext`].
705///
706/// [1]: https://neovim.io/doc/user/api.html#nvim_load_context()
707pub fn load_context(ctx: EditorContext) {
708    let ctx = Dictionary::from(ctx);
709    let _ = unsafe { nvim_load_context(ctx.non_owning()) };
710}
711
712/// Binding to [`nvim_notify()`][1].
713///
714/// [1]: https://neovim.io/doc/user/api.html#nvim_notify()
715pub fn notify(
716    msg: &str,
717    log_level: LogLevel,
718    opts: &NotifyOpts,
719) -> Result<()> {
720    let msg = nvim::String::from(msg);
721    let opts = Dictionary::from(opts);
722    let mut err = nvim::Error::new();
723    let _ = unsafe {
724        nvim_notify(
725            msg.non_owning(),
726            log_level as Integer,
727            opts.non_owning(),
728            &mut err,
729        )
730    };
731    choose!(err, ())
732}
733
734/// Binding to [`nvim_open_term()`][1].
735///
736/// Opens a terminal instance in a buffer. Returns the id of a channel that can
737/// be used to send data to the instance via
738/// [`nvim_oxi::api::chan_send`](chan_send).
739///
740/// [1]: https://neovim.io/doc/user/api.html#nvim_open_term()
741pub fn open_term(buffer: &Buffer, opts: &OpenTermOpts) -> Result<u32> {
742    #[cfg(not(feature = "neovim-0-10"))] // 0nly on 0.9.
743    let opts = Dictionary::from(opts);
744    let mut err = nvim::Error::new();
745    let channel_id = unsafe {
746        nvim_open_term(
747            buffer.0,
748            #[cfg(not(feature = "neovim-0-10"))] // 0nly on 0.9.
749            opts.non_owning(),
750            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
751            opts,
752            &mut err,
753        )
754    };
755    choose!(
756        err,
757        match channel_id {
758            0 => Err(Error::custom("Couldn't create terminal instance")),
759            other => Ok(other.try_into().expect("always positive")),
760        }
761    )
762}
763
764/// Binding to [`nvim_out_write()`][1].
765///
766/// Writes a message to the Vim output buffer, without appending a "\n". The
767/// message is buffered and won't be displayed until a linefeed is written.
768///
769/// [1]: https://neovim.io/doc/user/api.html#nvim_out_write()
770pub fn out_write<Msg>(str: Msg)
771where
772    Msg: Into<nvim::String>,
773{
774    unsafe { nvim_out_write(str.into().non_owning()) }
775}
776
777/// Binding to [`nvim_paste()`][1].
778///
779/// Returns `true` if the client may continue the paste, `false` if it must
780/// cancel it.
781///
782/// [1]: https://neovim.io/doc/user/api.html#nvim_paste()
783pub fn paste<Data>(data: Data, crlf: bool, phase: PastePhase) -> Result<bool>
784where
785    Data: Into<nvim::String>,
786{
787    let mut err = nvim::Error::new();
788    let go_on = unsafe {
789        nvim_paste(
790            data.into().non_owning(),
791            crlf,
792            phase as Integer,
793            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
794            types::arena(),
795            &mut err,
796        )
797    };
798    choose!(err, Ok(go_on))
799}
800
801/// Binding to [`nvim_put()`][1].
802///
803/// Puts text at cursor, in any mode.
804///
805/// [1]: https://neovim.io/doc/user/api.html#nvim_put()
806pub fn put<Line, Lines>(
807    lines: Lines,
808    reg_type: RegisterType,
809    after: bool,
810    follow: bool,
811) -> Result<()>
812where
813    Lines: Iterator<Item = Line>,
814    Line: Into<nvim::String>,
815{
816    let lines = lines.into_iter().map(Into::into).collect::<Array>();
817    let reg_type = nvim::String::from(reg_type);
818    let mut err = nvim::Error::new();
819    unsafe {
820        nvim_put(
821            lines.non_owning(),
822            reg_type.non_owning(),
823            after,
824            follow,
825            &mut err,
826        )
827    };
828    choose!(err, ())
829}
830
831/// Binding to [`nvim_replace_termcodes()`][1].
832///
833/// Replaces terminal codes and keycodes (`<CR>`, `<Esc>`, ...) in a string
834/// with the internal representation.
835///
836/// [1]: https://neovim.io/doc/user/api.html#nvim_replace_termcodes()
837pub fn replace_termcodes<Input>(
838    str: Input,
839    from_part: bool,
840    do_lt: bool,
841    special: bool,
842) -> nvim::String
843where
844    Input: Into<nvim::String>,
845{
846    let str = str.into();
847    unsafe {
848        nvim_replace_termcodes(str.non_owning(), from_part, do_lt, special)
849    }
850}
851
852/// Binding to [`nvim_select_popupmenu_item()`][1].
853///
854/// Selects an item in the completion popupmenu.
855///
856/// [1]: https://neovim.io/doc/user/api.html#nvim_select_popupmenu_item()
857pub fn select_popupmenu_item(
858    item: usize,
859    insert: bool,
860    finish: bool,
861    opts: &SelectPopupMenuItemOpts,
862) -> Result<()> {
863    #[cfg(not(feature = "neovim-0-10"))] // 0nly on 0.9.
864    let opts = Dictionary::from(opts);
865    let mut err = nvim::Error::new();
866    unsafe {
867        nvim_select_popupmenu_item(
868            item.try_into()?,
869            insert,
870            finish,
871            #[cfg(not(feature = "neovim-0-10"))] // 0nly on 0.9.
872            opts.non_owning(),
873            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
874            opts,
875            &mut err,
876        )
877    };
878    choose!(err, ())
879}
880
881/// Binding to [`nvim_set_current_buf()`][1].
882///
883/// Sets the current buffer.
884///
885/// [1]: https://neovim.io/doc/user/api.html#nvim_set_current_buf()
886pub fn set_current_buf(buf: &Buffer) -> Result<()> {
887    let mut err = nvim::Error::new();
888    unsafe { nvim_set_current_buf(buf.0, &mut err) };
889    choose!(err, ())
890}
891
892/// Binding to [`nvim_set_current_dir()`][1].
893///
894/// Changes the global working directory.
895///
896/// [1]: https://neovim.io/doc/user/api.html#nvim_set_current_dir()
897pub fn set_current_dir<Dir>(dir: Dir) -> Result<()>
898where
899    Dir: AsRef<Path>,
900{
901    let dir = nvim::String::from(dir.as_ref());
902    let mut err = nvim::Error::new();
903    unsafe { nvim_set_current_dir(dir.non_owning(), &mut err) };
904    choose!(err, ())
905}
906
907/// Binding to [`nvim_set_current_line()`][1].
908///
909/// Sets the current line.
910///
911/// [1]: https://neovim.io/doc/user/api.html#nvim_set_current_line()
912pub fn set_current_line<Line>(line: Line) -> Result<()>
913where
914    Line: Into<nvim::String>,
915{
916    let mut err = nvim::Error::new();
917    unsafe {
918        nvim_set_current_line(
919            line.into().non_owning(),
920            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
921            types::arena(),
922            &mut err,
923        )
924    };
925    choose!(err, ())
926}
927
928/// Binding to [`nvim_set_current_tabpage()`][1].
929///
930/// Sets the current tabpage.
931///
932/// [1]: https://neovim.io/doc/user/api.html#nvim_set_current_tabpage()
933pub fn set_current_tabpage(tabpage: &TabPage) -> Result<()> {
934    let mut err = nvim::Error::new();
935    unsafe { nvim_set_current_tabpage(tabpage.0, &mut err) };
936    choose!(err, ())
937}
938
939/// Binding to [`nvim_set_current_win()`][1].
940///
941/// Sets the current window.
942///
943/// [1]: https://neovim.io/doc/user/api.html#nvim_set_current_win()
944pub fn set_current_win(win: &Window) -> Result<()> {
945    let mut err = nvim::Error::new();
946    unsafe { nvim_set_current_win(win.0, &mut err) };
947    choose!(err, ())
948}
949
950/// Binding to [`nvim_set_hl()`][1].
951///
952/// Sets a highlight group.
953///
954/// [1]: https://neovim.io/doc/user/api.html#nvim_set_hl()
955pub fn set_hl(ns_id: u32, name: &str, opts: &SetHighlightOpts) -> Result<()> {
956    let name = nvim::String::from(name);
957    let mut err = nvim::Error::new();
958    unsafe {
959        nvim_set_hl(
960            #[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
961            LUA_INTERNAL_CALL,
962            ns_id as Integer,
963            name.non_owning(),
964            opts,
965            &mut err,
966        )
967    };
968    choose!(err, ())
969}
970
971/// Binding to [`nvim_set_hl_ns()`][1].
972///
973/// Set the active namespace for the highlights defined with [`set_hl`]. This
974/// can be set for a single window, see [`Window::set_hl`].
975///
976/// [1]: https://neovim.io/doc/user/api.html#nvim_set_hl_ns()
977#[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
978#[cfg_attr(
979    docsrs,
980    doc(cfg(any(feature = "neovim-0-10", feature = "neovim-nightly")))
981)]
982pub fn set_hl_ns(ns_id: u32) -> Result<()> {
983    let mut err = nvim::Error::new();
984    unsafe { nvim_set_hl_ns(ns_id as Integer, &mut err) };
985    choose!(err, ())
986}
987
988/// Binding to [`nvim_set_hl_ns_fast()`][1].
989///
990/// Set the active namespace for the highlights defined with [`set_hl`] while
991/// redrawing.
992///
993/// This function is meant to be called while redrawing, primarily from
994/// [`set_decoration_provider`](crate::set_decoration_provider)'s `on_win` and
995/// `on_lines` callbacks, which are allowed to change the namespace during a
996/// redraw cycle.
997///
998/// [1]: https://neovim.io/doc/user/api.html#nvim_set_hl_ns_fast()
999#[cfg(feature = "neovim-0-10")] // On 0.10 and nightly.
1000#[cfg_attr(
1001    docsrs,
1002    doc(cfg(any(feature = "neovim-0-10", feature = "neovim-nightly")))
1003)]
1004pub fn set_hl_ns_fast(ns_id: u32) -> Result<()> {
1005    let mut err = nvim::Error::new();
1006    unsafe { nvim_set_hl_ns_fast(ns_id as Integer, &mut err) };
1007    choose!(err, ())
1008}
1009
1010/// Binding to [`nvim_set_keymap()`][1].
1011///
1012/// Sets a global mapping for the given mode. To set a buffer-local mapping use
1013/// [`Buffer::set_keymap`] instead.
1014///
1015/// [1]: https://neovim.io/doc/user/api.html#nvim_set_keymap()
1016pub fn set_keymap(
1017    mode: Mode,
1018    lhs: &str,
1019    rhs: &str,
1020    opts: &SetKeymapOpts,
1021) -> Result<()> {
1022    let mode = nvim::String::from(mode);
1023    let lhs = nvim::String::from(lhs);
1024    let rhs = nvim::String::from(rhs);
1025    let mut err = nvim::Error::new();
1026    unsafe {
1027        nvim_set_keymap(
1028            LUA_INTERNAL_CALL,
1029            mode.non_owning(),
1030            lhs.non_owning(),
1031            rhs.non_owning(),
1032            opts,
1033            &mut err,
1034        )
1035    };
1036    choose!(err, ())
1037}
1038
1039/// Binding to [`nvim_set_var()`][1].
1040///
1041/// Sets a global (`g:`) variable.
1042///
1043/// [1]: https://neovim.io/doc/user/api.html#nvim_set_var()
1044pub fn set_var<Var>(name: &str, value: Var) -> Result<()>
1045where
1046    Var: ToObject,
1047{
1048    let name = nvim::String::from(name);
1049    let value = value.to_object()?;
1050    let mut err = nvim::Error::new();
1051    unsafe { nvim_set_var(name.non_owning(), value.non_owning(), &mut err) };
1052    choose!(err, ())
1053}
1054
1055/// Binding to [`nvim_set_vvar()`][1].
1056///
1057/// Sets a `v:` variable, if it's not readonly.
1058///
1059/// [1]: https://neovim.io/doc/user/api.html#nvim_set_vvar()
1060pub fn set_vvar<Var>(name: &str, value: Var) -> Result<()>
1061where
1062    Var: ToObject,
1063{
1064    let name = nvim::String::from(name);
1065    let value = value.to_object()?;
1066    let mut err = nvim::Error::new();
1067    unsafe { nvim_set_vvar(name.non_owning(), value.non_owning(), &mut err) };
1068    choose!(err, ())
1069}
1070
1071/// Binding to [`nvim_strwidth()`][1].
1072///
1073/// Calculates the number of display cells occupied by `text`. Control
1074/// characters like `<Tab>` count as one cell.
1075///
1076/// [1]: https://neovim.io/doc/user/api.html#nvim_strwidth()
1077pub fn strwidth(text: &str) -> Result<usize> {
1078    let text = nvim::String::from(text);
1079    let mut err = nvim::Error::new();
1080    let width = unsafe { nvim_strwidth(text.non_owning(), &mut err) };
1081    choose!(err, Ok(width.try_into().expect("always positive")))
1082}