diff options
author | Daniel S Poulin | 2022-03-01 01:31:24 +0000 |
---|---|---|
committer | GitHub | 2022-03-01 01:31:24 +0000 |
commit | 78d37fd332ab98e867b8e74f08c4cf45295c167a (patch) | |
tree | 19e216bea4dd82553089f7d343dd03edcb7986e1 /helix-term/src | |
parent | 59c691d2dbdf14c02d0a4b8f9b014112ead6cda5 (diff) |
Implement bulk buffer closing commands (#1677)
* Implement buffer-close-all
* Implement buffer-close-others
* Refactor all buffer close variants to use shared logic
* Fix clippy lint
* Docgen for new commands
* Shorten error message for attempting to close buffers that don't exist
* Refactor shared buffer methods to pass only editor, not whole compositor
* Switch signature of bulk buffer closing to use slice of DocumentIds
Addresses feedback that accepting an IntoIterator implementor is too
much for an internal. Also possibly saves some moving?
Diffstat (limited to 'helix-term/src')
-rw-r--r-- | helix-term/src/commands.rs | 120 |
1 files changed, 103 insertions, 17 deletions
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 2c5a2d90..74d4c8d7 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2077,18 +2077,27 @@ pub mod cmd { Ok(()) } - fn buffer_close_impl( + fn buffer_close_by_ids_impl( editor: &mut Editor, - args: &[Cow<str>], + doc_ids: &[DocumentId], force: bool, ) -> anyhow::Result<()> { + for &doc_id in doc_ids { + editor.close_document(doc_id, force)?; + } + + Ok(()) + } + + fn buffer_gather_paths_impl(editor: &mut Editor, args: &[Cow<str>]) -> Vec<DocumentId> { + // No arguments implies current document if args.is_empty() { let doc_id = view!(editor).doc; - editor.close_document(doc_id, force)?; - return Ok(()); + return vec![doc_id]; } let mut nonexistent_buffers = vec![]; + let mut document_ids = vec![]; for arg in args { let doc_id = editor.documents().find_map(|doc| { let arg_path = Some(Path::new(arg.as_ref())); @@ -2102,21 +2111,19 @@ pub mod cmd { }); match doc_id { - Some(doc_id) => editor.close_document(doc_id, force)?, - None => nonexistent_buffers.push(arg), + Some(doc_id) => document_ids.push(doc_id), + None => nonexistent_buffers.push(format!("'{}'", arg)), } } - let nonexistent_buffers: Vec<_> = nonexistent_buffers - .into_iter() - .map(|str| format!("'{}'", str)) - .collect(); - editor.set_error(format!( - "couldn't close buffer(s) {}: does not exist", - nonexistent_buffers.join(", ") - )); + if !nonexistent_buffers.is_empty() { + editor.set_error(format!( + "cannot close non-existent buffers: {}", + nonexistent_buffers.join(", ") + )); + } - Ok(()) + document_ids } fn buffer_close( @@ -2124,7 +2131,8 @@ pub mod cmd { args: &[Cow<str>], _event: PromptEvent, ) -> anyhow::Result<()> { - buffer_close_impl(cx.editor, args, false) + let document_ids = buffer_gather_paths_impl(cx.editor, args); + buffer_close_by_ids_impl(cx.editor, &document_ids, false) } fn force_buffer_close( @@ -2132,7 +2140,57 @@ pub mod cmd { args: &[Cow<str>], _event: PromptEvent, ) -> anyhow::Result<()> { - buffer_close_impl(cx.editor, args, true) + let document_ids = buffer_gather_paths_impl(cx.editor, args); + buffer_close_by_ids_impl(cx.editor, &document_ids, true) + } + + fn buffer_gather_others_impl(editor: &mut Editor) -> Vec<DocumentId> { + let current_document = &doc!(editor).id(); + editor + .documents() + .map(|doc| doc.id()) + .filter(|doc_id| doc_id != current_document) + .collect() + } + + fn buffer_close_others( + cx: &mut compositor::Context, + _args: &[Cow<str>], + _event: PromptEvent, + ) -> anyhow::Result<()> { + let document_ids = buffer_gather_others_impl(cx.editor); + buffer_close_by_ids_impl(cx.editor, &document_ids, false) + } + + fn force_buffer_close_others( + cx: &mut compositor::Context, + _args: &[Cow<str>], + _event: PromptEvent, + ) -> anyhow::Result<()> { + let document_ids = buffer_gather_others_impl(cx.editor); + buffer_close_by_ids_impl(cx.editor, &document_ids, true) + } + + fn buffer_gather_all_impl(editor: &mut Editor) -> Vec<DocumentId> { + editor.documents().map(|doc| doc.id()).collect() + } + + fn buffer_close_all( + cx: &mut compositor::Context, + _args: &[Cow<str>], + _event: PromptEvent, + ) -> anyhow::Result<()> { + let document_ids = buffer_gather_all_impl(cx.editor); + buffer_close_by_ids_impl(cx.editor, &document_ids, false) + } + + fn force_buffer_close_all( + cx: &mut compositor::Context, + _args: &[Cow<str>], + _event: PromptEvent, + ) -> anyhow::Result<()> { + let document_ids = buffer_gather_all_impl(cx.editor); + buffer_close_by_ids_impl(cx.editor, &document_ids, true) } fn write_impl(cx: &mut compositor::Context, path: Option<&Cow<str>>) -> anyhow::Result<()> { @@ -2971,6 +3029,34 @@ pub mod cmd { completer: Some(completers::buffer), }, TypableCommand { + name: "buffer-close-others", + aliases: &["bco", "bcloseother"], + doc: "Close all buffers but the currently focused one.", + fun: buffer_close_others, + completer: None, + }, + TypableCommand { + name: "buffer-close-others!", + aliases: &["bco!", "bcloseother!"], + doc: "Close all buffers but the currently focused one.", + fun: force_buffer_close_others, + completer: None, + }, + TypableCommand { + name: "buffer-close-all", + aliases: &["bca", "bcloseall"], + doc: "Close all buffers, without quiting.", + fun: buffer_close_all, + completer: None, + }, + TypableCommand { + name: "buffer-close-all!", + aliases: &["bca!", "bcloseall!"], + doc: "Close all buffers forcefully (ignoring unsaved changes), without quiting.", + fun: force_buffer_close_all, + completer: None, + }, + TypableCommand { name: "write", aliases: &["w"], doc: "Write changes to disk. Accepts an optional path (:write some/path.txt)", |