mirror of https://github.com/helix-editor/helix
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
parent
59c691d2db
commit
78d37fd332
|
@ -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()
|
editor.set_error(format!(
|
||||||
.map(|str| format!("'{}'", str))
|
"cannot close non-existent buffers: {}",
|
||||||
.collect();
|
nonexistent_buffers.join(", ")
|
||||||
editor.set_error(format!(
|
));
|
||||||
"couldn't close buffer(s) {}: does not exist",
|
}
|
||||||
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…
Reference in New Issue