(index<- )        ./libterm/lib.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 2013-2014 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  #![crate_id = "term#0.11-pre"]
  14  #![comment = "Simple ANSI color library"]
  15  #![license = "MIT/ASL2"]
  16  #![crate_type = "rlib"]
  17  #![crate_type = "dylib"]
  18  #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
  19         html_favicon_url = "http://www.rust-lang.org/favicon.ico",
  20         html_root_url = "http://static.rust-lang.org/doc/master")]
  21  
  22  #![feature(macro_rules)]
  23  
  24  #![deny(missing_doc)]
  25  
  26  extern crate collections;
  27  
  28  use std::io;
  29  use std::os;
  30  use terminfo::TermInfo;
  31  use terminfo::searcher::open;
  32  use terminfo::parser::compiled::{parse, msys_terminfo};
  33  use terminfo::parm::{expand, Number, Variables};
  34  
  35  pub mod terminfo;
  36  
  37  // FIXME (#2807): Windows support.
  38  
  39  /// Terminal color definitions
  40  pub mod color {
  41      /// Number for a terminal color
  42      pub type Color = u16;
  43  
  44      pub static BLACK:   Color = 0u16;
  45      pub static RED:     Color = 1u16;
  46      pub static GREEN:   Color = 2u16;
  47      pub static YELLOW:  Color = 3u16;
  48      pub static BLUE:    Color = 4u16;
  49      pub static MAGENTA: Color = 5u16;
  50      pub static CYAN:    Color = 6u16;
  51      pub static WHITE:   Color = 7u16;
  52  
  53      pub static BRIGHT_BLACK:   Color = 8u16;
  54      pub static BRIGHT_RED:     Color = 9u16;
  55      pub static BRIGHT_GREEN:   Color = 10u16;
  56      pub static BRIGHT_YELLOW:  Color = 11u16;
  57      pub static BRIGHT_BLUE:    Color = 12u16;
  58      pub static BRIGHT_MAGENTA: Color = 13u16;
  59      pub static BRIGHT_CYAN:    Color = 14u16;
  60      pub static BRIGHT_WHITE:   Color = 15u16;
  61  }
  62  
  63  /// Terminal attributes
  64  pub mod attr {
  65      /// Terminal attributes for use with term.attr().
  66      ///
  67      /// Most attributes can only be turned on and must be turned off with term.reset().
  68      /// The ones that can be turned off explicitly take a boolean value.
  69      /// Color is also represented as an attribute for convenience.
  70      pub enum Attr {
  71          /// Bold (or possibly bright) mode
  72          Bold,
  73          /// Dim mode, also called faint or half-bright. Often not supported
  74          Dim,
  75          /// Italics mode. Often not supported
  76          Italic(bool),
  77          /// Underline mode
  78          Underline(bool),
  79          /// Blink mode
  80          Blink,
  81          /// Standout mode. Often implemented as Reverse, sometimes coupled with Bold
  82          Standout(bool),
  83          /// Reverse mode, inverts the foreground and background colors
  84          Reverse,
  85          /// Secure mode, also called invis mode. Hides the printed text
  86          Secure,
  87          /// Convenience attribute to set the foreground color
  88          ForegroundColor(super::color::Color),
  89          /// Convenience attribute to set the background color
  90          BackgroundColor(super::color::Color)
  91      }
  92  }
  93  
  94  fn cap_for_attr(attrattr::Attr) -> &'static str {
  95      match attr {
  96          attr::Bold               => "bold",
  97          attr::Dim                => "dim",
  98          attr::Italic(true)       => "sitm",
  99          attr::Italic(false)      => "ritm",
 100          attr::Underline(true)    => "smul",
 101          attr::Underline(false)   => "rmul",
 102          attr::Blink              => "blink",
 103          attr::Standout(true)     => "smso",
 104          attr::Standout(false)    => "rmso",
 105          attr::Reverse            => "rev",
 106          attr::Secure             => "invis",
 107          attr::ForegroundColor(_) => "setaf",
 108          attr::BackgroundColor(_) => "setab"
 109      }
 110  }
 111  
 112  /// A Terminal that knows how many colors it supports, with a reference to its
 113  /// parsed TermInfo database record.
 114  pub struct Terminal<T> {
 115      num_colors: u16,
 116      out: T,
 117      ti: Box<TermInfo>,
 118  }
 119  
 120  impl<T: Writer> Terminal<T> {
 121      /// Returns a wrapped output stream (`Terminal<T>`) as a `Result`.
 122      ///
 123      /// Returns `Err()` if the TERM environment variable is undefined.
 124      /// TERM should be set to something like `xterm-color` or `screen-256color`.
 125      ///
 126      /// Returns `Err()` on failure to open the terminfo database correctly.
 127      /// Also, in the event that the individual terminfo database entry can not
 128      /// be parsed.
 129      pub fn new(outT) -> Result<Terminal<T>, ~str> {
 130          let term = match os::getenv("TERM") {
 131              Some(t) => t,
 132              None => return Err("TERM environment variable undefined".to_owned())
 133          };
 134  
 135          let mut file = match open(term) {
 136              Ok(file) => file,
 137              Err(err) => {
 138                  if "cygwin" == term { // msys terminal
 139                      return Ok(Terminal {
 140                          out: out,
 141                          ti: msys_terminfo(),
 142                          num_colors: 8
 143                      });
 144                  }
 145                  return Err(err);
 146              }
 147          };
 148  
 149          let inf = try!(parse(&mut file, false));
 150  
 151          let nc = if inf.strings.find_equiv(&("setaf")).is_some()
 152                   && inf.strings.find_equiv(&("setab")).is_some() {
 153                       inf.numbers.find_equiv(&("colors")).map_or(0, |&n| n)
 154                   } else { 0 };
 155  
 156          return Ok(Terminal {out: out, ti: inf, num_colors: nc});
 157      }
 158      /// Sets the foreground color to the given color.
 159      ///
 160      /// If the color is a bright color, but the terminal only supports 8 colors,
 161      /// the corresponding normal color will be used instead.
 162      ///
 163      /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
 164      /// if there was an I/O error.
 165      pub fn fg(&mut self, colorcolor::Color) -> io::IoResult<bool> {
 166          let color = self.dim_if_necessary(color);
 167          if self.num_colors > color {
 168              let s = expand(self.ti
 169                                 .strings
 170                                 .find_equiv(&("setaf"))
 171                                 .unwrap()
 172                                 .as_slice(),
 173                             [Number(color as int)], &mut Variables::new());
 174              if s.is_ok() {
 175                  try!(self.out.write(s.unwrap().as_slice()));
 176                  return Ok(true)
 177              }
 178          }
 179          Ok(false)
 180      }
 181      /// Sets the background color to the given color.
 182      ///
 183      /// If the color is a bright color, but the terminal only supports 8 colors,
 184      /// the corresponding normal color will be used instead.
 185      ///
 186      /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
 187      /// if there was an I/O error.
 188      pub fn bg(&mut self, colorcolor::Color) -> io::IoResult<bool> {
 189          let color = self.dim_if_necessary(color);
 190          if self.num_colors > color {
 191              let s = expand(self.ti
 192                                 .strings
 193                                 .find_equiv(&("setab"))
 194                                 .unwrap()
 195                                 .as_slice(),
 196                             [Number(color as int)], &mut Variables::new());
 197              if s.is_ok() {
 198                  try!(self.out.write(s.unwrap().as_slice()));
 199                  return Ok(true)
 200              }
 201          }
 202          Ok(false)
 203      }
 204  
 205      /// Sets the given terminal attribute, if supported.
 206      /// Returns `Ok(true)` if the attribute was supported, `Ok(false)` otherwise,
 207      /// and `Err(e)` if there was an I/O error.
 208      pub fn attr(&mut self, attrattr::Attr) -> io::IoResult<bool> {
 209          match attr {
 210              attr::ForegroundColor(c) => self.fg(c),
 211              attr::BackgroundColor(c) => self.bg(c),
 212              _ => {
 213                  let cap = cap_for_attr(attr);
 214                  let parm = self.ti.strings.find_equiv(&cap);
 215                  if parm.is_some() {
 216                      let s = expand(parm.unwrap().as_slice(),
 217                                     [],
 218                                     &mut Variables::new());
 219                      if s.is_ok() {
 220                          try!(self.out.write(s.unwrap().as_slice()));
 221                          return Ok(true)
 222                      }
 223                  }
 224                  Ok(false)
 225              }
 226          }
 227      }
 228  
 229      /// Returns whether the given terminal attribute is supported.
 230      pub fn supports_attr(&self, attrattr::Attr) -> bool {
 231          match attr {
 232              attr::ForegroundColor(_) | attr::BackgroundColor(_) => {
 233                  self.num_colors > 0
 234              }
 235              _ => {
 236                  let cap = cap_for_attr(attr);
 237                  self.ti.strings.find_equiv(&cap).is_some()
 238              }
 239          }
 240      }
 241  
 242      /// Resets all terminal attributes and color to the default.
 243      /// Returns `Ok()`.
 244      pub fn reset(&mut self) -> io::IoResult<()> {
 245          let mut cap = self.ti.strings.find_equiv(&("sgr0"));
 246          if cap.is_none() {
 247              // are there any terminals that have color/attrs and not sgr0?
 248              // Try falling back to sgr, then op
 249              cap = self.ti.strings.find_equiv(&("sgr"));
 250              if cap.is_none() {
 251                  cap = self.ti.strings.find_equiv(&("op"));
 252              }
 253          }
 254          let s = cap.map_or(Err("can't find terminfo capability `sgr0`".to_owned()), |op| {
 255              expand(op.as_slice(), [], &mut Variables::new())
 256          });
 257          if s.is_ok() {
 258              return self.out.write(s.unwrap().as_slice())
 259          }
 260          Ok(())
 261      }
 262  
 263      fn dim_if_necessary(&self, colorcolor::Color) -> color::Color {
 264          if color >= self.num_colors && color >= 8 && color < 16 {
 265              color-8
 266          } else { color }
 267      }
 268  
 269      /// Returns the contained stream
 270      pub fn unwrap(self) -> T { self.out }
 271  
 272      /// Gets an immutable reference to the stream inside
 273      pub fn get_ref<'a>(&'a self) -> &'a T { &self.out }
 274  
 275      /// Gets a mutable reference to the stream inside
 276      pub fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.out }
 277  }
 278  
 279  impl<T: Writer> Writer for Terminal<T> {
 280      fn write(&mut self, buf&[u8]) -> io::IoResult<()> {
 281          self.out.write(buf)
 282      }
 283  
 284      fn flush(&mut self) -> io::IoResult<()> {
 285          self.out.flush()
 286      }
 287  }


