auto merge of #10637 : luqmana/rust/nmt, r=cmr
There's no need for it to be @mut.
This commit is contained in:
commit
09eca11805
|
@ -13,7 +13,7 @@
|
|||
#[allow(missing_doc)];
|
||||
|
||||
|
||||
use std::io;
|
||||
use std::io::{Decorator, Writer};
|
||||
|
||||
#[cfg(not(target_os = "win32"))] use std::os;
|
||||
#[cfg(not(target_os = "win32"))] use terminfo::*;
|
||||
|
@ -94,21 +94,21 @@ fn cap_for_attr(attr: attr::Attr) -> &'static str {
|
|||
}
|
||||
|
||||
#[cfg(not(target_os = "win32"))]
|
||||
pub struct Terminal {
|
||||
pub struct Terminal<T> {
|
||||
priv num_colors: u16,
|
||||
priv out: @mut io::Writer,
|
||||
priv out: T,
|
||||
priv ti: ~TermInfo
|
||||
}
|
||||
|
||||
#[cfg(target_os = "win32")]
|
||||
pub struct Terminal {
|
||||
pub struct Terminal<T> {
|
||||
priv num_colors: u16,
|
||||
priv out: @mut io::Writer,
|
||||
priv out: T,
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "win32"))]
|
||||
impl Terminal {
|
||||
pub fn new(out: @mut io::Writer) -> Result<Terminal, ~str> {
|
||||
impl<T: Writer> Terminal<T> {
|
||||
pub fn new(out: T) -> Result<Terminal<T>, ~str> {
|
||||
let term = os::getenv("TERM");
|
||||
if term.is_none() {
|
||||
return Err(~"TERM environment variable undefined");
|
||||
|
@ -138,7 +138,7 @@ impl Terminal {
|
|||
/// the corresponding normal color will be used instead.
|
||||
///
|
||||
/// Returns true if the color was set, false otherwise.
|
||||
pub fn fg(&self, color: color::Color) -> bool {
|
||||
pub fn fg(&mut self, color: color::Color) -> bool {
|
||||
let color = self.dim_if_necessary(color);
|
||||
if self.num_colors > color {
|
||||
let s = expand(*self.ti.strings.find_equiv(&("setaf")).unwrap(),
|
||||
|
@ -158,7 +158,7 @@ impl Terminal {
|
|||
/// the corresponding normal color will be used instead.
|
||||
///
|
||||
/// Returns true if the color was set, false otherwise.
|
||||
pub fn bg(&self, color: color::Color) -> bool {
|
||||
pub fn bg(&mut self, color: color::Color) -> bool {
|
||||
let color = self.dim_if_necessary(color);
|
||||
if self.num_colors > color {
|
||||
let s = expand(*self.ti.strings.find_equiv(&("setab")).unwrap(),
|
||||
|
@ -175,7 +175,7 @@ impl Terminal {
|
|||
|
||||
/// Sets the given terminal attribute, if supported.
|
||||
/// Returns true if the attribute was supported, false otherwise.
|
||||
pub fn attr(&self, attr: attr::Attr) -> bool {
|
||||
pub fn attr(&mut self, attr: attr::Attr) -> bool {
|
||||
match attr {
|
||||
attr::ForegroundColor(c) => self.fg(c),
|
||||
attr::BackgroundColor(c) => self.bg(c),
|
||||
|
@ -210,7 +210,7 @@ impl Terminal {
|
|||
}
|
||||
|
||||
/// Resets all terminal attributes and color to the default.
|
||||
pub fn reset(&self) {
|
||||
pub fn reset(&mut self) {
|
||||
let mut cap = self.ti.strings.find_equiv(&("sgr0"));
|
||||
if cap.is_none() {
|
||||
// are there any terminals that have color/attrs and not sgr0?
|
||||
|
@ -242,20 +242,20 @@ impl Terminal {
|
|||
}
|
||||
|
||||
#[cfg(target_os = "win32")]
|
||||
impl Terminal {
|
||||
pub fn new(out: @mut io::Writer) -> Result<Terminal, ~str> {
|
||||
impl<T: Writer> Terminal<T> {
|
||||
pub fn new(out: T) -> Result<Terminal<T>, ~str> {
|
||||
return Ok(Terminal {out: out, num_colors: 0});
|
||||
}
|
||||
|
||||
pub fn fg(&self, _color: color::Color) -> bool {
|
||||
pub fn fg(&mut self, _color: color::Color) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn bg(&self, _color: color::Color) -> bool {
|
||||
pub fn bg(&mut self, _color: color::Color) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn attr(&self, _attr: attr::Attr) -> bool {
|
||||
pub fn attr(&mut self, _attr: attr::Attr) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
|
@ -266,3 +266,27 @@ impl Terminal {
|
|||
pub fn reset(&self) {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Writer> Decorator<T> for Terminal<T> {
|
||||
fn inner(self) -> T {
|
||||
self.out
|
||||
}
|
||||
|
||||
fn inner_ref<'a>(&'a self) -> &'a T {
|
||||
&self.out
|
||||
}
|
||||
|
||||
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut T {
|
||||
&mut self.out
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Writer> Writer for Terminal<T> {
|
||||
fn write(&mut self, buf: &[u8]) {
|
||||
self.out.write(buf);
|
||||
}
|
||||
|
||||
fn flush(&mut self) {
|
||||
self.out.flush();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@ use std::clone::Clone;
|
|||
use std::comm::{stream, SharedChan, GenericPort, GenericChan};
|
||||
use std::io;
|
||||
use std::io::File;
|
||||
use std::io::Writer;
|
||||
use std::io::stdio::StdWriter;
|
||||
use std::task;
|
||||
use std::to_str::ToStr;
|
||||
use std::f64;
|
||||
|
@ -338,10 +340,9 @@ pub enum TestResult {
|
|||
TrBench(BenchSamples),
|
||||
}
|
||||
|
||||
struct ConsoleTestState {
|
||||
out: @mut io::Writer,
|
||||
log_out: Option<@mut io::Writer>,
|
||||
term: Option<term::Terminal>,
|
||||
struct ConsoleTestState<T> {
|
||||
log_out: Option<File>,
|
||||
out: Either<term::Terminal<T>, T>,
|
||||
use_color: bool,
|
||||
total: uint,
|
||||
passed: uint,
|
||||
|
@ -353,22 +354,20 @@ struct ConsoleTestState {
|
|||
max_name_len: uint, // number of columns to fill when aligning names
|
||||
}
|
||||
|
||||
impl ConsoleTestState {
|
||||
pub fn new(opts: &TestOpts) -> ConsoleTestState {
|
||||
impl<T: Writer> ConsoleTestState<T> {
|
||||
pub fn new(opts: &TestOpts, _: Option<T>) -> ConsoleTestState<StdWriter> {
|
||||
let log_out = match opts.logfile {
|
||||
Some(ref path) => Some(@mut File::create(path) as @mut io::Writer),
|
||||
Some(ref path) => File::create(path),
|
||||
None => None
|
||||
};
|
||||
let out = @mut io::stdio::stdout() as @mut io::Writer;
|
||||
let term = match term::Terminal::new(out) {
|
||||
Err(_) => None,
|
||||
Ok(t) => Some(t)
|
||||
let out = match term::Terminal::new(io::stdout()) {
|
||||
Err(_) => Right(io::stdout()),
|
||||
Ok(t) => Left(t)
|
||||
};
|
||||
ConsoleTestState {
|
||||
out: out,
|
||||
log_out: log_out,
|
||||
use_color: use_color(),
|
||||
term: term,
|
||||
total: 0u,
|
||||
passed: 0u,
|
||||
failed: 0u,
|
||||
|
@ -380,115 +379,123 @@ impl ConsoleTestState {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn write_ok(&self) {
|
||||
pub fn write_ok(&mut self) {
|
||||
self.write_pretty("ok", term::color::GREEN);
|
||||
}
|
||||
|
||||
pub fn write_failed(&self) {
|
||||
pub fn write_failed(&mut self) {
|
||||
self.write_pretty("FAILED", term::color::RED);
|
||||
}
|
||||
|
||||
pub fn write_ignored(&self) {
|
||||
pub fn write_ignored(&mut self) {
|
||||
self.write_pretty("ignored", term::color::YELLOW);
|
||||
}
|
||||
|
||||
pub fn write_metric(&self) {
|
||||
pub fn write_metric(&mut self) {
|
||||
self.write_pretty("metric", term::color::CYAN);
|
||||
}
|
||||
|
||||
pub fn write_bench(&self) {
|
||||
pub fn write_bench(&mut self) {
|
||||
self.write_pretty("bench", term::color::CYAN);
|
||||
}
|
||||
|
||||
pub fn write_added(&self) {
|
||||
pub fn write_added(&mut self) {
|
||||
self.write_pretty("added", term::color::GREEN);
|
||||
}
|
||||
|
||||
pub fn write_improved(&self) {
|
||||
pub fn write_improved(&mut self) {
|
||||
self.write_pretty("improved", term::color::GREEN);
|
||||
}
|
||||
|
||||
pub fn write_removed(&self) {
|
||||
pub fn write_removed(&mut self) {
|
||||
self.write_pretty("removed", term::color::YELLOW);
|
||||
}
|
||||
|
||||
pub fn write_regressed(&self) {
|
||||
pub fn write_regressed(&mut self) {
|
||||
self.write_pretty("regressed", term::color::RED);
|
||||
}
|
||||
|
||||
pub fn write_pretty(&self,
|
||||
pub fn write_pretty(&mut self,
|
||||
word: &str,
|
||||
color: term::color::Color) {
|
||||
match self.term {
|
||||
None => self.out.write(word.as_bytes()),
|
||||
Some(ref t) => {
|
||||
match self.out {
|
||||
Left(ref mut term) => {
|
||||
if self.use_color {
|
||||
t.fg(color);
|
||||
term.fg(color);
|
||||
}
|
||||
self.out.write(word.as_bytes());
|
||||
term.write(word.as_bytes());
|
||||
if self.use_color {
|
||||
t.reset();
|
||||
term.reset();
|
||||
}
|
||||
}
|
||||
Right(ref mut stdout) => stdout.write(word.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_plain(&mut self, s: &str) {
|
||||
match self.out {
|
||||
Left(ref mut term) => term.write(s.as_bytes()),
|
||||
Right(ref mut stdout) => stdout.write(s.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_run_start(&mut self, len: uint) {
|
||||
self.total = len;
|
||||
let noun = if len != 1 { &"tests" } else { &"test" };
|
||||
write!(self.out, "\nrunning {} {}\n", len, noun);
|
||||
self.write_plain(format!("\nrunning {} {}\n", len, noun));
|
||||
}
|
||||
|
||||
pub fn write_test_start(&self, test: &TestDesc, align: NamePadding) {
|
||||
pub fn write_test_start(&mut self, test: &TestDesc, align: NamePadding) {
|
||||
let name = test.padded_name(self.max_name_len, align);
|
||||
write!(self.out, "test {} ... ", name);
|
||||
self.write_plain(format!("test {} ... ", name));
|
||||
}
|
||||
|
||||
pub fn write_result(&self, result: &TestResult) {
|
||||
pub fn write_result(&mut self, result: &TestResult) {
|
||||
match *result {
|
||||
TrOk => self.write_ok(),
|
||||
TrFailed => self.write_failed(),
|
||||
TrIgnored => self.write_ignored(),
|
||||
TrMetrics(ref mm) => {
|
||||
self.write_metric();
|
||||
write!(self.out, ": {}", fmt_metrics(mm));
|
||||
self.write_plain(format!(": {}", fmt_metrics(mm)));
|
||||
}
|
||||
TrBench(ref bs) => {
|
||||
self.write_bench();
|
||||
write!(self.out, ": {}", fmt_bench_samples(bs));
|
||||
self.write_plain(format!(": {}", fmt_bench_samples(bs)));
|
||||
}
|
||||
}
|
||||
write!(self.out, "\n");
|
||||
self.write_plain("\n");
|
||||
}
|
||||
|
||||
pub fn write_log(&self, test: &TestDesc, result: &TestResult) {
|
||||
pub fn write_log(&mut self, test: &TestDesc, result: &TestResult) {
|
||||
match self.log_out {
|
||||
None => (),
|
||||
Some(out) => {
|
||||
write!(out, "{} {}",match *result {
|
||||
TrOk => ~"ok",
|
||||
TrFailed => ~"failed",
|
||||
TrIgnored => ~"ignored",
|
||||
TrMetrics(ref mm) => fmt_metrics(mm),
|
||||
TrBench(ref bs) => fmt_bench_samples(bs)
|
||||
}, test.name.to_str());
|
||||
Some(ref mut o) => {
|
||||
let s = format!("{} {}", match *result {
|
||||
TrOk => ~"ok",
|
||||
TrFailed => ~"failed",
|
||||
TrIgnored => ~"ignored",
|
||||
TrMetrics(ref mm) => fmt_metrics(mm),
|
||||
TrBench(ref bs) => fmt_bench_samples(bs)
|
||||
}, test.name.to_str());
|
||||
o.write(s.as_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_failures(&self) {
|
||||
write!(self.out, "\nfailures:\n");
|
||||
pub fn write_failures(&mut self) {
|
||||
self.write_plain("\nfailures:\n");
|
||||
let mut failures = ~[];
|
||||
for f in self.failures.iter() {
|
||||
failures.push(f.name.to_str());
|
||||
}
|
||||
sort::tim_sort(failures);
|
||||
for name in failures.iter() {
|
||||
writeln!(self.out, " {}", name.to_str());
|
||||
self.write_plain(format!(" {}\n", name.to_str()));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_metric_diff(&self, diff: &MetricDiff) {
|
||||
pub fn write_metric_diff(&mut self, diff: &MetricDiff) {
|
||||
let mut noise = 0;
|
||||
let mut improved = 0;
|
||||
let mut regressed = 0;
|
||||
|
@ -501,38 +508,38 @@ impl ConsoleTestState {
|
|||
MetricAdded => {
|
||||
added += 1;
|
||||
self.write_added();
|
||||
writeln!(self.out, ": {}", *k);
|
||||
self.write_plain(format!(": {}\n", *k));
|
||||
}
|
||||
MetricRemoved => {
|
||||
removed += 1;
|
||||
self.write_removed();
|
||||
writeln!(self.out, ": {}", *k);
|
||||
self.write_plain(format!(": {}\n", *k));
|
||||
}
|
||||
Improvement(pct) => {
|
||||
improved += 1;
|
||||
write!(self.out, "{}: ", *k);
|
||||
self.write_plain(format!(": {}", *k));
|
||||
self.write_improved();
|
||||
writeln!(self.out, " by {:.2f}%", pct as f64);
|
||||
self.write_plain(format!(" by {:.2f}%\n", pct as f64));
|
||||
}
|
||||
Regression(pct) => {
|
||||
regressed += 1;
|
||||
write!(self.out, "{}: ", *k);
|
||||
self.write_plain(format!(": {}", *k));
|
||||
self.write_regressed();
|
||||
writeln!(self.out, " by {:.2f}%", pct as f64);
|
||||
self.write_plain(format!(" by {:.2f}%\n", pct as f64));
|
||||
}
|
||||
}
|
||||
}
|
||||
writeln!(self.out, "result of ratchet: {} matrics added, {} removed, \
|
||||
{} improved, {} regressed, {} noise",
|
||||
added, removed, improved, regressed, noise);
|
||||
self.write_plain(format!("result of ratchet: {} matrics added, {} removed, \
|
||||
{} improved, {} regressed, {} noise\n",
|
||||
added, removed, improved, regressed, noise));
|
||||
if regressed == 0 {
|
||||
writeln!(self.out, "updated ratchet file");
|
||||
self.write_plain("updated ratchet file\n");
|
||||
} else {
|
||||
writeln!(self.out, "left ratchet file untouched");
|
||||
self.write_plain("left ratchet file untouched\n");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_run_finish(&self,
|
||||
pub fn write_run_finish(&mut self,
|
||||
ratchet_metrics: &Option<Path>,
|
||||
ratchet_pct: Option<f64>) -> bool {
|
||||
assert!(self.passed + self.failed + self.ignored + self.measured == self.total);
|
||||
|
@ -540,12 +547,12 @@ impl ConsoleTestState {
|
|||
let ratchet_success = match *ratchet_metrics {
|
||||
None => true,
|
||||
Some(ref pth) => {
|
||||
write!(self.out, "\nusing metrics ratcher: {}\n", pth.display());
|
||||
self.write_plain(format!("\nusing metrics ratcher: {}\n", pth.display()));
|
||||
match ratchet_pct {
|
||||
None => (),
|
||||
Some(pct) =>
|
||||
writeln!(self.out, "with noise-tolerance forced to: {}%",
|
||||
pct)
|
||||
self.write_plain(format!("with noise-tolerance forced to: {}%\n",
|
||||
pct))
|
||||
}
|
||||
let (diff, ok) = self.metrics.ratchet(pth, ratchet_pct);
|
||||
self.write_metric_diff(&diff);
|
||||
|
@ -560,15 +567,16 @@ impl ConsoleTestState {
|
|||
|
||||
let success = ratchet_success && test_success;
|
||||
|
||||
write!(self.out, "\ntest result: ");
|
||||
self.write_plain("\ntest result: ");
|
||||
if success {
|
||||
// There's no parallelism at this point so it's safe to use color
|
||||
self.write_ok();
|
||||
} else {
|
||||
self.write_failed();
|
||||
}
|
||||
write!(self.out, ". {} passed; {} failed; {} ignored; {} measured\n\n",
|
||||
self.passed, self.failed, self.ignored, self.measured);
|
||||
let s = format!(". {} passed; {} failed; {} ignored; {} measured\n\n",
|
||||
self.passed, self.failed, self.ignored, self.measured);
|
||||
self.write_plain(s);
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
@ -599,7 +607,7 @@ pub fn fmt_bench_samples(bs: &BenchSamples) -> ~str {
|
|||
// A simple console test runner
|
||||
pub fn run_tests_console(opts: &TestOpts,
|
||||
tests: ~[TestDescAndFn]) -> bool {
|
||||
fn callback(event: &TestEvent, st: &mut ConsoleTestState) {
|
||||
fn callback<T: Writer>(event: &TestEvent, st: &mut ConsoleTestState<T>) {
|
||||
debug!("callback(event={:?})", event);
|
||||
match (*event).clone() {
|
||||
TeFiltered(ref filtered_tests) => st.write_run_start(filtered_tests.len()),
|
||||
|
@ -632,7 +640,7 @@ pub fn run_tests_console(opts: &TestOpts,
|
|||
}
|
||||
}
|
||||
}
|
||||
let st = @mut ConsoleTestState::new(opts);
|
||||
let mut st = ConsoleTestState::new(opts, None::<StdWriter>);
|
||||
fn len_if_padded(t: &TestDescAndFn) -> uint {
|
||||
match t.testfn.padding() {
|
||||
PadNone => 0u,
|
||||
|
@ -647,12 +655,12 @@ pub fn run_tests_console(opts: &TestOpts,
|
|||
},
|
||||
None => {}
|
||||
}
|
||||
run_tests(opts, tests, |x| callback(&x, st));
|
||||
run_tests(opts, tests, |x| callback(&x, &mut st));
|
||||
match opts.save_metrics {
|
||||
None => (),
|
||||
Some(ref pth) => {
|
||||
st.metrics.save(pth);
|
||||
write!(st.out, "\nmetrics saved to: {}", pth.display());
|
||||
st.write_plain(format!("\nmetrics saved to: {}", pth.display()));
|
||||
}
|
||||
}
|
||||
return st.write_run_finish(&opts.ratchet_metrics, opts.ratchet_noise_percent);
|
||||
|
@ -660,13 +668,11 @@ pub fn run_tests_console(opts: &TestOpts,
|
|||
|
||||
#[test]
|
||||
fn should_sort_failures_before_printing_them() {
|
||||
use std::io;
|
||||
use std::io::Decorator;
|
||||
use std::io::mem::MemWriter;
|
||||
use std::str;
|
||||
fn dummy() {}
|
||||
|
||||
let m = @mut MemWriter::new();
|
||||
let test_a = TestDesc {
|
||||
name: StaticTestName("a"),
|
||||
ignore: false,
|
||||
|
@ -679,10 +685,9 @@ fn should_sort_failures_before_printing_them() {
|
|||
should_fail: false
|
||||
};
|
||||
|
||||
let st = @ConsoleTestState {
|
||||
out: m as @mut io::Writer,
|
||||
let mut st = ConsoleTestState {
|
||||
log_out: None,
|
||||
term: None,
|
||||
out: Right(MemWriter::new()),
|
||||
use_color: false,
|
||||
total: 0u,
|
||||
passed: 0u,
|
||||
|
@ -695,7 +700,10 @@ fn should_sort_failures_before_printing_them() {
|
|||
};
|
||||
|
||||
st.write_failures();
|
||||
let s = str::from_utf8(*m.inner_ref());
|
||||
let s = match st.out {
|
||||
Right(ref m) => str::from_utf8(*m.inner_ref()),
|
||||
Left(_) => unreachable!()
|
||||
};
|
||||
|
||||
let apos = s.find_str("a").unwrap();
|
||||
let bpos = s.find_str("b").unwrap();
|
||||
|
|
|
@ -12,35 +12,32 @@ use extra::term;
|
|||
use std::io;
|
||||
|
||||
pub fn note(msg: &str) {
|
||||
pretty_message(msg, "note: ", term::color::GREEN,
|
||||
@mut io::stdout() as @mut io::Writer)
|
||||
pretty_message(msg, "note: ", term::color::GREEN);
|
||||
}
|
||||
|
||||
pub fn warn(msg: &str) {
|
||||
pretty_message(msg, "warning: ", term::color::YELLOW,
|
||||
@mut io::stdout() as @mut io::Writer)
|
||||
pretty_message(msg, "warning: ", term::color::YELLOW);
|
||||
}
|
||||
|
||||
pub fn error(msg: &str) {
|
||||
pretty_message(msg, "error: ", term::color::RED,
|
||||
@mut io::stdout() as @mut io::Writer)
|
||||
pretty_message(msg, "error: ", term::color::RED);
|
||||
}
|
||||
|
||||
fn pretty_message<'a>(msg: &'a str,
|
||||
prefix: &'a str,
|
||||
color: term::color::Color,
|
||||
out: @mut io::Writer) {
|
||||
let term = term::Terminal::new(out);
|
||||
color: term::color::Color) {
|
||||
let mut term = term::Terminal::new(io::stdout());
|
||||
let mut stdout = io::stdout();
|
||||
match term {
|
||||
Ok(ref t) => {
|
||||
Ok(ref mut t) => {
|
||||
t.fg(color);
|
||||
out.write(prefix.as_bytes());
|
||||
t.write(prefix.as_bytes());
|
||||
t.reset();
|
||||
},
|
||||
_ => {
|
||||
out.write(prefix.as_bytes());
|
||||
stdout.write(prefix.as_bytes());
|
||||
}
|
||||
}
|
||||
out.write(msg.as_bytes());
|
||||
out.write(['\n' as u8]);
|
||||
stdout.write(msg.as_bytes());
|
||||
stdout.write(['\n' as u8]);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ use codemap::{Pos, Span};
|
|||
use codemap;
|
||||
|
||||
use std::io;
|
||||
use std::io::stdio::StdWriter;
|
||||
use std::local_data;
|
||||
use extra::term;
|
||||
|
||||
|
@ -197,38 +198,44 @@ fn diagnosticcolor(lvl: level) -> term::color::Color {
|
|||
}
|
||||
|
||||
fn print_maybe_styled(msg: &str, color: term::attr::Attr) {
|
||||
local_data_key!(tls_terminal: @Option<term::Terminal>)
|
||||
local_data_key!(tls_terminal: ~Option<term::Terminal<StdWriter>>)
|
||||
|
||||
let stderr = @mut io::stderr() as @mut io::Writer;
|
||||
fn is_stderr_screen() -> bool {
|
||||
use std::libc;
|
||||
unsafe { libc::isatty(libc::STDERR_FILENO) != 0 }
|
||||
}
|
||||
fn write_pretty<T: Writer>(term: &mut term::Terminal<T>, s: &str, c: term::attr::Attr) {
|
||||
term.attr(c);
|
||||
term.write(s.as_bytes());
|
||||
term.reset();
|
||||
}
|
||||
|
||||
if is_stderr_screen() {
|
||||
let t = match local_data::get(tls_terminal, |v| v.map(|k| *k)) {
|
||||
None => {
|
||||
let t = term::Terminal::new(stderr);
|
||||
let tls = @match t {
|
||||
Ok(t) => Some(t),
|
||||
Err(_) => None
|
||||
};
|
||||
local_data::set(tls_terminal, tls);
|
||||
&*tls
|
||||
local_data::get_mut(tls_terminal, |term| {
|
||||
match term {
|
||||
Some(term) => {
|
||||
match **term {
|
||||
Some(ref mut term) => write_pretty(term, msg, color),
|
||||
None => io::stderr().write(msg.as_bytes())
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let t = ~match term::Terminal::new(io::stderr()) {
|
||||
Ok(mut term) => {
|
||||
write_pretty(&mut term, msg, color);
|
||||
Some(term)
|
||||
}
|
||||
Err(_) => {
|
||||
io::stderr().write(msg.as_bytes());
|
||||
None
|
||||
}
|
||||
};
|
||||
local_data::set(tls_terminal, t);
|
||||
}
|
||||
}
|
||||
Some(tls) => &*tls
|
||||
};
|
||||
|
||||
match t {
|
||||
&Some(ref term) => {
|
||||
term.attr(color);
|
||||
write!(stderr, "{}", msg);
|
||||
term.reset();
|
||||
},
|
||||
_ => write!(stderr, "{}", msg)
|
||||
}
|
||||
});
|
||||
} else {
|
||||
write!(stderr, "{}", msg);
|
||||
io::stderr().write(msg.as_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue