Implement copy paste for ProjectPanel

This commit is contained in:
Antonio Scandurra
2022-05-30 14:52:34 +02:00
parent 37a0c7f046
commit 3336bc6ab3
7 changed files with 253 additions and 55 deletions
+70
View File
@@ -15,6 +15,7 @@ use text::Rope;
pub trait Fs: Send + Sync {
async fn create_dir(&self, path: &Path) -> Result<()>;
async fn create_file(&self, path: &Path, options: CreateOptions) -> Result<()>;
async fn copy(&self, source: &Path, target: &Path, options: CopyOptions) -> Result<()>;
async fn rename(&self, source: &Path, target: &Path, options: RenameOptions) -> Result<()>;
async fn remove_dir(&self, path: &Path, options: RemoveOptions) -> Result<()>;
async fn remove_file(&self, path: &Path, options: RemoveOptions) -> Result<()>;
@@ -44,6 +45,12 @@ pub struct CreateOptions {
pub ignore_if_exists: bool,
}
#[derive(Copy, Clone, Default)]
pub struct CopyOptions {
pub overwrite: bool,
pub ignore_if_exists: bool,
}
#[derive(Copy, Clone, Default)]
pub struct RenameOptions {
pub overwrite: bool,
@@ -84,6 +91,35 @@ impl Fs for RealFs {
Ok(())
}
async fn copy(&self, source: &Path, target: &Path, options: CopyOptions) -> Result<()> {
if !options.overwrite && smol::fs::metadata(target).await.is_ok() {
if options.ignore_if_exists {
return Ok(());
} else {
return Err(anyhow!("{target:?} already exists"));
}
}
let metadata = smol::fs::metadata(source).await?;
let _ = smol::fs::remove_dir_all(target).await;
if metadata.is_dir() {
self.create_dir(target).await?;
let mut children = smol::fs::read_dir(source).await?;
while let Some(child) = children.next().await {
if let Ok(child) = child {
let child_source_path = child.path();
let child_target_path = target.join(child.file_name());
self.copy(&child_source_path, &child_target_path, options)
.await?;
}
}
} else {
smol::fs::copy(source, target).await?;
}
Ok(())
}
async fn rename(&self, source: &Path, target: &Path, options: RenameOptions) -> Result<()> {
if !options.overwrite && smol::fs::metadata(target).await.is_ok() {
if options.ignore_if_exists {
@@ -511,6 +547,40 @@ impl Fs for FakeFs {
Ok(())
}
async fn copy(&self, source: &Path, target: &Path, options: CopyOptions) -> Result<()> {
let source = normalize_path(source);
let target = normalize_path(target);
let mut state = self.state.lock().await;
state.validate_path(&source)?;
state.validate_path(&target)?;
if !options.overwrite && state.entries.contains_key(&target) {
if options.ignore_if_exists {
return Ok(());
} else {
return Err(anyhow!("{target:?} already exists"));
}
}
let mut new_entries = Vec::new();
for (path, entry) in &state.entries {
if let Ok(relative_path) = path.strip_prefix(&source) {
new_entries.push((relative_path.to_path_buf(), entry.clone()));
}
}
let mut events = Vec::new();
for (relative_path, entry) in new_entries {
let new_path = normalize_path(&target.join(relative_path));
events.push(new_path.clone());
state.entries.insert(new_path, entry);
}
state.emit_event(&events).await;
Ok(())
}
async fn remove_dir(&self, dir_path: &Path, options: RemoveOptions) -> Result<()> {
let dir_path = normalize_path(dir_path);
let mut state = self.state.lock().await;