1use std::error::Error as StdError;
2use std::fmt;
3use std::result::Result as StdResult;
4
5use luajit::{self as lua, Poppable, Pushable};
6use serde::{Deserialize, Serialize};
7use types::{
8 self as nvim,
9 conversion::{self, FromObject, ToObject},
10 Array,
11 Function,
12 Integer,
13 Object,
14 WinHandle,
15};
16
17use crate::choose;
18use crate::ffi::window::*;
19#[cfg(feature = "neovim-0-10")] use crate::opts::WinTextHeightOpts;
21#[cfg(feature = "neovim-0-10")] use crate::types::WinTextHeightInfos;
23use crate::Result;
24use crate::{Buffer, IntoResult, TabPage};
25
26#[derive(Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
28pub struct Window(pub(crate) WinHandle);
29
30impl fmt::Debug for Window {
31 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32 f.debug_tuple("Window").field(&self.0).finish()
33 }
34}
35
36impl fmt::Display for Window {
37 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38 fmt::Debug::fmt(self, f)
39 }
40}
41
42impl<H: Into<WinHandle>> From<H> for Window {
43 fn from(handle: H) -> Self {
44 Self(handle.into())
45 }
46}
47
48impl From<Window> for Object {
49 fn from(win: Window) -> Self {
50 win.0.into()
51 }
52}
53
54impl From<&Window> for Object {
55 fn from(win: &Window) -> Self {
56 win.0.into()
57 }
58}
59
60impl FromObject for Window {
61 fn from_object(obj: Object) -> StdResult<Self, conversion::Error> {
62 Ok(WinHandle::from_object(obj)?.into())
63 }
64}
65
66impl Poppable for Window {
67 unsafe fn pop(
68 lstate: *mut lua::ffi::lua_State,
69 ) -> std::result::Result<Self, lua::Error> {
70 WinHandle::pop(lstate).map(Into::into)
71 }
72}
73
74impl Pushable for Window {
75 unsafe fn push(
76 self,
77 lstate: *mut lua::ffi::lua_State,
78 ) -> std::result::Result<std::ffi::c_int, lua::Error> {
79 self.0.push(lstate)
80 }
81}
82
83impl Window {
84 #[inline(always)]
86 pub fn current() -> Self {
87 crate::get_current_win()
88 }
89
90 #[inline(always)]
92 pub fn handle(&self) -> i32 {
93 self.0
94 }
95
96 pub fn call<F, Res, Ret>(&self, fun: F) -> Result<Ret>
102 where
103 F: FnOnce(()) -> Res + 'static,
104 Res: IntoResult<Ret>,
105 Res::Error: StdError + 'static,
106 Ret: Pushable + FromObject,
107 {
108 let fun = Function::from_fn_once(fun);
109 let mut err = nvim::Error::new();
110 let obj = unsafe { nvim_win_call(self.0, fun.lua_ref(), &mut err) };
111
112 choose!(err, {
113 fun.remove_from_lua_registry();
114 Ok(Ret::from_object(obj)?)
115 })
116 }
117
118 pub fn close(self, force: bool) -> Result<()> {
125 let mut err = nvim::Error::new();
126 unsafe { nvim_win_close(self.0, force, &mut err) };
127 choose!(err, ())
128 }
129
130 pub fn del_var(&mut self, name: &str) -> Result<()> {
136 let mut err = nvim::Error::new();
137 let name = nvim::String::from(name);
138 unsafe { nvim_win_del_var(self.0, name.non_owning(), &mut err) };
139 choose!(err, ())
140 }
141
142 pub fn get_buf(&self) -> Result<Buffer> {
148 let mut err = nvim::Error::new();
149 let handle = unsafe { nvim_win_get_buf(self.0, &mut err) };
150 choose!(err, Ok(handle.into()))
151 }
152
153 pub fn get_cursor(&self) -> Result<(usize, usize)> {
159 let mut err = nvim::Error::new();
160 let arr = unsafe {
161 nvim_win_get_cursor(
162 self.0,
163 #[cfg(feature = "neovim-0-10")] types::arena(),
165 &mut err,
166 )
167 };
168 choose!(err, {
169 let mut iter = arr.into_iter();
170 let line = usize::from_object(iter.next().unwrap())?;
171 let col = usize::from_object(iter.next().unwrap())?;
172 Ok((line, col))
173 })
174 }
175
176 pub fn get_height(&self) -> Result<u32> {
182 let mut err = nvim::Error::new();
183 let height = unsafe { nvim_win_get_height(self.0, &mut err) };
184 choose!(err, Ok(height.try_into().expect("always positive")))
185 }
186
187 pub fn get_number(&self) -> Result<u32> {
193 let mut err = nvim::Error::new();
194 let nr = unsafe { nvim_win_get_number(self.0, &mut err) };
195 choose!(err, Ok(nr.try_into().expect("always positive")))
196 }
197
198 pub fn get_position(&self) -> Result<(usize, usize)> {
204 let mut err = nvim::Error::new();
205 let arr = unsafe {
206 nvim_win_get_position(
207 self.0,
208 #[cfg(feature = "neovim-0-10")] types::arena(),
210 &mut err,
211 )
212 };
213 choose!(err, {
214 let mut iter = arr.into_iter();
215 let line = usize::from_object(iter.next().unwrap())?;
216 let col = usize::from_object(iter.next().unwrap())?;
217 Ok((line, col))
218 })
219 }
220
221 pub fn get_tabpage(&self) -> Result<TabPage> {
227 let mut err = nvim::Error::new();
228 let handle = unsafe { nvim_win_get_tabpage(self.0, &mut err) };
229 choose!(err, Ok(handle.into()))
230 }
231
232 pub fn get_var<Var>(&self, name: &str) -> Result<Var>
238 where
239 Var: FromObject,
240 {
241 let mut err = nvim::Error::new();
242 let name = nvim::String::from(name);
243 let obj = unsafe {
244 nvim_win_get_var(
245 self.0,
246 name.non_owning(),
247 #[cfg(feature = "neovim-0-10")] types::arena(),
249 &mut err,
250 )
251 };
252 choose!(err, Ok(Var::from_object(obj)?))
253 }
254
255 pub fn get_width(&self) -> Result<u32> {
261 let mut err = nvim::Error::new();
262 let width = unsafe { nvim_win_get_width(self.0, &mut err) };
263 choose!(err, Ok(width.try_into().expect("always positive")))
264 }
265
266 pub fn hide(self) -> Result<()> {
272 let mut err = nvim::Error::new();
273 unsafe { nvim_win_hide(self.0, &mut err) };
274 choose!(err, ())
275 }
276
277 pub fn is_valid(&self) -> bool {
283 unsafe { nvim_win_is_valid(self.0) }
284 }
285
286 pub fn set_buf(&mut self, buffer: &Buffer) -> Result<()> {
292 let mut err = nvim::Error::new();
293 unsafe { nvim_win_set_buf(self.0, buffer.0, &mut err) };
294 choose!(err, ())
295 }
296
297 pub fn set_cursor(&mut self, line: usize, col: usize) -> Result<()> {
304 let mut err = nvim::Error::new();
305 let pos = Array::from_iter([line as Integer, col as Integer]);
306 unsafe { nvim_win_set_cursor(self.0, pos.non_owning(), &mut err) };
307 choose!(err, ())
308 }
309
310 pub fn set_height(&mut self, height: u32) -> Result<()> {
316 let mut err = nvim::Error::new();
317 unsafe { nvim_win_set_height(self.0, height.into(), &mut err) };
318 choose!(err, ())
319 }
320
321 #[cfg(feature = "neovim-0-10")] #[cfg_attr(
332 docsrs,
333 doc(cfg(any(feature = "neovim-0-10", feature = "neovim-nightly")))
334 )]
335 pub fn set_hl(&mut self, ns_id: u32) -> Result<()> {
336 let mut err = nvim::Error::new();
337 unsafe { nvim_win_set_hl(self.0, ns_id.into(), &mut err) };
338 choose!(err, ())
339 }
340
341 pub fn set_var<Var>(&mut self, name: &str, value: Var) -> Result<()>
347 where
348 Var: ToObject,
349 {
350 let mut err = nvim::Error::new();
351 let name = nvim::String::from(name);
352 unsafe {
353 nvim_win_set_var(
354 self.0,
355 name.non_owning(),
356 value.to_object()?.non_owning(),
357 &mut err,
358 )
359 };
360 choose!(err, ())
361 }
362
363 pub fn set_width(&mut self, width: u32) -> Result<()> {
369 let mut err = nvim::Error::new();
370 unsafe { nvim_win_set_width(self.0, width.into(), &mut err) };
371 choose!(err, ())
372 }
373
374 #[cfg(feature = "neovim-0-10")] #[cfg_attr(
382 docsrs,
383 doc(cfg(any(feature = "neovim-0-10", feature = "neovim-nightly")))
384 )]
385 pub fn text_height(
386 &self,
387 opts: &WinTextHeightOpts,
388 ) -> Result<WinTextHeightInfos> {
389 let mut err = nvim::Error::new();
390 let dict = unsafe {
391 nvim_win_text_height(self.0, opts, types::arena(), &mut err)
392 };
393 choose!(err, dict.try_into().map_err(Into::into))
394 }
395}