quinjet 0.0.50

A fast, live, keyboard-first Git source-control interface for the terminal
#[cfg_attr(not(test), expect(clippy::wildcard_imports, reason = "shared"))]
use super::*;

#[expect(
    clippy::too_many_arguments,
    reason = "the picker receives its modal state, list geometry, and palette"
)]
pub(super) fn draw_stashes(
    frame: &mut Frame<'_>,
    items: &[Stash],
    selected: usize,
    query: &crate::app::TextBuffer,
    loading: bool,
    list: &mut ModalList<'_>,
    theme: &Theme,
) {
    let height = frame.area().height.saturating_sub(6).min(27);
    let area = centered_rect(
        frame.area().width.saturating_sub(10).min(88),
        height,
        frame.area(),
    );
    frame.render_widget(Clear, area);
    let block = modal_block(" Stashes ", theme);
    let inner = block.inner(area);
    frame.render_widget(block, area);
    let query_area = Rect::new(inner.x, inner.y, inner.width, 1);
    frame.render_widget(
        Paragraph::new(Line::from(vec![
            Span::styled(" / ", Style::default().fg(theme.accent)),
            Span::styled(query.value.as_str(), Style::default().fg(theme.text)),
        ]))
        .style(Style::default().bg(theme.panel_alt)),
        query_area,
    );
    set_text_cursor(
        frame,
        Rect::new(
            query_area.x + 3,
            query_area.y,
            query_area.width.saturating_sub(3),
            1,
        ),
        query,
        false,
    );
    let list_area = Rect::new(
        inner.x,
        inner.y + 2,
        inner.width,
        inner.height.saturating_sub(5),
    );
    if loading {
        frame.render_widget(
            Paragraph::new("Loading stashes…").style(Style::default().fg(theme.muted)),
            list_area,
        );
    } else {
        let visible = App::filtered_stashes(items, &query.value);
        let offset = list.offset(selected, list_area.height as usize, visible.len());
        let lines = visible
            .iter()
            .skip(offset)
            .take(list_area.height as usize)
            .enumerate()
            .filter_map(|(visible_offset, index)| {
                let stash = items.get(*index)?;
                let active = offset + visible_offset == selected;
                let background = if active { theme.selected } else { theme.panel };
                let branch = if stash.branch.is_empty() {
                    String::new()
                } else {
                    format!(" on {}", stash.branch)
                };
                Some(Line::from(vec![
                    Span::styled(
                        if active { "" } else { "   " },
                        Style::default().fg(theme.accent).bg(background),
                    ),
                    Span::styled(
                        format!("{}  ", stash.reference),
                        Style::default()
                            .fg(theme.modified)
                            .bg(background)
                            .add_modifier(Modifier::BOLD),
                    ),
                    Span::styled(
                        truncate_middle(
                            &stash.message,
                            list_area.width.saturating_sub(40) as usize,
                        ),
                        Style::default().fg(theme.text).bg(background),
                    ),
                    Span::styled(
                        format!(
                            "{branch}  {}  {}",
                            stash.short_id,
                            format_relative_timestamp(&stash.relative_date)
                        ),
                        Style::default().fg(theme.muted).bg(background),
                    ),
                ]))
            })
            .collect::<Vec<_>>();
        for index in 0..lines.len() {
            list.hit(
                Rect::new(
                    list_area.x,
                    list_area.y.saturating_add(cells(index)),
                    list_area.width,
                    1,
                ),
                offset.saturating_add(index),
            );
        }
        frame.render_widget(Paragraph::new(lines), list_area);
        if visible.is_empty() {
            frame.render_widget(
                Paragraph::new(if items.is_empty() {
                    "No stashes: Ctrl+n creates one"
                } else {
                    "No stashes match this filter"
                })
                .style(Style::default().fg(theme.muted)),
                list_area,
            );
        }
    }
    draw_modal_hint(
        frame,
        area,
        "Enter preview  Ctrl+n new  Ctrl+u +untracked  Ctrl+s staged  Alt+a apply  Alt+p pop  Del drop",
        theme,
    );
}