matrixcode-tui 0.4.8

MatrixCode TUI - Terminal UI library for AI Code Agent
Documentation
//! TUI drawing module.

mod helpers;
mod hint;  // New hint bar module
mod input;
mod messages;
mod status;

use crate::app::TuiApp;
use ratatui::layout::Rect;

impl TuiApp {
    pub(crate) fn draw(&self, f: &mut ratatui::Frame) {
        let total_height = f.area().height;
        let width = f.area().width;

        // Fixed heights for bottom components
        let status_height: u16 = 1;
        let hint_height: u16 = if self.should_show_hint() { 1 } else { 0 };
        let gap_height: u16 = 1;
        let queue_height: u16 = if self.pending_messages.is_empty() { 0 } else { 1 };

        // Dynamic input height based on content
        let input_height: u16 = self.calculate_input_height();

        // Calculate reserved height from bottom
        let reserved = status_height + input_height + hint_height + gap_height + queue_height;

        // Messages height: what's left, minimum 5 lines
        let messages_height = total_height.saturating_sub(reserved).max(5);

        // Ensure messages_height doesn't exceed available space
        let messages_height = messages_height.min(total_height.saturating_sub(reserved));

        // Calculate Y positions from bottom up
        let status_y = total_height - status_height;
        let input_y = status_y - input_height;
        let hint_y = input_y - hint_height;
        let gap_y = hint_y - gap_height;
        let queue_y = gap_y - queue_height;

        // Create areas - messages area starts from top (y=0)
        let messages_area = Rect::new(0, 0, width, messages_height);
        let queue_area = Rect::new(0, queue_y, width, queue_height);
        let hint_area = Rect::new(0, hint_y, width, hint_height);
        let input_area = Rect::new(0, input_y, width, input_height);
        let status_area = Rect::new(0, status_y, width, status_height);

        // Render in order: messages first (top), then bottom components
        self.draw_messages(f, messages_area);
        if queue_height > 0 {
            self.draw_queue(f, queue_area);
        }
        if hint_height > 0 {
            self.draw_hint(f, hint_area);
        }
        self.draw_input(f, input_area);
        self.draw_status(f, status_area);
    }

    /// Calculate required input area height based on current state
    pub(crate) fn calculate_input_height(&self) -> u16 {
        let base_height: u16 = 2; // Default for single line input

        // Ask mode with options needs 2 lines (prompt + options)
        if self.activity == crate::types::Activity::Asking && self.waiting_for_ask && !self.ask_options.is_empty() {
            return 2;
        }

        // Multiline input: calculate based on line count
        if self.input.contains('\n') {
            let line_count = self.input.lines().count() as u16;
            // Add 1 for char count line if needed
            let extra = if self.input.chars().count() > 50 || line_count > 1 {
                1
            } else {
                0
            };
            // Cap at reasonable max (leave room for messages)
            return (line_count + extra).min(6).max(base_height);
        }

        base_height
    }
}