1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
use std::path::Path;
use std::pin::Pin;
use std::future::Future;
use serde::Serialize;
use tokio::fs;
type BoxRecursive<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
#[derive(Debug, Serialize)]
pub struct FileEntry {
pub name: String,
pub path: String,
pub is_dir: bool,
pub children: Option<Vec<FileEntry>>,
}
#[tauri::command]
pub async fn read_file(path: String) -> Result<String, String> {
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<Vec<FileEntry>, 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<FileEntry> = 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<Vec<FileEntry>, String> {
read_dir_recursive(Path::new(&path)).await
}
|