libterm/lib.rs:42:4-42:4 -NK_AS_STR_TODO- definition:
    pub type Color = u16;
    pub static BLACK:   Color = 0u16;
    pub static RED:     Color = 1u16;
references:- 22
263:     fn dim_if_necessary(&self, color: color::Color) -> color::Color {
264:         if color >= self.num_colors && color >= 8 && color < 16 {


libterm/lib.rs:70:4-70:4 -enum- definition:
    pub enum Attr {
        /// Bold (or possibly bright) mode
        Bold,
references:- 3
94: fn cap_for_attr(attr: attr::Attr) -> &'static str {
95:     match attr {
--
207:     /// and `Err(e)` if there was an I/O error.
208:     pub fn attr(&mut self, attr: attr::Attr) -> io::IoResult<bool> {
209:         match attr {
--
229:     /// Returns whether the given terminal attribute is supported.
230:     pub fn supports_attr(&self, attr: attr::Attr) -> bool {
231:         match attr {


libterm/lib.rs:113:37-113:37 -struct- definition:
/// parsed TermInfo database record.
pub struct Terminal<T> {
    num_colors: u16,
references:- 5
138:                 if "cygwin" == term { // msys terminal
139:                     return Ok(Terminal {
140:                         out: out,
--
156:         return Ok(Terminal {out: out, ti: inf, num_colors: nc});
157:     }
--
279: impl<T: Writer> Writer for Terminal<T> {
280:     fn write(&mut self, buf: &[u8]) -> io::IoResult<()> {


libterm/lib.rs:93:1-93:1 -fn- definition:
fn cap_for_attr(attr: attr::Attr) -> &'static str {
    match attr {
        attr::Bold               => "bold",
references:- 2
235:             _ => {
236:                 let cap = cap_for_attr(attr);
237:                 self.ti.strings.find_equiv(&cap).is_some()