Auto merge of #87247 - crlf0710:merge-libterm-into-libtest, r=nagisa

Merge libterm into libtest

I think it's quite clear at this point that rust won't stablize the current libterm APIs to the outside world. And its only user is libtest. The compiler doesn't use this api at all. So I'm merging the crate into libtest as a module.

This also allows me to remove 15% of the libterm code, since these APIs are dead-code now.
This commit is contained in:
bors 2021-07-20 16:03:47 +00:00
commit 39d8d3ab6a
17 changed files with 133 additions and 410 deletions

View File

@ -5095,14 +5095,6 @@ dependencies = [
"serde_json", "serde_json",
] ]
[[package]]
name = "term"
version = "0.0.0"
dependencies = [
"core",
"std",
]
[[package]] [[package]]
name = "term" name = "term"
version = "0.6.1" version = "0.6.1"
@ -5155,7 +5147,6 @@ dependencies = [
"panic_unwind", "panic_unwind",
"proc_macro", "proc_macro",
"std", "std",
"term 0.0.0",
] ]
[[package]] [[package]]

View File

@ -1,9 +0,0 @@
[package]
authors = ["The Rust Project Developers"]
name = "term"
version = "0.0.0"
edition = "2018"
[dependencies]
core = { path = "../core" }
std = { path = "../std" }

View File

@ -1,194 +0,0 @@
//! Terminal formatting library.
//!
//! This crate provides the `Terminal` trait, which abstracts over an [ANSI
//! Terminal][ansi] to provide color printing, among other things. There are two
//! implementations, the `TerminfoTerminal`, which uses control characters from
//! a [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console
//! API][win].
//!
//! # Examples
//!
//! ```no_run
//! # #![feature(rustc_private)]
//! extern crate term;
//! use std::io::prelude::*;
//!
//! fn main() {
//! let mut t = term::stdout().unwrap();
//!
//! t.fg(term::color::GREEN).unwrap();
//! write!(t, "hello, ").unwrap();
//!
//! t.fg(term::color::RED).unwrap();
//! writeln!(t, "world!").unwrap();
//!
//! assert!(t.reset().unwrap());
//! }
//! ```
//!
//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code
//! [win]: https://docs.microsoft.com/en-us/windows/console/character-mode-applications
//! [ti]: https://en.wikipedia.org/wiki/Terminfo
#![doc(html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))))]
#![deny(missing_docs)]
#![cfg_attr(windows, feature(libc))]
use std::io::prelude::*;
use std::io::{self, Stderr, Stdout};
pub use terminfo::TerminfoTerminal;
#[cfg(windows)]
pub use win::WinConsole;
pub mod terminfo;
#[cfg(windows)]
mod win;
/// Alias for stdout terminals.
pub type StdoutTerminal = dyn Terminal<Output = Stdout> + Send;
/// Alias for stderr terminals.
pub type StderrTerminal = dyn Terminal<Output = Stderr> + Send;
#[cfg(not(windows))]
/// Returns a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<StdoutTerminal>> {
TerminfoTerminal::new(io::stdout()).map(|t| Box::new(t) as Box<StdoutTerminal>)
}
#[cfg(windows)]
/// Returns a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<StdoutTerminal>> {
TerminfoTerminal::new(io::stdout())
.map(|t| Box::new(t) as Box<StdoutTerminal>)
.or_else(|| WinConsole::new(io::stdout()).ok().map(|t| Box::new(t) as Box<StdoutTerminal>))
}
#[cfg(not(windows))]
/// Returns a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<StderrTerminal>> {
TerminfoTerminal::new(io::stderr()).map(|t| Box::new(t) as Box<StderrTerminal>)
}
#[cfg(windows)]
/// Returns a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<StderrTerminal>> {
TerminfoTerminal::new(io::stderr())
.map(|t| Box::new(t) as Box<StderrTerminal>)
.or_else(|| WinConsole::new(io::stderr()).ok().map(|t| Box::new(t) as Box<StderrTerminal>))
}
/// Terminal color definitions
#[allow(missing_docs)]
pub mod color {
/// Number for a terminal color
pub type Color = u32;
pub const BLACK: Color = 0;
pub const RED: Color = 1;
pub const GREEN: Color = 2;
pub const YELLOW: Color = 3;
pub const BLUE: Color = 4;
pub const MAGENTA: Color = 5;
pub const CYAN: Color = 6;
pub const WHITE: Color = 7;
pub const BRIGHT_BLACK: Color = 8;
pub const BRIGHT_RED: Color = 9;
pub const BRIGHT_GREEN: Color = 10;
pub const BRIGHT_YELLOW: Color = 11;
pub const BRIGHT_BLUE: Color = 12;
pub const BRIGHT_MAGENTA: Color = 13;
pub const BRIGHT_CYAN: Color = 14;
pub const BRIGHT_WHITE: Color = 15;
}
/// Terminal attributes for use with term.attr().
///
/// Most attributes can only be turned on and must be turned off with term.reset().
/// The ones that can be turned off explicitly take a boolean value.
/// Color is also represented as an attribute for convenience.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum Attr {
/// Bold (or possibly bright) mode
Bold,
/// Dim mode, also called faint or half-bright. Often not supported
Dim,
/// Italics mode. Often not supported
Italic(bool),
/// Underline mode
Underline(bool),
/// Blink mode
Blink,
/// Standout mode. Often implemented as Reverse, sometimes coupled with Bold
Standout(bool),
/// Reverse mode, inverts the foreground and background colors
Reverse,
/// Secure mode, also called invis mode. Hides the printed text
Secure,
/// Convenience attribute to set the foreground color
ForegroundColor(color::Color),
/// Convenience attribute to set the background color
BackgroundColor(color::Color),
}
/// A terminal with similar capabilities to an ANSI Terminal
/// (foreground/background colors etc).
pub trait Terminal: Write {
/// The terminal's output writer type.
type Output: Write;
/// Sets the foreground color to the given color.
///
/// If the color is a bright color, but the terminal only supports 8 colors,
/// the corresponding normal color will be used instead.
///
/// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
/// if there was an I/O error.
fn fg(&mut self, color: color::Color) -> io::Result<bool>;
/// Sets the background color to the given color.
///
/// If the color is a bright color, but the terminal only supports 8 colors,
/// the corresponding normal color will be used instead.
///
/// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
/// if there was an I/O error.
fn bg(&mut self, color: color::Color) -> io::Result<bool>;
/// Sets the given terminal attribute, if supported. Returns `Ok(true)`
/// if the attribute was supported, `Ok(false)` otherwise, and `Err(e)` if
/// there was an I/O error.
fn attr(&mut self, attr: Attr) -> io::Result<bool>;
/// Returns `true` if the given terminal attribute is supported.
fn supports_attr(&self, attr: Attr) -> bool;
/// Resets all terminal attributes and colors to their defaults.
///
/// Returns `Ok(true)` if the terminal was reset, `Ok(false)` otherwise, and `Err(e)` if there
/// was an I/O error.
///
/// *Note: This does not flush.*
///
/// That means the reset command may get buffered so, if you aren't planning on doing anything
/// else that might flush stdout's buffer (e.g., writing a line of text), you should flush after
/// calling reset.
fn reset(&mut self) -> io::Result<bool>;
/// Gets an immutable reference to the stream inside
fn get_ref(&self) -> &Self::Output;
/// Gets a mutable reference to the stream inside
fn get_mut(&mut self) -> &mut Self::Output;
/// Returns the contained stream, destroying the `Terminal`
fn into_inner(self) -> Self::Output
where
Self: Sized;
}

