1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Simple ANSI color library
13 #[allow(missing_doc)];
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};
24 // FIXME (#2807): Windows support.
29 pub static BLACK: Color = 0u16;
30 pub static RED: Color = 1u16;
31 pub static GREEN: Color = 2u16;
32 pub static YELLOW: Color = 3u16;
33 pub static BLUE: Color = 4u16;
34 pub static MAGENTA: Color = 5u16;
35 pub static CYAN: Color = 6u16;
36 pub static WHITE: Color = 7u16;
38 pub static BRIGHT_BLACK: Color = 8u16;
39 pub static BRIGHT_RED: Color = 9u16;
40 pub static BRIGHT_GREEN: Color = 10u16;
41 pub static BRIGHT_YELLOW: Color = 11u16;
42 pub static BRIGHT_BLUE: Color = 12u16;
43 pub static BRIGHT_MAGENTA: Color = 13u16;
44 pub static BRIGHT_CYAN: Color = 14u16;
45 pub static BRIGHT_WHITE: Color = 15u16;
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.
54 /// Bold (or possibly bright) mode
56 /// Dim mode, also called faint or half-bright. Often not supported
58 /// Italics mode. Often not supported
64 /// Standout mode. Often implemented as Reverse, sometimes coupled with Bold
66 /// Reverse mode, inverts the foreground and background colors
68 /// Secure mode, also called invis mode. Hides the printed text
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)
77 #[cfg(not(target_os = "win32"))]
78 fn cap_for_attr(attr: attr::Attr) -> &'static str {
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"
96 #[cfg(not(target_os = "win32"))]
99 priv out: @mut io::Writer,
103 #[cfg(target_os = "win32")]
104 pub struct Terminal {
105 priv num_colors: u16,
106 priv out: @mut io::Writer,
109 #[cfg(not(target_os = "win32"))]
111 pub fn new(out: @mut io::Writer) -> Result<Terminal, ~str> {
112 let term = os::getenv("TERM");
114 return Err(~"TERM environment variable undefined");
117 let entry = open(term.unwrap());
119 return Err(entry.unwrap_err());
122 let ti = parse(entry.unwrap(), false);
124 return Err(ti.unwrap_err());
127 let inf = ti.unwrap();
128 let nc = if inf.strings.find_equiv(&("setaf")).is_some()
129 && inf.strings.find_equiv(&("setab")).is_some() {
130 inf.numbers.find_equiv(&("colors")).map_default(0, |&n| n)
133 return Ok(Terminal {out: out, ti: inf, num_colors: nc});
135 /// Sets the foreground color to the given color.
137 /// If the color is a bright color, but the terminal only supports 8 colors,
138 /// the corresponding normal color will be used instead.
140 /// Returns true if the color was set, false otherwise.
141 pub fn fg(&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());
147 self.out.write(s.unwrap());
150 warn!("{}", s.unwrap_err());
155 /// Sets the background color to the given color.
157 /// If the color is a bright color, but the terminal only supports 8 colors,
158 /// the corresponding normal color will be used instead.
160 /// Returns true if the color was set, false otherwise.
161 pub fn bg(&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());
167 self.out.write(s.unwrap());
170 warn!("{}", s.unwrap_err());
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 {
180 attr::ForegroundColor(c) => self.fg(c),
181 attr::BackgroundColor(c) => self.bg(c),
183 let cap = cap_for_attr(attr);
184 let parm = self.ti.strings.find_equiv(&cap);
186 let s = expand(*parm.unwrap(), [], &mut Variables::new());
188 self.out.write(s.unwrap());
191 warn!("{}", s.unwrap_err());
199 /// Returns whether the given terminal attribute is supported.
200 pub fn supports_attr(&self, attr: attr::Attr) -> bool {
202 attr::ForegroundColor(_) | attr::BackgroundColor(_) => {
206 let cap = cap_for_attr(attr);
207 self.ti.strings.find_equiv(&cap).is_some()
212 /// Resets all terminal attributes and color to the default.
213 pub fn reset(&self) {
214 let mut cap = self.ti.strings.find_equiv(&("sgr0"));
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"));
220 cap = self.ti.strings.find_equiv(&("op"));
223 let s = do cap.map_default(Err(~"can't find terminfo capability `sgr0`")) |op| {
224 expand(*op, [], &mut Variables::new())
227 self.out.write(s.unwrap());
228 } else if self.num_colors > 0 {
229 warn!("{}", s.unwrap_err());
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());
237 fn dim_if_necessary(&self, color: color::Color) -> color::Color {
238 if color >= self.num_colors && color >= 8 && color < 16 {
244 #[cfg(target_os = "win32")]
246 pub fn new(out: @mut io::Writer) -> Result<Terminal, ~str> {
247 return Ok(Terminal {out: out, num_colors: 0});
250 pub fn fg(&self, _color: color::Color) -> bool {
254 pub fn bg(&self, _color: color::Color) -> bool {
258 pub fn attr(&self, _attr: attr::Attr) -> bool {
262 pub fn supports_attr(&self, _attr: attr::Attr) -> bool {
266 pub fn reset(&self) {