feat: 建立 HoloLake 编号通信根与人格第零层合同
This commit is contained in:
parent
7a14c06e41
commit
64abf969bf
37 changed files with 3455 additions and 161 deletions
|
|
@ -137,7 +137,6 @@ enum ImportDisposition {
|
|||
Conflict,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_knowledge_snapshot(app: AppHandle) -> Result<KnowledgeSnapshot, String> {
|
||||
let roots = knowledge_roots(&app)?;
|
||||
tauri::async_runtime::spawn_blocking(move || snapshot_at(&roots.0, roots.1.as_deref()))
|
||||
|
|
@ -145,7 +144,6 @@ pub async fn get_knowledge_snapshot(app: AppHandle) -> Result<KnowledgeSnapshot,
|
|||
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_JOIN_FAILED: {error}"))?
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn read_knowledge_document(
|
||||
app: AppHandle,
|
||||
input: ReadKnowledgeDocumentInput,
|
||||
|
|
@ -158,7 +156,6 @@ pub async fn read_knowledge_document(
|
|||
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_JOIN_FAILED: {error}"))?
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn search_knowledge(
|
||||
app: AppHandle,
|
||||
input: SearchKnowledgeInput,
|
||||
|
|
@ -169,7 +166,6 @@ pub async fn search_knowledge(
|
|||
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_JOIN_FAILED: {error}"))?
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn save_knowledge_document(
|
||||
app: AppHandle,
|
||||
input: SaveKnowledgeDocumentInput,
|
||||
|
|
@ -200,7 +196,6 @@ pub struct ExportKnowledgeDocumentReceipt {
|
|||
pub bytes: u64,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn export_knowledge_document(
|
||||
app: AppHandle,
|
||||
input: ExportKnowledgeDocumentInput,
|
||||
|
|
@ -219,22 +214,50 @@ pub async fn export_knowledge_document(
|
|||
suggested = "知识页".to_string();
|
||||
}
|
||||
// Windows 保留设备名(CON/NUL/COM1…)不能直接当文件名,撞名就补个尾巴。
|
||||
if matches!(suggested.to_ascii_uppercase().as_str(),
|
||||
"CON" | "PRN" | "AUX" | "NUL"
|
||||
| "COM1" | "COM2" | "COM3" | "COM4" | "COM5" | "COM6" | "COM7" | "COM8" | "COM9"
|
||||
| "LPT1" | "LPT2" | "LPT3" | "LPT4" | "LPT5" | "LPT6" | "LPT7" | "LPT8" | "LPT9") {
|
||||
if matches!(
|
||||
suggested.to_ascii_uppercase().as_str(),
|
||||
"CON"
|
||||
| "PRN"
|
||||
| "AUX"
|
||||
| "NUL"
|
||||
| "COM1"
|
||||
| "COM2"
|
||||
| "COM3"
|
||||
| "COM4"
|
||||
| "COM5"
|
||||
| "COM6"
|
||||
| "COM7"
|
||||
| "COM8"
|
||||
| "COM9"
|
||||
| "LPT1"
|
||||
| "LPT2"
|
||||
| "LPT3"
|
||||
| "LPT4"
|
||||
| "LPT5"
|
||||
| "LPT6"
|
||||
| "LPT7"
|
||||
| "LPT8"
|
||||
| "LPT9"
|
||||
) {
|
||||
suggested.push_str("·页");
|
||||
}
|
||||
suggested.push('.');
|
||||
suggested.push_str(extension);
|
||||
let filter_label = if extension == "html" { "网页文件" } else { "Markdown" };
|
||||
let filter_label = if extension == "html" {
|
||||
"网页文件"
|
||||
} else {
|
||||
"Markdown"
|
||||
};
|
||||
let (sender, receiver) = std::sync::mpsc::channel::<Option<PathBuf>>();
|
||||
app.dialog()
|
||||
.file()
|
||||
.set_file_name(&suggested)
|
||||
.add_filter(filter_label, &[extension])
|
||||
.save_file(move |selection| {
|
||||
let picked = selection.as_ref().and_then(|path| path.as_path()).map(|path| path.to_path_buf());
|
||||
let picked = selection
|
||||
.as_ref()
|
||||
.and_then(|path| path.as_path())
|
||||
.map(|path| path.to_path_buf());
|
||||
let _ = sender.send(picked);
|
||||
});
|
||||
let picked = tauri::async_runtime::spawn_blocking(move || receiver.recv().ok().flatten())
|
||||
|
|
@ -287,7 +310,10 @@ async fn confirm_destructive(app: &AppHandle, message: String) -> Result<bool, S
|
|||
.message(message)
|
||||
.title("删除确认")
|
||||
.kind(MessageDialogKind::Warning)
|
||||
.buttons(MessageDialogButtons::OkCancelCustom("确认删除".to_string(), "取消".to_string()))
|
||||
.buttons(MessageDialogButtons::OkCancelCustom(
|
||||
"确认删除".to_string(),
|
||||
"取消".to_string(),
|
||||
))
|
||||
.blocking_show()
|
||||
})
|
||||
.await
|
||||
|
|
@ -301,14 +327,17 @@ pub struct CreateKnowledgeDocumentInput {
|
|||
pub title: String,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn create_knowledge_document(
|
||||
app: AppHandle,
|
||||
input: CreateKnowledgeDocumentInput,
|
||||
) -> Result<KnowledgeDeleteReceipt, String> {
|
||||
// 新建空白页:标题撞名自动补序号,落进本机库并进 Git 托管。
|
||||
let roots = knowledge_roots(&app)?;
|
||||
let base = if input.title.trim().is_empty() { "未命名页面".to_string() } else { input.title.trim().to_string() };
|
||||
let base = if input.title.trim().is_empty() {
|
||||
"未命名页面".to_string()
|
||||
} else {
|
||||
input.title.trim().to_string()
|
||||
};
|
||||
let docs = roots.0.join("docs");
|
||||
let mut name = base.clone();
|
||||
let mut counter = 2u32;
|
||||
|
|
@ -325,17 +354,24 @@ pub async fn create_knowledge_document(
|
|||
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_CREATE_FAILED: {error}"))?;
|
||||
file.write_all(body.as_bytes())
|
||||
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_CREATE_FAILED: {error}"))?;
|
||||
file.sync_all().map_err(|error| format!("HOLOLAKE_KNOWLEDGE_CREATE_FAILED: {error}"))?;
|
||||
file.sync_all()
|
||||
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_CREATE_FAILED: {error}"))?;
|
||||
git(&roots.0, &["add", "--", &format!("docs/{name}.md")], "ADD")?;
|
||||
git(&roots.0, &["commit", "-m", &format!("新建页面:{name}")], "COMMIT")?;
|
||||
git(
|
||||
&roots.0,
|
||||
&["commit", "-m", &format!("新建页面:{name}")],
|
||||
"COMMIT",
|
||||
)?;
|
||||
Ok::<(), String>(())
|
||||
})
|
||||
.await
|
||||
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_CREATE_JOIN_FAILED: {error}"))??;
|
||||
Ok(KnowledgeDeleteReceipt { removed: format!("{receipt_name}.md"), pages: 1 })
|
||||
Ok(KnowledgeDeleteReceipt {
|
||||
removed: format!("{receipt_name}.md"),
|
||||
pages: 1,
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn delete_knowledge_document(
|
||||
app: AppHandle,
|
||||
input: DeleteKnowledgeDocumentInput,
|
||||
|
|
@ -354,11 +390,15 @@ pub async fn delete_knowledge_document(
|
|||
.and_then(OsStr::to_str)
|
||||
.unwrap_or("这一页")
|
||||
.to_string();
|
||||
if !confirm_destructive(&app, format!("把页面「{title}」移到回收站?随时可以找回。")).await? {
|
||||
if !confirm_destructive(&app, format!("把页面「{title}」移到回收站?随时可以找回。")).await?
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
move_to_trash(&roots.0, &target)?;
|
||||
Ok(Some(KnowledgeDeleteReceipt { removed: input.path, pages: 1 }))
|
||||
Ok(Some(KnowledgeDeleteReceipt {
|
||||
removed: input.path,
|
||||
pages: 1,
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
|
|
@ -367,7 +407,6 @@ pub struct DeleteKnowledgeFolderInput {
|
|||
pub folder: String,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn delete_knowledge_folder(
|
||||
app: AppHandle,
|
||||
input: DeleteKnowledgeFolderInput,
|
||||
|
|
@ -391,23 +430,31 @@ pub async fn delete_knowledge_folder(
|
|||
.count()
|
||||
})
|
||||
.unwrap_or(0);
|
||||
if !confirm_destructive(&app, format!("把文件夹「{name}」和里面全部 {pages} 个页面移到回收站?随时可以找回。")).await? {
|
||||
if !confirm_destructive(
|
||||
&app,
|
||||
format!("把文件夹「{name}」和里面全部 {pages} 个页面移到回收站?随时可以找回。"),
|
||||
)
|
||||
.await?
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
move_to_trash(&roots.0, &target)?;
|
||||
Ok(Some(KnowledgeDeleteReceipt { removed: input.folder, pages }))
|
||||
Ok(Some(KnowledgeDeleteReceipt {
|
||||
removed: input.folder,
|
||||
pages,
|
||||
}))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn print_knowledge_document(app: AppHandle) -> Result<(), String> {
|
||||
// PDF 走系统打印通道:打印框里选"存储为 PDF"即得 PDF 文件。
|
||||
let window = app
|
||||
.get_webview_window("main")
|
||||
.ok_or_else(|| "HOLOLAKE_PRINT_WINDOW_NOT_FOUND".to_string())?;
|
||||
window.print().map_err(|error| format!("HOLOLAKE_PRINT_FAILED: {error}"))
|
||||
window
|
||||
.print()
|
||||
.map_err(|error| format!("HOLOLAKE_PRINT_FAILED: {error}"))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn select_and_import_knowledge_folder(
|
||||
app: AppHandle,
|
||||
) -> Result<Option<KnowledgeImportResult>, String> {
|
||||
|
|
@ -476,7 +523,9 @@ fn move_to_trash(root: &Path, target: &Path) -> Result<PathBuf, String> {
|
|||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.map(|duration| duration.as_secs())
|
||||
.unwrap_or(0);
|
||||
let destination = root.join(".trash").join(format!("{}-{stamp}", relative.display()));
|
||||
let destination = root
|
||||
.join(".trash")
|
||||
.join(format!("{}-{stamp}", relative.display()));
|
||||
if let Some(parent) = destination.parent() {
|
||||
fs::create_dir_all(parent)
|
||||
.map_err(|error| format!("HOLOLAKE_KNOWLEDGE_DELETE_FAILED: {error}"))?;
|
||||
|
|
@ -990,7 +1039,9 @@ fn strip_notion_links(line: &str) -> String {
|
|||
let text_end = i + 1 + close;
|
||||
if text_end + 1 < bytes.len() && bytes[text_end + 1] == '(' {
|
||||
if let Some(paren_end) = bytes[text_end + 2..].iter().position(|c| *c == ')') {
|
||||
let href: String = bytes[text_end + 2..text_end + 2 + paren_end].iter().collect();
|
||||
let href: String = bytes[text_end + 2..text_end + 2 + paren_end]
|
||||
.iter()
|
||||
.collect();
|
||||
if href.contains("notion.so") || href.contains("notion.site") {
|
||||
out.extend(bytes[i + 1..text_end].iter());
|
||||
i = text_end + 2 + paren_end + 1;
|
||||
|
|
|
|||
Loading…
Reference in a new issue