From f5081af1eea6fba44f12396617e02e42c8b165e1 Mon Sep 17 00:00:00 2001 From: metafates Date: Sat, 13 Apr 2024 21:24:13 +0300 Subject: [PATCH] normalize bufferline duplicate file names --- helix-term/src/ui/editor.rs | 107 ++++++++++++++++++++++++++++++++---- 1 file changed, 97 insertions(+), 10 deletions(-) diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 7b130a38a..0640f1831 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -25,9 +25,12 @@ use helix_view::{ graphics::{Color, CursorKind, Modifier, Rect, Style}, input::{KeyEvent, MouseButton, MouseEvent, MouseEventKind}, keyboard::{KeyCode, KeyModifiers}, - Document, Editor, Theme, View, + Document, DocumentId, Editor, Theme, View, +}; +use std::{ + collections::HashMap, fmt::Display, mem::take, num::NonZeroUsize, path::PathBuf, rc::Rc, + sync::Arc, }; -use std::{mem::take, num::NonZeroUsize, path::PathBuf, rc::Rc, sync::Arc}; use tui::{buffer::Buffer as Surface, text::Span}; @@ -579,7 +582,6 @@ impl EditorView { /// Render bufferline at the top pub fn render_bufferline(editor: &Editor, viewport: Rect, surface: &mut Surface) { - let scratch = PathBuf::from(SCRATCH_BUFFER_NAME); // default filename to use for scratch buffer surface.clear_with( viewport, editor @@ -601,14 +603,14 @@ impl EditorView { let mut x = viewport.x; let current_doc = view!(editor).doc; + let documents_paths = build_bufferline_paths(editor); + for doc in editor.documents() { - let fname = doc - .path() - .unwrap_or(&scratch) - .file_name() - .unwrap_or_default() - .to_str() - .unwrap_or_default(); + let fname = if let Some(name) = documents_paths.get(&doc.id()) { + name.to_string() + } else { + SCRATCH_BUFFER_NAME.to_string() + }; let style = if current_doc == doc.id() { bufferline_active @@ -1581,6 +1583,91 @@ impl Component for EditorView { } } +struct LevelledPathBuf { + path_buf: PathBuf, + level: usize, +} + +impl LevelledPathBuf { + pub fn new(path: PathBuf) -> Self { + LevelledPathBuf { + path_buf: path, + level: 1, + } + } + + pub fn increment(&mut self) { + self.level += 1; + } +} + +impl Display for LevelledPathBuf { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let components: Vec<_> = self.path_buf.components().rev().take(self.level).collect(); + + let path = components + .into_iter() + .rev() + .fold(PathBuf::new(), |acc, curr| acc.join(curr)); + + f.write_str(path.to_str().unwrap_or_default().to_string().as_str()) + } +} + +fn get_ids_of_duplicate_paths( + levels: &HashMap, +) -> Option> { + let mut duplicates: HashMap> = HashMap::new(); + + for (id, path) in levels { + let name = path.to_string(); + + if let Some(v) = duplicates.get_mut(&name) { + v.push(id.to_owned()); + } else { + duplicates.insert(name, vec![id.to_owned()]); + } + } + + duplicates + .into_iter() + .filter_map(|s| if s.1.len() > 1 { Some(s.1) } else { None }) + .reduce(|mut acc, mut curr| { + acc.append(&mut curr); + + acc + }) +} + +fn adjust_paths_levels(levels: &mut HashMap) { + while let Some(duplicates) = get_ids_of_duplicate_paths(&levels) { + for id in duplicates { + if let Some(level) = levels.get_mut(&id) { + level.increment() + } + } + } +} + +fn build_bufferline_paths(editor: &Editor) -> HashMap { + let mut levels: HashMap = editor + .documents() + .filter_map(|d| { + if let Some(path) = d.relative_path() { + Some((d.id(), LevelledPathBuf::new(path.to_path_buf()))) + } else if let Some(path) = d.path() { + Some((d.id(), LevelledPathBuf::new(path.to_owned()))) + } else { + None + } + }) + .collect(); + + adjust_paths_levels(&mut levels); + + levels +} + fn canonicalize_key(key: &mut KeyEvent) { if let KeyEvent { code: KeyCode::Char(_),