1use nvim_oxi::api::Buffer;
4use nvim_oxi::api::Window;
5use nvim_oxi::api::opts::OptionOptsBuilder;
6use nvim_oxi::conversion::FromObject;
7
8use crate::buffer::BufferExt;
9
10pub fn set_current(window: &Window) -> Option<()> {
17 nvim_oxi::api::set_current_win(window)
18 .inspect_err(|err| {
19 crate::notify::error(format!(
20 "error setting current window | window={window:?}, error={err:?}"
21 ));
22 })
23 .ok()?;
24 Some(())
25}
26
27pub fn get_buffer(window: &Window) -> Option<Buffer> {
34 window
35 .get_buf()
36 .inspect_err(|err| {
37 crate::notify::error(format!(
38 "error getting window buffer | window={window:?}, error={err:?}"
39 ));
40 })
41 .ok()
42}
43
44pub fn find_with_buffer(buffer_type: &str) -> Option<(Window, Buffer)> {
45 nvim_oxi::api::list_wins().find_map(|win| {
46 if let Some(buffer) = get_buffer(&win)
47 && buffer.get_buf_type().is_some_and(|bt| bt == buffer_type)
48 {
49 Some((win, buffer))
50 } else {
51 None
52 }
53 })
54}
55
56pub fn find_focusable_float(allowed_filetypes: &[&str]) -> Option<Window> {
67 for win in nvim_oxi::api::list_wins() {
68 if !is_floating(&win) {
69 continue;
70 }
71
72 let is_focusable =
73 nvim_oxi::api::call_function::<_, nvim_oxi::Dictionary>("nvim_win_get_config", (win.clone(),))
74 .ok()
75 .and_then(|cfg| cfg.get("focusable").cloned())
76 .and_then(|obj| bool::from_object(obj).ok())
77 .unwrap_or(true);
78
79 if !is_focusable {
80 continue;
81 }
82
83 let Some(buf) = get_buffer(&win) else {
84 continue;
85 };
86
87 let opts = OptionOptsBuilder::default().buf(buf).build();
88 let has_allowed_ft = nvim_oxi::api::get_option_value::<String>("filetype", &opts)
89 .ok()
90 .is_some_and(|ft| allowed_filetypes.contains(&ft.as_str()));
91
92 if has_allowed_ft {
93 return Some(win);
94 }
95 }
96
97 None
98}
99
100pub fn is_floating(window: &Window) -> bool {
101 nvim_oxi::api::call_function::<_, nvim_oxi::Dictionary>("nvim_win_get_config", (window.clone(),))
102 .ok()
103 .and_then(|cfg| cfg.get("relative").cloned())
104 .and_then(|obj| String::from_object(obj).ok())
105 .is_some_and(|s| !s.is_empty())
106}
107
108pub fn get_number(win: &Window) -> Option<u32> {
109 win.get_number()
110 .inspect_err(|err| crate::notify::error(format!("error getting window number | window={win:?} error={err:?}")))
111 .ok()
112}