diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index 4b737893d..54b06fbe9 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -9,6 +9,8 @@ | `:buffer-close-others!`, `:bco!`, `:bcloseother!` | Force close all buffers but the currently focused one. | | `:buffer-close-all`, `:bca`, `:bcloseall` | Close all buffers without quitting. | | `:buffer-close-all!`, `:bca!`, `:bcloseall!` | Force close all buffers ignoring unsaved changes without quitting. | +| `:buffer-close-hidden`, `:bch`, `:bclosehidden` | Close all buffers that are not visible. | +| `:buffer-close-hidden!`, `:bch!`, `:bclosehidden!` | Force close all buffers that are not visible ignoring unsaved changes. | | `:buffer-next`, `:bn`, `:bnext` | Goto next buffer. | | `:buffer-previous`, `:bp`, `:bprev` | Goto previous buffer. | | `:write`, `:w` | Write changes to disk. Accepts an optional path (:write some/path.txt) | diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index abe6dd97e..fd3f6e239 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -136,15 +136,18 @@ fn open(cx: &mut compositor::Context, args: &[Cow], event: PromptEvent) -> Ok(()) } -fn buffer_close_by_ids_impl( +fn buffer_close_by_ids_impl<'a, T>( cx: &mut compositor::Context, - doc_ids: &[DocumentId], + doc_ids: T, force: bool, -) -> anyhow::Result<()> { +) -> anyhow::Result<()> +where + T: IntoIterator, +{ cx.block_try_flush_writes()?; let (modified_ids, modified_names): (Vec<_>, Vec<_>) = doc_ids - .iter() + .into_iter() .filter_map(|&doc_id| { if let Err(CloseError::BufferModified(name)) = cx.editor.close_document(doc_id, force) { Some((doc_id, name)) @@ -299,6 +302,46 @@ fn force_buffer_close_all( buffer_close_by_ids_impl(cx, &document_ids, true) } +fn buffer_close_hidden( + cx: &mut compositor::Context, + _args: &[Cow], + event: PromptEvent, +) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + + let mut visible_doc_ids = cx + .editor + .documents() + .map(|doc| doc.id()) + .collect::>(); + for view in cx.editor.tree.views() { + visible_doc_ids.remove(&view.0.doc); + } + buffer_close_by_ids_impl(cx, &visible_doc_ids, false) +} + +fn force_buffer_close_hidden( + cx: &mut compositor::Context, + _args: &[Cow], + event: PromptEvent, +) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + + let mut visible_doc_ids = cx + .editor + .documents() + .map(|doc| doc.id()) + .collect::>(); + for view in cx.editor.tree.views() { + visible_doc_ids.remove(&view.0.doc); + } + buffer_close_by_ids_impl(cx, &visible_doc_ids, true) +} + fn buffer_next( cx: &mut compositor::Context, _args: &[Cow], @@ -2472,6 +2515,20 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: force_buffer_close_all, signature: CommandSignature::none(), }, + TypableCommand { + name: "buffer-close-hidden", + aliases: &["bch", "bclosehidden"], + doc: "Close all buffers that are not visible.", + fun: buffer_close_hidden, + signature: CommandSignature::none(), + }, + TypableCommand { + name: "buffer-close-hidden!", + aliases: &["bch!", "bclosehidden!"], + doc: "Force close all buffers that are not visible ignoring unsaved changes.", + fun: force_buffer_close_hidden, + signature: CommandSignature::none(), + }, TypableCommand { name: "buffer-next", aliases: &["bn", "bnext"],