添加显示图片和视频功能
This commit is contained in:
@@ -36,5 +36,6 @@
|
|||||||
"topic_20260707-092315_b8c3939bfc696802": "auto",
|
"topic_20260707-092315_b8c3939bfc696802": "auto",
|
||||||
"topic_20260707-092711_af706c3fcc7e435e": "auto",
|
"topic_20260707-092711_af706c3fcc7e435e": "auto",
|
||||||
"topic_20260707-095503_bf879b65e4666516": "auto",
|
"topic_20260707-095503_bf879b65e4666516": "auto",
|
||||||
"topic_20260708-020616_9ab54d98daf65053": "auto"
|
"topic_20260708-020616_9ab54d98daf65053": "auto",
|
||||||
|
"topic_20260708-093419_71d1fea2e4b5a40f": "auto"
|
||||||
}
|
}
|
||||||
@@ -36,5 +36,6 @@
|
|||||||
"topic_20260707-092315_b8c3939bfc696802": "当我点击目录树切换显示文件的时候,右…",
|
"topic_20260707-092315_b8c3939bfc696802": "当我点击目录树切换显示文件的时候,右…",
|
||||||
"topic_20260707-092711_af706c3fcc7e435e": "帮我检查一下app.vue里的too…",
|
"topic_20260707-092711_af706c3fcc7e435e": "帮我检查一下app.vue里的too…",
|
||||||
"topic_20260707-095503_bf879b65e4666516": "帮我移除markdownEditor…",
|
"topic_20260707-095503_bf879b65e4666516": "帮我移除markdownEditor…",
|
||||||
"topic_20260708-020616_9ab54d98daf65053": "帮我分析一下现在的markdownE…"
|
"topic_20260708-020616_9ab54d98daf65053": "帮我分析一下现在的markdownE…",
|
||||||
|
"topic_20260708-093419_71d1fea2e4b5a40f": "新的会话"
|
||||||
}
|
}
|
||||||
78
src-tauri/Cargo.lock
generated
78
src-tauri/Cargo.lock
generated
@@ -1011,6 +1011,15 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fsevent-sys"
|
||||||
|
version = "4.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.32"
|
version = "0.3.32"
|
||||||
@@ -1695,6 +1704,26 @@ dependencies = [
|
|||||||
"cfb",
|
"cfb",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inotify"
|
||||||
|
version = "0.11.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd854a95a4ac672fed8c054136039fd32c22cf039ff09ead7280afe920486483"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.13.0",
|
||||||
|
"inotify-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inotify-sys"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c033f80b2c113cdf91ab7a33faa9cbc014726dcad99880c8609af2a370edf37d"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.12.0"
|
version = "2.12.0"
|
||||||
@@ -1837,6 +1866,26 @@ dependencies = [
|
|||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kqueue"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "273c0752728918e0ac4976f2b275b6fefb9ecd400585dec929419f3844cd87b5"
|
||||||
|
dependencies = [
|
||||||
|
"kqueue-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "kqueue-sys"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "07293a4e297ac234359b510362495713f75ea345d5307140414f20c69ffeb087"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.13.0",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libappindicator"
|
name = "libappindicator"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@@ -1971,6 +2020,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda"
|
checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
|
"log",
|
||||||
"wasi",
|
"wasi",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
@@ -2026,6 +2076,33 @@ version = "1.0.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "notify"
|
||||||
|
version = "8.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.13.0",
|
||||||
|
"fsevent-sys",
|
||||||
|
"inotify",
|
||||||
|
"kqueue",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"mio",
|
||||||
|
"notify-types",
|
||||||
|
"walkdir",
|
||||||
|
"windows-sys 0.60.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "notify-types"
|
||||||
|
version = "2.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.13.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-conv"
|
name = "num-conv"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@@ -4853,6 +4930,7 @@ dependencies = [
|
|||||||
name = "yurou"
|
name = "yurou"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"notify",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tauri",
|
"tauri",
|
||||||
|
|||||||
@@ -24,4 +24,5 @@ tauri-plugin-opener = "2"
|
|||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
time = ">=0.3.0, <0.3.47"
|
time = ">=0.3.0, <0.3.47"
|
||||||
|
notify = "8.2.0"
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
|
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
|
||||||
|
use notify::{RecursiveMode, Watcher};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::Mutex;
|
||||||
use tauri::menu::{MenuBuilder, MenuItemBuilder, SubmenuBuilder};
|
use tauri::menu::{MenuBuilder, MenuItemBuilder, SubmenuBuilder};
|
||||||
use tauri::{Emitter, Manager};
|
use tauri::{Emitter, Manager};
|
||||||
use tauri_plugin_dialog::DialogExt;
|
use tauri_plugin_dialog::DialogExt;
|
||||||
@@ -11,6 +14,24 @@ struct DirEntry {
|
|||||||
is_dir: bool,
|
is_dir: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct WorkspaceWatcherState {
|
||||||
|
watcher: Mutex<Option<notify::RecommendedWatcher>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, serde::Serialize)]
|
||||||
|
struct WorkspaceChangedPayload {
|
||||||
|
root: String,
|
||||||
|
paths: Vec<String>,
|
||||||
|
kind: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, serde::Serialize)]
|
||||||
|
struct WorkspaceWatchErrorPayload {
|
||||||
|
root: String,
|
||||||
|
message: String,
|
||||||
|
}
|
||||||
|
|
||||||
fn is_hidden_entry(entry: &fs::DirEntry) -> bool {
|
fn is_hidden_entry(entry: &fs::DirEntry) -> bool {
|
||||||
let name = entry.file_name();
|
let name = entry.file_name();
|
||||||
let is_dot_hidden = name.to_string_lossy().starts_with('.');
|
let is_dot_hidden = name.to_string_lossy().starts_with('.');
|
||||||
@@ -94,6 +115,73 @@ fn write_file(path: String, content: String) -> Result<(), String> {
|
|||||||
fs::write(&path, &content).map_err(|e| format!("无法保存文件: {}", e))
|
fs::write(&path, &content).map_err(|e| format!("无法保存文件: {}", e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
fn watch_workspace(
|
||||||
|
app: tauri::AppHandle,
|
||||||
|
state: tauri::State<'_, WorkspaceWatcherState>,
|
||||||
|
path: String,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let watch_path = PathBuf::from(&path);
|
||||||
|
if !watch_path.is_dir() {
|
||||||
|
return Err("工作目录不存在或不是文件夹".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let root = watch_path.to_string_lossy().to_string();
|
||||||
|
let event_root = root.clone();
|
||||||
|
let error_root = root.clone();
|
||||||
|
let app_handle = app.clone();
|
||||||
|
let mut watcher =
|
||||||
|
notify::recommended_watcher(move |result: notify::Result<notify::Event>| match result {
|
||||||
|
Ok(event) => {
|
||||||
|
if event.kind.is_access() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let payload = WorkspaceChangedPayload {
|
||||||
|
root: event_root.clone(),
|
||||||
|
paths: event
|
||||||
|
.paths
|
||||||
|
.iter()
|
||||||
|
.map(|path| path.to_string_lossy().to_string())
|
||||||
|
.collect(),
|
||||||
|
kind: format!("{:?}", event.kind),
|
||||||
|
};
|
||||||
|
let _ = app_handle.emit("workspace-changed", payload);
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
let _ = app_handle.emit(
|
||||||
|
"workspace-watch-error",
|
||||||
|
WorkspaceWatchErrorPayload {
|
||||||
|
root: error_root.clone(),
|
||||||
|
message: error.to_string(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map_err(|e| format!("无法监听工作目录: {}", e))?;
|
||||||
|
|
||||||
|
watcher
|
||||||
|
.watch(&watch_path, RecursiveMode::Recursive)
|
||||||
|
.map_err(|e| format!("无法监听工作目录: {}", e))?;
|
||||||
|
|
||||||
|
let mut current = state
|
||||||
|
.watcher
|
||||||
|
.lock()
|
||||||
|
.map_err(|_| "无法更新工作目录监听状态".to_string())?;
|
||||||
|
*current = Some(watcher);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
fn unwatch_workspace(state: tauri::State<'_, WorkspaceWatcherState>) -> Result<(), String> {
|
||||||
|
let mut current = state
|
||||||
|
.watcher
|
||||||
|
.lock()
|
||||||
|
.map_err(|_| "无法更新工作目录监听状态".to_string())?;
|
||||||
|
*current = None;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
fn pick_save_file(app: tauri::AppHandle) -> Option<String> {
|
fn pick_save_file(app: tauri::AppHandle) -> Option<String> {
|
||||||
app.dialog()
|
app.dialog()
|
||||||
@@ -112,12 +200,15 @@ pub fn run() {
|
|||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.plugin(tauri_plugin_opener::init())
|
.plugin(tauri_plugin_opener::init())
|
||||||
.plugin(tauri_plugin_dialog::init())
|
.plugin(tauri_plugin_dialog::init())
|
||||||
|
.manage(WorkspaceWatcherState::default())
|
||||||
.invoke_handler(tauri::generate_handler![
|
.invoke_handler(tauri::generate_handler![
|
||||||
greet,
|
greet,
|
||||||
pick_folder,
|
pick_folder,
|
||||||
read_dir,
|
read_dir,
|
||||||
read_file,
|
read_file,
|
||||||
write_file,
|
write_file,
|
||||||
|
watch_workspace,
|
||||||
|
unwatch_workspace,
|
||||||
pick_save_file
|
pick_save_file
|
||||||
])
|
])
|
||||||
.setup(|app| {
|
.setup(|app| {
|
||||||
|
|||||||
131
src/App.vue
131
src/App.vue
@@ -93,6 +93,17 @@ interface WorkspaceEntry {
|
|||||||
path: string;
|
path: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface WorkspaceChangedPayload {
|
||||||
|
root: string;
|
||||||
|
paths: string[];
|
||||||
|
kind: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WorkspaceWatchErrorPayload {
|
||||||
|
root: string;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
const folderPath = ref("");
|
const folderPath = ref("");
|
||||||
const dirEntries = ref<DirEntry[]>([]);
|
const dirEntries = ref<DirEntry[]>([]);
|
||||||
const LAST_WORKSPACE_PATH_KEY = "yurou:last-workspace-path";
|
const LAST_WORKSPACE_PATH_KEY = "yurou:last-workspace-path";
|
||||||
@@ -100,6 +111,10 @@ const RECENT_WORKSPACES_KEY = "yurou:recent-workspaces";
|
|||||||
const MAX_RECENT_WORKSPACES = 12;
|
const MAX_RECENT_WORKSPACES = 12;
|
||||||
const recentWorkspaces = ref<WorkspaceEntry[]>(loadRecentWorkspaces());
|
const recentWorkspaces = ref<WorkspaceEntry[]>(loadRecentWorkspaces());
|
||||||
const editorResetKey = ref(0);
|
const editorResetKey = ref(0);
|
||||||
|
const WORKSPACE_REFRESH_DELAY_MS = 140;
|
||||||
|
let workspaceRefreshTimer: ReturnType<typeof setTimeout> | null = null;
|
||||||
|
let workspaceRefreshInFlight = false;
|
||||||
|
let workspaceRefreshQueued = false;
|
||||||
|
|
||||||
// ---- editor zoom (Ctrl+scroll) ----
|
// ---- editor zoom (Ctrl+scroll) ----
|
||||||
const ZOOM_MIN = 0.7;
|
const ZOOM_MIN = 0.7;
|
||||||
@@ -552,24 +567,49 @@ async function saveCurrentWorkspaceDocumentBeforeSwitch() {
|
|||||||
return doSave(contentToSave);
|
return doSave(contentToSave);
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetWorkspaceAndEditorState() {
|
function resetWorkspaceAndEditorState(options: { stopWatcher?: boolean } = {}) {
|
||||||
|
if (options.stopWatcher !== false) {
|
||||||
|
void stopWorkspaceWatcher();
|
||||||
|
} else {
|
||||||
|
clearPendingWorkspaceRefresh();
|
||||||
|
}
|
||||||
folderPath.value = "";
|
folderPath.value = "";
|
||||||
dirEntries.value = [];
|
dirEntries.value = [];
|
||||||
resetMarkdownEditorState();
|
resetMarkdownEditorState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function startWorkspaceWatcher(path: string) {
|
||||||
|
if (!isTauri()) return;
|
||||||
|
try {
|
||||||
|
await invoke("watch_workspace", {path});
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to watch workspace:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function stopWorkspaceWatcher() {
|
||||||
|
clearPendingWorkspaceRefresh();
|
||||||
|
if (!isTauri()) return;
|
||||||
|
try {
|
||||||
|
await invoke("unwatch_workspace");
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to stop watching workspace:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function switchWorkspace(path: string, options: { persist?: boolean; resetEditor?: boolean } = {}) {
|
async function switchWorkspace(path: string, options: { persist?: boolean; resetEditor?: boolean } = {}) {
|
||||||
const normalized = normalizeWorkspacePath(path);
|
const normalized = normalizeWorkspacePath(path);
|
||||||
|
|
||||||
if (options.resetEditor !== false) {
|
if (options.resetEditor !== false) {
|
||||||
const saved = await saveCurrentWorkspaceDocumentBeforeSwitch();
|
const saved = await saveCurrentWorkspaceDocumentBeforeSwitch();
|
||||||
if (!saved) return false;
|
if (!saved) return false;
|
||||||
resetWorkspaceAndEditorState();
|
resetWorkspaceAndEditorState({stopWatcher: false});
|
||||||
}
|
}
|
||||||
|
|
||||||
const loaded = await loadDir(normalized);
|
const loaded = await loadDir(normalized);
|
||||||
|
|
||||||
if (!loaded) {
|
if (!loaded) {
|
||||||
|
await stopWorkspaceWatcher();
|
||||||
forgetWorkspace(normalized);
|
forgetWorkspace(normalized);
|
||||||
|
|
||||||
const lastWorkspacePath = getLastWorkspacePath();
|
const lastWorkspacePath = getLastWorkspacePath();
|
||||||
@@ -580,6 +620,7 @@ async function switchWorkspace(path: string, options: { persist?: boolean; reset
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void startWorkspaceWatcher(normalized);
|
||||||
rememberWorkspace(normalized);
|
rememberWorkspace(normalized);
|
||||||
|
|
||||||
if (options.persist !== false) {
|
if (options.persist !== false) {
|
||||||
@@ -680,6 +721,79 @@ function findEntry(entries: DirEntry[], path: string): DirEntry | null {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function mergeLoadedDirectoryEntries(freshEntries: DirEntry[], currentEntries: DirEntry[]): Promise<DirEntry[]> {
|
||||||
|
const currentByPath = new Map(
|
||||||
|
currentEntries.map((entry) => [getWorkspaceIdentity(entry.path), entry]),
|
||||||
|
);
|
||||||
|
|
||||||
|
return Promise.all(
|
||||||
|
freshEntries.map(async (freshEntry) => {
|
||||||
|
const currentEntry = currentByPath.get(getWorkspaceIdentity(freshEntry.path));
|
||||||
|
if (!freshEntry.is_dir || currentEntry?.children === undefined) {
|
||||||
|
return freshEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const children = await invoke<DirEntry[]>("read_dir", {path: freshEntry.path});
|
||||||
|
freshEntry.children = await mergeLoadedDirectoryEntries(children, currentEntry.children);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to refresh subdirectory:", e);
|
||||||
|
freshEntry.children = currentEntry.children;
|
||||||
|
}
|
||||||
|
|
||||||
|
return freshEntry;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearPendingWorkspaceRefresh() {
|
||||||
|
if (workspaceRefreshTimer) {
|
||||||
|
clearTimeout(workspaceRefreshTimer);
|
||||||
|
workspaceRefreshTimer = null;
|
||||||
|
}
|
||||||
|
workspaceRefreshQueued = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleWorkspaceRefresh(root = folderPath.value) {
|
||||||
|
const expectedRoot = normalizeWorkspacePath(root);
|
||||||
|
if (!expectedRoot) return;
|
||||||
|
|
||||||
|
if (workspaceRefreshTimer) {
|
||||||
|
clearTimeout(workspaceRefreshTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
workspaceRefreshTimer = setTimeout(() => {
|
||||||
|
workspaceRefreshTimer = null;
|
||||||
|
void refreshWorkspaceTree(expectedRoot);
|
||||||
|
}, WORKSPACE_REFRESH_DELAY_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function refreshWorkspaceTree(expectedRoot = folderPath.value) {
|
||||||
|
const normalizedRoot = normalizeWorkspacePath(expectedRoot);
|
||||||
|
if (!normalizedRoot || !folderPath.value) return;
|
||||||
|
if (getWorkspaceIdentity(folderPath.value) !== getWorkspaceIdentity(normalizedRoot)) return;
|
||||||
|
|
||||||
|
if (workspaceRefreshInFlight) {
|
||||||
|
workspaceRefreshQueued = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
workspaceRefreshInFlight = true;
|
||||||
|
try {
|
||||||
|
const entries = await invoke<DirEntry[]>("read_dir", {path: normalizedRoot});
|
||||||
|
if (!folderPath.value || getWorkspaceIdentity(folderPath.value) !== getWorkspaceIdentity(normalizedRoot)) return;
|
||||||
|
dirEntries.value = await mergeLoadedDirectoryEntries(entries, dirEntries.value);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to refresh workspace:", e);
|
||||||
|
} finally {
|
||||||
|
workspaceRefreshInFlight = false;
|
||||||
|
if (workspaceRefreshQueued) {
|
||||||
|
workspaceRefreshQueued = false;
|
||||||
|
scheduleWorkspaceRefresh(normalizedRoot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function onToggleFolder(path: string) {
|
async function onToggleFolder(path: string) {
|
||||||
const entry = findEntry(dirEntries.value, path);
|
const entry = findEntry(dirEntries.value, path);
|
||||||
if (!entry || entry.children !== undefined) return;
|
if (!entry || entry.children !== undefined) return;
|
||||||
@@ -793,6 +907,19 @@ registerTauriListener<string>("folder-opened", (event) => {
|
|||||||
void switchWorkspace(event.payload);
|
void switchWorkspace(event.payload);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
registerTauriListener<WorkspaceChangedPayload>("workspace-changed", (event) => {
|
||||||
|
if (!folderPath.value) return;
|
||||||
|
if (getWorkspaceIdentity(event.payload.root) !== getWorkspaceIdentity(folderPath.value)) return;
|
||||||
|
scheduleWorkspaceRefresh(event.payload.root);
|
||||||
|
});
|
||||||
|
|
||||||
|
registerTauriListener<WorkspaceWatchErrorPayload>("workspace-watch-error", (event) => {
|
||||||
|
if (!folderPath.value) return;
|
||||||
|
if (getWorkspaceIdentity(event.payload.root) !== getWorkspaceIdentity(folderPath.value)) return;
|
||||||
|
console.error("Workspace watcher error:", event.payload.message);
|
||||||
|
scheduleWorkspaceRefresh(event.payload.root);
|
||||||
|
});
|
||||||
|
|
||||||
registerTauriListener("menu-save", () => {
|
registerTauriListener("menu-save", () => {
|
||||||
doSave();
|
doSave();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user