Skip to content

Commit 690495d

Browse files
committed
term: Add new function .attr() to toggle terminal attributes
Also add .supports_attr() to test for attribute support without writing anything to output. Update .reset() to use sgr0 instead of op.
1 parent 7d8a0fd commit 690495d

File tree

1 file changed

+108
-5
lines changed

1 file changed

+108
-5
lines changed

src/libextra/term.rs

Lines changed: 108 additions & 5 deletions
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,
@@ -124,17 +172,64 @@ impl Terminal {
124172
}
125173
false
126174
}
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.
127213
pub fn reset(&self) {
128-
let mut vars = Variables::new();
129-
let s = do self.ti.strings.find_equiv(&("op"))
130-
.map_consume_default(Err(~"can't find terminfo capability `op`")) |op| {
131-
expand(copy *op, [], &mut vars)
132-
};
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+
};
133226
if s.is_ok() {
134227
self.out.write(s.unwrap());
135228
} else if self.num_colors > 0 {
136229
warn!("%s", s.unwrap_err());
137230
} 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.
138233
debug!("%s", s.unwrap_err());
139234
}
140235
}
@@ -160,6 +255,14 @@ impl Terminal {
160255
false
161256
}
162257

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+
163266
pub fn reset(&self) {
164267
}
165268
}

0 commit comments

Comments
 (0)