Add ability to configure atomic saving

pull/13656/head
Isaac Mills 2025-05-30 10:16:47 -06:00
parent 8961ae1dc6
commit faa6736d29
No known key found for this signature in database
GPG Key ID: B67D7410F33A0F61
3 changed files with 23 additions and 1 deletions

View File

@ -34,6 +34,7 @@ pub struct EditorConfig {
// pub spelling_language: Option<SpellingLanguage>, // pub spelling_language: Option<SpellingLanguage>,
pub trim_trailing_whitespace: Option<bool>, pub trim_trailing_whitespace: Option<bool>,
pub insert_final_newline: Option<bool>, pub insert_final_newline: Option<bool>,
pub atomic_save: Option<bool>,
pub max_line_length: Option<NonZeroU16>, pub max_line_length: Option<NonZeroU16>,
} }
@ -159,6 +160,13 @@ impl EditorConfig {
"false" => Some(false), "false" => Some(false),
_ => None, _ => None,
}); });
let atomic_save = pairs
.get("atomic_save")
.and_then(|value| match value.as_ref() {
"true" => Some(true),
"false" => Some(false),
_ => None,
});
// This option is not in the spec but is supported by some editors. // This option is not in the spec but is supported by some editors.
// <https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties#max_line_length> // <https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties#max_line_length>
let max_line_length = pairs let max_line_length = pairs
@ -172,6 +180,7 @@ impl EditorConfig {
encoding, encoding,
trim_trailing_whitespace, trim_trailing_whitespace,
insert_final_newline, insert_final_newline,
atomic_save,
max_line_length, max_line_length,
} }
} }
@ -305,6 +314,7 @@ mod test {
[docs/**.txt] [docs/**.txt]
insert_final_newline = true insert_final_newline = true
atomic_write = true
"#; "#;
assert_eq!( assert_eq!(
@ -326,6 +336,7 @@ mod test {
EditorConfig { EditorConfig {
indent_style: Some(IndentStyle::Spaces(4)), indent_style: Some(IndentStyle::Spaces(4)),
insert_final_newline: Some(true), insert_final_newline: Some(true),
atomic_save: Some(true),
..Default::default() ..Default::default()
} }
); );

View File

@ -980,6 +980,7 @@ impl Document {
// mark changes up to now as saved // mark changes up to now as saved
let current_rev = self.get_current_revision(); let current_rev = self.get_current_revision();
let doc_id = self.id(); let doc_id = self.id();
let atomic_write = self.atomic_save();
let encoding_with_bom_info = (self.encoding, self.has_bom); let encoding_with_bom_info = (self.encoding, self.has_bom);
let last_saved_time = self.last_saved_time; let last_saved_time = self.last_saved_time;
@ -1029,7 +1030,7 @@ impl Document {
// Assume it is a hardlink to prevent data loss if the metadata cant be read (e.g. on certain Windows configurations) // 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; let is_hardlink = helix_stdx::faccess::hardlink_count(&write_path).unwrap_or(2) > 1;
let backup = if path.exists() { let backup = if path.exists() && atomic_write {
let path_ = write_path.clone(); let path_ = write_path.clone();
// hacks: we use tempfile to handle the complex task of creating // hacks: we use tempfile to handle the complex task of creating
// non clobbered temporary path for us we don't want // non clobbered temporary path for us we don't want
@ -1914,6 +1915,13 @@ impl Document {
.unwrap_or_else(|| self.config.load().insert_final_newline) .unwrap_or_else(|| self.config.load().insert_final_newline)
} }
/// Whether the document should write it's contents to a backup file, then rename the backup to the target file when saving. This prevents data loss when saving, but may confuse some file watching/hot reloading programs.
pub fn atomic_save(&self) -> bool {
self.editor_config
.atomic_save
.unwrap_or_else(|| self.config.load().atomic_save)
}
/// Whether the document should trim whitespace preceding line endings on save. /// Whether the document should trim whitespace preceding line endings on save.
pub fn trim_trailing_whitespace(&self) -> bool { pub fn trim_trailing_whitespace(&self) -> bool {
self.editor_config self.editor_config

View File

@ -346,6 +346,8 @@ pub struct Config {
pub default_line_ending: LineEndingConfig, pub default_line_ending: LineEndingConfig,
/// Whether to automatically insert a trailing line-ending on write if missing. Defaults to `true`. /// Whether to automatically insert a trailing line-ending on write if missing. Defaults to `true`.
pub insert_final_newline: bool, pub insert_final_newline: bool,
/// Whether the document should write it's contents to a backup file, then rename the backup to the target file when saving. This prevents data loss when saving, but may confuse some file watching/hot reloading programs. Defaults to `true`
pub atomic_save: bool,
/// Whether to automatically remove all trailing line-endings after the final one on write. /// Whether to automatically remove all trailing line-endings after the final one on write.
/// Defaults to `false`. /// Defaults to `false`.
pub trim_final_newlines: bool, pub trim_final_newlines: bool,
@ -1017,6 +1019,7 @@ impl Default for Config {
workspace_lsp_roots: Vec::new(), workspace_lsp_roots: Vec::new(),
default_line_ending: LineEndingConfig::default(), default_line_ending: LineEndingConfig::default(),
insert_final_newline: true, insert_final_newline: true,
atomic_save: true,
trim_final_newlines: false, trim_final_newlines: false,
trim_trailing_whitespace: false, trim_trailing_whitespace: false,
smart_tab: Some(SmartTabConfig::default()), smart_tab: Some(SmartTabConfig::default()),