diff options
Diffstat (limited to 'src/libterm/terminfo/mod.rs')
| -rw-r--r-- | src/libterm/terminfo/mod.rs | 245 |
1 files changed, 0 insertions, 245 deletions
diff --git a/src/libterm/terminfo/mod.rs b/src/libterm/terminfo/mod.rs deleted file mode 100644 index fec59aaa0c2..00000000000 --- a/src/libterm/terminfo/mod.rs +++ /dev/null @@ -1,245 +0,0 @@ -//! Terminfo database interface. - -use std::collections::HashMap; -use std::env; -use std::error; -use std::fmt; -use std::fs::File; -use std::io::{self, prelude::*, BufReader}; -use std::path::Path; - -use crate::color; -use crate::Attr; -use crate::Terminal; - -use parm::{expand, Param, Variables}; -use parser::compiled::{msys_terminfo, parse}; -use searcher::get_dbpath_for_term; - -/// A parsed terminfo database entry. -#[derive(Debug)] -pub struct TermInfo { - /// Names for the terminal - pub names: Vec<String>, - /// Map of capability name to boolean value - pub bools: HashMap<String, bool>, - /// Map of capability name to numeric value - pub numbers: HashMap<String, u32>, - /// Map of capability name to raw (unexpanded) string - pub strings: HashMap<String, Vec<u8>>, -} - -/// A terminfo creation error. -#[derive(Debug)] -pub enum Error { - /// TermUnset Indicates that the environment doesn't include enough information to find - /// the terminfo entry. - TermUnset, - /// MalformedTerminfo indicates that parsing the terminfo entry failed. - MalformedTerminfo(String), - /// io::Error forwards any io::Errors encountered when finding or reading the terminfo entry. - IoError(io::Error), -} - -impl error::Error for Error { - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - use Error::*; - match self { - IoError(e) => Some(e), - _ => None, - } - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use Error::*; - match *self { - TermUnset => Ok(()), - MalformedTerminfo(ref e) => e.fmt(f), - IoError(ref e) => e.fmt(f), - } - } -} - -impl TermInfo { - /// Creates a TermInfo based on current environment. - pub fn from_env() -> Result<TermInfo, Error> { - let term = match env::var("TERM") { - Ok(name) => TermInfo::from_name(&name), - Err(..) => return Err(Error::TermUnset), - }; - - if term.is_err() && env::var("MSYSCON").map_or(false, |s| "mintty.exe" == s) { - // msys terminal - Ok(msys_terminfo()) - } else { - term - } - } - - /// Creates a TermInfo for the named terminal. - pub fn from_name(name: &str) -> Result<TermInfo, Error> { - get_dbpath_for_term(name) - .ok_or_else(|| { - Error::IoError(io::Error::new(io::ErrorKind::NotFound, "terminfo file not found")) - }) - .and_then(|p| TermInfo::from_path(&(*p))) - } - - /// Parse the given TermInfo. - pub fn from_path<P: AsRef<Path>>(path: P) -> Result<TermInfo, Error> { - Self::_from_path(path.as_ref()) - } - // Keep the metadata small - fn _from_path(path: &Path) -> Result<TermInfo, Error> { - let file = File::open(path).map_err(Error::IoError)?; - let mut reader = BufReader::new(file); - parse(&mut reader, false).map_err(Error::MalformedTerminfo) - } -} - -pub mod searcher; - -/// TermInfo format parsing. -pub mod parser { - //! ncurses-compatible compiled terminfo format parsing (term(5)) - pub mod compiled; -} -pub mod parm; - -fn cap_for_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: u32, - out: T, - ti: TermInfo, -} - -impl<T: Write + Send> Terminal for TerminfoTerminal<T> { - type Output = T; - fn fg(&mut self, color: color::Color) -> io::Result<bool> { - let color = self.dim_if_necessary(color); - if self.num_colors > color { - return self.apply_cap("setaf", &[Param::Number(color as i32)]); - } - Ok(false) - } - - fn bg(&mut self, color: color::Color) -> io::Result<bool> { - let color = self.dim_if_necessary(color); - if self.num_colors > color { - return self.apply_cap("setab", &[Param::Number(color as i32)]); - } - Ok(false) - } - - fn attr(&mut self, attr: Attr) -> io::Result<bool> { - match attr { - Attr::ForegroundColor(c) => self.fg(c), - Attr::BackgroundColor(c) => self.bg(c), - _ => self.apply_cap(cap_for_attr(attr), &[]), - } - } - - fn supports_attr(&self, attr: Attr) -> bool { - match attr { - Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => self.num_colors > 0, - _ => { - let cap = cap_for_attr(attr); - self.ti.strings.get(cap).is_some() - } - } - } - - fn reset(&mut self) -> io::Result<bool> { - // are there any terminals that have color/attrs and not sgr0? - // Try falling back to sgr, then op - let cmd = match ["sgr0", "sgr", "op"].iter().find_map(|cap| self.ti.strings.get(*cap)) { - Some(op) => match expand(&op, &[], &mut Variables::new()) { - Ok(cmd) => cmd, - Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidData, e)), - }, - None => return Ok(false), - }; - self.out.write_all(&cmd).and(Ok(true)) - } - - fn get_ref(&self) -> &T { - &self.out - } - - fn get_mut(&mut self) -> &mut T { - &mut self.out - } - - fn into_inner(self) -> T - where - Self: Sized, - { - self.out - } -} - -impl<T: Write + Send> TerminfoTerminal<T> { - /// Creates a new TerminfoTerminal with the given TermInfo and Write. - pub fn new_with_terminfo(out: T, terminfo: TermInfo) -> TerminfoTerminal<T> { - let nc = if terminfo.strings.contains_key("setaf") && terminfo.strings.contains_key("setab") - { - terminfo.numbers.get("colors").map_or(0, |&n| n) - } else { - 0 - }; - - TerminfoTerminal { out, ti: terminfo, num_colors: nc } - } - - /// Creates a new TerminfoTerminal for the current environment with the given Write. - /// - /// Returns `None` when the terminfo cannot be found or parsed. - pub fn new(out: T) -> Option<TerminfoTerminal<T>> { - TermInfo::from_env().map(move |ti| TerminfoTerminal::new_with_terminfo(out, ti)).ok() - } - - fn dim_if_necessary(&self, color: color::Color) -> color::Color { - if color >= self.num_colors && color >= 8 && color < 16 { color - 8 } else { color } - } - - fn apply_cap(&mut self, cmd: &str, params: &[Param]) -> io::Result<bool> { - match self.ti.strings.get(cmd) { - Some(cmd) => match expand(&cmd, params, &mut Variables::new()) { - Ok(s) => self.out.write_all(&s).and(Ok(true)), - Err(e) => Err(io::Error::new(io::ErrorKind::InvalidData, e)), - }, - None => Ok(false), - } - } -} - -impl<T: Write> Write for TerminfoTerminal<T> { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - self.out.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.out.flush() - } -} |
