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#[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 #[inline(always)]
82 pub fn current() -> Self {
83 crate::get_current_win()
84 }
85
86 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 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 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 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 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 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 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 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 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 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 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 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 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 pub fn is_valid(&self) -> bool {
241 unsafe { nvim_win_is_valid(self.0) }
242 }
243
244 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 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 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 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 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 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}