Skip to content

Commit

Permalink
Minimize syscalls by caching the terminal
Browse files Browse the repository at this point in the history
  • Loading branch information
aloucks committed Nov 25, 2021
1 parent 571028b commit 7036ec3
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 10 deletions.
7 changes: 5 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ home = {git = "https://github.com/rbtcollins/home", rev = "a243ee2fbee6022c57d56
lazy_static = "1"
libc = "0.2"
num_cpus = "1.13"
once_cell = "1.8"
opener = "0.4.0"
# Used by `curl` or `reqwest` backend although it isn't imported
# by our rustup.
Expand Down
57 changes: 55 additions & 2 deletions src/cli/term2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

use std::io;
use std::io::Write;
use std::sync::{Arc, Mutex};

use once_cell::sync::OnceCell;

use termcolor::{ColorChoice, ColorSpec, StandardStream, WriteColor};

Expand Down Expand Up @@ -143,10 +146,60 @@ impl AutomationFriendlyTerminal {
}
}

/// A cheaply clonable handle to a terminal.
#[derive(Clone)]
struct SharedTerminal {
inner: Arc<Mutex<Box<dyn Terminal + Send + Sync>>>,
}

impl io::Write for SharedTerminal {
fn write(&mut self, buf: &[u8]) -> std::result::Result<usize, io::Error> {
self.inner.lock().unwrap().write(buf)
}

fn flush(&mut self) -> std::result::Result<(), io::Error> {
self.inner.lock().unwrap().flush()
}
}

impl Terminal for SharedTerminal {
fn fg(&mut self, color: Color) -> io::Result<()> {
self.inner.lock().unwrap().fg(color)
}

fn bg(&mut self, color: Color) -> io::Result<()> {
self.inner.lock().unwrap().bg(color)
}

fn attr(&mut self, attr: Attr) -> io::Result<()> {
self.inner.lock().unwrap().attr(attr)
}

fn reset(&mut self) -> io::Result<()> {
self.inner.lock().unwrap().reset()
}

fn carriage_return(&mut self) -> io::Result<()> {
self.inner.lock().unwrap().carriage_return()
}
}

pub(crate) fn stdout() -> Box<dyn Terminal> {
process().stdout()
static STDOUT: OnceCell<Box<SharedTerminal>> = OnceCell::new();
let shared = STDOUT.get_or_init(|| {
Box::new(SharedTerminal {
inner: Arc::new(Mutex::new(process().stdout())),
})
});
Box::<SharedTerminal>::clone(shared)
}

pub(crate) fn stderr() -> Box<dyn Terminal> {
process().stderr()
static STDERR: OnceCell<Box<SharedTerminal>> = OnceCell::new();
let shared = STDERR.get_or_init(|| {
Box::new(SharedTerminal {
inner: Arc::new(Mutex::new(process().stderr())),
})
});
Box::<SharedTerminal>::clone(shared)
}
12 changes: 6 additions & 6 deletions src/currentprocess/filesource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,14 @@ pub trait Writer: Write + Isatty + Send {

/// Stand-in for std::io::stdout
pub trait StdoutSource {
fn stdout(&self) -> Box<dyn Terminal>;
fn stdout(&self) -> Box<dyn Terminal + Send + Sync>;
}

// -------------- stderr -------------------------------

/// Stand-in for std::io::stderr
pub trait StderrSource {
fn stderr(&self) -> Box<dyn Terminal>;
fn stderr(&self) -> Box<dyn Terminal + Send + Sync>;
}

// ----------------- OS support for writers -----------------
Expand All @@ -123,7 +123,7 @@ impl Isatty for io::Stdout {
}

impl StdoutSource for super::OSProcess {
fn stdout(&self) -> Box<dyn Terminal> {
fn stdout(&self) -> Box<dyn Terminal + Send + Sync> {
Box::new(AutomationFriendlyTerminal::stdout())
}
}
Expand All @@ -143,7 +143,7 @@ impl Isatty for io::Stderr {
}

impl StderrSource for super::OSProcess {
fn stderr(&self) -> Box<dyn Terminal> {
fn stderr(&self) -> Box<dyn Terminal + Send + Sync> {
Box::new(AutomationFriendlyTerminal::stderr())
}
}
Expand Down Expand Up @@ -209,13 +209,13 @@ impl Isatty for TestWriter {
}

impl StdoutSource for super::TestProcess {
fn stdout(&self) -> Box<dyn Terminal> {
fn stdout(&self) -> Box<dyn Terminal + Send + Sync> {
Box::new(TestWriter(self.stdout.clone()))
}
}

impl StderrSource for super::TestProcess {
fn stderr(&self) -> Box<dyn Terminal> {
fn stderr(&self) -> Box<dyn Terminal + Send + Sync> {
Box::new(TestWriter(self.stderr.clone()))
}
}

0 comments on commit 7036ec3

Please sign in to comment.