Skip to content

Commit 68a32aa

Browse files
committed
auto merge of #7716 : kballard/rust/term-attr, r=cmr
Teach `extra::term` to support more terminal attributes than just color. Fix the compiler diagnostic messages to print in bold instead of bright white. This matches Clang's output. Cache the term::Terminal instead of re-parsing for every diagnostic (fixes #6827).
2 parents 4f33302 + 1d4c314 commit 68a32aa

File tree

2 files changed

+154
-23
lines changed

2 files changed

+154
-23
lines changed

src/libextra/term.rs

+122-9
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,54 @@ pub mod color {
4545
pub static BRIGHT_WHITE: Color = 15u16;
4646
}
4747

48+
pub mod attr {
49+
/// Terminal attributes for use with term.attr().
50+
/// Most attributes can only be turned on and must be turned off with term.reset().
51+
/// The ones that can be turned off explicitly take a boolean value.
52+
/// Color is also represented as an attribute for convenience.
53+
pub enum Attr {
54+
/// Bold (or possibly bright) mode
55+
Bold,
56+
/// Dim mode, also called faint or half-bright. Often not supported
57+
Dim,
58+
/// Italics mode. Often not supported
59+
Italic(bool),
60+
/// Underline mode
61+
Underline(bool),
62+
/// Blink mode
63+
Blink,
64+
/// Standout mode. Often implemented as Reverse, sometimes coupled with Bold
65+
Standout(bool),
66+
/// Reverse mode, inverts the foreground and background colors
67+
Reverse,
68+
/// Secure mode, also called invis mode. Hides the printed text
69+
Secure,
70+
/// Convenience attribute to set the foreground color
71+
ForegroundColor(super::color::Color),
72+
/// Convenience attribute to set the background color
73+
BackgroundColor(super::color::Color)
74+
}
75+
}
76+
77+
#[cfg(not(target_os = "win32"))]
78+
priv fn cap_for_attr(attr: attr::Attr) -> &'static str {
79+
match attr {
80+
attr::Bold => "bold",
81+
attr::Dim => "dim",
82+
attr::Italic(true) => "sitm",
83+
attr::Italic(false) => "ritm",
84+
attr::Underline(true) => "smul",
85+
attr::Underline(false) => "rmul",
86+
attr::Blink => "blink",
87+
attr::Standout(true) => "smso",
88+
attr::Standout(false) => "rmso",
89+
attr::Reverse => "rev",
90+
attr::Secure => "invis",
91+
attr::ForegroundColor(_) => "setaf",
92+
attr::BackgroundColor(_) => "setab"
93+
}
94+
}
95+
4896
#[cfg(not(target_os = "win32"))]
4997
pub struct Terminal {
5098
num_colors: u16,
@@ -88,45 +136,100 @@ impl Terminal {
88136
///
89137
/// If the color is a bright color, but the terminal only supports 8 colors,
90138
/// the corresponding normal color will be used instead.
91-
pub fn fg(&self, color: color::Color) {
139+
///
140+
/// Returns true if the color was set, false otherwise.
141+
pub fn fg(&self, color: color::Color) -> bool {
92142
let color = self.dim_if_necessary(color);
93143
if self.num_colors > color {
94144
let s = expand(*self.ti.strings.find_equiv(&("setaf")).unwrap(),
95145
[Number(color as int)], &mut Variables::new());
96146
if s.is_ok() {
97147
self.out.write(s.unwrap());
148+
return true
98149
} else {
99150
warn!("%s", s.unwrap_err());
100151
}
101152
}
153+
false
102154
}
103155
/// Sets the background color to the given color.
104156
///
105157
/// If the color is a bright color, but the terminal only supports 8 colors,
106158
/// the corresponding normal color will be used instead.
107-
pub fn bg(&self, color: color::Color) {
159+
///
160+
/// Rturns true if the color was set, false otherwise.
161+
pub fn bg(&self, color: color::Color) -> bool {
108162
let color = self.dim_if_necessary(color);
109163
if self.num_colors > color {
110164
let s = expand(*self.ti.strings.find_equiv(&("setab")).unwrap(),
111165
[Number(color as int)], &mut Variables::new());
112166
if s.is_ok() {
113167
self.out.write(s.unwrap());
168+
return true
114169
} else {
115170
warn!("%s", s.unwrap_err());
116171
}
117172
}
173+
false
174+
}
175+
176+
/// Sets the given terminal attribute, if supported.
177+
/// Returns true if the attribute was supported, false otherwise.
178+
pub fn attr(&self, attr: attr::Attr) -> bool {
179+
match attr {
180+
attr::ForegroundColor(c) => self.fg(c),
181+
attr::BackgroundColor(c) => self.bg(c),
182+
_ => {
183+
let cap = cap_for_attr(attr);
184+
let parm = self.ti.strings.find_equiv(&cap);
185+
if parm.is_some() {
186+
let s = expand(*parm.unwrap(), [], &mut Variables::new());
187+
if s.is_ok() {
188+
self.out.write(s.unwrap());
189+
return true
190+
} else {
191+
warn!("%s", s.unwrap_err());
192+
}
193+
}
194+
false
195+
}
196+
}
118197
}
198+
199+
/// Returns whether the given terminal attribute is supported.
200+
pub fn supports_attr(&self, attr: attr::Attr) -> bool {
201+
match attr {
202+
attr::ForegroundColor(_) | attr::BackgroundColor(_) => {
203+
self.num_colors > 0
204+
}
205+
_ => {
206+
let cap = cap_for_attr(attr);
207+
self.ti.strings.find_equiv(&cap).is_some()
208+
}
209+
}
210+
}
211+
212+
/// Resets all terminal attributes and color to the default.
119213
pub fn reset(&self) {
120-
let mut vars = Variables::new();
121-
let s = do self.ti.strings.find_equiv(&("op"))
122-
.map_consume_default(Err(~"can't find terminfo capability `op`")) |op| {
123-
expand(copy *op, [], &mut vars)
124-
};
214+
let mut cap = self.ti.strings.find_equiv(&("sgr0"));
215+
if cap.is_none() {
216+
// are there any terminals that have color/attrs and not sgr0?
217+
// Try falling back to sgr, then op
218+
cap = self.ti.strings.find_equiv(&("sgr"));
219+
if cap.is_none() {
220+
cap = self.ti.strings.find_equiv(&("op"));
221+
}
222+
}
223+
let s = do cap.map_consume_default(Err(~"can't find terminfo capability `sgr0`")) |op| {
224+
expand(*op, [], &mut Variables::new())
225+
};
125226
if s.is_ok() {
126227
self.out.write(s.unwrap());
127228
} else if self.num_colors > 0 {
128229
warn!("%s", s.unwrap_err());
129230
} else {
231+
// if we support attributes but not color, it would be nice to still warn!()
232+
// but it's not worth testing all known attributes just for this.
130233
debug!("%s", s.unwrap_err());
131234
}
132235
}
@@ -144,10 +247,20 @@ impl Terminal {
144247
return Ok(Terminal {out: out, num_colors: 0});
145248
}
146249

147-
pub fn fg(&self, _color: color::Color) {
250+
pub fn fg(&self, _color: color::Color) -> bool {
251+
false
252+
}
253+
254+
pub fn bg(&self, _color: color::Color) -> bool {
255+
false
256+
}
257+
258+
pub fn attr(&self, _attr: attr::Attr) -> bool {
259+
false
148260
}
149261

150-
pub fn bg(&self, _color: color::Color) {
262+
pub fn supports_attr(&self, _attr: attr::Attr) -> bool {
263+
false
151264
}
152265

153266
pub fn reset(&self) {

src/libsyntax/diagnostic.rs

+32-14
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use codemap;
1313

1414
use std::io;
1515
use std::uint;
16+
use std::local_data;
1617
use extra::term;
1718

1819
pub type Emitter = @fn(cmsp: Option<(@codemap::CodeMap, span)>,
@@ -186,22 +187,38 @@ fn diagnosticcolor(lvl: level) -> term::color::Color {
186187
}
187188
}
188189

189-
fn print_maybe_colored(msg: &str, color: term::color::Color) {
190+
fn print_maybe_styled(msg: &str, color: term::attr::Attr) {
191+
#[cfg(not(stage0))]
192+
static tls_terminal: local_data::Key<@Option<term::Terminal>> = &local_data::Key;
193+
#[cfg(stage0)]
194+
fn tls_terminal(_: @Option<term::Terminal>) {}
195+
190196
let stderr = io::stderr();
191197

192-
let t = term::Terminal::new(stderr);
198+
if stderr.get_type() == io::Screen {
199+
let t = match local_data::get(tls_terminal, |v| v.map_consume(|&k|k)) {
200+
None => {
201+
let t = term::Terminal::new(stderr);
202+
let tls = @match t {
203+
Ok(t) => Some(t),
204+
Err(_) => None
205+
};
206+
local_data::set(tls_terminal, tls);
207+
&*tls
208+
}
209+
Some(tls) => &*tls
210+
};
193211

194-
match t {
195-
Ok(term) => {
196-
if stderr.get_type() == io::Screen {
197-
term.fg(color);
212+
match t {
213+
&Some(ref term) => {
214+
term.attr(color);
198215
stderr.write_str(msg);
199216
term.reset();
200-
} else {
201-
stderr.write_str(msg);
202-
}
203-
},
204-
_ => stderr.write_str(msg)
217+
},
218+
_ => stderr.write_str(msg)
219+
}
220+
} else {
221+
stderr.write_str(msg);
205222
}
206223
}
207224

@@ -212,8 +229,9 @@ fn print_diagnostic(topic: &str, lvl: level, msg: &str) {
212229
stderr.write_str(fmt!("%s ", topic));
213230
}
214231

215-
print_maybe_colored(fmt!("%s: ", diagnosticstr(lvl)), diagnosticcolor(lvl));
216-
print_maybe_colored(fmt!("%s\n", msg), term::color::BRIGHT_WHITE);
232+
print_maybe_styled(fmt!("%s: ", diagnosticstr(lvl)),
233+
term::attr::ForegroundColor(diagnosticcolor(lvl)));
234+
print_maybe_styled(fmt!("%s\n", msg), term::attr::Bold);
217235
}
218236

219237
pub fn collect(messages: @mut ~[~str])
@@ -312,7 +330,7 @@ fn highlight_lines(cm: @codemap::CodeMap,
312330
s.push_char('~')
313331
}
314332
}
315-
print_maybe_colored(s + "\n", diagnosticcolor(lvl));
333+
print_maybe_styled(s + "\n", term::attr::ForegroundColor(diagnosticcolor(lvl)));
316334
}
317335
}
318336

0 commit comments

Comments
 (0)