Radish alpha
r
Radicle terminal user interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
lib: Support multiple terminal viewports
Erik Kundt committed 1 year ago
commit 098adf470e5075929e8fe98259245fc099618138
parent aaa869bc44fc4ca7d405e882a1f0a3ffe6fa506b
7 files changed +28 -26
modified examples/basic.rs
@@ -1,5 +1,6 @@
use anyhow::Result;

+
use ratatui::Viewport;
use termion::event::Key;

use ratatui::layout::Constraint;
@@ -107,7 +108,7 @@ pub async fn main() -> Result<()> {
        })
        .on_update(|_| WindowProps::default().current_page(0).to_boxed_any().into());

-
    tui::rm(channel, app, window).await?;
+
    tui::rm(app, window, Viewport::default(), channel).await?;

    Ok(())
}
modified examples/hello.rs
@@ -1,5 +1,6 @@
use anyhow::Result;

+
use ratatui::Viewport;
use termion::event::Key;

use ratatui::style::Color;
@@ -69,7 +70,7 @@ pub async fn main() -> Result<()> {
                .into()
        });

-
    tui::rm(channel, app, scene).await?;
+
    tui::rm(app, scene, Viewport::default(), channel).await?;

    Ok(())
}
modified examples/hello_im.rs
@@ -2,7 +2,7 @@ use anyhow::Result;

use termion::event::Key;

-
use ratatui::Frame;
+
use ratatui::{Frame, Viewport};

use radicle_tui as tui;

@@ -67,7 +67,7 @@ pub async fn main() -> Result<()> {
        alien: ALIEN.to_string(),
    };

-
    tui::im(Channel::default(), app).await?;
+
    tui::im(app, Viewport::default(), Channel::default()).await?;

    Ok(())
}
modified src/lib.rs
@@ -7,6 +7,7 @@ pub mod ui;
use std::any::Any;
use std::fmt::Debug;

+
use ratatui::Viewport;
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};

