diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 0ac303f63451..8656ec0727e5 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -64,8 +64,19 @@ pub enum Mode { #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Serialize, serde::Deserialize)] #[serde(rename_all = "kebab-case", deny_unknown_fields)] -pub enum BackupStrategy { +pub struct BackupConfig { + kind: BackupConfigKind, +} +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Serialize, serde::Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +pub enum BackupConfigKind { #[default] + Auto, + Copy, + None, +} +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum BackupKind { Move, Copy, None, @@ -927,7 +938,7 @@ impl Document { let encoding_with_bom_info = (self.encoding, self.has_bom); let last_saved_time = self.last_saved_time; - let backup_strategy_config = self.config.load().backup_strategy; + let backup_config_kind = self.config.load().backup.kind; // We encode the file according to the `Document`'s encoding. let future = async move { use tokio::fs; @@ -971,19 +982,26 @@ impl Document { )); } - let backup_strategy = { - // Assume it is a hardlink to prevent data loss if the metadata cant be read (e.g. on certain Windows configurations) - let is_hardlink = helix_stdx::faccess::hardlink_count(&write_path).unwrap_or(2) > 1; - - if is_hardlink { - BackupStrategy::Copy - } else { - backup_strategy_config + let backup_kind = { + match backup_config_kind { + BackupConfigKind::Copy => BackupKind::Copy, + BackupConfigKind::None => BackupKind::None, + BackupConfigKind::Auto => { + // Assume it is a hardlink to prevent data loss if the metadata cant be read (e.g. on certain Windows configurations) + let is_hardlink = + helix_stdx::faccess::hardlink_count(&write_path).unwrap_or(2) > 1; + + if is_hardlink { + BackupKind::Copy + } else { + BackupKind::Move + } + } } }; - let backup = match backup_strategy { - BackupStrategy::Move | BackupStrategy::Copy if path.exists() => { + let backup = match backup_kind { + BackupKind::Copy | BackupKind::Move if path.exists() => { let path_ = write_path.clone(); // hacks: we use tempfile to handle the complex task of creating // non clobbered temporary path for us we don't want @@ -995,14 +1013,14 @@ impl Document { .prefix(path_.file_name()?) .suffix(".bck") .make_in(path_.parent()?, |backup| { - match backup_strategy { - BackupStrategy::Copy => { + match backup_kind { + BackupKind::Copy => { std::fs::copy(&path_, backup)?; } - BackupStrategy::Move => { + BackupKind::Move => { std::fs::rename(&path_, backup)?; } - BackupStrategy::None => unreachable!(), + BackupKind::None => unreachable!(), } Ok(()) }) @@ -1031,31 +1049,36 @@ impl Document { .and_then(|metadata| metadata.modified()) .unwrap_or_else(|_| SystemTime::now()); - if let Err(err) = write_result { + if let Err(write_err) = write_result { if let Some(backup) = backup { - match backup_strategy { - BackupStrategy::Copy => { + match backup_kind { + BackupKind::Copy => { // Restore backup - if let Err(e) = tokio::fs::copy(&backup, &write_path).await { - log::error!("Failed to restore backup on write failure: {e}") + if let Err(restore_err) = tokio::fs::copy(&backup, &write_path).await { + log::error!( + "Failed to restore backup on write failure: {restore_err}" + ) } } - BackupStrategy::Move => { + BackupKind::Move => { // restore backup - if let Err(e) = tokio::fs::rename(&backup, &write_path).await { - log::error!("Failed to restore backup on write failure: {e}"); + if let Err(restore_err) = tokio::fs::rename(&backup, &write_path).await + { + log::error!( + "Failed to restore backup on write failure: {restore_err}" + ); } } - BackupStrategy::None => unreachable!(), + BackupKind::None => unreachable!(), } } else { log::error!( - "Failed to restore backup on write failure (backup doesn't exist) for write error: {err}" + "Failed to restore backup on write failure (backup doesn't exist) for write error: {write_err}" ); } } else if let Some(backup) = backup { // backup exists & successfully saved. delete backup - if backup_strategy == BackupStrategy::Move { + if backup_kind == BackupKind::Move { // the file is newly created one, therefore the metadata must be copied let backup = backup.clone(); let _ = tokio::task::spawn_blocking(move || { diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 589ebd5f6eaa..791efc2d8319 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -2,8 +2,8 @@ use crate::{ annotations::diagnostics::{DiagnosticFilter, InlineDiagnosticsConfig}, clipboard::ClipboardProvider, document::{ - BackupStrategy, DocumentOpenError, DocumentSavedEventFuture, DocumentSavedEventResult, - Mode, SavePoint, + BackupConfig, BackupConfigKind, DocumentOpenError, DocumentSavedEventFuture, + DocumentSavedEventResult, Mode, SavePoint, }, events::DocumentFocusLost, graphics::{CursorKind, Rect}, @@ -361,7 +361,7 @@ pub struct Config { pub end_of_line_diagnostics: DiagnosticFilter, // Set to override the default clipboard provider pub clipboard_provider: ClipboardProvider, - pub backup_strategy: BackupStrategy, + pub backup: BackupConfig, } #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Eq, PartialOrd, Ord)] @@ -1003,7 +1003,7 @@ impl Default for Config { inline_diagnostics: InlineDiagnosticsConfig::default(), end_of_line_diagnostics: DiagnosticFilter::Disable, clipboard_provider: ClipboardProvider::default(), - backup_strategy: BackupStrategy::default(), + backup: BackupConfig::default(), } } }