1 // Copyright 2012-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.
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.
11 //! Terminfo database interface.
13 use collections::HashMap;
14 use std::io::IoResult;
20 use self::searcher::open;
21 use self::parser::compiled::{parse, msys_terminfo};
22 use self::parm::{expand, Number, Variables};
25 /// A parsed terminfo database entry.
28 /// Names for the terminal
29 pub names: Vec<String> ,
30 /// Map of capability name to boolean value
31 pub bools: HashMap<String, bool>,
32 /// Map of capability name to numeric value
33 pub numbers: HashMap<String, u16>,
34 /// Map of capability name to raw (unexpanded) string
35 pub strings: HashMap<String, Vec<u8> >
40 /// TermInfo format parsing.
42 //! ncurses-compatible compiled terminfo format parsing (term(5))
48 fn cap_for_attr(attr: attr::Attr) -> &'static str {
52 attr::Italic(true) => "sitm",
53 attr::Italic(false) => "ritm",
54 attr::Underline(true) => "smul",
55 attr::Underline(false) => "rmul",
56 attr::Blink => "blink",
57 attr::Standout(true) => "smso",
58 attr::Standout(false) => "rmso",
59 attr::Reverse => "rev",
60 attr::Secure => "invis",
61 attr::ForegroundColor(_) => "setaf",
62 attr::BackgroundColor(_) => "setab"
66 /// A Terminal that knows how many colors it supports, with a reference to its
67 /// parsed Terminfo database record.
68 pub struct TerminfoTerminal<T> {
74 impl<T: Writer> Terminal<T> for TerminfoTerminal<T> {
75 fn new(out: T) -> Option<TerminfoTerminal<T>> {
76 let term = match os::getenv("TERM") {
79 debug!("TERM environment variable not defined");
84 let entry = open(term.as_slice());
86 if os::getenv("MSYSCON").map_or(false, |s| {
87 "mintty.exe" == s.as_slice()
90 return Some(TerminfoTerminal {out: out, ti: msys_terminfo(), num_colors: 8});
92 debug!("error finding terminfo entry: {}", entry.err().unwrap());
96 let mut file = entry.unwrap();
97 let ti = parse(&mut file, false);
99 debug!("error parsing terminfo entry: {}", ti.unwrap_err());
103 let inf = ti.unwrap();
104 let nc = if inf.strings.find_equiv(&("setaf")).is_some()
105 && inf.strings.find_equiv(&("setab")).is_some() {
106 inf.numbers.find_equiv(&("colors")).map_or(0, |&n| n)
109 return Some(TerminfoTerminal {out: out, ti: inf, num_colors: nc});
112 fn fg(&mut self, color: color::Color) -> IoResult<bool> {
113 let color = self.dim_if_necessary(color);
114 if self.num_colors > color {
115 let s = expand(self.ti
117 .find_equiv(&("setaf"))
120 [Number(color as int)], &mut Variables::new());
122 try!(self.out.write(s.unwrap().as_slice()));
129 fn bg(&mut self, color: color::Color) -> IoResult<bool> {
130 let color = self.dim_if_necessary(color);
131 if self.num_colors > color {
132 let s = expand(self.ti
134 .find_equiv(&("setab"))
137 [Number(color as int)], &mut Variables::new());
139 try!(self.out.write(s.unwrap().as_slice()));
146 fn attr(&mut self, attr: attr::Attr) -> IoResult<bool> {
148 attr::ForegroundColor(c) => self.fg(c),
149 attr::BackgroundColor(c) => self.bg(c),
151 let cap = cap_for_attr(attr);
152 let parm = self.ti.strings.find_equiv(&cap);
154 let s = expand(parm.unwrap().as_slice(),
156 &mut Variables::new());
158 try!(self.out.write(s.unwrap().as_slice()));
167 fn supports_attr(&self, attr: attr::Attr) -> bool {
169 attr::ForegroundColor(_) | attr::BackgroundColor(_) => {
173 let cap = cap_for_attr(attr);
174 self.ti.strings.find_equiv(&cap).is_some()
179 fn reset(&mut self) -> IoResult<()> {
180 let mut cap = self.ti.strings.find_equiv(&("sgr0"));
182 // are there any terminals that have color/attrs and not sgr0?
183 // Try falling back to sgr, then op
184 cap = self.ti.strings.find_equiv(&("sgr"));
186 cap = self.ti.strings.find_equiv(&("op"));
189 let s = cap.map_or(Err("can't find terminfo capability `sgr0`".to_strbuf()), |op| {
190 expand(op.as_slice(), [], &mut Variables::new())
193 return self.out.write(s.unwrap().as_slice())
198 fn unwrap(self) -> T { self.out }
200 fn get_ref<'a>(&'a self) -> &'a T { &self.out }
202 fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.out }
205 impl<T: Writer> TerminfoTerminal<T> {
206 fn dim_if_necessary(&self, color: color::Color) -> color::Color {
207 if color >= self.num_colors && color >= 8 && color < 16 {
214 impl<T: Writer> Writer for TerminfoTerminal<T> {
215 fn write(&mut self, buf: &[u8]) -> IoResult<()> {
219 fn flush(&mut self) -> IoResult<()> {