mudrs-milk 0.0.1

WIP Mud Client
Documentation
use std::{
    io,
    sync::Arc,
    time::{
        Duration,
        Instant,
    },
};

use futures::{
    join,
    lock::Mutex,
};
#[allow(unused_imports)]
use tracing::debug;
use tui::{
    backend::Backend,
    layout::{
        Constraint,
        Direction,
        Layout,
    },
    Terminal,
};

use crate::widget::{
    input::InputBuffer,
    scrollback::ScrollbackBuffer,
};

pub struct Renderer<T: Backend> {
    pub terminal: Terminal<T>,

    input_handle: Arc<Mutex<InputBuffer>>,

    scrollback_handle: Arc<Mutex<ScrollbackBuffer>>,

    frame_duration: Duration,
    last_refresh: Instant,
}

impl<T: Backend> Renderer<T> {
    pub fn new(
        mut backend: T,
        input_handle: Arc<Mutex<InputBuffer>>,
        scrollback_handle: Arc<Mutex<ScrollbackBuffer>>,
        max_refresh: f64,
    ) -> Result<Self, io::Error> {
        backend.clear()?;
        let terminal = Terminal::new(backend)?;
        Ok(Renderer {
            terminal,
            input_handle,
            scrollback_handle,

            last_refresh: Instant::now(),

            frame_duration: Duration::from_secs_f64(1f64 / max_refresh),
        })
    }

    pub async fn render(&mut self) -> Result<(), anyhow::Error> {
        let terminal = &mut self.terminal;
        let (input, scrollback) = join!(self.input_handle.lock(), self.scrollback_handle.lock());

        let now = Instant::now();
        if now - self.last_refresh < self.frame_duration {
            return Ok(());
        }
        self.last_refresh = now;

        // terminal.hide_cursor()?;
        terminal.draw(|f| {
            let size = f.size();

            let input_lines = input.wrapped(size.width as usize);
            let chunks = Layout::default()
                .direction(Direction::Vertical)
                .margin(0)
                .constraints(
                    [
                        // Constraint::Length(1),
                        Constraint::Min(1),
                        Constraint::Length(input_lines.len() as u16),
                    ]
                    .as_ref(),
                )
                .split(f.size());

            let input_chunk = chunks[1];
            let output_chunk = chunks[0];

            let (cursor_x, cursor_y) = input_lines.cursor_pos();
            f.render_widget(input_lines, input_chunk);

            let scrollback = scrollback.widget();
            f.render_widget(scrollback, output_chunk);

            // Make the cursor visible and ask tui-rs to put it at the specified coordinates after rendering
            f.set_cursor(
                input_chunk.x + cursor_x as u16,
                input_chunk.y + cursor_y as u16,
            );
        })?;
        // terminal.show_cursor()?;
        Ok(())
    }
}