Skip to content

Commit ea8b273

Browse files
committed
Support ANSI colors in msys terminals. See rust-lang#2807
1 parent c2c2c4d commit ea8b273

File tree

1 file changed

+93
-103
lines changed

1 file changed

+93
-103
lines changed

src/libextra/term.rs

Lines changed: 93 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,11 @@
1515

1616
use std::io::{Decorator, Writer};
1717

18-
#[cfg(not(target_os = "win32"))] use std::os;
19-
#[cfg(not(target_os = "win32"))] use terminfo::*;
20-
#[cfg(not(target_os = "win32"))] use terminfo::searcher::open;
21-
#[cfg(not(target_os = "win32"))] use terminfo::parser::compiled::parse;
22-
#[cfg(not(target_os = "win32"))] use terminfo::parm::{expand, Number, Variables};
23-
24-
// FIXME (#2807): Windows support.
18+
use std::os;
19+
use terminfo::*;
20+
use terminfo::searcher::open;
21+
use terminfo::parser::compiled::parse;
22+
use terminfo::parm::{expand, Number, Variables};
2523

2624
pub mod color {
2725
pub type Color = u16;
@@ -74,7 +72,6 @@ pub mod attr {
7472
}
7573
}
7674

77-
#[cfg(not(target_os = "win32"))]
7875
fn cap_for_attr(attr: attr::Attr) -> &'static str {
7976
match attr {
8077
attr::Bold => "bold",
@@ -93,29 +90,24 @@ fn cap_for_attr(attr: attr::Attr) -> &'static str {
9390
}
9491
}
9592

96-
#[cfg(not(target_os = "win32"))]
9793
pub struct Terminal<T> {
9894
priv num_colors: u16,
9995
priv out: T,
100-
priv ti: ~TermInfo
96+
priv ti: Option<~TermInfo>
10197
}
10298

103-
#[cfg(target_os = "win32")]
104-
pub struct Terminal<T> {
105-
priv num_colors: u16,
106-
priv out: T,
107-
}
108-
109-
#[cfg(not(target_os = "win32"))]
11099
impl<T: Writer> Terminal<T> {
111100
pub fn new(out: T) -> Result<Terminal<T>, ~str> {
112-
let term = os::getenv("TERM");
113-
if term.is_none() {
114-
return Err(~"TERM environment variable undefined");
115-
}
101+
let term = match os::getenv("TERM") {
102+
None => return Err(~"TERM environment variable undefined"),
103+
Some(t) => t
104+
};
116105

117-
let entry = open(term.unwrap());
106+
let entry = open(term);
118107
if entry.is_err() {
108+
if term == ~"cygwin" {
109+
return Ok(Terminal {out: out, ti: None, num_colors: 16});
110+
}
119111
return Err(entry.unwrap_err());
120112
}
121113

@@ -130,47 +122,56 @@ impl<T: Writer> Terminal<T> {
130122
inf.numbers.find_equiv(&("colors")).map_default(0, |&n| n)
131123
} else { 0 };
132124

133-
return Ok(Terminal {out: out, ti: inf, num_colors: nc});
125+
return Ok(Terminal {out: out, ti: Some(inf), num_colors: nc});
134126
}
127+
128+
/// Helper function, see fg and bg.
129+
fn set_color(&mut self, color: color::Color, cap: &str) -> bool {
130+
let color = self.dim_if_necessary(color);
131+
if self.num_colors > color {
132+
match self.ti {
133+
None => {
134+
let ansi = if color < 8 {
135+
format!("\x1b[{}m", 30 + color)
136+
} else {
137+
format!("\x1b[{};1m", 22 + color)
138+
};
139+
self.out.write(ansi.as_bytes());
140+
return true
141+
},
142+
Some(ref ti) => {
143+
let s = expand(*ti.strings.find_equiv(&(cap)).unwrap(),
144+
[Number(color as int)], &mut Variables::new());
145+
if s.is_ok() {
146+
self.out.write(s.unwrap());
147+
return true
148+
} else {
149+
warn!("{}", s.unwrap_err());
150+
}
151+
}
152+
}
153+
}
154+
false
155+
}
156+
135157
/// Sets the foreground color to the given color.
136158
///
137159
/// If the color is a bright color, but the terminal only supports 8 colors,
138160
/// the corresponding normal color will be used instead.
139161
///
140162
/// Returns true if the color was set, false otherwise.
141163
pub fn fg(&mut self, color: color::Color) -> bool {
142-
let color = self.dim_if_necessary(color);
143-
if self.num_colors > color {
144-
let s = expand(*self.ti.strings.find_equiv(&("setaf")).unwrap(),
145-
[Number(color as int)], &mut Variables::new());
146-
if s.is_ok() {
147-
self.out.write(s.unwrap());
148-
return true
149-
} else {
150-
warn!("{}", s.unwrap_err());
151-
}
152-
}
153-
false
164+
self.set_color(color, "setaf")
154165
}
166+
155167
/// Sets the background color to the given color.
156168
///
157169
/// If the color is a bright color, but the terminal only supports 8 colors,
158170
/// the corresponding normal color will be used instead.
159171
///
160172
/// Returns true if the color was set, false otherwise.
161173
pub fn bg(&mut self, color: color::Color) -> bool {
162-
let color = self.dim_if_necessary(color);
163-
if self.num_colors > color {
164-
let s = expand(*self.ti.strings.find_equiv(&("setab")).unwrap(),
165-
[Number(color as int)], &mut Variables::new());
166-
if s.is_ok() {
167-
self.out.write(s.unwrap());
168-
return true
169-
} else {
170-
warn!("{}", s.unwrap_err());
171-
}
172-
}
173-
false
174+
self.set_color(color, "setab")
174175
}
175176

176177
/// Sets the given terminal attribute, if supported.
@@ -180,18 +181,23 @@ impl<T: Writer> Terminal<T> {
180181
attr::ForegroundColor(c) => self.fg(c),
181182
attr::BackgroundColor(c) => self.bg(c),
182183
_ => {
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.unwrap_err());
184+
match self.ti {
185+
None => return false,
186+
Some(ref ti) => {
187+
let cap = cap_for_attr(attr);
188+
let parm = ti.strings.find_equiv(&cap);
189+
if parm.is_some() {
190+
let s = expand(*parm.unwrap(), [], &mut Variables::new());
191+
if s.is_ok() {
192+
self.out.write(s.unwrap());
193+
return true
194+
} else {
195+
warn!("{}", s.unwrap_err());
196+
}
197+
}
198+
false
192199
}
193200
}
194-
false
195201
}
196202
}
197203
}
@@ -204,34 +210,44 @@ impl<T: Writer> Terminal<T> {
204210
}
205211
_ => {
206212
let cap = cap_for_attr(attr);
207-
self.ti.strings.find_equiv(&cap).is_some()
213+
match self.ti {
214+
None => return false,
215+
Some(ref ti) => ti.strings.find_equiv(&cap).is_some()
216+
}
208217
}
209218
}
210219
}
211220

