From faa6736d29191bbaebee62f948e513a9755b7c06 Mon Sep 17 00:00:00 2001 From: Isaac Mills Date: Fri, 30 May 2025 10:16:47 -0600 Subject: [PATCH 1/8] Add ability to configure atomic saving --- helix-core/src/editor_config.rs | 11 +++++++++++ helix-view/src/document.rs | 10 +++++++++- helix-view/src/editor.rs | 3 +++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/helix-core/src/editor_config.rs b/helix-core/src/editor_config.rs index 714f577c5..7515dd231 100644 --- a/helix-core/src/editor_config.rs +++ b/helix-core/src/editor_config.rs @@ -34,6 +34,7 @@ pub struct EditorConfig { // pub spelling_language: Option, pub trim_trailing_whitespace: Option, pub insert_final_newline: Option, + pub atomic_save: Option, pub max_line_length: Option, } @@ -159,6 +160,13 @@ impl EditorConfig { "false" => Some(false), _ => 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. // let max_line_length = pairs @@ -172,6 +180,7 @@ impl EditorConfig { encoding, trim_trailing_whitespace, insert_final_newline, + atomic_save, max_line_length, } } @@ -305,6 +314,7 @@ mod test { [docs/**.txt] insert_final_newline = true + atomic_write = true "#; assert_eq!( @@ -326,6 +336,7 @@ mod test { EditorConfig { indent_style: Some(IndentStyle::Spaces(4)), insert_final_newline: Some(true), + atomic_save: Some(true), ..Default::default() } ); diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index fb89e2e0c..458016492 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -980,6 +980,7 @@ impl Document { // mark changes up to now as saved let current_rev = self.get_current_revision(); let doc_id = self.id(); + let atomic_write = self.atomic_save(); let encoding_with_bom_info = (self.encoding, self.has_bom); 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) 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(); // hacks: we use tempfile to handle the complex task of creating // 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) } + /// 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. pub fn trim_trailing_whitespace(&self) -> bool { self.editor_config diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index bc811b88b..3a0b48d05 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -346,6 +346,8 @@ pub struct Config { pub default_line_ending: LineEndingConfig, /// Whether to automatically insert a trailing line-ending on write if missing. Defaults to `true`. 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. /// Defaults to `false`. pub trim_final_newlines: bool, @@ -1017,6 +1019,7 @@ impl Default for Config { workspace_lsp_roots: Vec::new(), default_line_ending: LineEndingConfig::default(), insert_final_newline: true, + atomic_save: true, trim_final_newlines: false, trim_trailing_whitespace: false, smart_tab: Some(SmartTabConfig::default()), From 94edf50ba6e6b17d593305e2c7def48232373731 Mon Sep 17 00:00:00 2001 From: Isaac Mills Date: Fri, 30 May 2025 10:20:20 -0600 Subject: [PATCH 2/8] Add ability to configure atomic saving to helix book --- book/src/editor.md | 1 + helix-view/src/document.rs | 2 +- helix-view/src/editor.rs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/book/src/editor.md b/book/src/editor.md index 00db71d27..0eae867c5 100644 --- a/book/src/editor.md +++ b/book/src/editor.md @@ -53,6 +53,7 @@ | `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml` | `[]` | | `default-line-ending` | The line ending to use for new documents. Can be `native`, `lf`, `crlf`, `ff`, `cr` or `nel`. `native` uses the platform's native line ending (`crlf` on Windows, otherwise `lf`). | `native` | | `insert-final-newline` | Whether to automatically insert a trailing line-ending on write if missing | `true` | +| `atomic-save` | 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 if the editor is interupted while writing the file, but may confuse some file watching/hot reloading programs. | `true` | | `trim-final-newlines` | Whether to automatically remove line-endings after the final one on write | `false` | | `trim-trailing-whitespace` | Whether to automatically remove whitespace preceding line endings on write | `false` | | `popup-border` | Draw border around `popup`, `menu`, `all`, or `none` | `none` | diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 458016492..bfbfa9e08 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -1915,7 +1915,7 @@ impl Document { .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. + /// 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 if the editor is interupted while writing the file, but may confuse some file watching/hot reloading programs. pub fn atomic_save(&self) -> bool { self.editor_config .atomic_save diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 3a0b48d05..447b39a8a 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -346,7 +346,7 @@ pub struct Config { pub default_line_ending: LineEndingConfig, /// Whether to automatically insert a trailing line-ending on write if missing. Defaults to `true`. 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` + /// 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 if the editor is interupted while writing the file, 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. /// Defaults to `false`. From 2b7e73f00dbe2fdab5290c83451f7d47a9dc6ac1 Mon Sep 17 00:00:00 2001 From: Isaac Mills Date: Fri, 30 May 2025 10:22:41 -0600 Subject: [PATCH 3/8] Remove instances of atmoic_write in code --- helix-core/src/editor_config.rs | 2 +- helix-view/src/document.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/helix-core/src/editor_config.rs b/helix-core/src/editor_config.rs index 7515dd231..00206ca6b 100644 --- a/helix-core/src/editor_config.rs +++ b/helix-core/src/editor_config.rs @@ -314,7 +314,7 @@ mod test { [docs/**.txt] insert_final_newline = true - atomic_write = true + atomic_save = true "#; assert_eq!( diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index bfbfa9e08..4a76b38cd 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -980,7 +980,7 @@ impl Document { // mark changes up to now as saved let current_rev = self.get_current_revision(); let doc_id = self.id(); - let atomic_write = self.atomic_save(); + let atomic_save = self.atomic_save(); let encoding_with_bom_info = (self.encoding, self.has_bom); let last_saved_time = self.last_saved_time; @@ -1030,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) let is_hardlink = helix_stdx::faccess::hardlink_count(&write_path).unwrap_or(2) > 1; - let backup = if path.exists() && atomic_write { + let backup = if path.exists() && atomic_save { 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 From 884c7f1f6b2109ae3594690dc4a7d17dcbac1105 Mon Sep 17 00:00:00 2001 From: Isaac Mills Date: Fri, 30 May 2025 10:48:04 -0600 Subject: [PATCH 4/8] Small gramatical fix to atomic_save documentation --- book/src/editor.md | 2 +- helix-view/src/document.rs | 2 +- helix-view/src/editor.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/book/src/editor.md b/book/src/editor.md index 0eae867c5..e7f016b00 100644 --- a/book/src/editor.md +++ b/book/src/editor.md @@ -53,7 +53,7 @@ | `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml` | `[]` | | `default-line-ending` | The line ending to use for new documents. Can be `native`, `lf`, `crlf`, `ff`, `cr` or `nel`. `native` uses the platform's native line ending (`crlf` on Windows, otherwise `lf`). | `native` | | `insert-final-newline` | Whether to automatically insert a trailing line-ending on write if missing | `true` | -| `atomic-save` | 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 if the editor is interupted while writing the file, but may confuse some file watching/hot reloading programs. | `true` | +| `atomic-save` | Whether the document should write it's contents to a backup file, then rename that backup to the target file when saving. This prevents data loss if the editor is interupted while writing the file, but may confuse some file watching/hot reloading programs. | `true` | | `trim-final-newlines` | Whether to automatically remove line-endings after the final one on write | `false` | | `trim-trailing-whitespace` | Whether to automatically remove whitespace preceding line endings on write | `false` | | `popup-border` | Draw border around `popup`, `menu`, `all`, or `none` | `none` | diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 4a76b38cd..4f9308ad5 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -1915,7 +1915,7 @@ impl Document { .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 if the editor is interupted while writing the file, but may confuse some file watching/hot reloading programs. + /// Whether the document should write it's contents to a backup file, then rename that backup to the target file when saving. This prevents data loss if the editor is interupted while writing the file, but may confuse some file watching/hot reloading programs. pub fn atomic_save(&self) -> bool { self.editor_config .atomic_save diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 447b39a8a..629223263 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -346,7 +346,7 @@ pub struct Config { pub default_line_ending: LineEndingConfig, /// Whether to automatically insert a trailing line-ending on write if missing. Defaults to `true`. 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 if the editor is interupted while writing the file, but may confuse some file watching/hot reloading programs. Defaults to `true` + /// Whether the document should write it's contents to a backup file, then rename that backup to the target file when saving. This prevents data loss if the editor is interupted while writing the file, 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. /// Defaults to `false`. From d37bac00bd8c05b92b159f0f0c4ab334c5a14593 Mon Sep 17 00:00:00 2001 From: Isaac Mills Date: Thu, 5 Jun 2025 09:22:26 -0600 Subject: [PATCH 5/8] Make atomic_save not configurable via editor config --- helix-core/src/editor_config.rs | 11 ----------- helix-view/src/document.rs | 4 +--- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/helix-core/src/editor_config.rs b/helix-core/src/editor_config.rs index 00206ca6b..714f577c5 100644 --- a/helix-core/src/editor_config.rs +++ b/helix-core/src/editor_config.rs @@ -34,7 +34,6 @@ pub struct EditorConfig { // pub spelling_language: Option, pub trim_trailing_whitespace: Option, pub insert_final_newline: Option, - pub atomic_save: Option, pub max_line_length: Option, } @@ -160,13 +159,6 @@ impl EditorConfig { "false" => Some(false), _ => 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. // let max_line_length = pairs @@ -180,7 +172,6 @@ impl EditorConfig { encoding, trim_trailing_whitespace, insert_final_newline, - atomic_save, max_line_length, } } @@ -314,7 +305,6 @@ mod test { [docs/**.txt] insert_final_newline = true - atomic_save = true "#; assert_eq!( @@ -336,7 +326,6 @@ mod test { EditorConfig { indent_style: Some(IndentStyle::Spaces(4)), insert_final_newline: Some(true), - atomic_save: Some(true), ..Default::default() } ); diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 4f9308ad5..d020368ed 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -1917,9 +1917,7 @@ impl Document { /// Whether the document should write it's contents to a backup file, then rename that backup to the target file when saving. This prevents data loss if the editor is interupted while writing the file, 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) + self.config.load().atomic_save } /// Whether the document should trim whitespace preceding line endings on save. From 7cfed5f9fc9eed3f67f5b992a0b6b19fb01320ec Mon Sep 17 00:00:00 2001 From: StratusFearMe21 <57533634+StratusFearMe21@users.noreply.github.com> Date: Fri, 6 Jun 2025 15:46:32 -0600 Subject: [PATCH 6/8] Update helix-view/src/editor.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Łukasz Langa --- helix-view/src/editor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 629223263..a2ebbb2e3 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -346,7 +346,7 @@ pub struct Config { pub default_line_ending: LineEndingConfig, /// Whether to automatically insert a trailing line-ending on write if missing. Defaults to `true`. pub insert_final_newline: bool, - /// Whether the document should write it's contents to a backup file, then rename that backup to the target file when saving. This prevents data loss if the editor is interupted while writing the file, but may confuse some file watching/hot reloading programs. Defaults to `true` + /// Whether the document should write its contents to a backup file, then rename that backup to the target file when saving. This prevents data loss if the editor is interrupted while writing the file, 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. /// Defaults to `false`. From 4d2b7276c8ff93d7bfdbcf65900fa1ad14f0c5d2 Mon Sep 17 00:00:00 2001 From: StratusFearMe21 <57533634+StratusFearMe21@users.noreply.github.com> Date: Fri, 6 Jun 2025 15:46:46 -0600 Subject: [PATCH 7/8] Update book/src/editor.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Łukasz Langa --- book/src/editor.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/book/src/editor.md b/book/src/editor.md index e7f016b00..f7386757e 100644 --- a/book/src/editor.md +++ b/book/src/editor.md @@ -53,7 +53,7 @@ | `workspace-lsp-roots` | Directories relative to the workspace root that are treated as LSP roots. Should only be set in `.helix/config.toml` | `[]` | | `default-line-ending` | The line ending to use for new documents. Can be `native`, `lf`, `crlf`, `ff`, `cr` or `nel`. `native` uses the platform's native line ending (`crlf` on Windows, otherwise `lf`). | `native` | | `insert-final-newline` | Whether to automatically insert a trailing line-ending on write if missing | `true` | -| `atomic-save` | Whether the document should write it's contents to a backup file, then rename that backup to the target file when saving. This prevents data loss if the editor is interupted while writing the file, but may confuse some file watching/hot reloading programs. | `true` | +| `atomic-save` | Whether the document should write its contents to a backup file, then rename that backup to the target file when saving. This prevents data loss if the editor is interrupted while writing the file, but may confuse some file watching/hot reloading programs. | `true` | | `trim-final-newlines` | Whether to automatically remove line-endings after the final one on write | `false` | | `trim-trailing-whitespace` | Whether to automatically remove whitespace preceding line endings on write | `false` | | `popup-border` | Draw border around `popup`, `menu`, `all`, or `none` | `none` | From a8a6f33f07147f454b6d3399db236651a705bd10 Mon Sep 17 00:00:00 2001 From: StratusFearMe21 <57533634+StratusFearMe21@users.noreply.github.com> Date: Fri, 6 Jun 2025 15:46:54 -0600 Subject: [PATCH 8/8] Update helix-view/src/document.rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Łukasz Langa --- helix-view/src/document.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index d020368ed..95811f099 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -1915,7 +1915,7 @@ impl Document { .unwrap_or_else(|| self.config.load().insert_final_newline) } - /// Whether the document should write it's contents to a backup file, then rename that backup to the target file when saving. This prevents data loss if the editor is interupted while writing the file, but may confuse some file watching/hot reloading programs. + /// Whether the document should write its contents to a backup file, then rename that backup to the target file when saving. This prevents data loss if the editor is interrupted while writing the file, but may confuse some file watching/hot reloading programs. pub fn atomic_save(&self) -> bool { self.config.load().atomic_save }