@@ -2077,18 +2077,27 @@ pub mod cmd {
20772077 Ok(())
20782078 }
20792079
2080− fn buffer_close_impl(
2080+ fn buffer_close_by_ids_impl(
20812081 editor: &mut Editor,
2082− args: &[Cow<str>],
2082+ doc_ids: &[DocumentId],
20832083 force: bool,
20842084 ) -> anyhow::Result<()> {
2085+ for &doc_id in doc_ids {
2086+ editor.close_document(doc_id, force)?;
2087+ }
2088+
2089+ Ok(())
2090+ }
2091+
2092+ fn buffer_gather_paths_impl(editor: &mut Editor, args: &[Cow<str>]) -> Vec<DocumentId> {
2093+ // No arguments implies current document
20852094 if args.is_empty() {
20862095 let doc_id = view!(editor).doc;
2087− editor.close_document(doc_id, force)?;
2088− return Ok(());
2096+ return vec![doc_id];
20892097 }
20902098
20912099 let mut nonexistent_buffers = vec![];
2100+ let mut document_ids = vec![];
20922101 for arg in args {
20932102 let doc_id = editor.documents().find_map(|doc| {
20942103 let arg_path = Some(Path::new(arg.as_ref()));
@@ -2102,21 +2111,19 @@ pub mod cmd {
21022111 });
21032112
21042113 match doc_id {
2105− Some(doc_id) => editor.close_document(doc_id, force)?,
2106− None => nonexistent_buffers.push(arg),
2114+ Some(doc_id) => document_ids.push(doc_id),
2115+ None => nonexistent_buffers.push(format!("'{}'", arg)),
21072116 }
21082117 }
21092118
2110− let nonexistent_buffers: Vec<_> = nonexistent_buffers
2111− .into_iter()
2112− .map(|str| format!("'{}'", str))
2113− .collect();
2114− editor.set_error(format!(
2115− "couldn't close buffer(s) {}: does not exist",
2116− nonexistent_buffers.join(", ")
2117− ));
2119+ if !nonexistent_buffers.is_empty() {
2120+ editor.set_error(format!(
2121+ "cannot close non-existent buffers: {}",
2122+ nonexistent_buffers.join(", ")
2123+ ));
2124+ }
21182125
2119− Ok(())
2126+ document_ids
21202127 }
21212128
21222129 fn buffer_close(
@@ -2124,7 +2131,8 @@ pub mod cmd {
21242131 args: &[Cow<str>],
21252132 _event: PromptEvent,
21262133 ) -> anyhow::Result<()> {
2127− buffer_close_impl(cx.editor, args, false)
2134+ let document_ids = buffer_gather_paths_impl(cx.editor, args);
2135+ buffer_close_by_ids_impl(cx.editor, &document_ids, false)
21282136 }
21292137
21302138 fn force_buffer_close(
@@ -2132,7 +2140,57 @@ pub mod cmd {
21322140 args: &[Cow<str>],
21332141 _event: PromptEvent,
21342142 ) -> anyhow::Result<()> {
2135− buffer_close_impl(cx.editor, args, true)
2143+ let document_ids = buffer_gather_paths_impl(cx.editor, args);
2144+ buffer_close_by_ids_impl(cx.editor, &document_ids, true)
2145+ }
2146+
2147+ fn buffer_gather_others_impl(editor: &mut Editor) -> Vec<DocumentId> {
2148+ let current_document = &doc!(editor).id();
2149+ editor
2150+ .documents()
2151+ .map(|doc| doc.id())
2152+ .filter(|doc_id| doc_id != current_document)
2153+ .collect()
2154+ }
2155+
2156+ fn buffer_close_others(
2157+ cx: &mut compositor::Context,
2158+ _args: &[Cow<str>],
2159+ _event: PromptEvent,
2160+ ) -> anyhow::Result<()> {
2161+ let document_ids = buffer_gather_others_impl(cx.editor);
2162+ buffer_close_by_ids_impl(cx.editor, &document_ids, false)
2163+ }
2164+
2165+ fn force_buffer_close_others(
2166+ cx: &mut compositor::Context,
2167+ _args: &[Cow<str>],
2168+ _event: PromptEvent,
2169+ ) -> anyhow::Result<()> {
2170+ let document_ids = buffer_gather_others_impl(cx.editor);
2171+ buffer_close_by_ids_impl(cx.editor, &document_ids, true)
2172+ }
2173+
2174+ fn buffer_gather_all_impl(editor: &mut Editor) -> Vec<DocumentId> {
2175+ editor.documents().map(|doc| doc.id()).collect()
2176+ }
2177+
2178+ fn buffer_close_all(
2179+ cx: &mut compositor::Context,
2180+ _args: &[Cow<str>],
2181+ _event: PromptEvent,
2182+ ) -> anyhow::Result<()> {
2183+ let document_ids = buffer_gather_all_impl(cx.editor);
2184+ buffer_close_by_ids_impl(cx.editor, &document_ids, false)
2185+ }
2186+
2187+ fn force_buffer_close_all(
2188+ cx: &mut compositor::Context,
2189+ _args: &[Cow<str>],
2190+ _event: PromptEvent,
2191+ ) -> anyhow::Result<()> {
2192+ let document_ids = buffer_gather_all_impl(cx.editor);
2193+ buffer_close_by_ids_impl(cx.editor, &document_ids, true)
21362194 }
21372195
21382196 fn write_impl(cx: &mut compositor::Context, path: Option<&Cow<str>>) -> anyhow::Result<()> {
@@ -2970,6 +3028,34 @@ pub mod cmd {
29703028 fun: force_buffer_close,
29713029 completer: Some(completers::buffer),
29723030 },
3031+ TypableCommand {
3032+ name: "buffer-close-others",
3033+ aliases: &["bco", "bcloseother"],
3034+ doc: "Close all buffers but the currently focused one.",
3035+ fun: buffer_close_others,
3036+ completer: None,
3037+ },
3038+ TypableCommand {
3039+ name: "buffer-close-others!",
3040+ aliases: &["bco!", "bcloseother!"],
3041+ doc: "Close all buffers but the currently focused one.",
3042+ fun: force_buffer_close_others,
3043+ completer: None,
3044+ },
3045+ TypableCommand {
3046+ name: "buffer-close-all",
3047+ aliases: &["bca", "bcloseall"],
3048+ doc: "Close all buffers, without quiting.",
3049+ fun: buffer_close_all,
3050+ completer: None,
3051+ },
3052+ TypableCommand {
3053+ name: "buffer-close-all!",
3054+ aliases: &["bca!", "bcloseall!"],
3055+ doc: "Close all buffers forcefully (ignoring unsaved changes), without quiting.",
3056+ fun: force_buffer_close_all,
3057+ completer: None,
3058+ },
29733059 TypableCommand {
29743060 name: "write",
29753061 aliases: &["w"],