use super::*; pub struct DirectoryListing { children: Vec, length: u32, selected: Option, child_path_buffer: BedrockPathBuffer, } impl DirectoryListing { pub fn from_path(path: &BedrockFilePath) -> Option { macro_rules! unres { ($result:expr) => { match $result { Ok(v) => v, Err(_) => continue} }; } macro_rules! unopt { ($option:expr) => { match $option { Some(v) => v, None => continue} }; } #[cfg(target_family = "windows")] { if path.as_path().components().count() == 0 { return Some(Self::construct_virtual_root()) } } let mut children = Vec::new(); if let Ok(dir_listing) = std::fs::read_dir(path.as_path()) { for (i, entry_result) in dir_listing.enumerate() { // Firebreak to prevent emulator from consuming an absurd amount // of memory when opening too large of a directory. if i == (u16::MAX as usize) { break; } let entry = unres!(entry_result); let entry_path = unopt!(BedrockFilePath::from_path(&entry.path(), path.base())); if entry_path.is_hidden() { continue; } children.push(entry_path); } } children.sort(); let length = u32::try_from(children.len()).ok()?; let selected = None; let child_path_buffer = BedrockPathBuffer::new(); Some( Self { children, length, selected, child_path_buffer } ) } /// Generate entries for a virtual root directory. #[cfg(target_family = "windows")] fn construct_virtual_root() -> Self { let mut children = Vec::new(); let base = PathBuf::from(""); let drive_bits = unsafe { windows::Win32::Storage::FileSystem::GetLogicalDrives() }; for i in 0..26 { if drive_bits & (0x1 << i) != 0 { let letter: char = (b'A' + i).into(); let path = PathBuf::from(format!("{letter}:/")); if let Some(drive) = BedrockFilePath::from_path(&path, &base) { children.push(drive); } } } let length = children.len() as u32; let selected = None; let child_path_buffer = BedrockPathBuffer::new(); Self { children, length, selected, child_path_buffer } } /// Attempts to return a directory child by index. pub fn get(&self, index: u32) -> Option<&BedrockFilePath> { self.children.get(index as usize) } pub fn length(&self) -> u32 { self.length } /// Returns the index of the selected child, or zero if no child is selected. pub fn selected(&self) -> u32 { self.selected.unwrap_or(0) } /// Attempts to select a child by index. pub fn set_selected(&mut self, index: u32) { if let Some(child) = self.get(index) { let buffer = child.as_buffer(); self.child_path_buffer.populate(buffer); self.selected = Some(index); } else { self.child_path_buffer.clear(); self.selected = None; } } pub fn child_path_buffer(&mut self) -> &mut BedrockPathBuffer { &mut self.child_path_buffer } pub fn child_type(&self) -> Option { self.selected.and_then(|s| self.get(s).and_then(|i| i.entry_type())) } pub fn child_path(&self) -> Option { self.selected.and_then(|s| self.get(s).and_then(|i| Some(i.clone()))) } }