nvim_api/
window.rs

1use std::fmt;
2use std::result::Result as StdResult;
3
4use luajit_bindings::{self as lua, Poppable, Pushable};
5use nvim_types::{
6    self as nvim,
7    conversion::{self, FromObject, ToObject},
8    Array,
9    Function,
10    Integer,
11    Object,
12    WinHandle,
13};
14use serde::{Deserialize, Serialize};
15
16use crate::choose;
17use crate::ffi::window::*;
18use crate::Result;
19use crate::LUA_INTERNAL_CALL;
20use crate::{Buffer, TabPage};
21
22/// A wrapper around a Neovim window handle.
23#[derive(Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
24pub struct Window(pub(crate) WinHandle);
25
26impl fmt::Debug for Window {
27    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
28        f.debug_tuple("Window").field(&self.0).finish()
29    }
30}
31
32impl fmt::Display for Window {
33    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34        fmt::Debug::fmt(self, f)
35    }
36}
37
38impl<H: Into<WinHandle>> From<H> for Window {
39    fn from(handle: H) -> Self {
40        Self(handle.into())
41    }
42}
43
44impl From<Window> for Object {
45    fn from(win: Window) -> Self {
46        win.0.into()
47    }
48}
49
50impl From<&Window> for Object {
51    fn from(win: &Window) -> Self {
52        win.0.into()
53    }
54}
55
56impl FromObject for Window {
57    fn from_object(obj: Object) -> StdResult<Self, conversion::Error> {
58        Ok(WinHandle::from_object(obj)?.into())
59    }
60}
61
62impl Poppable for Window {
63    unsafe fn pop(
64        lstate: *mut lua::ffi::lua_State,
65    ) -> std::result::Result<Self, lua::Error> {
66        WinHandle::pop(lstate).map(Into::into)
67    }
68}
69
70impl Pushable for Window {
71    unsafe fn push(
72        self,
73        lstate: *mut lua::ffi::lua_State,
74    ) -> std::result::Result<std::ffi::c_int, lua::Error> {
75        self.0.push(lstate)
76    }
77}
78
79impl Window {
80    /// Shorthand for [`get_current_win`](crate::get_current_win).
81    #[inline(always)]
82    pub fn current() -> Self {
83        crate::get_current_win()
84    }
85
86    /// Binding to [`nvim_win_call`][1].
87    ///
88    /// Calls a function with this window as the temporary current window.
89    ///
90    /// [1]: https://neovim.io/doc/user/api.html#nvim_win_call()
91    pub fn call<R, F>(&self, fun: F) -> Result<R>
92    where
93        F: FnOnce(()) -> Result<R> + 'static,
94        R: Pushable + FromObject,
95    {
96        let fun = Function::from_fn_once(fun);
97        let mut err = nvim::Error::new();
98        let obj = unsafe { nvim_win_call(self.0, fun.lua_ref(), &mut err) };
99
100        choose!(err, {
101            fun.remove_from_lua_registry();
102            Ok(R::from_object(obj)?)
103        })
104    }
105
106    /// Binding to [`nvim_win_close`](https://neovim.io/doc/user/api.html#nvim_win_close()).
107    ///
108    /// Closes the window. Not allowed when
109    /// [`textlock`](https://neovim.io/doc/user/eval.html#textlock) is active.
110    pub fn close(self, force: bool) -> Result<()> {
111        let mut err = nvim::Error::new();
112        unsafe { nvim_win_close(self.0, force, &mut err) };
113        choose!(err, ())
114    }
115
116    /// Binding to [`nvim_win_del_var`](https://neovim.io/doc/user/api.html#nvim_win_del_var()).
117    ///
118    /// Removes a window-scoped (`w:`) variable.
119    pub fn del_var(&mut self, name: &str) -> Result<()> {
120        let mut err = nvim::Error::new();
121        let name = nvim::String::from(name);
122        unsafe { nvim_win_del_var(self.0, name.non_owning(), &mut err) };
123        choose!(err, ())
124    }
125
126    /// Binding to [`nvim_win_get_buf`](https://neovim.io/doc/user/api.html#nvim_win_get_buf()).
127    ///
128    /// Gets the current [`Buffer`] in the window.
129    pub fn get_buf(&self) -> Result<Buffer> {
130        let mut err = nvim::Error::new();
131        let handle = unsafe { nvim_win_get_buf(self.0, &mut err) };
132        choose!(err, Ok(handle.into()))
133    }
134
135    /// Binding to [`nvim_win_get_cursor`](https://neovim.io/doc/user/api.html#nvim_win_get_cursor()).
136    ///
137    /// Gets the (1,0)-indexed cursor position in the window.
138    pub fn get_cursor(&self) -> Result<(usize, usize)> {
139        let mut err = nvim::Error::new();
140        let arr = unsafe { nvim_win_get_cursor(self.0, &mut err) };
141        choose!(err, {
142            let mut iter = arr.into_iter();
143            let line = usize::from_object(iter.next().unwrap())?;
144            let col = usize::from_object(iter.next().unwrap())?;
145            Ok((line, col))
146        })
147    }
148
149    /// Binding to [`nvim_win_get_height`](https://neovim.io/doc/user/api.html#nvim_win_get_height()).
150    ///
151    /// Gets the window height as a count of rows.
152    pub fn get_height(&self) -> Result<u32> {
153        let mut err = nvim::Error::new();
154        let height = unsafe { nvim_win_get_height(self.0, &mut err) };
155        choose!(err, Ok(height.try_into().expect("always positive")))
156    }
157
158    /// Binding to [`nvim_win_get_number`](https://neovim.io/doc/user/api.html#nvim_win_get_number()).
159    ///
160    /// Gets the window number.
161    pub fn get_number(&self) -> Result<u32> {
162        let mut err = nvim::Error::new();
163        let nr = unsafe { nvim_win_get_number(self.0, &mut err) };
164        choose!(err, Ok(nr.try_into().expect("always positive")))
165    }
166
167    /// Binding to [`nvim_win_get_option`](https://neovim.io/doc/user/api.html#nvim_win_get_option()).
168    ///
169    /// Gets a window option value.
170    pub fn get_option<Opt>(&self, name: &str) -> Result<Opt>
171    where
172        Opt: FromObject,
173    {
174        let mut err = nvim::Error::new();
175        let name = nvim::String::from(name);
176        let obj = unsafe {
177            nvim_win_get_option(self.0, name.non_owning(), &mut err)
178        };
179        choose!(err, Ok(Opt::from_object(obj)?))
180    }
181
182    /// Binding to [`nvim_win_get_position`](https://neovim.io/doc/user/api.html#nvim_win_get_position()).
183    ///
184    /// Gets the window position in display cells.
185    pub fn get_position(&self) -> Result<(usize, usize)> {
186        let mut err = nvim::Error::new();
187        let arr = unsafe { nvim_win_get_position(self.0, &mut err) };
188        choose!(err, {
189            let mut iter = arr.into_iter();
190            let line = usize::from_object(iter.next().unwrap())?;
191            let col = usize::from_object(iter.next().unwrap())?;
192            Ok((line, col))
193        })
194    }
195
196    /// Binding to [`nvim_win_get_tabpage`](https://neovim.io/doc/user/api.html#nvim_win_get_tabpage()).
197    ///
198    /// Gets the window's `TabPage`.
199    pub fn get_tabpage(&self) -> Result<TabPage> {
200        let mut err = nvim::Error::new();
201        let handle = unsafe { nvim_win_get_tabpage(self.0, &mut err) };
202        choose!(err, Ok(handle.into()))
203    }
204
205    /// Binding to [`nvim_win_get_var`](https://neovim.io/doc/user/api.html#nvim_win_get_var()).
206    ///
207    /// Gets a window-scoped (`w:`) variable.
208    pub fn get_var<Var>(&self, name: &str) -> Result<Var>
209    where
210        Var: FromObject,
211    {
212        let mut err = nvim::Error::new();
213        let name = nvim::String::from(name);
214        let obj =
215            unsafe { nvim_win_get_var(self.0, name.non_owning(), &mut err) };
216        choose!(err, Ok(Var::from_object(obj)?))
217    }
218
219    /// Binding to [`nvim_win_get_width`](https://neovim.io/doc/user/api.html#nvim_win_get_width()).
220    ///
221    /// Gets the window width as a number of columns.
222    pub fn get_width(&self) -> Result<u32> {
223        let mut err = nvim::Error::new();
224        let width = unsafe { nvim_win_get_width(self.0, &mut err) };
225        choose!(err, Ok(width.try_into().expect("always positive")))
226    }
227
228    /// Binding to [`nvim_win_hide`](https://neovim.io/doc/user/api.html#nvim_win_hide()).
229    ///
230    /// Closes the window and hides the buffer it contains.
231    pub fn hide(self) -> Result<()> {
232        let mut err = nvim::Error::new();
233        unsafe { nvim_win_hide(self.0, &mut err) };
234        choose!(err, ())
235    }
236
237    /// Binding to [`nvim_win_is_valid`](https://neovim.io/doc/user/api.html#nvim_win_is_valid()).
238    ///
239    /// Checks if the window is valid.
240    pub fn is_valid(&self) -> bool {
241        unsafe { nvim_win_is_valid(self.0) }
242    }
243
244    /// Binding to [`nvim_win_set_buf`](https://neovim.io/doc/user/api.html#nvim_win_set_buf()).
245    ///
246    /// Sets `buffer` as the current buffer in the window.
247    pub fn set_buf(&mut self, buffer: &Buffer) -> Result<()> {
248        let mut err = nvim::Error::new();
249        unsafe { nvim_win_set_buf(self.0, buffer.0, &mut err) };
250        choose!(err, ())
251    }
252
253    /// Binding to [`nvim_win_set_cursor`](https://neovim.io/doc/user/api.html#nvim_win_set_cursor()).
254    ///
255    /// Sets the (1,0)-indexed cursor in the window. This will scroll the
256    /// window even if it's not the current one.
257    pub fn set_cursor(&mut self, line: usize, col: usize) -> Result<()> {
258        let mut err = nvim::Error::new();
259        let pos = Array::from_iter([line as Integer, col as Integer]);
260        unsafe { nvim_win_set_cursor(self.0, pos.non_owning(), &mut err) };
261        choose!(err, ())
262    }
263
264    /// Binding to [`nvim_win_set_height`](https://neovim.io/doc/user/api.html#nvim_win_set_height()).
265    ///
266    /// Sets the window height.
267    pub fn set_height(&mut self, height: u32) -> Result<()> {
268        let mut err = nvim::Error::new();
269        unsafe { nvim_win_set_height(self.0, height.into(), &mut err) };
270        choose!(err, ())
271    }
272
273    /// Binding to [`nvim_win_set_option`](https://neovim.io/doc/user/api.html#nvim_win_set_option()).
274    ///
275    /// Sets a window option value. Passing `None` as value deletes the option
276    /// (only works if there's a global fallback).
277    pub fn set_option<Opt>(&mut self, name: &str, value: Opt) -> Result<()>
278    where
279        Opt: ToObject,
280    {
281        let mut err = nvim::Error::new();
282        let name = nvim::String::from(name);
283        unsafe {
284            nvim_win_set_option(
285                LUA_INTERNAL_CALL,
286                self.0,
287                name.non_owning(),
288                value.to_object()?.non_owning(),
289                &mut err,
290            )
291        };
292        choose!(err, ())
293    }
294
295    /// Binding to [`nvim_win_set_var`](https://neovim.io/doc/user/api.html#nvim_win_set_var()).
296    ///
297    /// Sets a window-scoped (`w:`) variable.
298    pub fn set_var<Var>(&mut self, name: &str, value: Var) -> Result<()>
299    where
300        Var: ToObject,
301    {
302        let mut err = nvim::Error::new();
303        let name = nvim::String::from(name);
304        unsafe {
305            nvim_win_set_var(
306                self.0,
307                name.non_owning(),
308                value.to_object()?.non_owning(),
309                &mut err,
310            )
311        };
312        choose!(err, ())
313    }
314
315    /// Binding to [`nvim_win_set_width`](https://neovim.io/doc/user/api.html#nvim_win_set_width()).
316    ///
317    /// Sets the window width.
318    pub fn set_width(&mut self, width: u32) -> Result<()> {
319        let mut err = nvim::Error::new();
320        unsafe { nvim_win_set_width(self.0, width.into(), &mut err) };
321        choose!(err, ())
322    }
323}