Codex Handbook
tui/src/bottom_pane/selection_tabs.rs 106 lines
use ratatui::buffer::Buffer;use ratatui::layout::Rect;use ratatui::style::Styled;use ratatui::style::Stylize;use ratatui::text::Line;use ratatui::text::Span;use ratatui::widgets::Widget;use crate::render::renderable::Renderable;use crate::style::accent_style;use super::SelectionItem;const TAB_GAP_WIDTH: usize = 2;pub(crate) struct SelectionTab {    pub(crate) id: String,    pub(crate) label: String,    pub(crate) header: Box<dyn Renderable>,    pub(crate) items: Vec<SelectionItem>,}pub(crate) fn tab_bar_height(tabs: &[SelectionTab], active_idx: usize, width: u16) -> u16 {    if tabs.is_empty() {        return 0;    }    tab_bar_lines(tabs, active_idx, width)        .len()        .try_into()        .unwrap_or(u16::MAX)}pub(crate) fn render_tab_bar(    tabs: &[SelectionTab],    active_idx: usize,    area: Rect,    buf: &mut Buffer,) {    for (offset, line) in tab_bar_lines(tabs, active_idx, area.width)        .into_iter()        .take(area.height as usize)        .enumerate()    {        line.render(            Rect {                x: area.x,                y: area.y.saturating_add(offset as u16),                width: area.width,                height: 1,            },            buf,        );    }}fn tab_bar_lines(tabs: &[SelectionTab], active_idx: usize, width: u16) -> Vec<Line<'static>> {    if tabs.is_empty() {        return Vec::new();    }    let max_width = width.max(1) as usize;    let mut lines = Vec::new();    let mut current_spans: Vec<Span<'static>> = Vec::new();    let mut current_width = 0usize;    for (idx, tab) in tabs.iter().enumerate() {        let unit = tab_unit(tab.label.as_str(), idx == active_idx);        let unit_width = Line::from(unit.clone()).width();        let gap_width = if current_spans.is_empty() {            0        } else {            TAB_GAP_WIDTH        };        if !current_spans.is_empty() && current_width + gap_width + unit_width > max_width {            lines.push(Line::from(current_spans));            current_spans = Vec::new();            current_width = 0;        }        if !current_spans.is_empty() {            current_spans.push("  ".into());            current_width += TAB_GAP_WIDTH;        }        current_width += unit_width;        current_spans.extend(unit);    }    if !current_spans.is_empty() {        lines.push(Line::from(current_spans));    }    lines}fn tab_unit(label: &str, active: bool) -> Vec<Span<'static>> {    if active {        let style = accent_style();        vec![            "[".set_style(style),            label.to_string().set_style(style),            "]".set_style(style),        ]    } else {        vec![label.to_string().dim()]    }}