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.
This commit is contained in:
Kevin Ballard 2013-07-10 14:46:20 -07:00
parent 7d8a0fdb7d
commit 690495de03

View File

@ -45,6 +45,54 @@ pub mod color {
pub static BRIGHT_WHITE: Color = 15u16;
}
pub mod attr {
/// Terminal attributes for use with term.attr().
/// Most attributes can only be turned on and must be turned off with term.reset().
/// The ones that can be turned off explicitly take a boolean value.
/// Color is also represented as an attribute for convenience.
pub enum Attr {
/// Bold (or possibly bright) mode
Bold,
/// Dim mode, also called faint or half-bright. Often not supported
Dim,
/// Italics mode. Often not supported
Italic(bool),
/// Underline mode
Underline(bool),
/// Blink mode
Blink,
/// Standout mode. Often implemented as Reverse, sometimes coupled with Bold
Standout(bool),
/// Reverse mode, inverts the foreground and background colors
Reverse,
/// Secure mode, also called invis mode. Hides the printed text
Secure,
/// Convenience attribute to set the foreground color
ForegroundColor(super::color::Color),
/// Convenience attribute to set the background color
BackgroundColor(super::color::Color)
}
}
#[cfg(not(target_os = "win32"))]
priv fn cap_for_attr(attr: attr::Attr) -> &'static str {
match attr {
attr::Bold => "bold",
attr::Dim => "dim",
attr::Italic(true) => "sitm",
attr::Italic(false) => "ritm",
attr::Underline(true) => "smul",
attr::Underline(false) => "rmul",
attr::Blink => "blink",
attr::Standout(true) => "smso",
attr::Standout(false) => "rmso",
attr::Reverse => "rev",
attr::Secure => "invis",
attr::ForegroundColor(_) => "setaf",
attr::BackgroundColor(_) => "setab"
}
}
#[cfg(not(target_os = "win32"))]
pub struct Terminal {
num_colors: u16,
@ -124,17 +172,64 @@ impl Terminal {
}
false
}
/// Sets the given terminal attribute, if supported.
/// Returns true if the attribute was supported, false otherwise.
pub fn attr(&self, attr: attr::Attr) -> bool {
match attr {
attr::ForegroundColor(c) => self.fg(c),
attr::BackgroundColor(c) => self.bg(c),
_ => {
let cap = cap_for_attr(attr);
let parm = self.ti.strings.find_equiv(&cap);
if parm.is_some() {
let s = expand(*parm.unwrap(), [], &mut Variables::new());
if s.is_ok() {
self.out.write(s.unwrap());
return true
} else {
warn!("%s", s.unwrap_err());
}
}
false
}
}
}
/// Returns whether the given terminal attribute is supported.
pub fn supports_attr(&self, attr: attr::Attr) -> bool {
match attr {
attr::ForegroundColor(_) | attr::BackgroundColor(_) => {
self.num_colors > 0
}
_ => {
let cap = cap_for_attr(attr);
self.ti.strings.find_equiv(&cap).is_some()
}
}
}
/// Resets all terminal attributes and color to the default.
pub fn reset(&self) {
let mut vars = Variables::new();
let s = do self.ti.strings.find_equiv(&("op"))
.map_consume_default(Err(~"can't find terminfo capability `op`")) |op| {
expand(copy *op, [], &mut vars)
};
let mut cap = self.ti.strings.find_equiv(&("sgr0"));
if cap.is_none() {
// are there any terminals that have color/attrs and not sgr0?
// Try falling back to sgr, then op
cap = self.ti.strings.find_equiv(&("sgr"));
if cap.is_none() {
cap = self.ti.strings.find_equiv(&("op"));
}
}
let s = do cap.map_consume_default(Err(~"can't find terminfo capability `sgr0`")) |op| {
expand(*op, [], &mut Variables::new())
};
if s.is_ok() {
self.out.write(s.unwrap());
} else if self.num_colors > 0 {
warn!("%s", s.unwrap_err());
} else {
// if we support attributes but not color, it would be nice to still warn!()
// but it's not worth testing all known attributes just for this.
debug!("%s", s.unwrap_err());
}
}
@ -160,6 +255,14 @@ impl Terminal {
false
}
pub fn attr(&self, _attr: attr::Attr) -> bool {
false
}
pub fn supports_attr(&self, _attr: attr::Attr) -> bool {
false
}
pub fn reset(&self) {
}
}