#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
use std::rc::Rc;
use crate::ported::eval::typval::{
tv_get_number, tv_get_number_chk, tv_list_alloc_ret, tv_list_append_number,
};
use crate::ported::eval::typval_defs_h::{list_T, typval_T, varnumber_T, VarType::VAR_UNKNOWN};
use crate::ported::eval_h::FAIL;
use crate::ported::message::emsg;
use crate::ported::window::{
curtab, curwin, find_tabpage, first_tabpage, firstwin, handle_T, tabpage_T, win_T,
win_get_tabwin,
};
const LOWEST_WIN_ID: i32 = 1000;
const e_invalwindow: &str = "E957: Invalid window number";
pub fn win_has_winnr(
wp: &Rc<std::cell::RefCell<win_T>>,
tp: &Rc<std::cell::RefCell<tabpage_T>>,
) -> bool {
let twin = if curtab.with(|c| c.borrow().as_ref().is_some_and(|ct| Rc::ptr_eq(ct, tp))) {
curwin.with(|c| c.borrow().clone())
} else {
tp.borrow().tp_curwin.clone()
};
twin.as_ref().is_some_and(|t| Rc::ptr_eq(t, wp))
|| (!wp.borrow().w_config.hide && wp.borrow().w_config.focusable)
}
pub fn win_getid(argvars: &[typval_T]) -> i32 {
if argvars.first().map_or(true, |t| t.v_type == VAR_UNKNOWN) {
return curwin.with(|c| c.borrow().as_ref().map_or(0, |w| w.borrow().handle));
}
let mut winnr = tv_get_number(&argvars[0]) as i32; if winnr <= 0 {
return 0; }
let tp: Option<Rc<std::cell::RefCell<tabpage_T>>>;
let mut wp: Option<Rc<std::cell::RefCell<win_T>>>;
if argvars.get(1).map_or(true, |t| t.v_type == VAR_UNKNOWN) {
tp = curtab.with(|c| c.borrow().clone()); wp = firstwin.with(|c| c.borrow().clone()); } else {
let mut tabnr = tv_get_number(&argvars[1]) as i32; let mut found: Option<Rc<std::cell::RefCell<tabpage_T>>> = None;
let mut tp2 = first_tabpage.with(|c| c.borrow().clone());
while let Some(t) = tp2.clone() {
tabnr -= 1;
if tabnr == 0 {
found = Some(t.clone()); break; }
tp2 = t.borrow().tp_next.clone();
}
tp = found;
if tp.is_none() {
return -1; }
let tp_rc = tp.clone().unwrap();
if curtab.with(|c| c.borrow().as_ref().is_some_and(|ct| Rc::ptr_eq(ct, &tp_rc))) {
wp = firstwin.with(|c| c.borrow().clone()); } else {
wp = tp_rc.borrow().tp_firstwin.clone(); }
}
if let Some(tp_rc) = tp {
while let Some(w) = wp.clone() {
winnr -= win_has_winnr(&w, &tp_rc) as i32; if winnr == 0 {
return w.borrow().handle; }
wp = w.borrow().w_next.clone();
}
}
0 }
pub fn win_id2tabwin(argvars: &[typval_T], rettv: &mut typval_T) {
let id = tv_get_number(&argvars[0]) as handle_T;
let mut winnr = 1; let mut tabnr = 1; win_get_tabwin(id, &mut tabnr, &mut winnr);
let list = tv_list_alloc_ret(rettv, 2); tv_list_append_number(&mut list.borrow_mut(), tabnr as varnumber_T); tv_list_append_number(&mut list.borrow_mut(), winnr as varnumber_T); }
pub fn win_id2wp(id: i32) -> Option<Rc<std::cell::RefCell<win_T>>> {
win_id2wp_tp(id, None) }
pub fn win_id2wp_tp(
id: i32,
tpp: Option<&mut Option<Rc<std::cell::RefCell<tabpage_T>>>>,
) -> Option<Rc<std::cell::RefCell<win_T>>> {
let mut tp = first_tabpage.with(|c| c.borrow().clone());
while let Some(tp_rc) = tp.clone() {
let is_curtab =
curtab.with(|c| c.borrow().as_ref().is_some_and(|ct| Rc::ptr_eq(ct, &tp_rc)));
let mut wp = if is_curtab {
firstwin.with(|c| c.borrow().clone())
} else {
tp_rc.borrow().tp_firstwin.clone()
};
while let Some(w) = wp.clone() {
if w.borrow().handle == id {
if let Some(out) = tpp {
*out = Some(tp_rc.clone()); }
return Some(w); }
wp = w.borrow().w_next.clone();
}
tp = tp_rc.borrow().tp_next.clone();
}
None }
pub fn win_id2win(argvars: &[typval_T]) -> i32 {
let mut nr = 1; let id = tv_get_number(&argvars[0]) as i32;
if let Some(tp_rc) = curtab.with(|c| c.borrow().clone()) {
let mut wp = firstwin.with(|c| c.borrow().clone());
while let Some(w) = wp.clone() {
if w.borrow().handle == id {
return if win_has_winnr(&w, &tp_rc) { nr } else { 0 }; }
nr += win_has_winnr(&w, &tp_rc) as i32; wp = w.borrow().w_next.clone();
}
}
0 }
pub fn win_findbuf(argvars: &[typval_T], list: &mut list_T) {
let bufnr = tv_get_number(&argvars[0]) as i32;
let mut tp = first_tabpage.with(|c| c.borrow().clone());
while let Some(tp_rc) = tp.clone() {
let is_curtab =
curtab.with(|c| c.borrow().as_ref().is_some_and(|ct| Rc::ptr_eq(ct, &tp_rc)));
let mut wp = if is_curtab {
firstwin.with(|c| c.borrow().clone())
} else {
tp_rc.borrow().tp_firstwin.clone()
};
while let Some(w) = wp.clone() {
let matches = w
.borrow()
.w_buffer
.as_ref()
.is_some_and(|b| b.borrow().handle == bufnr);
if matches {
tv_list_append_number(list, w.borrow().handle as varnumber_T); }
wp = w.borrow().w_next.clone();
}
tp = tp_rc.borrow().tp_next.clone();
}
}
pub fn find_win_by_nr(
vp: &typval_T,
tp: Option<Rc<std::cell::RefCell<tabpage_T>>>,
) -> Option<Rc<std::cell::RefCell<win_T>>> {
let mut nr = tv_get_number_chk(vp, None) as i32;
if nr < 0 {
return None; }
if nr == 0 {
return curwin.with(|c| c.borrow().clone()); }
let tp = match tp {
Some(tp) => Some(tp),
None => curtab.with(|c| c.borrow().clone()), };
if let Some(tp_rc) = tp {
let is_curtab =
curtab.with(|c| c.borrow().as_ref().is_some_and(|ct| Rc::ptr_eq(ct, &tp_rc)));
let mut wp = if is_curtab {
firstwin.with(|c| c.borrow().clone())
} else {
tp_rc.borrow().tp_firstwin.clone()
};
while let Some(w) = wp.clone() {
if nr >= LOWEST_WIN_ID {
if w.borrow().handle == nr {
return Some(w); }
} else {
nr -= 1;
if nr <= 0 {
return Some(w); }
}
wp = w.borrow().w_next.clone();
}
}
None }
pub fn find_win_by_nr_or_id(vp: &typval_T) -> Option<Rc<std::cell::RefCell<win_T>>> {
let nr = tv_get_number_chk(vp, None) as i32;
if nr >= LOWEST_WIN_ID {
return win_id2wp(tv_get_number(vp) as i32); }
find_win_by_nr(vp, None) }
pub fn find_tabwin(wvp: &typval_T, tvp: &typval_T) -> Option<Rc<std::cell::RefCell<win_T>>> {
let mut wp: Option<Rc<std::cell::RefCell<win_T>>> = None; let mut tp: Option<Rc<std::cell::RefCell<tabpage_T>>> = None;
if wvp.v_type != VAR_UNKNOWN {
if tvp.v_type != VAR_UNKNOWN {
let n = tv_get_number(tvp) as i32; if n >= 0 {
tp = find_tabpage(n); }
} else {
tp = curtab.with(|c| c.borrow().clone()); }
if tp.is_some() {
wp = find_win_by_nr(wvp, tp); }
} else {
wp = curwin.with(|c| c.borrow().clone()); }
wp }
pub fn get_optional_window(
argvars: &[typval_T],
idx: usize,
) -> Option<Rc<std::cell::RefCell<win_T>>> {
if argvars.get(idx).map_or(true, |t| t.v_type == VAR_UNKNOWN) {
return curwin.with(|c| c.borrow().clone()); }
let win = find_win_by_nr_or_id(&argvars[idx]); if win.is_none() {
emsg(e_invalwindow); return None; }
win }
pub fn get_winnr(_argvar: &typval_T) -> i32 {
0
}
pub fn switch_win() -> i32 {
FAIL
}
pub fn switch_win_noblock() -> i32 {
FAIL
}
pub fn restore_win() {}
pub fn restore_win_noblock() {}
pub fn get_win_info() {}
pub fn get_tabpage_info() {}
pub fn get_framelayout() {}
pub fn win_execute_before() {}
pub fn win_execute_after() {}
#[cfg(test)]
mod tests {
use super::*;
use crate::ported::eval::typval_defs_h::{
typval_vval_union::v_number, VarLockStatus, VarType::VAR_NUMBER,
};
use crate::ported::window::{buf_T, tabpage_T, win_T, WinConfig};
use std::cell::RefCell;
fn num(n: varnumber_T) -> typval_T {
typval_T {
v_type: VAR_NUMBER,
v_lock: VarLockStatus::VAR_UNLOCKED,
vval: v_number(n),
}
}
fn setup() -> (Rc<RefCell<win_T>>, Rc<RefCell<win_T>>) {
let b7 = Rc::new(RefCell::new(buf_T {
handle: 7,
..Default::default()
}));
let b9 = Rc::new(RefCell::new(buf_T {
handle: 9,
..Default::default()
}));
let w0 = Rc::new(RefCell::new(win_T {
handle: 1000,
w_buffer: Some(b7),
w_config: WinConfig {
focusable: true,
hide: false,
},
..Default::default()
}));
let w1 = Rc::new(RefCell::new(win_T {
handle: 1001,
w_buffer: Some(b9),
w_config: WinConfig {
focusable: true,
hide: false,
},
..Default::default()
}));
w0.borrow_mut().w_next = Some(w1.clone());
w1.borrow_mut().w_prev = Some(Rc::downgrade(&w0));
let tab = Rc::new(RefCell::new(tabpage_T {
handle: 1,
tp_firstwin: Some(w0.clone()),
tp_lastwin: Some(w1.clone()),
tp_curwin: Some(w0.clone()),
..Default::default()
}));
firstwin.with(|c| *c.borrow_mut() = Some(w0.clone()));
curwin.with(|c| *c.borrow_mut() = Some(w0.clone()));
first_tabpage.with(|c| *c.borrow_mut() = Some(tab.clone()));
curtab.with(|c| *c.borrow_mut() = Some(tab.clone()));
(w0, w1)
}
#[test]
fn win_id2wp_and_win_id2win() {
let (w0, w1) = setup();
assert!(Rc::ptr_eq(&win_id2wp(1000).unwrap(), &w0));
assert!(Rc::ptr_eq(&win_id2wp(1001).unwrap(), &w1));
assert!(win_id2wp(4242).is_none());
assert_eq!(win_id2win(&[num(1000)]), 1);
assert_eq!(win_id2win(&[num(1001)]), 2);
assert_eq!(win_id2win(&[num(4242)]), 0);
}
#[test]
fn win_id2wp_tp_sets_tab() {
let (_w0, w1) = setup();
let mut tab_out: Option<Rc<RefCell<tabpage_T>>> = None;
let wp = win_id2wp_tp(1001, Some(&mut tab_out)).unwrap();
assert!(Rc::ptr_eq(&wp, &w1));
assert_eq!(tab_out.unwrap().borrow().handle, 1);
}
#[test]
fn find_win_by_nr_or_id_number_vs_id() {
let (w0, w1) = setup();
assert!(Rc::ptr_eq(&find_win_by_nr_or_id(&num(0)).unwrap(), &w0));
assert!(Rc::ptr_eq(&find_win_by_nr_or_id(&num(2)).unwrap(), &w1));
assert!(Rc::ptr_eq(&find_win_by_nr_or_id(&num(1000)).unwrap(), &w0));
assert!(find_win_by_nr_or_id(&num(-3)).is_none());
}
#[test]
fn win_findbuf_collects_matching_windows() {
setup();
let mut list = list_T::default();
win_findbuf(&[num(9)], &mut list);
assert_eq!(list.lv_len, 1);
assert_eq!(super::tv_get_number(&list.lv_items[0].li_tv), 1001);
}
#[test]
fn get_optional_window_default_and_lookup() {
let (w0, w1) = setup();
assert!(Rc::ptr_eq(&get_optional_window(&[], 0).unwrap(), &w0));
assert!(Rc::ptr_eq(
&get_optional_window(&[num(1001)], 0).unwrap(),
&w1
));
assert!(get_optional_window(&[num(4242)], 0).is_none());
}
#[test]
fn win_id2tabwin_returns_pair() {
setup();
let mut rettv = typval_T::default();
win_id2tabwin(&[num(1001)], &mut rettv);
if let crate::ported::eval::typval_defs_h::typval_vval_union::v_list(Some(l)) = &rettv.vval
{
let l = l.borrow();
assert_eq!(l.lv_len, 2);
assert_eq!(super::tv_get_number(&l.lv_items[0].li_tv), 1);
assert_eq!(super::tv_get_number(&l.lv_items[1].li_tv), 2);
} else {
panic!("expected a VAR_LIST rettv");
}
}
}