diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 4a6c08894719..159edd3aa9ab 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -46,7 +46,7 @@ use helix_core::{ }; use helix_view::{ document::{FormatterError, Mode, SCRATCH_BUFFER_NAME}, - editor::Action, + editor::{Action, CloseError}, expansion, info::Info, input::KeyEvent, @@ -3157,8 +3157,6 @@ fn file_explorer_in_current_directory(cx: &mut Context) { } fn buffer_picker(cx: &mut Context) { - let current = view!(cx.editor).doc; - struct BufferMeta { id: DocumentId, path: Option, @@ -3167,23 +3165,30 @@ fn buffer_picker(cx: &mut Context) { focused_at: std::time::Instant, } - let new_meta = |doc: &Document| BufferMeta { - id: doc.id(), - path: doc.path().cloned(), - is_modified: doc.is_modified(), - is_current: doc.id() == current, - focused_at: doc.focused_at, - }; + let get_items = |editor: &Editor| -> Vec { + let current = view!(editor).doc; - let mut items = cx - .editor - .documents - .values() - .map(new_meta) - .collect::>(); + let new_meta = |doc: &Document| BufferMeta { + id: doc.id(), + path: doc.path().cloned(), + is_modified: doc.is_modified(), + is_current: doc.id() == current, + focused_at: doc.focused_at, + }; - // mru - items.sort_unstable_by_key(|item| std::cmp::Reverse(item.focused_at)); + let mut items = editor + .documents + .values() + .map(new_meta) + .collect::>(); + + // mru + items.sort_unstable_by_key(|item| std::cmp::Reverse(item.focused_at)); + + items + }; + + let items = get_items(cx.editor); let columns = [ PickerColumn::new("id", |meta: &BufferMeta, _| meta.id.to_string().into()), @@ -3234,6 +3239,19 @@ fn buffer_picker(cx: &mut Context) { (cursor_line, cursor_line) }); Some((meta.id.into(), lines)) + }) + .with_delete_item(move |editor, meta| { + if let Err(err) = editor.close_document(meta.id, false) { + editor.set_error(match err { + CloseError::BufferModified(s) => format!("Could not close modified buffer: {}", s), + CloseError::SaveError(s) => format!("Could not close buffer: {}", s), + CloseError::DoesNotExist => "Buffer does not exist".to_owned(), + }); + } else { + editor.clear_status(); + } + + get_items(editor) }); cx.push_layer(Box::new(overlaid(picker))); } diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 4f77f8b92c59..57b7b3bb9d55 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -269,6 +269,8 @@ pub struct Picker { /// An event handler for syntax highlighting the currently previewed file. preview_highlight_handler: Sender>, dynamic_query_handler: Option>, + /// Called to delete an item from the picker's list. + delete_item_fn: Option>, } impl Picker { @@ -394,6 +396,7 @@ impl Picker { file_fn: None, preview_highlight_handler: PreviewHighlightHandler::::default().spawn(), dynamic_query_handler: None, + delete_item_fn: None, } } @@ -434,6 +437,11 @@ impl Picker { self } + pub fn with_delete_item(mut self, f: impl Fn(&mut Editor, &T) -> Vec + 'static) -> Self { + self.delete_item_fn = Some(Box::new(f)); + self + } + pub fn with_dynamic_query( mut self, callback: DynQueryCallback, @@ -1143,6 +1151,20 @@ impl Component for Picker { self.toggle_preview(); } + alt!('d') | key!(Delete) => { + if let Some(option) = self.selection() { + if let Some(delete_fn) = &self.delete_item_fn { + let new_items = delete_fn(ctx.editor, option); + let new_len = new_items.len() as u32; + self.matcher.restart(false); + let injector = self.matcher.injector(); + for item in new_items { + inject_nucleo_item(&injector, &self.columns, item, &self.editor_data); + } + self.cursor = self.cursor.min(new_len.saturating_sub(1)); + } + } + } _ => { self.prompt_handle_event(event, ctx); } @@ -1187,3 +1209,4 @@ impl Drop for Picker { } type PickerCallback = Box; +type PickerDeleteItem = Box Vec>;