159 lines
4.4 KiB
Rust
159 lines
4.4 KiB
Rust
use serde::Serialize;
|
|
use std::fs;
|
|
use std::path::Path;
|
|
|
|
#[derive(Serialize, Clone)]
|
|
struct FileEntry {
|
|
name: String,
|
|
path: String,
|
|
is_dir: bool,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
children: Option<Vec<FileEntry>>,
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn greet(name: &str) -> String {
|
|
format!("Hello, {}! You've been greeted from Rust!", name)
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn read_directory(dir_path: String) -> Result<Vec<FileEntry>, String> {
|
|
let path = Path::new(&dir_path);
|
|
if !path.is_dir() {
|
|
return Err(format!("路径不是目录: {}", dir_path));
|
|
}
|
|
read_dir_recursive(path).map_err(|e| e.to_string())
|
|
}
|
|
|
|
fn read_dir_recursive(dir: &Path) -> Result<Vec<FileEntry>, std::io::Error> {
|
|
let mut entries = Vec::new();
|
|
let read_dir = match fs::read_dir(dir) {
|
|
Ok(rd) => rd,
|
|
Err(_) => return Ok(entries),
|
|
};
|
|
|
|
for entry in read_dir.flatten() {
|
|
let path = entry.path();
|
|
let name = entry.file_name().to_string_lossy().to_string();
|
|
|
|
if name.starts_with('.') || name == "node_modules" || name == "target" {
|
|
continue;
|
|
}
|
|
|
|
let is_dir = path.is_dir();
|
|
let children = if is_dir {
|
|
Some(read_dir_recursive(&path)?)
|
|
} else {
|
|
None
|
|
};
|
|
|
|
if is_dir {
|
|
let child_count = children.as_ref().map_or(0, |c| c.len());
|
|
if child_count == 0 && !has_md_files(&path)? {
|
|
continue;
|
|
}
|
|
} else if !name.ends_with(".md") {
|
|
continue;
|
|
}
|
|
|
|
entries.push(FileEntry {
|
|
name,
|
|
path: path.to_string_lossy().to_string(),
|
|
is_dir,
|
|
children,
|
|
});
|
|
}
|
|
|
|
entries.sort_by(|a, b| {
|
|
if a.is_dir != b.is_dir {
|
|
b.is_dir.cmp(&a.is_dir)
|
|
} else {
|
|
a.name.to_lowercase().cmp(&b.name.to_lowercase())
|
|
}
|
|
});
|
|
|
|
Ok(entries)
|
|
}
|
|
|
|
fn has_md_files(dir: &Path) -> Result<bool, std::io::Error> {
|
|
for entry in fs::read_dir(dir)? {
|
|
let entry = entry?;
|
|
let name = entry.file_name().to_string_lossy().to_string();
|
|
if name.starts_with('.') {
|
|
continue;
|
|
}
|
|
if entry.path().is_dir() {
|
|
if has_md_files(&entry.path())? {
|
|
return Ok(true);
|
|
}
|
|
} else if name.ends_with(".md") {
|
|
return Ok(true);
|
|
}
|
|
}
|
|
Ok(false)
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn read_file_content(file_path: String) -> Result<String, String> {
|
|
fs::read_to_string(&file_path).map_err(|e| format!("读取文件失败: {}", e))
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn write_file_content(file_path: String, content: String) -> Result<(), String> {
|
|
fs::write(&file_path, &content).map_err(|e| format!("保存文件失败: {}", e))
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn create_file(file_path: String) -> Result<(), String> {
|
|
if Path::new(&file_path).exists() {
|
|
return Err("文件已存在".to_string());
|
|
}
|
|
if let Some(parent) = Path::new(&file_path).parent() {
|
|
fs::create_dir_all(parent).map_err(|e| format!("创建目录失败: {}", e))?;
|
|
}
|
|
fs::write(&file_path, "").map_err(|e| format!("创建文件失败: {}", e))
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn rename_file(old_path: String, new_path: String) -> Result<(), String> {
|
|
if Path::new(&new_path).exists() {
|
|
return Err("目标路径已存在".to_string());
|
|
}
|
|
fs::rename(&old_path, &new_path).map_err(|e| format!("重命名失败: {}", e))
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn delete_file(file_path: String) -> Result<(), String> {
|
|
let path = Path::new(&file_path);
|
|
if path.is_dir() {
|
|
fs::remove_dir_all(&file_path).map_err(|e| format!("删除目录失败: {}", e))
|
|
} else {
|
|
fs::remove_file(&file_path).map_err(|e| format!("删除文件失败: {}", e))
|
|
}
|
|
}
|
|
|
|
#[tauri::command]
|
|
fn file_exists(file_path: String) -> bool {
|
|
Path::new(&file_path).exists()
|
|
}
|
|
|
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
|
pub fn run() {
|
|
tauri::Builder::default()
|
|
.plugin(tauri_plugin_opener::init())
|
|
.plugin(tauri_plugin_fs::init())
|
|
.plugin(tauri_plugin_dialog::init())
|
|
.invoke_handler(tauri::generate_handler![
|
|
greet,
|
|
read_directory,
|
|
read_file_content,
|
|
write_file_content,
|
|
create_file,
|
|
rename_file,
|
|
delete_file,
|
|
file_exists
|
|
])
|
|
.run(tauri::generate_context!())
|
|
.expect("error while running tauri application");
|
|
}
|