(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(attrattr::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, colorcolor::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, colorcolor::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, attrattr::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, attrattr::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, colorcolor::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>,