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?
pull/1726/head
Daniel S Poulin 3 years ago committed by GitHub
parent 59c691d2db
commit 78d37fd332
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -5,6 +5,10 @@
| `:open`, `:o` | Open a file from disk into the current view. | | `:open`, `:o` | Open a file from disk into the current view. |
| `:buffer-close`, `:bc`, `:bclose` | Close the current buffer. | | `:buffer-close`, `:bc`, `:bclose` | Close the current buffer. |
| `:buffer-close!`, `:bc!`, `:bclose!` | Close the current buffer forcefully (ignoring unsaved changes). | | `:buffer-close!`, `:bc!`, `:bclose!` | Close the current buffer forcefully (ignoring unsaved changes). |
| `:buffer-close-others`, `:bco`, `:bcloseother` | Close all buffers but the currently focused one. |
| `:buffer-close-others!`, `:bco!`, `:bcloseother!` | Close all buffers but the currently focused one. |
| `:buffer-close-all`, `:bca`, `:bcloseall` | Close all buffers, without quiting. |
| `:buffer-close-all!`, `:bca!`, `:bcloseall!` | Close all buffers forcefully (ignoring unsaved changes), without quiting. |
| `:write`, `:w` | Write changes to disk. Accepts an optional path (:write some/path.txt) | | `:write`, `:w` | Write changes to disk. Accepts an optional path (:write some/path.txt) |
| `:new`, `:n` | Create a new scratch buffer. | | `:new`, `:n` | Create a new scratch buffer. |
| `:format`, `:fmt` | Format the file using the LSP formatter. | | `:format`, `:fmt` | Format the file using the LSP formatter. |

@ -2077,18 +2077,27 @@ pub mod cmd {
Ok(()) Ok(())
} }
fn buffer_close_impl( fn buffer_close_by_ids_impl(
editor: &mut Editor, editor: &mut Editor,
args: &[Cow<str>], doc_ids: &[DocumentId],
force: bool, force: bool,
) -> anyhow::Result<()> { ) -> 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() { if args.is_empty() {
let doc_id = view!(editor).doc; let doc_id = view!(editor).doc;
editor.close_document(doc_id, force)?; return vec![doc_id];
return Ok(());
} }
let mut nonexistent_buffers = vec![]; let mut nonexistent_buffers = vec![];
let mut document_ids = vec![];
for arg in args { for arg in args {
let doc_id = editor.documents().find_map(|doc| { let doc_id = editor.documents().find_map(|doc| {
let arg_path = Some(Path::new(arg.as_ref())); let arg_path = Some(Path::new(arg.as_ref()));
@ -2102,21 +2111,19 @@ pub mod cmd {
}); });
match doc_id { match doc_id {
Some(doc_id) => editor.close_document(doc_id, force)?, Some(doc_id) => document_ids.push(doc_id),
None => nonexistent_buffers.push(arg), None => nonexistent_buffers.push(format!("'{}'", arg)),
} }
} }
let nonexistent_buffers: Vec<_> = nonexistent_buffers if !nonexistent_buffers.is_empty() {
.into_iter()
.map(|str| format!("'{}'", str))
.collect();
editor.set_error(format!( editor.set_error(format!(
"couldn't close buffer(s) {}: does not exist", "cannot close non-existent buffers: {}",
nonexistent_buffers.join(", ") nonexistent_buffers.join(", ")
)); ));
}
Ok(()) document_ids
} }
fn buffer_close( fn buffer_close(
@ -2124,7 +2131,8 @@ pub mod cmd {
args: &[Cow<str>], args: &[Cow<str>],
_event: PromptEvent, _event: PromptEvent,
) -> anyhow::Result<()> { ) -> 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( fn force_buffer_close(
@ -2132,7 +2140,57 @@ pub mod cmd {
args: &[Cow<str>], args: &[Cow<str>],
_event: PromptEvent, _event: PromptEvent,
) -> anyhow::Result<()> { ) -> 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<()> { fn write_impl(cx: &mut compositor::Context, path: Option<&Cow<str>>) -> anyhow::Result<()> {
@ -2970,6 +3028,34 @@ pub mod cmd {
fun: force_buffer_close, fun: force_buffer_close,
completer: Some(completers::buffer), 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 { TypableCommand {
name: "write", name: "write",
aliases: &["w"], aliases: &["w"],

Loading…
Cancel
Save