From 2ba49e9fc8939aa5b18874a54fb582fa1e1ac19c Mon Sep 17 00:00:00 2001 From: Mason Johnson Date: Sun, 31 Mar 2024 20:46:19 -0600 Subject: [PATCH 1/2] implement buffer ordering --- helix-term/src/commands.rs | 38 ++++++++++++++++++++++++++---- helix-term/src/ui/editor.rs | 46 +++++++++++++++++++------------------ helix-view/src/editor.rs | 14 +++++++++++ 3 files changed, 72 insertions(+), 26 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index d927d3f471b0..cec9cd9d1add 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -509,6 +509,8 @@ impl MappableCommand { command_palette, "Open command palette", goto_word, "Jump to a two-character label", extend_to_word, "Extend to a two-character label", + buffer_order_increment, "Increment current buffer's order", + buffer_order_decrement, "Decrement current buffer's order", ); } @@ -800,16 +802,16 @@ fn goto_buffer(editor: &mut Editor, direction: Direction) { let id = match direction { Direction::Forward => { - let iter = editor.documents.keys(); + let iter = editor.document_ordering.iter(); let mut iter = iter.skip_while(|id| *id != ¤t); iter.next(); // skip current item - iter.next().or_else(|| editor.documents.keys().next()) + iter.next().or_else(|| editor.document_ordering.first()) } Direction::Backward => { - let iter = editor.documents.keys(); + let iter = editor.document_ordering.iter(); let mut iter = iter.rev().skip_while(|id| *id != ¤t); iter.next(); // skip current item - iter.next().or_else(|| editor.documents.keys().next_back()) + iter.next().or_else(|| editor.document_ordering.last()) } } .unwrap(); @@ -5840,6 +5842,34 @@ fn extend_to_word(cx: &mut Context) { jump_to_word(cx, Movement::Extend) } +fn buffer_order_increment(cx: &mut Context) { + let current_doc_id = doc_mut!(cx.editor).id(); + let doc_idx = cx + .editor + .document_ordering + .iter() + .position(|id| id == ¤t_doc_id) + .unwrap(); + + if doc_idx < cx.editor.document_ordering.len() - 1 { + cx.editor.document_ordering.swap(doc_idx, doc_idx + 1); + } +} + +fn buffer_order_decrement(cx: &mut Context) { + let current_doc_id = doc_mut!(cx.editor).id(); + let doc_idx = cx + .editor + .document_ordering + .iter() + .position(|id| id == ¤t_doc_id) + .unwrap(); + + if doc_idx > 0 { + cx.editor.document_ordering.swap(doc_idx, doc_idx - 1); + } +} + fn jump_to_label(cx: &mut Context, labels: Vec, behaviour: Movement) { let doc = doc!(cx.editor); let alphabet = &cx.editor.config().jump_label_alphabet; diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index ad7aa5c5a89a..aaed2817f56f 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -582,31 +582,33 @@ impl EditorView { let mut x = viewport.x; let current_doc = view!(editor).doc; - for doc in editor.documents() { - let fname = doc - .path() - .unwrap_or(&scratch) - .file_name() - .unwrap_or_default() - .to_str() - .unwrap_or_default(); - - let style = if current_doc == doc.id() { - bufferline_active - } else { - bufferline_inactive - }; + for doc_id in &editor.document_ordering { + if let Some(doc) = editor.documents.get(doc_id) { + let fname = doc + .path() + .unwrap_or(&scratch) + .file_name() + .unwrap_or_default() + .to_str() + .unwrap_or_default(); + + let style = if current_doc == doc.id() { + bufferline_active + } else { + bufferline_inactive + }; - let text = format!(" {}{} ", fname, if doc.is_modified() { "[+]" } else { "" }); - let used_width = viewport.x.saturating_sub(x); - let rem_width = surface.area.width.saturating_sub(used_width); + let text = format!(" {}{} ", fname, if doc.is_modified() { "[+]" } else { "" }); + let used_width = viewport.x.saturating_sub(x); + let rem_width = surface.area.width.saturating_sub(used_width); - x = surface - .set_stringn(x, viewport.y, text, rem_width as usize, style) - .0; + x = surface + .set_stringn(x, viewport.y, text, rem_width as usize, style) + .0; - if x >= surface.area.right() { - break; + if x >= surface.area.right() { + break; + } } } } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index dd360a78ebdd..75edddc3cd1e 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -937,6 +937,8 @@ pub struct Editor { pub next_document_id: DocumentId, pub documents: BTreeMap, + pub document_ordering: Vec, + // We Flatten<> to resolve the inner DocumentSavedEventFuture. For that we need a stream of streams, hence the Once<>. // https://stackoverflow.com/a/66875668 pub saves: HashMap>>, @@ -1085,6 +1087,7 @@ impl Editor { tree: Tree::new(area), next_document_id: DocumentId::default(), documents: BTreeMap::new(), + document_ordering: Vec::new(), saves: HashMap::new(), save_queue: SelectAll::new(), write_count: 0, @@ -1495,6 +1498,13 @@ impl Editor { // borrow, invalidating direct access to `doc.id`. let id = doc.id; self.documents.remove(&id); + if let Some(d_idx) = self + .document_ordering + .iter() + .position(|doc_id| doc_id == &id) + { + self.document_ordering.remove(d_idx); + } // Remove the scratch buffer from any jumplists for (view, _) in self.tree.views_mut() { @@ -1560,6 +1570,7 @@ impl Editor { DocumentId(unsafe { NonZeroUsize::new_unchecked(self.next_document_id.0.get() + 1) }); doc.id = id; self.documents.insert(id, doc); + self.document_ordering.push(id); let (save_sender, save_receiver) = tokio::sync::mpsc::unbounded_channel(); self.saves.insert(id, save_sender); @@ -1696,6 +1707,9 @@ impl Editor { } self.documents.remove(&doc_id); + if let Some(d_idx) = self.document_ordering.iter().position(|id| id == &doc_id) { + self.document_ordering.remove(d_idx); + } // If the document we removed was visible in all views, we will have no more views. We don't // want to close the editor just for a simple buffer close, so we need to create a new view From b154a74baa3807c8afd692d36176bad6171894ab Mon Sep 17 00:00:00 2001 From: Mason Johnson Date: Mon, 1 Apr 2024 18:05:33 -0600 Subject: [PATCH 2/2] add error logs --- helix-term/src/ui/editor.rs | 4 ++++ helix-view/src/editor.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index aaed2817f56f..67c39e6ad4eb 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -609,6 +609,10 @@ impl EditorView { if x >= surface.area.right() { break; } + } else { + log::error!( + "document id in document ordering not found in document list, ID: {doc_id}" + ) } } } diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 75edddc3cd1e..c7940d92b0e5 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -1504,6 +1504,8 @@ impl Editor { .position(|doc_id| doc_id == &id) { self.document_ordering.remove(d_idx); + } else { + log::error!("closed document not found in document ordering, ID: {id}") } // Remove the scratch buffer from any jumplists @@ -1709,6 +1711,8 @@ impl Editor { self.documents.remove(&doc_id); if let Some(d_idx) = self.document_ordering.iter().position(|id| id == &doc_id) { self.document_ordering.remove(d_idx); + } else { + log::error!("closed document not found in document ordering, ID: {doc_id}") } // If the document we removed was visible in all views, we will have no more views. We don't