Rollup merge of #68036 - euclio:libterm-ncurses6-fix, r=KodrAus

libterm: parse extended terminfo format

Fixes #45728.

Modifies libterm to parse the extended terminfo format introduced in ncurses 6.1. This fixes the lack of color in test output for users with newer ncurses versions.

The ideal fix for this would be to migrate libtest to use `termcolor` (https://github.com/rust-lang/rust/issues/60349), but that's blocked for the foreseeable future.
This commit is contained in:
Yuki Okushi 2020-01-14 14:02:20 +09:00 committed by GitHub
commit 974b69927b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 27 additions and 20 deletions

View file

@ -91,7 +91,7 @@ pub fn stderr() -> Option<Box<StderrTerminal>> {
#[allow(missing_docs)]
pub mod color {
/// Number for a terminal color
pub type Color = u16;
pub type Color = u32;
pub const BLACK: Color = 0;
pub const RED: Color = 1;

View file

@ -24,7 +24,7 @@ pub struct TermInfo {
/// Map of capability name to boolean value
pub bools: HashMap<String, bool>,
/// Map of capability name to numeric value
pub numbers: HashMap<String, u16>,
pub numbers: HashMap<String, u32>,
/// Map of capability name to raw (unexpanded) string
pub strings: HashMap<String, Vec<u8>>,
}
@ -129,7 +129,7 @@ fn cap_for_attr(attr: Attr) -> &'static str {
/// 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,
num_colors: u32,
out: T,
ti: TermInfo,
}

View file

@ -159,16 +159,16 @@ pub static stringnames: &[&str] = &[ "cbt", "_", "cr", "csr", "tbc", "clear",
fn read_le_u16(r: &mut dyn io::Read) -> io::Result<u16> {
let mut b = [0; 2];
let mut amt = 0;
while amt < b.len() {
match r.read(&mut b[amt..])? {
0 => return Err(io::Error::new(io::ErrorKind::Other, "end of file")),
n => amt += n,
}
}
r.read_exact(&mut b)?;
Ok((b[0] as u16) | ((b[1] as u16) << 8))
}
fn read_le_u32(r: &mut dyn io::Read) -> io::Result<u32> {
let mut b = [0; 4];
r.read_exact(&mut b)?;
Ok((b[0] as u32) | ((b[1] as u32) << 8) | ((b[2] as u32) << 16) | ((b[3] as u32) << 24))
}
fn read_byte(r: &mut dyn io::Read) -> io::Result<u8> {
match r.bytes().next() {
Some(s) => s,
@ -194,9 +194,12 @@ pub fn parse(file: &mut dyn io::Read, longnames: bool) -> Result<TermInfo, Strin
// Check magic number
let magic = t!(read_le_u16(file));
if magic != 0x011A {
return Err(format!("invalid magic number: expected {:x}, found {:x}", 0x011A, magic));
}
let extended = match magic {
0o0432 => false,
0o01036 => true,
_ => return Err(format!("invalid magic number, found {:o}", magic)),
};
// According to the spec, these fields must be >= -1 where -1 means that the feature is not
// supported. Using 0 instead of -1 works because we skip sections with length 0.
@ -258,11 +261,15 @@ pub fn parse(file: &mut dyn io::Read, longnames: bool) -> Result<TermInfo, Strin
t!(read_byte(file)); // compensate for padding
}
let numbers_map: HashMap<String, u16> = t! {
(0..numbers_count).filter_map(|i| match read_le_u16(file) {
Ok(0xFFFF) => None,
Ok(n) => Some(Ok((nnames[i].to_string(), n))),
Err(e) => Some(Err(e))
let numbers_map: HashMap<String, u32> = t! {
(0..numbers_count).filter_map(|i| {
let number = if extended { read_le_u32(file) } else { read_le_u16(file).map(Into::into) };
match number {
Ok(0xFFFF) => None,
Ok(n) => Some(Ok((nnames[i].to_string(), n))),
Err(e) => Some(Err(e))
}
}).collect()
};
@ -318,7 +325,7 @@ pub fn msys_terminfo() -> TermInfo {
strings.insert("setab".to_string(), b"\x1B[4%p1%dm".to_vec());
let mut numbers = HashMap::new();
numbers.insert("colors".to_string(), 8u16);
numbers.insert("colors".to_string(), 8);
TermInfo {
names: vec!["cygwin".to_string()], // msys is a fork of an older cygwin version

View file

@ -89,7 +89,7 @@ fn bits_to_color(bits: u16) -> color::Color {
_ => unreachable!(),
};
color | (bits & 0x8) // copy the hi-intensity bit
color | (u32::from(bits) & 0x8) // copy the hi-intensity bit
}
impl<T: Write + Send + 'static> WinConsole<T> {