use serde::ser::{Serialize, SerializeStruct, Serializer};
@@ -152,9 +153,10 @@ impl<A> Default for Channel<A> {
/// and run their main loops concurrently. Connect them to the `Channel` and also to
/// an interrupt broadcast channel also initialized in this function.
pub async fn rm<S, M, P>(
-
    channel: Channel<M>,
    state: S,
    root: rm::widget::Widget<S, M>,
+
    viewport: Viewport,
+
    channel: Channel<M>,
) -> Result<Option<P>>
where
    S: Update<M, Return = P> + Clone + Debug + Send + Sync + 'static,
@@ -168,7 +170,7 @@ where

    tokio::try_join!(
        store.run(state, terminator, channel.rx, interrupt_rx.resubscribe()),
-
        frontend.run(root, state_rx, interrupt_rx.resubscribe()),
+
        frontend.run(root, state_rx, interrupt_rx.resubscribe(), viewport),
    )?;

    if let Ok(reason) = interrupt_rx.recv().await {
@@ -184,11 +186,7 @@ where
/// Initialize a `Store` with the `State` given and a `Frontend` with the `App` given,
/// and run their main loops concurrently. Connect them to the `Channel` and also to
/// an interrupt broadcast channel also initialized in this function.
-
pub async fn im<S, M, P>(
-
    channel: Channel<M>,
-
    state: S,
-
    // app: impl im::App<State = S, Message = M>,
-
) -> Result<Option<P>>
+
pub async fn im<S, M, P>(state: S, viewport: Viewport, channel: Channel<M>) -> Result<Option<P>>
where
    S: Update<M, Return = P> + Show<M> + Clone + Debug + Send + Sync + 'static,
    M: Clone + Debug + Send + Sync + 'static,
@@ -202,7 +200,7 @@ where

    tokio::try_join!(
        store.run(state, terminator, channel.rx, interrupt_rx.resubscribe()),
-
        frontend.run(state_tx, state_rx, interrupt_rx.resubscribe()),
+
        frontend.run(state_tx, state_rx, interrupt_rx.resubscribe(), viewport),
    )?;

    if let Ok(reason) = interrupt_rx.recv().await {
modified src/terminal.rs
@@ -93,16 +93,17 @@ impl<W: Write> ratatui::backend::Backend for TermionBackendExt<W> {
}

/// Setup a `Terminal` with inline viewport using the `termion` backend.
-
pub fn setup(height: usize) -> anyhow::Result<Terminal<Backend>> {
+
pub fn setup(viewport: Viewport) -> anyhow::Result<Terminal<Backend>> {
+
    let is_fullscreen = viewport == Viewport::Fullscreen;
    let stdout = io::stdout().into_raw_mode()?;
-
    let options = TerminalOptions {
-
        viewport: Viewport::Inline(height as u16),
-
    };
-

-
    Ok(Terminal::with_options(
-
        TermionBackendExt::new(stdout),
-
        options,
-
    )?)
+
    let options = TerminalOptions { viewport };
+
    let mut terminal = Terminal::with_options(TermionBackendExt::new(stdout), options)?;
+

+
    if is_fullscreen {
+
        terminal.clear()?;
+
    }
+

+
    Ok(terminal)
}

/// Restore the `Terminal` on quit.
modified src/ui/im.rs
@@ -14,7 +14,7 @@ use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
use termion::event::Key;

use ratatui::layout::{Constraint, Rect};
-
use ratatui::Frame;
+
use ratatui::{Frame, Viewport};

use crate::event::Event;
use crate::store::Update;
@@ -26,7 +26,6 @@ use crate::ui::{Column, ToRow};
use crate::ui::im::widget::{HeaderedTable, Widget};

const RENDERING_TICK_RATE: Duration = Duration::from_millis(250);
-
const INLINE_HEIGHT: usize = 20;

/// The main UI trait for the ability to render an application.
pub trait Show<M> {
@@ -42,6 +41,7 @@ impl Frontend {
        state_tx: UnboundedSender<M>,
        mut state_rx: UnboundedReceiver<S>,
        mut interrupt_rx: broadcast::Receiver<Interrupted<P>>,
+
        viewport: Viewport,
    ) -> anyhow::Result<Interrupted<P>>
    where
        S: Update<M, Return = P> + Show<M>,
@@ -50,7 +50,7 @@ impl Frontend {
    {
        let mut ticker = tokio::time::interval(RENDERING_TICK_RATE);

-
        let mut terminal = terminal::setup(INLINE_HEIGHT)?;
+
        let mut terminal = terminal::setup(viewport)?;
        let mut events_rx = terminal::events();

        let mut state = state_rx.recv().await.unwrap();
modified src/ui/rm.rs
@@ -3,6 +3,7 @@ pub mod widget;
use std::fmt::Debug;
use std::time::Duration;

+
use ratatui::Viewport;
use tokio::sync::broadcast;
use tokio::sync::mpsc::UnboundedReceiver;

@@ -14,7 +15,6 @@ use crate::ui::rm::widget::RenderProps;
use crate::ui::rm::widget::Widget;

const RENDERING_TICK_RATE: Duration = Duration::from_millis(250);
-
const INLINE_HEIGHT: usize = 20;

/// The `Frontend` runs an applications' view concurrently. It handles
/// terminal events as well as state updates and renders the view accordingly.
@@ -44,6 +44,7 @@ impl Frontend {
        mut root: Widget<S, M>,
        mut state_rx: UnboundedReceiver<S>,
        mut interrupt_rx: broadcast::Receiver<Interrupted<R>>,
+
        viewport: Viewport,
    ) -> anyhow::Result<Interrupted<R>>
    where
        S: Update<M, Return = R> + 'static,
@@ -52,7 +53,7 @@ impl Frontend {
    {
        let mut ticker = tokio::time::interval(RENDERING_TICK_RATE);

-
        let mut terminal = terminal::setup(INLINE_HEIGHT)?;
+
        let mut terminal = terminal::setup(viewport)?;
        let mut events_rx = terminal::events();

        let mut root = {