tui-lipan 0.1.0

Opinionated, component-based TUI framework for Rust - declarative components, reconciliation, layout engine, focus, overlays, and rich widgets on top of ratatui.
Documentation
use std::cell::{Cell, RefCell};
use std::io::Write;

use crossterm::{execute, style::Print};
use ratatui::TerminalOptions;
use ratatui::backend::CrosstermBackend;

use crate::Result;
use crate::app::ContrastPolicy;
use crate::backend::ratatui_backend::common::to_ratatui_color;
use crate::backend::ratatui_backend::render::{
    RenderContext, build_join_index, render as render_tree,
};
use crate::core::element::Element;
use crate::core::node::NodeTree;
use crate::layout::measure::min_size_constrained;
use crate::layout::reconcile::reconcile_with_overlays_mode;
use crate::style::{Color, Rect, Style};

pub(crate) fn render(
    element: Element,
    contrast_policy: ContrastPolicy,
    terminal_bg: Option<Color>,
) -> Result<()> {
    let width = crossterm::terminal::size()?.0.max(1);
    let height = min_size_constrained(&element, Some(width), None).1;

    if height == 0 {
        return Ok(());
    }

    let bounds = Rect {
        x: 0,
        y: 0,
        w: width,
        h: height,
    };

    let mut tree = NodeTree::new();
    reconcile_with_overlays_mode(&mut tree, &element, bounds, None, &[], true);
    let join_index = build_join_index(&tree);

    let scrollbar_metrics_cache = RefCell::new(Default::default());
    let overlay_bg_snapshot = RefCell::new(Vec::new());
    let cursor_position = Cell::new(None);
    let ctx = RenderContext {
        tree: &tree,
        focused: None,
        hovered: None,
        mouse_pos: None,
        suppress_pointer_item_hover_nodes: None,
        blink_visible: true,
        effect_phase: 0,
        images_enabled: false,
        contrast_policy,
        read_only_selection: None,
        scrollbar_metrics_cache: &scrollbar_metrics_cache,
        overlay_bg_snapshot: &overlay_bg_snapshot,
        join_index: &join_index,
        cursor_position: &cursor_position,
        terminal_bg: terminal_bg.map(to_ratatui_color),
        drag_preview_label: None,
        drag_preview_at_mouse: false,
        drag_preview_snapshot_rect: None,
        dnd_snapshot_cells: &RefCell::new(None),
        drag_preview_max_width: None,
        drag_preview_max_height: None,
        drop_slot_source_preview_rect: None,
        paint_glyph_caches: None,
        copy_feedback: None,
        copy_feedback_style: Style::default(),
    };

    {
        let backend = CrosstermBackend::new(std::io::stdout());
        let mut terminal = ratatui::Terminal::with_options(
            backend,
            TerminalOptions {
                viewport: ratatui::Viewport::Inline(height),
            },
        )?;
        terminal.draw(|f| render_tree(f, &ctx))?;
    }

    let mut stdout = std::io::stdout();
    execute!(stdout, Print("\n"))?;
    stdout.flush()?;
    Ok(())
}