Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions packages/iocraft/src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ use core::{
pin::Pin,
task::{self, Poll},
};
use crossterm::{execute, terminal};
use futures::{
future::{select, FutureExt, LocalBoxFuture},
stream::{Stream, StreamExt},
Expand Down Expand Up @@ -461,16 +460,18 @@ impl<'a> Tree<'a> {
loop {
term.refresh_size();
let terminal_size = term.size();
execute!(term, terminal::BeginSynchronizedUpdate,)?;
let output = self.render(terminal_size.map(|(w, _)| w as usize), Some(&mut term));
if output.did_clear_terminal_output || prev_canvas.as_ref() != Some(&output.canvas) {
if !output.did_clear_terminal_output {
term.clear_canvas()?;
term.synchronized_update(|mut term| {
let output = self.render(terminal_size.map(|(w, _)| w as usize), Some(&mut term));
if output.did_clear_terminal_output || prev_canvas.as_ref() != Some(&output.canvas)
{
if !output.did_clear_terminal_output {
term.clear_canvas()?;
}
term.write_canvas(&output.canvas)?;
}
term.write_canvas(&output.canvas)?;
}
prev_canvas = Some(output.canvas);
execute!(term, terminal::EndSynchronizedUpdate)?;
prev_canvas = Some(output.canvas);
Ok(())
})?;
if self.system_context.should_exit() || term.received_ctrl_c() {
break;
}
Expand Down
29 changes: 29 additions & 0 deletions packages/iocraft/src/terminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,16 @@ impl Terminal {
self.received_ctrl_c
}

/// Wraps a series of terminal updates in a synchronized update block, making sure to end the
/// synchronized update even if there is an error or panic.
pub fn synchronized_update<F>(&mut self, f: F) -> io::Result<()>
where
F: FnOnce(&mut Self) -> io::Result<()>,
{
let t = SynchronizedUpdate::begin(self)?;
f(t.inner)
}

pub async fn wait(&mut self) {
match &mut self.event_stream {
Some(event_stream) => {
Expand Down Expand Up @@ -484,6 +494,25 @@ impl Write for Terminal {
}
}

/// Synchronized update terminal guard.
/// Enters synchronized update on creation, exits when dropped.
pub(crate) struct SynchronizedUpdate<'a> {
inner: &'a mut Terminal,
}

impl<'a> SynchronizedUpdate<'a> {
pub fn begin(terminal: &'a mut Terminal) -> io::Result<Self> {
execute!(terminal, terminal::BeginSynchronizedUpdate)?;
Ok(Self { inner: terminal })
}
}

impl Drop for SynchronizedUpdate<'_> {
fn drop(&mut self) {
let _ = execute!(self.inner, terminal::EndSynchronizedUpdate);
}
}

#[cfg(test)]
mod tests {
use crate::prelude::*;
Expand Down