add smart bufferline directories

pull/13344/head
mageowl 2025-04-15 07:44:52 -07:00
parent a4974f3d5a
commit 0df1ec27ce
2 changed files with 106 additions and 24 deletions

View File

@ -25,13 +25,13 @@ use helix_core::{
use helix_view::{ use helix_view::{
annotations::diagnostics::DiagnosticFilter, annotations::diagnostics::DiagnosticFilter,
document::{Mode, SCRATCH_BUFFER_NAME}, document::{Mode, SCRATCH_BUFFER_NAME},
editor::{CompleteAction, CursorShapeConfig}, editor::{BufferLineDirectories, CompleteAction, CursorShapeConfig},
graphics::{Color, CursorKind, Modifier, Rect, Style}, graphics::{Color, CursorKind, Modifier, Rect, Style},
input::{KeyEvent, MouseButton, MouseEvent, MouseEventKind}, input::{KeyEvent, MouseButton, MouseEvent, MouseEventKind},
keyboard::{KeyCode, KeyModifiers}, keyboard::{KeyCode, KeyModifiers},
Document, Editor, Theme, View, 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}; use tui::{buffer::Buffer as Surface, text::Span};
@ -632,13 +632,95 @@ impl EditorView {
let mut x = viewport.x; let mut x = viewport.x;
let current_doc = view!(editor).doc; 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<usize> = 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() { for doc in editor.documents() {
let path = doc.path().unwrap_or(&scratch); let fname = &fnames[&doc.id()];
let fname = path
.file_name()
.unwrap_or_default()
.to_str()
.unwrap_or_default();
let style = if current_doc == doc.id() { let style = if current_doc == doc.id() {
bufferline_active bufferline_active
@ -646,20 +728,7 @@ impl EditorView {
bufferline_inactive bufferline_inactive
}; };
let text = if editor.config().bufferline_show_parent { let text = format!(" {}{} ", fname, if doc.is_modified() { "[+]" } else { "" });
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 used_width = viewport.x.saturating_sub(x); let used_width = viewport.x.saturating_sub(x);
let rem_width = surface.area.width.saturating_sub(used_width); let rem_width = surface.area.width.saturating_sub(used_width);

View File

@ -333,7 +333,7 @@ pub struct Config {
/// Persistently display open buffers along the top /// Persistently display open buffers along the top
pub bufferline: BufferLine, pub bufferline: BufferLine,
/// Show the parent directory of files in the bufferline. /// Show the parent directory of files in the bufferline.
pub bufferline_show_parent: bool, pub bufferline_directories: BufferLineDirectories,
/// Vertical indent width guides. /// Vertical indent width guides.
pub indent_guides: IndentGuidesConfig, pub indent_guides: IndentGuidesConfig,
/// Whether to color modes with different colors. Defaults to `false`. /// Whether to color modes with different colors. Defaults to `false`.
@ -683,6 +683,19 @@ pub enum BufferLine {
Multiple, 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)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
pub enum LineNumber { pub enum LineNumber {
@ -1001,7 +1014,7 @@ impl Default for Config {
rulers: Vec::new(), rulers: Vec::new(),
whitespace: WhitespaceConfig::default(), whitespace: WhitespaceConfig::default(),
bufferline: BufferLine::default(), bufferline: BufferLine::default(),
bufferline_show_parent: false, bufferline_directories: BufferLineDirectories::default(),
indent_guides: IndentGuidesConfig::default(), indent_guides: IndentGuidesConfig::default(),
color_modes: false, color_modes: false,
soft_wrap: SoftWrap { soft_wrap: SoftWrap {