use crate::binding::{Workspace, WorkspaceKind};
use crate::nav::ws_key;
use std::path::PathBuf;
#[derive(Debug, Clone)]
pub struct Item {
pub ws: Workspace,
pub attention: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Kind {
Named,
Foreign,
Replay,
}
impl Kind {
fn of(kind: &WorkspaceKind) -> Self {
match kind {
WorkspaceKind::Named { .. } => Self::Named,
WorkspaceKind::Foreign => Self::Foreign,
WorkspaceKind::Replay => Self::Replay,
}
}
pub fn mark(self) -> Option<&'static str> {
match self {
Self::Named => None,
Self::Foreign => Some("foreign"),
Self::Replay => Some("⏮ replay"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Tab {
pub ws: PathBuf,
pub name: String,
pub attention: usize,
pub selected: bool,
pub pinned: bool,
pub kind: Kind,
}
impl Tab {
pub fn kind_suffix(&self) -> String {
self.kind
.mark()
.map(|mark| format!(" · {mark}"))
.unwrap_or_default()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct TabBar {
pub tabs: Vec<Tab>,
pub overflow: Vec<Tab>,
}
impl TabBar {
pub fn overflow_attention(&self) -> usize {
self.overflow
.iter()
.filter(|t| !t.pinned)
.map(|t| t.attention)
.sum()
}
}
pub fn build(items: &[Item], pinned: &[String], focused: Option<&std::path::Path>) -> TabBar {
let mut tabs: Vec<Tab> = Vec::new();
for key in pinned {
if let Some(it) = items.iter().find(|it| ws_key(&it.ws.path) == *key) {
tabs.push(tab(it, focused, true));
}
}
let mut named: Vec<Tab> = items
.iter()
.filter(|it| !is_pinned(it, pinned) && Kind::of(&it.ws.kind) == Kind::Named)
.map(|it| tab(it, focused, false))
.collect();
named.sort_by(|a, b| a.name.cmp(&b.name));
tabs.extend(named);
let overflow = items
.iter()
.filter(|it| Kind::of(&it.ws.kind) != Kind::Named)
.map(|it| tab(it, focused, is_pinned(it, pinned)))
.collect();
TabBar { tabs, overflow }
}
fn is_pinned(it: &Item, pinned: &[String]) -> bool {
pinned.iter().any(|k| *k == ws_key(&it.ws.path))
}
fn tab(it: &Item, focused: Option<&std::path::Path>, pinned: bool) -> Tab {
let name = it
.ws
.path
.file_name()
.map(|s| s.to_string_lossy().into_owned())
.unwrap_or_default();
Tab {
ws: it.ws.path.clone(),
name,
attention: it.attention,
selected: focused == Some(it.ws.path.as_path()),
pinned,
kind: Kind::of(&it.ws.kind),
}
}
#[cfg(test)]
mod tests;