View File

@ -10,7 +10,6 @@ crate-type = ["dylib", "rlib"]
[dependencies] [dependencies]
cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] } cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] }
getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] } getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] }
term = { path = "../term" }
std = { path = "../std" } std = { path = "../std" }
core = { path = "../core" } core = { path = "../core" }
libc = { version = "0.2", default-features = false } libc = { version = "0.2", default-features = false }

View File

@ -13,7 +13,7 @@ use super::{
formatters::{JsonFormatter, JunitFormatter, OutputFormatter, PrettyFormatter, TerseFormatter}, formatters::{JsonFormatter, JunitFormatter, OutputFormatter, PrettyFormatter, TerseFormatter},
helpers::{concurrency::get_concurrency, metrics::MetricMap}, helpers::{concurrency::get_concurrency, metrics::MetricMap},
options::{Options, OutputFormat}, options::{Options, OutputFormat},
run_tests, run_tests, term,
test_result::TestResult, test_result::TestResult,
time::{TestExecTime, TestSuiteExecTime}, time::{TestExecTime, TestSuiteExecTime},
types::{NamePadding, TestDesc, TestDescAndFn}, types::{NamePadding, TestDesc, TestDescAndFn},

View File

@ -4,6 +4,7 @@ use super::OutputFormatter;
use crate::{ use crate::{
bench::fmt_bench_samples, bench::fmt_bench_samples,
console::{ConsoleTestState, OutputLocation}, console::{ConsoleTestState, OutputLocation},
term,
test_result::TestResult, test_result::TestResult,
time, time,
types::TestDesc, types::TestDesc,

View File

@ -4,6 +4,7 @@ use super::OutputFormatter;
use crate::{ use crate::{
bench::fmt_bench_samples, bench::fmt_bench_samples,
console::{ConsoleTestState, OutputLocation}, console::{ConsoleTestState, OutputLocation},
term,
test_result::TestResult, test_result::TestResult,
time, time,
types::NamePadding, types::NamePadding,

View File

@ -20,7 +20,7 @@
#![crate_name = "test"] #![crate_name = "test"]
#![unstable(feature = "test", issue = "50297")] #![unstable(feature = "test", issue = "50297")]
#![doc(test(attr(deny(warnings))))] #![doc(test(attr(deny(warnings))))]
#![cfg_attr(unix, feature(libc))] #![feature(libc)]
#![feature(rustc_private)] #![feature(rustc_private)]
#![feature(nll)] #![feature(nll)]
#![feature(available_concurrency)] #![feature(available_concurrency)]
@ -80,6 +80,7 @@ mod formatters;
mod helpers; mod helpers;
mod options; mod options;
pub mod stats; pub mod stats;
mod term;
mod test_result; mod test_result;
mod time; mod time;
mod types; mod types;

85
library/test/src/term.rs Normal file
View File

@ -0,0 +1,85 @@
//! Terminal formatting module.
//!
//! This module provides the `Terminal` trait, which abstracts over an [ANSI
//! Terminal][ansi] to provide color printing, among other things. There are two
//! implementations, the `TerminfoTerminal`, which uses control characters from
//! a [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console
//! API][win].
//!
//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code
//! [win]: https://docs.microsoft.com/en-us/windows/console/character-mode-applications
//! [ti]: https://en.wikipedia.org/wiki/Terminfo
#![deny(missing_docs)]
use std::io::{self, prelude::*};
pub(crate) use terminfo::TerminfoTerminal;
#[cfg(windows)]
pub(crate) use win::WinConsole;
pub(crate) mod terminfo;
#[cfg(windows)]
mod win;
/// Alias for stdout terminals.
pub(crate) type StdoutTerminal = dyn Terminal + Send;
#[cfg(not(windows))]
/// Returns a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub(crate) fn stdout() -> Option<Box<StdoutTerminal>> {
TerminfoTerminal::new(io::stdout()).map(|t| Box::new(t) as Box<StdoutTerminal>)
}
#[cfg(windows)]
/// Returns a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub(crate) fn stdout() -> Option<Box<StdoutTerminal>> {
TerminfoTerminal::new(io::stdout())
.map(|t| Box::new(t) as Box<StdoutTerminal>)
.or_else(|| WinConsole::new(io::stdout()).ok().map(|t| Box::new(t) as Box<StdoutTerminal>))
}
/// Terminal color definitions
#[allow(missing_docs)]
#[cfg_attr(not(windows), allow(dead_code))]
pub(crate) mod color {
/// Number for a terminal color
pub(crate) type Color = u32;
pub(crate) const BLACK: Color = 0;
pub(crate) const RED: Color = 1;
pub(crate) const GREEN: Color = 2;
pub(crate) const YELLOW: Color = 3;
pub(crate) const BLUE: Color = 4;
pub(crate) const MAGENTA: Color = 5;
pub(crate) const CYAN: Color = 6;
pub(crate) const WHITE: Color = 7;
}
/// A terminal with similar capabilities to an ANSI Terminal
/// (foreground/background colors etc).
pub trait Terminal: Write {
/// Sets the foreground color to the given color.
///
/// If the color is a bright color, but the terminal only supports 8 colors,
/// the corresponding normal color will be used instead.
///
/// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
/// if there was an I/O error.
fn fg(&mut self, color: color::Color) -> io::Result<bool>;
/// Resets all terminal attributes and colors to their defaults.
///
/// Returns `Ok(true)` if the terminal was reset, `Ok(false)` otherwise, and `Err(e)` if there
/// was an I/O error.
///
/// *Note: This does not flush.*
///
/// That means the reset command may get buffered so, if you aren't planning on doing anything
/// else that might flush stdout's buffer (e.g., writing a line of text), you should flush after
/// calling reset.
fn reset(&mut self) -> io::Result<bool>;
}

View File

@ -8,9 +8,8 @@ use std::fs::File;
use std::io::{self, prelude::*, BufReader}; use std::io::{self, prelude::*, BufReader};
use std::path::Path; use std::path::Path;
use crate::color; use super::color;
use crate::Attr; use super::Terminal;
use crate::Terminal;
use parm::{expand, Param, Variables}; use parm::{expand, Param, Variables};
use parser::compiled::{msys_terminfo, parse}; use parser::compiled::{msys_terminfo, parse};
@ -18,20 +17,20 @@ use searcher::get_dbpath_for_term;
/// A parsed terminfo database entry. /// A parsed terminfo database entry.
#[derive(Debug)] #[derive(Debug)]
pub struct TermInfo { pub(crate) struct TermInfo {
/// Names for the terminal /// Names for the terminal
pub names: Vec<String>, pub(crate) names: Vec<String>,
/// Map of capability name to boolean value /// Map of capability name to boolean value
pub bools: HashMap<String, bool>, pub(crate) bools: HashMap<String, bool>,
/// Map of capability name to numeric value /// Map of capability name to numeric value
pub numbers: HashMap<String, u32>, pub(crate) numbers: HashMap<String, u32>,
/// Map of capability name to raw (unexpanded) string /// Map of capability name to raw (unexpanded) string
pub strings: HashMap<String, Vec<u8>>, pub(crate) strings: HashMap<String, Vec<u8>>,
} }
/// A terminfo creation error. /// A terminfo creation error.
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub(crate) enum Error {
/// TermUnset Indicates that the environment doesn't include enough information to find /// TermUnset Indicates that the environment doesn't include enough information to find
/// the terminfo entry. /// the terminfo entry.
TermUnset, TermUnset,
@ -64,7 +63,7 @@ impl fmt::Display for Error {
impl TermInfo { impl TermInfo {
/// Creates a TermInfo based on current environment. /// Creates a TermInfo based on current environment.
pub fn from_env() -> Result<TermInfo, Error> { pub(crate) fn from_env() -> Result<TermInfo, Error> {
let term = match env::var("TERM") { let term = match env::var("TERM") {
Ok(name) => TermInfo::from_name(&name), Ok(name) => TermInfo::from_name(&name),
Err(..) => return Err(Error::TermUnset), Err(..) => return Err(Error::TermUnset),
@ -79,7 +78,7 @@ impl TermInfo {
} }
/// Creates a TermInfo for the named terminal. /// Creates a TermInfo for the named terminal.
pub fn from_name(name: &str) -> Result<TermInfo, Error> { pub(crate) fn from_name(name: &str) -> Result<TermInfo, Error> {
get_dbpath_for_term(name) get_dbpath_for_term(name)
.ok_or_else(|| { .ok_or_else(|| {
Error::IoError(io::Error::new(io::ErrorKind::NotFound, "terminfo file not found")) Error::IoError(io::Error::new(io::ErrorKind::NotFound, "terminfo file not found"))
@ -88,7 +87,7 @@ impl TermInfo {
} }
/// Parse the given TermInfo. /// Parse the given TermInfo.
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<TermInfo, Error> { pub(crate) fn from_path<P: AsRef<Path>>(path: P) -> Result<TermInfo, Error> {
Self::_from_path(path.as_ref()) Self::_from_path(path.as_ref())
} }
// Keep the metadata small // Keep the metadata small
@ -99,43 +98,24 @@ impl TermInfo {
} }
} }
pub mod searcher; pub(crate) mod searcher;
/// TermInfo format parsing. /// TermInfo format parsing.
pub mod parser { pub(crate) mod parser {
//! ncurses-compatible compiled terminfo format parsing (term(5)) //! ncurses-compatible compiled terminfo format parsing (term(5))
pub mod compiled; pub(crate) 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",
}
} }
pub(crate) mod parm;
/// A Terminal that knows how many colors it supports, with a reference to its /// A Terminal that knows how many colors it supports, with a reference to its
/// parsed Terminfo database record. /// parsed Terminfo database record.
pub struct TerminfoTerminal<T> { pub(crate) struct TerminfoTerminal<T> {
num_colors: u32, num_colors: u32,
out: T, out: T,
ti: TermInfo, ti: TermInfo,
} }
impl<T: Write + Send> Terminal for TerminfoTerminal<T> { impl<T: Write + Send> Terminal for TerminfoTerminal<T> {
type Output = T;
fn fg(&mut self, color: color::Color) -> io::Result<bool> { fn fg(&mut self, color: color::Color) -> io::Result<bool> {
let color = self.dim_if_necessary(color); let color = self.dim_if_necessary(color);
if self.num_colors > color { if self.num_colors > color {
@ -144,32 +124,6 @@ impl<T: Write + Send> Terminal for TerminfoTerminal<T> {
Ok(false) 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> { fn reset(&mut self) -> io::Result<bool> {
// are there any terminals that have color/attrs and not sgr0? // are there any terminals that have color/attrs and not sgr0?
// Try falling back to sgr, then op // Try falling back to sgr, then op
@ -182,26 +136,11 @@ impl<T: Write + Send> Terminal for TerminfoTerminal<T> {
}; };
self.out.write_all(&cmd).and(Ok(true)) 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> { impl<T: Write + Send> TerminfoTerminal<T> {
/// Creates a new TerminfoTerminal with the given TermInfo and Write. /// Creates a new TerminfoTerminal with the given TermInfo and Write.
pub fn new_with_terminfo(out: T, terminfo: TermInfo) -> TerminfoTerminal<T> { pub(crate) fn new_with_terminfo(out: T, terminfo: TermInfo) -> TerminfoTerminal<T> {
let nc = if terminfo.strings.contains_key("setaf") && terminfo.strings.contains_key("setab") let nc = if terminfo.strings.contains_key("setaf") && terminfo.strings.contains_key("setab")
{ {
terminfo.numbers.get("colors").map_or(0, |&n| n) terminfo.numbers.get("colors").map_or(0, |&n| n)
@ -215,7 +154,7 @@ impl<T: Write + Send> TerminfoTerminal<T> {
/// Creates a new TerminfoTerminal for the current environment with the given Write. /// Creates a new TerminfoTerminal for the current environment with the given Write.
/// ///
/// Returns `None` when the terminfo cannot be found or parsed. /// Returns `None` when the terminfo cannot be found or parsed.
pub fn new(out: T) -> Option<TerminfoTerminal<T>> { pub(crate) fn new(out: T) -> Option<TerminfoTerminal<T>> {
TermInfo::from_env().map(move |ti| TerminfoTerminal::new_with_terminfo(out, ti)).ok() TermInfo::from_env().map(move |ti| TerminfoTerminal::new_with_terminfo(out, ti)).ok()
} }

View File

@ -35,13 +35,12 @@ enum FormatState {
/// Types of parameters a capability can use /// Types of parameters a capability can use
#[allow(missing_docs)] #[allow(missing_docs)]
#[derive(Clone)] #[derive(Clone)]
pub enum Param { pub(crate) enum Param {
Words(String),
Number(i32), Number(i32),
} }
/// Container for static and dynamic variable arrays /// Container for static and dynamic variable arrays
pub struct Variables { pub(crate) struct Variables {
/// Static variables A-Z /// Static variables A-Z
sta_va: [Param; 26], sta_va: [Param; 26],
/// Dynamic variables a-z /// Dynamic variables a-z
@ -50,7 +49,7 @@ pub struct Variables {
impl Variables { impl Variables {
/// Returns a new zero-initialized Variables /// Returns a new zero-initialized Variables
pub fn new() -> Variables { pub(crate) fn new() -> Variables {
Variables { Variables {
sta_va: [ sta_va: [
Number(0), Number(0),
@ -121,7 +120,11 @@ impl Variables {
/// ///
/// To be compatible with ncurses, `vars` should be the same between calls to `expand` for /// To be compatible with ncurses, `vars` should be the same between calls to `expand` for
/// multiple capabilities for the same terminal. /// multiple capabilities for the same terminal.
pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<u8>, String> { pub(crate) fn expand(
cap: &[u8],
params: &[Param],
vars: &mut Variables,
) -> Result<Vec<u8>, String> {
let mut state = Nothing; let mut state = Nothing;
// expanded cap will only rarely be larger than the cap itself // expanded cap will only rarely be larger than the cap itself
@ -168,7 +171,6 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<
Some(Number(0)) => output.push(128u8), Some(Number(0)) => output.push(128u8),
// Don't check bounds. ncurses just casts and truncates. // Don't check bounds. ncurses just casts and truncates.
Some(Number(c)) => output.push(c as u8), Some(Number(c)) => output.push(c as u8),
Some(_) => return Err("a non-char was used with %c".to_string()),
None => return Err("stack is empty".to_string()), None => return Err("stack is empty".to_string()),
} }
} }
@ -178,7 +180,6 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<
'\'' => state = CharConstant, '\'' => state = CharConstant,
'{' => state = IntConstant(0), '{' => state = IntConstant(0),
'l' => match stack.pop() { 'l' => match stack.pop() {
Some(Words(s)) => stack.push(Number(s.len() as i32)),
Some(_) => return Err("a non-str was used with %l".to_string()), Some(_) => return Err("a non-str was used with %l".to_string()),
None => return Err("stack is empty".to_string()), None => return Err("stack is empty".to_string()),
}, },
@ -195,9 +196,6 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<
'm' => x % y, 'm' => x % y,
_ => unreachable!("All cases handled"), _ => unreachable!("All cases handled"),
})), })),
(Some(_), Some(_)) => {
return Err(format!("non-numbers on stack with {}", cur));
}
_ => return Err("stack is empty".to_string()), _ => return Err("stack is empty".to_string()),
} }
} }
@ -216,9 +214,6 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<
0 0
}, },
)), )),
(Some(_), Some(_)) => {
return Err(format!("non-numbers on stack with {}", cur));
}
_ => return Err("stack is empty".to_string()), _ => return Err("stack is empty".to_string()),
}, },
'!' | '~' => match stack.pop() { '!' | '~' => match stack.pop() {
@ -228,7 +223,6 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<
'~' => !x, '~' => !x,
_ => unreachable!(), _ => unreachable!(),
})), })),
Some(_) => return Err(format!("non-numbers on stack with {}", cur)),
None => return Err("stack is empty".to_string()), None => return Err("stack is empty".to_string()),
}, },
'i' => match (&mparams[0], &mparams[1]) { 'i' => match (&mparams[0], &mparams[1]) {
@ -236,7 +230,6 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<
mparams[0] = Number(x + 1); mparams[0] = Number(x + 1);
mparams[1] = Number(y + 1); mparams[1] = Number(y + 1);
} }
_ => return Err("first two params not numbers with %i".to_string()),
}, },
// printf-style support for %doxXs // printf-style support for %doxXs
@ -271,7 +264,6 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<
't' => match stack.pop() { 't' => match stack.pop() {
Some(Number(0)) => state = SeekIfElse(0), Some(Number(0)) => state = SeekIfElse(0),
Some(Number(_)) => (), Some(Number(_)) => (),
Some(_) => return Err("non-number on stack with conditional".to_string()),
None => return Err("stack is empty".to_string()), None => return Err("stack is empty".to_string()),
}, },
'e' => state = SeekIfEnd(0), 'e' => state = SeekIfEnd(0),
@ -480,15 +472,6 @@ impl FormatOp {
_ => panic!("bad FormatOp char"), _ => panic!("bad FormatOp char"),
} }
} }
fn to_char(self) -> char {
match self {
FormatOp::Digit => 'd',
FormatOp::Octal => 'o',
FormatOp::LowerHex => 'x',
FormatOp::UpperHex => 'X',
FormatOp::String => 's',
}
}
} }
fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8>, String> { fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8>, String> {
@ -533,16 +516,6 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8>, String> {
} }
.into_bytes() .into_bytes()
} }
Words(s) => match op {
FormatOp::String => {
let mut s = s.into_bytes();
if flags.precision > 0 && flags.precision < s.len() {
s.truncate(flags.precision);
}
s
}
_ => return Err(format!("non-string on stack with %{}", op.to_char())),
},
}; };
if flags.width > s.len() { if flags.width > s.len() {
let n = flags.width - s.len(); let n = flags.width - s.len();

View File

@ -51,7 +51,10 @@ fn test_param_stack_failure_conditions() {
for &cap in caps.iter() { for &cap in caps.iter() {
let res = get_res("", cap, &[], vars); let res = get_res("", cap, &[], vars);
assert!(res.is_err(), "Op {} succeeded incorrectly with 0 stack entries", cap); assert!(res.is_err(), "Op {} succeeded incorrectly with 0 stack entries", cap);
let p = if cap == "%s" || cap == "%l" { Words("foo".to_string()) } else { Number(97) }; if cap == "%s" || cap == "%l" {
continue;
}
let p = Number(97);
let res = get_res("%p1", cap, &[p], vars); let res = get_res("%p1", cap, &[p], vars);
assert!(res.is_ok(), "Op {} failed with 1 stack entry: {}", cap, res.unwrap_err()); assert!(res.is_ok(), "Op {} failed with 1 stack entry: {}", cap, res.unwrap_err());
} }
@ -109,23 +112,6 @@ fn test_conditionals() {
fn test_format() { fn test_format() {
let mut varstruct = Variables::new(); let mut varstruct = Variables::new();
let vars = &mut varstruct; let vars = &mut varstruct;
assert_eq!(
expand(
b"%p1%s%p2%2s%p3%2s%p4%.2s",
&[
Words("foo".to_string()),
Words("foo".to_string()),
Words("f".to_string()),
Words("foo".to_string())
],
vars
),
Ok("foofoo ffo".bytes().collect::<Vec<_>>())
);
assert_eq!(
expand(b"%p1%:-4.2s", &[Words("foo".to_string())], vars),
Ok("fo ".bytes().collect::<Vec<_>>())
);
assert_eq!( assert_eq!(
expand(b"%p1%d%p1%.3d%p1%5d%p1%:+d", &[Number(1)], vars), expand(b"%p1%d%p1%.3d%p1%5d%p1%:+d", &[Number(1)], vars),

View File

@ -13,7 +13,7 @@ mod tests;
// These are the orders ncurses uses in its compiled format (as of 5.9). Not sure if portable. // These are the orders ncurses uses in its compiled format (as of 5.9). Not sure if portable.
#[rustfmt::skip] #[rustfmt::skip]
pub static boolfnames: &[&str] = &["auto_left_margin", "auto_right_margin", pub(crate) static boolfnames: &[&str] = &["auto_left_margin", "auto_right_margin",
"no_esc_ctlc", "ceol_standout_glitch", "eat_newline_glitch", "erase_overstrike", "generic_type", "no_esc_ctlc", "ceol_standout_glitch", "eat_newline_glitch", "erase_overstrike", "generic_type",
"hard_copy", "has_meta_key", "has_status_line", "insert_null_glitch", "memory_above", "hard_copy", "has_meta_key", "has_status_line", "insert_null_glitch", "memory_above",
"memory_below", "move_insert_mode", "move_standout_mode", "over_strike", "status_line_esc_ok", "memory_below", "move_insert_mode", "move_standout_mode", "over_strike", "status_line_esc_ok",
@ -26,13 +26,13 @@ pub static boolfnames: &[&str] = &["auto_left_margin", "auto_right_margin",
"return_does_clr_eol"]; "return_does_clr_eol"];
#[rustfmt::skip] #[rustfmt::skip]
pub static boolnames: &[&str] = &["bw", "am", "xsb", "xhp", "xenl", "eo", pub(crate) static boolnames: &[&str] = &["bw", "am", "xsb", "xhp", "xenl", "eo",
"gn", "hc", "km", "hs", "in", "db", "da", "mir", "msgr", "os", "eslok", "xt", "hz", "ul", "xon", "gn", "hc", "km", "hs", "in", "db", "da", "mir", "msgr", "os", "eslok", "xt", "hz", "ul", "xon",
"nxon", "mc5i", "chts", "nrrmc", "npc", "ndscr", "ccc", "bce", "hls", "xhpa", "crxm", "daisy", "nxon", "mc5i", "chts", "nrrmc", "npc", "ndscr", "ccc", "bce", "hls", "xhpa", "crxm", "daisy",
"xvpa", "sam", "cpix", "lpix", "OTbs", "OTns", "OTnc", "OTMT", "OTNL", "OTpt", "OTxr"]; "xvpa", "sam", "cpix", "lpix", "OTbs", "OTns", "OTnc", "OTMT", "OTNL", "OTpt", "OTxr"];
#[rustfmt::skip] #[rustfmt::skip]
pub static numfnames: &[&str] = &[ "columns", "init_tabs", "lines", pub(crate) static numfnames: &[&str] = &[ "columns", "init_tabs", "lines",
"lines_of_memory", "magic_cookie_glitch", "padding_baud_rate", "virtual_terminal", "lines_of_memory", "magic_cookie_glitch", "padding_baud_rate", "virtual_terminal",
"width_status_line", "num_labels", "label_height", "label_width", "max_attributes", "width_status_line", "num_labels", "label_height", "label_width", "max_attributes",
"maximum_windows", "max_colors", "max_pairs", "no_color_video", "buffer_capacity", "maximum_windows", "max_colors", "max_pairs", "no_color_video", "buffer_capacity",
@ -43,13 +43,13 @@ pub static numfnames: &[&str] = &[ "columns", "init_tabs", "lines",
"new_line_delay", "backspace_delay", "horizontal_tab_delay", "number_of_function_keys"]; "new_line_delay", "backspace_delay", "horizontal_tab_delay", "number_of_function_keys"];
#[rustfmt::skip] #[rustfmt::skip]
pub static numnames: &[&str] = &[ "cols", "it", "lines", "lm", "xmc", "pb", pub(crate) static numnames: &[&str] = &[ "cols", "it", "lines", "lm", "xmc", "pb",
"vt", "wsl", "nlab", "lh", "lw", "ma", "wnum", "colors", "pairs", "ncv", "bufsz", "spinv", "vt", "wsl", "nlab", "lh", "lw", "ma", "wnum", "colors", "pairs", "ncv", "bufsz", "spinv",
"spinh", "maddr", "mjump", "mcs", "mls", "npins", "orc", "orl", "orhi", "orvi", "cps", "widcs", "spinh", "maddr", "mjump", "mcs", "mls", "npins", "orc", "orl", "orhi", "orvi", "cps", "widcs",
"btns", "bitwin", "bitype", "UTug", "OTdC", "OTdN", "OTdB", "OTdT", "OTkn"]; "btns", "bitwin", "bitype", "UTug", "OTdC", "OTdN", "OTdB", "OTdT", "OTkn"];
#[rustfmt::skip] #[rustfmt::skip]
pub static stringfnames: &[&str] = &[ "back_tab", "bell", "carriage_return", pub(crate) static stringfnames: &[&str] = &[ "back_tab", "bell", "carriage_return",
"change_scroll_region", "clear_all_tabs", "clear_screen", "clr_eol", "clr_eos", "change_scroll_region", "clear_all_tabs", "clear_screen", "clr_eol", "clr_eos",
"column_address", "command_character", "cursor_address", "cursor_down", "cursor_home", "column_address", "command_character", "cursor_address", "cursor_down", "cursor_home",
"cursor_invisible", "cursor_left", "cursor_mem_address", "cursor_normal", "cursor_right", "cursor_invisible", "cursor_left", "cursor_mem_address", "cursor_normal", "cursor_right",
@ -123,7 +123,7 @@ pub static stringfnames: &[&str] = &[ "back_tab", "bell", "carriage_return",
"acs_plus", "memory_lock", "memory_unlock", "box_chars_1"]; "acs_plus", "memory_lock", "memory_unlock", "box_chars_1"];
#[rustfmt::skip] #[rustfmt::skip]
pub static stringnames: &[&str] = &[ "cbt", "_", "cr", "csr", "tbc", "clear", pub(crate) static stringnames: &[&str] = &[ "cbt", "_", "cr", "csr", "tbc", "clear",
"_", "_", "hpa", "cmdch", "cup", "cud1", "home", "civis", "cub1", "mrcup", "cnorm", "cuf1", "_", "_", "hpa", "cmdch", "cup", "cud1", "home", "civis", "cub1", "mrcup", "cnorm", "cuf1",
"ll", "cuu1", "cvvis", "dch1", "dl1", "dsl", "hd", "smacs", "blink", "bold", "smcup", "smdc", "ll", "cuu1", "cvvis", "dch1", "dl1", "dsl", "hd", "smacs", "blink", "bold", "smcup", "smdc",
"dim", "smir", "invis", "prot", "rev", "smso", "smul", "ech", "rmacs", "sgr0", "rmcup", "rmdc", "dim", "smir", "invis", "prot", "rev", "smso", "smul", "ech", "rmacs", "sgr0", "rmcup", "rmdc",
@ -178,7 +178,7 @@ fn read_byte(r: &mut dyn io::Read) -> io::Result<u8> {
/// Parse a compiled terminfo entry, using long capability names if `longnames` /// Parse a compiled terminfo entry, using long capability names if `longnames`
/// is true /// is true
pub fn parse(file: &mut dyn io::Read, longnames: bool) -> Result<TermInfo, String> { pub(crate) fn parse(file: &mut dyn io::Read, longnames: bool) -> Result<TermInfo, String> {
macro_rules! t( ($e:expr) => ( macro_rules! t( ($e:expr) => (
match $e { match $e {
Ok(e) => e, Ok(e) => e,
@ -317,7 +317,7 @@ pub fn parse(file: &mut dyn io::Read, longnames: bool) -> Result<TermInfo, Strin
} }
/// Creates a dummy TermInfo struct for msys terminals /// Creates a dummy TermInfo struct for msys terminals
pub fn msys_terminfo() -> TermInfo { pub(crate) fn msys_terminfo() -> TermInfo {
let mut strings = HashMap::new(); let mut strings = HashMap::new();
strings.insert("sgr0".to_string(), b"\x1B[0m".to_vec()); strings.insert("sgr0".to_string(), b"\x1B[0m".to_vec());
strings.insert("bold".to_string(), b"\x1B[1m".to_vec()); strings.insert("bold".to_string(), b"\x1B[1m".to_vec());

View File

@ -11,7 +11,7 @@ mod tests;
/// Return path to database entry for `term` /// Return path to database entry for `term`
#[allow(deprecated)] #[allow(deprecated)]
pub fn get_dbpath_for_term(term: &str) -> Option<PathBuf> { pub(crate) fn get_dbpath_for_term(term: &str) -> Option<PathBuf> {
let mut dirs_to_search = Vec::new(); let mut dirs_to_search = Vec::new();
let first_char = term.chars().next()?; let first_char = term.chars().next()?;

View File

@ -5,12 +5,11 @@
use std::io; use std::io;
use std::io::prelude::*; use std::io::prelude::*;
use crate::color; use super::color;
use crate::Attr; use super::Terminal;
use crate::Terminal;
/// A Terminal implementation that uses the Win32 Console API. /// A Terminal implementation that uses the Win32 Console API.
pub struct WinConsole<T> { pub(crate) struct WinConsole<T> {
buf: T, buf: T,
def_foreground: color::Color, def_foreground: color::Color,
def_background: color::Color, def_background: color::Color,
@ -115,7 +114,7 @@ impl<T: Write + Send + 'static> WinConsole<T> {
} }
/// Returns `None` whenever the terminal cannot be created for some reason. /// Returns `None` whenever the terminal cannot be created for some reason.
pub fn new(out: T) -> io::Result<WinConsole<T>> { pub(crate) fn new(out: T) -> io::Result<WinConsole<T>> {
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
let fg; let fg;
@ -154,8 +153,6 @@ impl<T: Write> Write for WinConsole<T> {
} }
impl<T: Write + Send + 'static> Terminal for WinConsole<T> { impl<T: Write + Send + 'static> Terminal for WinConsole<T> {
type Output = T;
fn fg(&mut self, color: color::Color) -> io::Result<bool> { fn fg(&mut self, color: color::Color) -> io::Result<bool> {
self.foreground = color; self.foreground = color;
self.apply(); self.apply();
@ -163,38 +160,6 @@ impl<T: Write + Send + 'static> Terminal for WinConsole<T> {
Ok(true) Ok(true)
} }
fn bg(&mut self, color: color::Color) -> io::Result<bool> {
self.background = color;
self.apply();
Ok(true)
}
fn attr(&mut self, attr: Attr) -> io::Result<bool> {
match attr {
Attr::ForegroundColor(f) => {
self.foreground = f;
self.apply();
Ok(true)
}
Attr::BackgroundColor(b) => {
self.background = b;
self.apply();
Ok(true)
}
_ => Ok(false),
}
}
fn supports_attr(&self, attr: Attr) -> bool {
// it claims support for underscore and reverse video, but I can't get
// it to do anything -cmr
match attr {
Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => true,
_ => false,
}
}
fn reset(&mut self) -> io::Result<bool> { fn reset(&mut self) -> io::Result<bool> {
self.foreground = self.def_foreground; self.foreground = self.def_foreground;
self.background = self.def_background; self.background = self.def_background;
@ -202,19 +167,4 @@ impl<T: Write + Send + 'static> Terminal for WinConsole<T> {
Ok(true) Ok(true)
} }
fn get_ref(&self) -> &T {
&self.buf
}
fn get_mut(&mut self) -> &mut T {
&mut self.buf
}
fn into_inner(self) -> T
where
Self: Sized,
{
self.buf
}
} }