feat(diff): compare directories and synchronize entries (#661)

Two folders can now be compared from the project view (Compare Directories with two folders selected, or Compare With… on one folder, also in Find Action). The result tree marks entries as only on left, only on right, contents differ or identical, with a name filter and a show-identical toggle; double-click opens the existing diff editor, and files or whole subdirectories can be copied to either side (overwrite and delete ask first, extra files in the target are kept). Comparison runs in the background with progress and cancel, honours the project's exclusions, and works for remote projects through the same file commands.

The comparison tree and diff preview are shared with the Git folder/revision comparison.

Verified on macOS (subdirectories, Chinese names, binary files, copy both ways, delete, cancel on large files); Windows and Linux not run.

Fixes #520
Цей коміт міститься в:
l0ng-ai authored and GitHub committed 2026-11-01 15:14:13 +08:00
1 джерело 482241ebb9
коміт 1716f3e062
23 files changed
+1552 -87

No files matched your search

+32
Переглянути файл
@@ -5,6 +5,38 @@ use ide_vfs::FileEntry;
use std::path::PathBuf;
use tauri::{State, Window};
#[tauri::command]
#[specta::specta]
pub async fn fs_entry_kind(state: State<'_, AppState>, path: PathBuf) -> IdeResult<ide_vfs::EntryKind> {
fs::entry_kind(&state.host, path).await
}
#[tauri::command]
#[specta::specta]
pub async fn fs_compare_directories(
window: Window,
state: State<'_, AppState>,
left: PathBuf,
right: PathBuf,
request: ide_core::RequestId,
on_progress: tauri::ipc::Channel<ide_vfs::DirectoryCompareProgress>,
) -> IdeResult<Vec<ide_vfs::DirectoryCompareEntry>> {
fs::compare_directories(&state.host, window.label(), left, right, request, super::sender(on_progress)).await
}
#[tauri::command]
#[specta::specta]
pub async fn fs_copy_merge(
window: Window,
state: State<'_, AppState>,
source_root: PathBuf,
destination_root: PathBuf,
path: PathBuf,
overwrite: bool,
) -> IdeResult<()> {
fs::copy_merge(&state.host, window.label(), source_root, destination_root, path, overwrite).await
}
#[tauri::command]
#[specta::specta]
pub fn fs_read_dir(window: Window, state: State<'_, AppState>, path: PathBuf) -> IdeResult<Vec<FileEntry>> {
+3
Переглянути файл
@@ -126,6 +126,7 @@ pub fn builder() -> tauri_specta::Builder<tauri::Wry> {
notebook::notebook_interrupt,
notebook::notebook_restart,
fs::fs_read_dir,
fs::fs_entry_kind,
bytes::fs_probe,
bytes::fs_read_range,
bytes::fs_read_image,
@@ -136,6 +137,8 @@ pub fn builder() -> tauri_specta::Builder<tauri::Wry> {
fs::fs_set_writable,
fs::fs_delete,
fs::fs_copy,
fs::fs_copy_merge,
fs::fs_compare_directories,
fs::fs_read_text,
clipboard::clipboard_file_list,
clipboard::clipboard_has_files,