magi-code 0.64.0

Repository-aware CLI coding agent for terminal work
Documentation
use super::{PICKER_MODAL, draw_modal_panel, picker_modal_list_area};
use crate::tui::{state::MissionControlState, theme::MATRIX_GREEN};
use ratatui::{
    Frame,
    layout::{Rect, Size},
    text::{Line, Span},
    widgets::{List, ListItem, ListState, Paragraph},
};
use tui_scrollview::{ScrollView, ScrollbarVisibility};

pub(crate) fn model_picker_list_area(area: Rect, has_notice: bool) -> Option<Rect> {
    let header_rows = 1 + u16::from(has_notice);
    picker_modal_list_area(area, "Model Picker", header_rows)
}

pub(in crate::tui::render) fn draw_model_picker(
    frame: &mut Frame<'_>,
    area: Rect,
    state: &MissionControlState,
) {
    let Some(picker) = &state.modals.model_picker else {
        return;
    };
    let Some(text_area) = draw_modal_panel(frame, area, "Model Picker", PICKER_MODAL) else {
        return;
    };
    if text_area.height == 0 {
        return;
    }
    let header = format!("current: {}", picker.current_model_id);
    frame.render_widget(
        Paragraph::new(header).style(MATRIX_GREEN.pane()),
        Rect::new(text_area.x, text_area.y, text_area.width, 1),
    );
    let mut list_y = text_area.y.saturating_add(1);
    if let Some(notice) = &picker.notice
        && list_y < text_area.y.saturating_add(text_area.height)
    {
        frame.render_widget(
            Paragraph::new(notice.clone()).style(MATRIX_GREEN.muted(false)),
            Rect::new(text_area.x, list_y, text_area.width, 1),
        );
        list_y = list_y.saturating_add(1);
    }
    let list_height = text_area
        .y
        .saturating_add(text_area.height)
        .saturating_sub(list_y);
    if list_height == 0 {
        return;
    }
    let content_height =
        super::super::usize_to_u16_saturating(picker.entries.len().max(usize::from(list_height)));
    let content_width =
        super::super::scroll_view_content_width(Rect::new(0, 0, text_area.width, list_height));
    let mut view = ScrollView::new(Size::new(content_width, content_height))
        .vertical_scrollbar_visibility(ScrollbarVisibility::Always)
        .horizontal_scrollbar_visibility(ScrollbarVisibility::Never);
    let items = picker
        .entries
        .iter()
        .map(|entry| {
            let current = if entry.id == picker.current_model_id {
                ""
            } else {
                "  "
            };
            let mut parts = vec![Span::raw(format!("{current}{}", entry.id))];
            if let Some(context) = entry.context_window {
                parts.push(Span::raw(format!("  ctx:{context}")));
            }
            if let Some(name) = &entry.display_name {
                parts.push(Span::raw(format!("  {name}")));
            }
            ListItem::new(Line::from(parts))
        })
        .collect::<Vec<_>>();
    let mut list_state = ListState::default().with_selected(Some(picker.selected));
    view.render_stateful_widget(
        List::new(items)
            .style(MATRIX_GREEN.pane())
            .highlight_style(MATRIX_GREEN.selection())
            .highlight_symbol("> "),
        Rect::new(0, 0, content_width, content_height),
        &mut list_state,
    );
    frame.render_stateful_widget(
        view,
        Rect::new(text_area.x, list_y, text_area.width, list_height),
        &mut *state.scroll_views.model_picker.borrow_mut(),
    );
}