termit 0.7.0

Terminal UI over crossterm
Documentation
use super::events::{AppEvent, Event};
use crate::{
    prelude::Point,
    sys::{get_terminal_size_no_sys, Control},
};
use futures_lite::{io, Stream};
use std::{
    pin::Pin,
    task::{Context, Poll},
};

pub(crate) struct Resizer<C, S> {
    inner: Pin<Box<S>>,
    size: Option<Point>,
    fails: bool,
    control: Pin<Box<C>>,
}

impl<C, S, A: AppEvent> Resizer<C, S>
where
    S: Stream<Item = io::Result<Event<A>>>,
{
    pub fn new(inner: Pin<Box<S>>, control: Pin<Box<C>>) -> Self {
        Self {
            inner,
            size: Default::default(),
            fails: false,
            control,
        }
    }
    fn send(&mut self) -> Poll<Option<io::Result<Event<A>>>>
    where
        C: Control,
    {
        let new_size = match self.control.as_ref().get_size() {
            Ok(size) => size,
            Err(_) => {
                // let's not try again if it fails once
                self.fails = true;
                get_terminal_size_no_sys().or(self.size).unwrap_or_default()
            }
        };
        if Some(new_size) != self.size {
            self.size = Some(new_size);
            return Poll::Ready(Some(Ok(Event::Resize(new_size))));
        }
        Poll::Pending
    }
}

impl<C, S, A: AppEvent> Stream for Resizer<C, S>
where
    C: Control,
    S: Stream<Item = io::Result<Event<A>>>,
{
    type Item = io::Result<Event<A>>;

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        if self.size.is_none() {
            // always send size on first poll
            return self.send();
        }
        if let ready @ Poll::Ready(_) = self.inner.as_mut().poll_next(cx) {
            return ready;
        }
        if !self.fails {
            //self.sent_resize = true;
            return self.send();
        }
        Poll::Pending
    }
}