diff options
| author | Corey Richardson <corey@octayn.net> | 2014-04-08 11:18:10 -0400 |
|---|---|---|
| committer | Corey Richardson <corey@octayn.net> | 2014-05-16 09:57:32 -0700 |
| commit | f923b93694706730dd8395dec63e949ba441e0d9 (patch) | |
| tree | e9c76d496c4431f5fe7380887913c7ca71a1c1e9 /src/libterm/terminfo | |
| parent | e30198d9d4d4d016949625062bde002bc33aa574 (diff) | |
term: add docs and windows support
Closes #2807
Diffstat (limited to 'src/libterm/terminfo')
| -rw-r--r-- | src/libterm/terminfo/mod.rs | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/src/libterm/terminfo/mod.rs b/src/libterm/terminfo/mod.rs index 46dd3978531..93a7657fae9 100644 --- a/src/libterm/terminfo/mod.rs +++ b/src/libterm/terminfo/mod.rs @@ -11,6 +11,16 @@ //! Terminfo database interface. use collections::HashMap; +use std::io::IoResult; +use std::os; + +use attr; +use color; +use Terminal; +use self::searcher::open; +use self::parser::compiled::{parse, msys_terminfo}; +use self::parm::{expand, Number, Variables}; + /// A parsed terminfo database entry. pub struct TermInfo { @@ -32,3 +42,179 @@ pub mod parser { pub mod compiled; } pub mod parm; + + +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" + } +} + +/// A Terminal that knows how many colors it supports, with a reference to its +/// parsed Terminfo database record. +pub struct TerminfoTerminal<T> { + num_colors: u16, + out: T, + ti: ~TermInfo +} + +impl<T: Writer> Terminal<T> for TerminfoTerminal<T> { + fn new(out: T) -> Option<TerminfoTerminal<T>> { + let term = match os::getenv("TERM") { + Some(t) => t, + None => { + debug!("TERM environment variable not defined"); + return None; + } + }; + + let entry = open(term); + if entry.is_err() { + if os::getenv("MSYSCON").map_or(false, |s| "mintty.exe" == s) { + // msys terminal + return Some(TerminfoTerminal {out: out, ti: msys_terminfo(), num_colors: 8}); + } + debug!("error finding terminfo entry: {}", entry.unwrap_err()); + return None; + } + + let mut file = entry.unwrap(); + let ti = parse(&mut file, false); + if ti.is_err() { + debug!("error parsing terminfo entry: {}", ti.unwrap_err()); + return None; + } + + let inf = ti.unwrap(); + let nc = if inf.strings.find_equiv(&("setaf")).is_some() + && inf.strings.find_equiv(&("setab")).is_some() { + inf.numbers.find_equiv(&("colors")).map_or(0, |&n| n) + } else { 0 }; + + return Some(TerminfoTerminal {out: out, ti: inf, num_colors: nc}); + } + + fn fg(&mut self, color: color::Color) -> IoResult<bool> { + let color = self.dim_if_necessary(color); + if self.num_colors > color { + let s = expand(self.ti + .strings + .find_equiv(&("setaf")) + .unwrap() + .as_slice(), + [Number(color as int)], &mut Variables::new()); + if s.is_ok() { + try!(self.out.write(s.unwrap().as_slice())); + return Ok(true) + } + } + Ok(false) + } + + fn bg(&mut self, color: color::Color) -> IoResult<bool> { + let color = self.dim_if_necessary(color); + if self.num_colors > color { + let s = expand(self.ti + .strings + .find_equiv(&("setab")) + .unwrap() + .as_slice(), + [Number(color as int)], &mut Variables::new()); + if s.is_ok() { + try!(self.out.write(s.unwrap().as_slice())); + return Ok(true) + } + } + Ok(false) + } + + fn attr(&mut self, attr: attr::Attr) -> IoResult<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().as_slice(), + [], + &mut Variables::new()); + if s.is_ok() { + try!(self.out.write(s.unwrap().as_slice())); + return Ok(true) + } + } + Ok(false) + } + } + } + + 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() + } + } + } + + fn reset(&mut self) -> IoResult<()> { + 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 = cap.map_or(Err(~"can't find terminfo capability `sgr0`"), |op| { + expand(op.as_slice(), [], &mut Variables::new()) + }); + if s.is_ok() { + return self.out.write(s.unwrap().as_slice()) + } + Ok(()) + } + + fn unwrap(self) -> T { self.out } + + fn get_ref<'a>(&'a self) -> &'a T { &self.out } + + fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.out } +} + +impl<T: Writer> TerminfoTerminal<T> { + fn dim_if_necessary(&self, color: color::Color) -> color::Color { + if color >= self.num_colors && color >= 8 && color < 16 { + color-8 + } else { color } + } +} + + +impl<T: Writer> Writer for TerminfoTerminal<T> { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { + self.out.write(buf) + } + + fn flush(&mut self) -> IoResult<()> { + self.out.flush() + } +} + |