212221
/// Resets all terminal attributes and color to the default.
213222
pub fn reset(&mut self) {
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"));
223+
match self.ti {
224+
None => if self.num_colors > 0 {
225+
self.out.write([27u8, 91u8, 51u8, 57u8, 59u8, 52u8, 57u8, 109u8])
226+
},
227+
Some(ref ti) => {
228+
let mut cap = ti.strings.find_equiv(&("sgr0"));
229+
if cap.is_none() {
230+
// are there any terminals that have color/attrs and not sgr0?
231+
// Try falling back to sgr, then op
232+
cap = ti.strings.find_equiv(&("sgr"));
233+
if cap.is_none() {
234+
cap = ti.strings.find_equiv(&("op"));
235+
}
236+
}
237+
let s = cap.map_default(Err(~"can't find terminfo capability `sgr0`"), |op| {
238+
expand(*op, [], &mut Variables::new())
239+
});
240+
if s.is_ok() {
241+
self.out.write(s.unwrap());
242+
} else if self.num_colors > 0 {
243+
warn!("{}", s.unwrap_err());
244+
} else {
245+
// if we support attributes but not color, it would be nice to still warn!()
246+
// but it's not worth testing all known attributes just for this.
247+
debug!("{}", s.unwrap_err());
248+
}
221249
}
222250
}
223-
let s = cap.map_default(Err(~"can't find terminfo capability `sgr0`"), |op| {
224-
expand(*op, [], &mut Variables::new())
225-
});
226-
if s.is_ok() {
227-
self.out.write(s.unwrap());
228-
} else if self.num_colors > 0 {
229-
warn!("{}", s.unwrap_err());
230-
} 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.
233-
debug!("{}", s.unwrap_err());
234-
}
235251
}
236252

237253
fn dim_if_necessary(&self, color: color::Color) -> color::Color {
@@ -241,32 +257,6 @@ impl<T: Writer> Terminal<T> {
241257
}
242258
}
243259

244-
#[cfg(target_os = "win32")]
245-
impl<T: Writer> Terminal<T> {
246-
pub fn new(out: T) -> Result<Terminal<T>, ~str> {
247-
return Ok(Terminal {out: out, num_colors: 0});
248-
}
249-
250-
pub fn fg(&mut self, _color: color::Color) -> bool {
251-
false
252-
}
253-
254-
pub fn bg(&mut self, _color: color::Color) -> bool {
255-
false
256-
}
257-
258-
pub fn attr(&mut self, _attr: attr::Attr) -> bool {
259-
false
260-
}
261-
262-
pub fn supports_attr(&self, _attr: attr::Attr) -> bool {
263-
false
264-
}
265-
266-
pub fn reset(&self) {
267-
}
268-
}
269-
270260
impl<T: Writer> Decorator<T> for Terminal<T> {
271261
fn inner(self) -> T {
272262
self.out

0 commit comments

Comments
 (0)