(index<- ) ./libextra/term.rs
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.
4 //
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.
10
11 //! Simple ANSI color library
12
13 #[allow(missing_doc)];
14
15
16 use std::io;
17
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.
25
26 pub mod color {
27 pub type Color = u16;
28
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;
37
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;
46 }
47
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 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
96 #[cfg(not(target_os = "win32"))]
97 pub struct Terminal {
98 num_colors: u16,
99 priv out: @io::Writer,
100 priv ti: ~TermInfo
101 }
102
103 #[cfg(target_os = "win32")]
104 pub struct Terminal {
105 num_colors: u16,
106 priv out: @io::Writer,
107 }
108
109 #[cfg(not(target_os = "win32"))]
110 impl Terminal {
111 pub fn new(out: @io::Writer) -> Result<Terminal, ~str> {
112 let term = os::getenv("TERM");
113 if term.is_none() {
114 return Err(~"TERM environment variable undefined");
115 }
116
117 let entry = open(term.unwrap());
118 if entry.is_err() {
119 return Err(entry.unwrap_err());
120 }
121
122 let ti = parse(entry.unwrap(), false);
123 if ti.is_err() {
124 return Err(ti.unwrap_err());
125 }
126
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_move_default(0, |&n| n)
131 } else { 0 };
132
133 return Ok(Terminal {out: out, ti: inf, num_colors: nc});
134 }
135 /// Sets the foreground color to the given color.
136 ///
137 /// If the color is a bright color, but the terminal only supports 8 colors,
138 /// the corresponding normal color will be used instead.
139 ///
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());
146 if s.is_ok() {
147 self.out.write(s.unwrap());
148 return true
149 } else {
150 warn!("%s", s.unwrap_err());
151 }
152 }
153 false
154 }
155 /// Sets the background color to the given color.
156 ///
157 /// If the color is a bright color, but the terminal only supports 8 colors,
158 /// the corresponding normal color will be used instead.
159 ///
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());
166 if s.is_ok() {
167 self.out.write(s.unwrap());
168 return true
169 } else {
170 warn!("%s", s.unwrap_err());
171 }
172 }
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 }
197 }
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.
213 pub fn reset(&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"));
221 }
222 }
223 let s = do cap.map_move_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", 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", s.unwrap_err());
234 }
235 }
236
237 fn dim_if_necessary(&self, color: color::Color) -> color::Color {
238 if color >= self.num_colors && color >= 8 && color < 16 {
239 color-8
240 } else { color }
241 }
242 }
243
244 #[cfg(target_os = "win32")]
245 impl Terminal {
246 pub fn new(out: @io::Writer) -> Result<Terminal, ~str> {
247 return Ok(Terminal {out: out, num_colors: 0});
248 }
249
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
260 }
261
262 pub fn supports_attr(&self, _attr: attr::Attr) -> bool {
263 false
264 }
265
266 pub fn reset(&self) {
267 }
268 }
libextra/term.rs:27:4-27:4 -ty- definition:
pub type Color = u16;
references:-39: pub static BRIGHT_RED: Color = 9u16;
43: pub static BRIGHT_MAGENTA: Color = 13u16;
44: pub static BRIGHT_CYAN: Color = 14u16;
73: BackgroundColor(super::color::Color)
36: pub static WHITE: Color = 7u16;
42: pub static BRIGHT_BLUE: Color = 12u16;
30: pub static RED: Color = 1u16;
34: pub static MAGENTA: Color = 5u16;
33: pub static BLUE: Color = 4u16;
38: pub static BRIGHT_BLACK: Color = 8u16;
29: pub static BLACK: Color = 0u16;
161: pub fn bg(&self, color: color::Color) -> bool {
237: fn dim_if_necessary(&self, color: color::Color) -> color::Color {
45: pub static BRIGHT_WHITE: Color = 15u16;
32: pub static YELLOW: Color = 3u16;
71: ForegroundColor(super::color::Color),
40: pub static BRIGHT_GREEN: Color = 10u16;
31: pub static GREEN: Color = 2u16;
237: fn dim_if_necessary(&self, color: color::Color) -> color::Color {
41: pub static BRIGHT_YELLOW: Color = 11u16;
35: pub static CYAN: Color = 6u16;
141: pub fn fg(&self, color: color::Color) -> bool {
libextra/test.rs:
394: color: term::color::Color) {
libextra/term.rs:77:33-77:33 -fn- definition:
#[cfg(not(target_os = "win32"))]
fn cap_for_attr(attr: attr::Attr) -> &'static str {
references:-206: let cap = cap_for_attr(attr);
183: let cap = cap_for_attr(attr);
libextra/term.rs:53:4-53:4 -enum- definition:
pub enum Attr {
/// Bold (or possibly bright) mode
references:-78: fn cap_for_attr(attr: attr::Attr) -> &'static str {
178: pub fn attr(&self, attr: attr::Attr) -> bool {
200: pub fn supports_attr(&self, attr: attr::Attr) -> bool {
libextra/term.rs:96:33-96:33 -struct- definition:
#[cfg(not(target_os = "win32"))]
pub struct Terminal {
references:-110: impl Terminal {
111: pub fn new(out: @io::Writer) -> Result<Terminal, ~str> {
133: return Ok(Terminal {out: out, ti: inf, num_colors: nc});
libextra/test.rs:
312: term: Option<term::Terminal>,