use std::path::Path; use std::pin::Pin; use std::future::Future; use serde::Serialize; use tokio::fs; type BoxRecursive<'a, T> = Pin + Send + 'a>>; #[derive(Debug, Serialize)] pub struct FileEntry { pub name: String, pub path: String, pub is_dir: bool, pub children: Option>, } #[tauri::command] pub async fn read_file(path: String) -> Result { fs::read_to_string(&path) .await .map_err(|e| format!("Falha ao ler arquivo ({}): {}", path, e)) } #[tauri::command] pub async fn write_file(path: String, content: String) -> Result<(), String> { let parent = Path::new(&path).parent(); if let Some(parent_dir) = parent { if !parent_dir.as_os_str().is_empty() { fs::create_dir_all(parent_dir) .await .map_err(|e| format!("Falha ao criar diretórios ({}): {}", parent_dir.display(), e))?; } } fs::write(&path, &content) .await .map_err(|e| format!("Falha ao escrever arquivo ({}): {}", path, e)) } fn should_skip(name: &str) -> bool { name.starts_with('.') || name == "node_modules" || name == "target" || name == ".git" } fn read_dir_recursive(path: &Path) -> BoxRecursive<'_, Result, String>> { Box::pin(async move { let mut entries = fs::read_dir(path) .await .map_err(|e| format!("Falha ao ler diretório ({}): {}", path.display(), e))?; let mut file_entries: Vec = Vec::new(); let mut pending = Vec::new(); while let Some(entry) = entries .next_entry() .await .map_err(|e| format!("Falha ao ler entrada em ({}): {}", path.display(), e))? { let file_name = entry.file_name().to_string_lossy().to_string(); if should_skip(&file_name) { continue; } let metadata = entry .metadata() .await .map_err(|e| format!("Falha ao ler metadados ({}): {}", file_name, e))?; let entry_path = entry.path().to_string_lossy().to_string(); let is_dir = metadata.is_dir(); if is_dir { pending.push((file_name, entry_path, entry.path())); } else { file_entries.push(FileEntry { name: file_name, path: entry_path, is_dir, children: None, }); } } for (name, entry_path, path_buf) in pending { let children = read_dir_recursive(&path_buf).await?; file_entries.push(FileEntry { name, path: entry_path, is_dir: true, children: Some(children), }); } file_entries.sort_by(|a, b| { if a.is_dir != b.is_dir { b.is_dir.cmp(&a.is_dir) } else { a.name.cmp(&b.name) } }); Ok(file_entries) }) } #[tauri::command] pub async fn create_dir(path: String) -> Result<(), String> { fs::create_dir_all(&path) .await .map_err(|e| format!("Falha ao criar diretório ({}): {}", path, e)) } #[tauri::command] pub async fn open_dir(path: String) -> Result, String> { read_dir_recursive(Path::new(&path)).await }