diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index f48e1490a..1631d3d4e 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -48,8 +48,10 @@ | `:show-directory`, `:pwd` | Show the current working directory. | | `:encoding` | Set encoding. Based on `https://encoding.spec.whatwg.org`. | | `:character-info`, `:char` | Get info about the character under the primary cursor. | -| `:reload`, `:rl` | Discard changes and reload from the source file. | -| `:reload-all`, `:rla` | Discard changes and reload all documents from the source files. | +| `:reload`, `:rl` | Reload from the source file, if no changes were made. | +| `:reload!`, `:rl!` | Discard changes and reload from the source file. | +| `:reload-all`, `:rla` | Reload all documents from the source files, if no changes were made. | +| `:reload-all!`, `:rla!` | Discard changes and reload all documents from the source files. | | `:update`, `:u` | Write changes only if the file has been modified. | | `:lsp-workspace-command` | Open workspace command picker | | `:lsp-restart` | Restarts the language servers used by the current doc | diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index cd40e0532..9c1bfbfe8 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1267,11 +1267,29 @@ fn get_character_info( Ok(()) } -/// Reload the [`Document`] from its source file. +// Reload the [`Document`] from its source file, if no changes were made. fn reload( cx: &mut compositor::Context, _args: &[Cow], event: PromptEvent, +) -> anyhow::Result<()> { + reload_impl(cx, _args, event, false) +} + +// Force reload the [`Document`] from its source file. +fn force_reload( + cx: &mut compositor::Context, + _args: &[Cow], + event: PromptEvent, +) -> anyhow::Result<()> { + reload_impl(cx, _args, event, true) +} + +fn reload_impl( + cx: &mut compositor::Context, + _args: &[Cow], + event: PromptEvent, + force: bool, ) -> anyhow::Result<()> { if event != PromptEvent::Validate { return Ok(()); @@ -1279,6 +1297,9 @@ fn reload( let scrolloff = cx.editor.config().scrolloff; let (view, doc) = current!(cx.editor); + if !force && doc.is_modified() { + bail!("Cannot reload unsaved buffer"); + } doc.reload(view, &cx.editor.diff_providers).map(|_| { view.ensure_cursor_in_view(doc, scrolloff); })?; @@ -1295,6 +1316,23 @@ fn reload_all( cx: &mut compositor::Context, _args: &[Cow], event: PromptEvent, +) -> anyhow::Result<()> { + reload_all_impl(cx, _args, event, false) +} + +fn force_reload_all( + cx: &mut compositor::Context, + _args: &[Cow], + event: PromptEvent, +) -> anyhow::Result<()> { + reload_all_impl(cx, _args, event, true) +} + +fn reload_all_impl( + cx: &mut compositor::Context, + _args: &[Cow], + event: PromptEvent, + force: bool, ) -> anyhow::Result<()> { if event != PromptEvent::Validate { return Ok(()); @@ -1318,8 +1356,13 @@ fn reload_all( }) .collect(); + let mut unsaved_buffer_count = 0; for (doc_id, view_ids) in docs_view_ids { let doc = doc_mut!(cx.editor, &doc_id); + if !force && doc.is_modified() { + unsaved_buffer_count += 1; + continue; + } // Every doc is guaranteed to have at least 1 view at this point. let view = view_mut!(cx.editor, view_ids[0]); @@ -1347,6 +1390,13 @@ fn reload_all( } } + if !force && unsaved_buffer_count > 0 { + bail!( + "{} unsaved buffer(s) remaining, all saved buffers reloaded", + unsaved_buffer_count + ); + } + Ok(()) } @@ -2863,17 +2913,31 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { name: "reload", aliases: &["rl"], - doc: "Discard changes and reload from the source file.", + doc: "Reload from the source file, if no changes were made.", fun: reload, signature: CommandSignature::none(), }, + TypableCommand { + name: "reload!", + aliases: &["rl!"], + doc: "Discard changes and reload from the source file.", + fun: force_reload, + signature: CommandSignature::none(), + }, TypableCommand { name: "reload-all", aliases: &["rla"], - doc: "Discard changes and reload all documents from the source files.", + doc: "Reload all documents from the source files, if no changes were made.", fun: reload_all, signature: CommandSignature::none(), }, + TypableCommand { + name: "reload-all!", + aliases: &["rla!"], + doc: "Discard changes and reload all documents from the source files.", + fun: force_reload_all, + signature: CommandSignature::none(), + }, TypableCommand { name: "update", aliases: &["u"],