fix(core): do not clone screen on every render loop of the TUI (#30872)

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->
Everytime the TUI is rendered with a terminal pane opened, we clone the
screen. This cloning is resource intensive as we would be creating a new
screen every couple of milliseconds.
 
## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
This has changes so that we can pass a reference to the screen to be
used in places where its needed. This avoids the cloning the screen.

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
This commit is contained in:
Jonathan Cammisuli 2025-04-25 13:25:53 -04:00 committed by GitHub
parent 8214ab49f2
commit 2f739e9fbf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 28 additions and 5 deletions

View File

@ -254,8 +254,8 @@ impl<'a> TerminalPane<'a> {
| TaskStatus::RemoteCache => Color::Green,
TaskStatus::Failure => Color::Red,
TaskStatus::Skipped => Color::Yellow,
TaskStatus::InProgress | TaskStatus::Shared=> Color::LightCyan,
TaskStatus::NotStarted | TaskStatus::Stopped=> Color::DarkGray,
TaskStatus::InProgress | TaskStatus::Shared => Color::LightCyan,
TaskStatus::NotStarted | TaskStatus::Stopped => Color::DarkGray,
})
}
@ -420,7 +420,7 @@ impl<'a> StatefulWidget for TerminalPane<'a> {
ScrollbarState::default()
};
let pseudo_term = PseudoTerminal::new(&screen).block(block);
let pseudo_term = PseudoTerminal::new(&*screen).block(block);
Widget::render(pseudo_term, area, buf);
// Only render scrollbar if needed

View File

@ -6,6 +6,26 @@ use vt100_ctt::Parser;
use super::utils::normalize_newlines;
/// A wrapper that provides access to the terminal screen without cloning
///
/// This struct uses a read lock guard internally to maintain the lock on the parser while
/// allowing access to just the screen through deref coercion. This approach avoids the need to
/// clone the entire screen while still providing safe access to it. The guard is kept private
/// to ensure the lock is held for the lifetime of this reference.
///
/// Using Deref allows callers to treat this as if it were a direct reference to Screen.
pub struct PtyScreenRef<'a> {
_guard: std::sync::RwLockReadGuard<'a, Parser>,
}
impl std::ops::Deref for PtyScreenRef<'_> {
type Target = vt100_ctt::Screen;
fn deref(&self) -> &Self::Target {
self._guard.screen()
}
}
#[derive(Clone)]
pub struct PtyInstance {
pub task_id: String,
@ -73,8 +93,11 @@ impl PtyInstance {
Ok(())
}
pub fn get_screen(&self) -> Option<vt100_ctt::Screen> {
self.parser.read().ok().map(|p| p.screen().clone())
pub fn get_screen(&self) -> Option<PtyScreenRef> {
self.parser
.read()
.ok()
.map(|guard| PtyScreenRef { _guard: guard })
}
pub fn scroll_up(&mut self) {