From 0df1ec27ceecb06b320ea4de9a7e43a689418691 Mon Sep 17 00:00:00 2001 From: mageowl <32573897+mageowl@users.noreply.github.com> Date: Tue, 15 Apr 2025 07:44:52 -0700 Subject: [PATCH] add smart bufferline directories --- helix-term/src/ui/editor.rs | 113 +++++++++++++++++++++++++++++------- helix-view/src/editor.rs | 17 +++++- 2 files changed, 106 insertions(+), 24 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 3d3de08e4..fb04e75c9 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -25,13 +25,13 @@ use helix_core::{ use helix_view::{ annotations::diagnostics::DiagnosticFilter, document::{Mode, SCRATCH_BUFFER_NAME}, - editor::{CompleteAction, CursorShapeConfig}, + editor::{BufferLineDirectories, CompleteAction, CursorShapeConfig}, graphics::{Color, CursorKind, Modifier, Rect, Style}, input::{KeyEvent, MouseButton, MouseEvent, MouseEventKind}, keyboard::{KeyCode, KeyModifiers}, Document, Editor, Theme, View, }; -use std::{mem::take, num::NonZeroUsize, path::PathBuf, rc::Rc}; +use std::{collections::HashMap, mem::take, num::NonZeroUsize, path::PathBuf, rc::Rc}; use tui::{buffer::Buffer as Surface, text::Span}; @@ -632,13 +632,95 @@ impl EditorView { let mut x = viewport.x; let current_doc = view!(editor).doc; + let mut documents: HashMap<_, _>; + let fnames: HashMap<_, _> = match &editor.config().bufferline_directories { + BufferLineDirectories::Smart => { + documents = editor + .documents() + .map(|doc| { + ( + doc.id(), + doc.path().map(|p| { + let mut p = p.clone(); + let f = PathBuf::from(p.file_name().unwrap_or_default()); + p.pop(); + (f, p) + }), + ) + }) + .collect(); + let mut ids: Vec<_> = documents.keys().copied().collect(); + let mut to_remove: Vec = Vec::with_capacity(ids.len()); + while !ids.is_empty() { + for (idx, id) in ids.iter().enumerate() { + let Some((current, full)) = &documents[id] else { + log::info!("to remove scratch"); + to_remove.push(idx); + continue; + }; + if documents + .iter() + .filter_map(|(id, o)| o.as_ref().map(|(p, _)| (id, p))) + .all(|(i, p)| p != current || i == id) + || full.as_os_str().is_empty() + { + log::info!("to remove idx"); + to_remove.push(idx); + } + } + + for idx in to_remove.iter().rev() { + log::info!("removed idx"); + ids.remove(*idx); + } + to_remove.clear(); + + for id in &ids { + let Some((current, mut full)) = documents.remove(id).flatten() else { + documents.insert(*id, None); + continue; + }; + let mut new = PathBuf::from(full.file_name().unwrap_or_default()); + new.push(current); + full.pop(); + documents.insert(*id, Some((new, full))); + } + } + log::info!("completed cycle"); + documents + .iter() + .map(|(id, op)| { + ( + *id, + op.as_ref() + .map(|(p, _)| p.to_str().unwrap_or_default()) + .unwrap_or(SCRATCH_BUFFER_NAME), + ) + }) + .collect() + } + bufferline_directories => editor + .documents() + .map(|doc| { + ( + doc.id(), + if *bufferline_directories == BufferLineDirectories::Never { + doc.path() + .unwrap_or(&scratch) + .file_name() + .unwrap_or_default() + .to_str() + .unwrap_or_default() + } else { + doc.path().unwrap_or(&scratch).to_str().unwrap_or_default() + }, + ) + }) + .collect(), + }; + for doc in editor.documents() { - let path = doc.path().unwrap_or(&scratch); - let fname = path - .file_name() - .unwrap_or_default() - .to_str() - .unwrap_or_default(); + let fname = &fnames[&doc.id()]; let style = if current_doc == doc.id() { bufferline_active @@ -646,20 +728,7 @@ impl EditorView { bufferline_inactive }; - let text = if editor.config().bufferline_show_parent { - let parent_dir = path - .parent() - .and_then(|p| p.file_name().unwrap_or_default().to_str()) - .unwrap_or_default(); - format!( - " {}/{}{} ", - parent_dir, - fname, - if doc.is_modified() { "[+]" } else { "" } - ) - } else { - format!(" {}{} ", fname, if doc.is_modified() { "[+]" } else { "" }) - }; + 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); diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 9e6de7b85..05337ecd8 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -333,7 +333,7 @@ pub struct Config { /// Persistently display open buffers along the top pub bufferline: BufferLine, /// Show the parent directory of files in the bufferline. - pub bufferline_show_parent: bool, + pub bufferline_directories: BufferLineDirectories, /// Vertical indent width guides. pub indent_guides: IndentGuidesConfig, /// Whether to color modes with different colors. Defaults to `false`. @@ -683,6 +683,19 @@ pub enum BufferLine { Multiple, } +/// bufferline directory render modes +#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "kebab-case")] +pub enum BufferLineDirectories { + /// Only render filenames + #[default] + Never, + /// Always render one parent directory + One, + /// Only render directories for files with the same name + Smart, +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(rename_all = "kebab-case")] pub enum LineNumber { @@ -1001,7 +1014,7 @@ impl Default for Config { rulers: Vec::new(), whitespace: WhitespaceConfig::default(), bufferline: BufferLine::default(), - bufferline_show_parent: false, + bufferline_directories: BufferLineDirectories::default(), indent_guides: IndentGuidesConfig::default(), color_modes: false, soft_wrap: SoftWrap {