aboutsummaryrefslogtreecommitdiff
path: root/src-tauri/src/commands.rs
blob: eb0a28f6422236680b4081d12f2da67d3ddce7d5 (plain)
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
}