magi-code 0.77.1

Repository-aware CLI coding agent for terminal work
Documentation
use super::{input, render, state};

pub(crate) fn key_viewports(
    terminal_area: ratatui::layout::Rect,
    state: &state::MissionControlState,
) -> input::KeyViewports {
    let layout = render::layout_for(terminal_area, state);
    let prompt_viewport = layout.pane_area(render::TuiPane::Prompt).map(|area| {
        let text_area = render::content_text_area_for_pane(render::TuiPane::Prompt, area);
        input::PromptViewport {
            visible_rows: text_area.height.max(1),
            wrap_width: render::scroll_view_content_width(text_area).max(1),
        }
    });
    let transcript_viewport = layout.pane_area(render::TuiPane::Transcript).map(|area| {
        let text_area = render::content_text_area_for_pane(render::TuiPane::Transcript, area);
        input::TranscriptViewport {
            visible_rows: text_area.height.max(1),
            wrap_width: render::transcript_scroll_view_content_width(text_area).max(1),
        }
    });
    let activity_tree_viewport = layout.pane_area(render::TuiPane::ActivityTree).map(|area| {
        let text_area = render::content_text_area_for_pane(render::TuiPane::ActivityTree, area);
        input::ActivityTreeViewport {
            visible_rows: text_area.height.max(1),
        }
    });
    let detail_viewport = layout.pane_area(render::TuiPane::Detail).map(|area| {
        let text_area = render::content_text_area_for_pane(render::TuiPane::Detail, area);
        let visible_rows = state.detail_body_viewport_rows(
            text_area.height,
            render::scroll_view_content_width(text_area).max(1),
        );
        input::DetailViewport {
            visible_rows,
            wrap_width: render::scroll_view_content_width(text_area).max(1),
        }
    });
    let system_prompt_viewport =
        render::system_prompt_text_area(terminal_area).map(|area| input::SystemPromptViewport {
            visible_rows: area.height.max(1),
            wrap_width: render::scroll_view_content_width(area).max(1),
        });
    let subagent_viewer_viewport =
        render::subagent_viewer_timeline_area(terminal_area).map(|area| {
            input::SystemPromptViewport {
                visible_rows: area.height.max(1),
                wrap_width: render::scroll_view_content_width(area).max(1),
            }
        });
    let connect_provider_modal_visible = render::connect_provider_modal_visible(terminal_area);
    let connect_provider_custom_field_visible =
        render::connect_provider_custom_field_visible(terminal_area);
    let connect_provider_oauth_controls_visible =
        render::connect_provider_oauth_controls_visible(terminal_area);
    let connect_provider_oauth_fallback_visible =
        render::connect_provider_oauth_fallback_visible(terminal_area);
    let logout_confirmation_action_row =
        state
            .modals
            .logout_confirmation
            .as_ref()
            .and_then(|confirmation| {
                render::logout_confirmation_action_row_area(
                    terminal_area,
                    &confirmation.label,
                    &confirmation.provider_id,
                )
            });
    let connect_provider_viewport = state.modals.connect_provider.as_ref().and_then(|connect| {
        if connect.stage == state::ConnectProviderStage::ChooseProvider {
            picker_viewport(render::connect_provider_choice_list_area(terminal_area))
        } else {
            None
        }
    });
    let logout_picker_viewport = state.modals.logout_picker.as_ref().and_then(|picker| {
        picker_viewport(render::logout_picker_list_area(
            terminal_area,
            picker.notice.is_some(),
        ))
    });
    let model_picker_viewport = state.modals.model_picker.as_ref().and_then(|picker| {
        picker_viewport(render::model_picker_list_area(
            terminal_area,
            picker.notice.is_some(),
        ))
    });
    let skills_modal_viewport = picker_viewport(render::skills_modal_list_area(terminal_area));
    let skills_scope_visible = render::settings_scope_visible(terminal_area);
    let mcp_modal_viewport = picker_viewport(render::mcp_modal_list_area(terminal_area));
    let tools_modal_viewport = picker_viewport(render::tools_modal_list_area(terminal_area));
    let tools_scope_visible = render::settings_scope_visible(terminal_area);
    let subagents_modal_viewport =
        picker_viewport(render::subagents_modal_list_area(terminal_area));
    let subagents_scope_visible = render::settings_scope_visible(terminal_area);
    let session_picker_viewport_value = session_picker_viewport(terminal_area);
    let models_modal_viewport = picker_viewport(render::models_modal_list_area(terminal_area));
    let models_scope_visible = render::settings_scope_visible(terminal_area);
    let theme_picker_viewport = picker_viewport(render::theme_picker_list_area(terminal_area));
    let theme_query_visible = render::theme_picker_query_visible(terminal_area);
    input::KeyViewports {
        prompt: prompt_viewport,
        transcript: transcript_viewport,
        activity_tree: activity_tree_viewport,
        detail: detail_viewport,
        summary: layout
            .summary
            .map(|area| render::summary_section_body(area, state.session_files.focused)),
        system_prompt: system_prompt_viewport,
        rewind_modal: render::rewind_modal_text_area(terminal_area).map(|area| {
            input::SystemPromptViewport {
                visible_rows: area.height.max(1),
                wrap_width: render::scroll_view_content_width(area).max(1),
            }
        }),
        usage_modal: render::usage_modal_text_area(terminal_area).map(|area| {
            input::SystemPromptViewport {
                visible_rows: area.height.max(1),
                wrap_width: render::scroll_view_content_width(area).max(1),
            }
        }),
        connect_provider: connect_provider_viewport,
        connect_provider_modal_visible,
        connect_provider_custom_field_visible,
        connect_provider_oauth_controls_visible,
        connect_provider_oauth_fallback_visible,
        logout_picker: logout_picker_viewport,
        logout_confirmation_action_row,
        model_picker: model_picker_viewport,
        sessions_modal: session_picker_viewport_value,
        subagent_viewer: subagent_viewer_viewport,
        skills_modal: skills_modal_viewport,
        skills_scope_visible,
        mcp_modal: mcp_modal_viewport,
        tools_modal: tools_modal_viewport,
        tools_scope_visible,
        subagents_modal: subagents_modal_viewport,
        subagents_scope_visible,
        models_modal: models_modal_viewport,
        models_scope_visible,
        theme_picker: theme_picker_viewport,
        theme_query_visible,
    }
}

pub(crate) fn paste_viewports(
    terminal_area: ratatui::layout::Rect,
    state: &state::MissionControlState,
) -> input::KeyViewports {
    key_viewports(terminal_area, state)
}

fn picker_viewport(list_area: Option<ratatui::layout::Rect>) -> Option<input::PickerViewport> {
    list_area.map(|area| input::PickerViewport {
        visible_rows: area.height.max(1),
    })
}

fn session_picker_viewport(
    terminal_area: ratatui::layout::Rect,
) -> Option<input::SessionPickerViewport> {
    render::sessions_modal_areas(terminal_area).map(|areas| input::SessionPickerViewport {
        list_rows: areas.list.height.max(1),
        preview_rows: areas.preview.map(|area| area.height.max(1)).unwrap_or(1),
        preview_width: areas
            .preview
            .map(|area| render::scroll_view_content_width(area).max(1))
            .unwrap_or(1),
        preview_visible: areas.preview.is_some(),
    })
}