quinjet 0.0.40

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

pub(super) fn review_line_selected(app: &App, line: &DiffLine, old_side: Option<bool>) -> bool {
    let Some(cursor) = app.pull_request_review_cursor.as_ref() else {
        return false;
    };
    if app.pull_request_single_file.as_ref() != Some(&cursor.path) {
        return false;
    }
    match (cursor.side, old_side) {
        (crate::git::github::PullRequestReviewSide::Left, Some(false))
        | (crate::git::github::PullRequestReviewSide::Right, Some(true)) => false,
        (crate::git::github::PullRequestReviewSide::Left, _) => line.old_line == Some(cursor.line),
        (
            crate::git::github::PullRequestReviewSide::Right
            | crate::git::github::PullRequestReviewSide::Unknown,
            _,
        ) => line.new_line == Some(cursor.line),
    }
}

pub(super) fn draw_review_editor(
    frame: &mut Frame<'_>,
    title: &str,
    input: &crate::app::TextBuffer,
    decision: Option<crate::git::github::PullRequestReviewDecision>,
    theme: &Theme,
) {
    let width = frame.area().width.saturating_sub(12).min(76);
    let area = centered_rect(width, 12, frame.area());
    frame.render_widget(Clear, area);
    let block = modal_block(title, theme);
    let inner = block.inner(area);
    frame.render_widget(block, area);
    let input_y = inner.y + u16::from(decision.is_some());
    if let Some(selected) = decision {
        let labels = crate::git::github::PullRequestReviewDecision::ALL
            .iter()
            .map(|choice| {
                if *choice == selected {
                    Span::styled(
                        format!(" {} ", choice.label()),
                        Style::default()
                            .fg(theme.text)
                            .bg(theme.selected)
                            .add_modifier(Modifier::BOLD),
                    )
                } else {
                    Span::styled(
                        format!(" {} ", choice.label()),
                        Style::default().fg(theme.muted).bg(theme.panel_alt),
                    )
                }
            })
            .collect::<Vec<_>>();
        frame.render_widget(
            Paragraph::new(Line::from(labels)).style(Style::default().bg(theme.panel_alt)),
            Rect::new(inner.x, inner.y, inner.width, 1),
        );
    }
    let input_area = Rect::new(
        inner.x,
        input_y,
        inner.width,
        inner.bottom().saturating_sub(input_y).saturating_sub(1),
    );
    frame.render_widget(
        Paragraph::new(input.value.as_str())
            .style(Style::default().fg(theme.text).bg(theme.panel_alt))
            .wrap(Wrap { trim: false })
            .block(
                Block::default()
                    .borders(Borders::ALL)
                    .border_style(Style::default().fg(theme.border_focus)),
            ),
        input_area,
    );
    set_text_cursor(frame, input_area.inner(Margin::new(1, 1)), input, true);
    draw_modal_hint(
        frame,
        area,
        if decision.is_some() {
            "Tab decision   Ctrl+Enter submit   Esc close"
        } else {
            "Ctrl+Enter add to pending review   Esc close"
        },
        theme,
    );
}

pub(super) fn draw_review_thread_actions(
    frame: &mut Frame<'_>,
    hits: &mut Vec<(Rect, ModalAction)>,
    items: &[crate::app::PullRequestReviewThreadAction],
    selected: usize,
    theme: &Theme,
) {
    let width = items
        .iter()
        .map(|item| item.label().width())
        .max()
        .unwrap_or(24)
        .saturating_add(6);
    let height = items.len().saturating_add(3);
    let area = centered_rect(
        u16::try_from(width).unwrap_or(72).min(72),
        u16::try_from(height).unwrap_or(20).min(20),
        frame.area(),
    );
    frame.render_widget(Clear, area);
    let block = modal_block(" Review Thread ", theme);
    let inner = block.inner(area);
    frame.render_widget(block, area);
    for (index, item) in items.iter().enumerate() {
        let row = Rect::new(
            inner.x,
            inner.y.saturating_add(u16::try_from(index).unwrap_or(0)),
            inner.width,
            1,
        );
        frame.render_widget(
            Paragraph::new(format!("  {}", item.label())).style(if index == selected {
                Style::default().fg(theme.text).bg(theme.selected)
            } else {
                Style::default().fg(theme.text).bg(theme.panel)
            }),
            row,
        );
        hits.push((row, ModalAction::PullRequestReviewThreadAction(index)));
    }
    draw_modal_hint(frame, area, "j/k select   Enter open   Esc cancel", theme);
}