Rustfmt libterm, skip long static in compiled.rs

This commit is contained in:
Bryce Van Dyk 2015-11-22 13:24:56 +13:00
parent 685e098561
commit 7d54c32c94
6 changed files with 505 additions and 388 deletions

View File

@ -63,8 +63,12 @@
#![feature(str_char)]
#![feature(vec_push_all)]
#![cfg_attr(windows, feature(libc))]
// Handle rustfmt skips
#![feature(custom_attribute)]
#![allow(unused_attributes)]
#[macro_use] extern crate log;
#[macro_use]
extern crate log;
pub use terminfo::TerminfoTerminal;
#[cfg(windows)]
@ -100,26 +104,18 @@ impl Write for WriterWrapper {
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
TerminfoTerminal::new(WriterWrapper {
wrapped: box std::io::stdout(),
})
TerminfoTerminal::new(WriterWrapper { wrapped: box std::io::stdout() })
}
#[cfg(windows)]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
let ti = TerminfoTerminal::new(WriterWrapper {
wrapped: box std::io::stdout(),
});
let ti = TerminfoTerminal::new(WriterWrapper { wrapped: box std::io::stdout() });
match ti {
Some(t) => Some(t),
None => {
WinConsole::new(WriterWrapper {
wrapped: box std::io::stdout(),
})
}
None => WinConsole::new(WriterWrapper { wrapped: box std::io::stdout() }),
}
}
@ -127,26 +123,18 @@ pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send>> {
TerminfoTerminal::new(WriterWrapper {
wrapped: box std::io::stderr(),
})
TerminfoTerminal::new(WriterWrapper { wrapped: box std::io::stderr() })
}
#[cfg(windows)]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send>> {
let ti = TerminfoTerminal::new(WriterWrapper {
wrapped: box std::io::stderr(),
});
let ti = TerminfoTerminal::new(WriterWrapper { wrapped: box std::io::stderr() });
match ti {
Some(t) => Some(t),
None => {
WinConsole::new(WriterWrapper {
wrapped: box std::io::stderr(),
})
}
None => WinConsole::new(WriterWrapper { wrapped: box std::io::stderr() }),
}
}
@ -157,23 +145,23 @@ pub mod color {
/// Number for a terminal color
pub type Color = u16;
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 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 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_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;
pub const BRIGHT_CYAN: Color = 14;
pub const BRIGHT_WHITE: Color = 15;
}
/// Terminal attributes
@ -206,7 +194,7 @@ pub mod attr {
/// Convenience attribute to set the foreground color
ForegroundColor(super::color::Color),
/// Convenience attribute to set the background color
BackgroundColor(super::color::Color)
BackgroundColor(super::color::Color),
}
}

View File

@ -28,13 +28,13 @@ use self::parm::{expand, Number, Variables};
#[derive(Debug)]
pub struct TermInfo {
/// Names for the terminal
pub names: Vec<String> ,
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, u16>,
/// Map of capability name to raw (unexpanded) string
pub strings: HashMap<String, Vec<u8> >
pub strings: HashMap<String, Vec<u8>>,
}
pub mod searcher;
@ -49,19 +49,19 @@ 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::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"
attr::BackgroundColor(_) => "setab",
}
}
@ -70,7 +70,7 @@ fn cap_for_attr(attr: attr::Attr) -> &'static str {
pub struct TerminfoTerminal<T> {
num_colors: u16,
out: T,
ti: Box<TermInfo>
ti: Box<TermInfo>,
}
impl<T: Write+Send+'static> Terminal<T> for TerminfoTerminal<T> {
@ -80,12 +80,12 @@ impl<T: Write+Send+'static> Terminal<T> for TerminfoTerminal<T> {
let s = expand(self.ti
.strings
.get("setaf")
.unwrap()
,
&[Number(color as isize)], &mut Variables::new());
.unwrap(),
&[Number(color as isize)],
&mut Variables::new());
if s.is_ok() {
try!(self.out.write_all(&s.unwrap()));
return Ok(true)
return Ok(true);
}
}
Ok(false)
@ -97,12 +97,12 @@ impl<T: Write+Send+'static> Terminal<T> for TerminfoTerminal<T> {
let s = expand(self.ti
.strings
.get("setab")
.unwrap()
,
&[Number(color as isize)], &mut Variables::new());
.unwrap(),
&[Number(color as isize)],
&mut Variables::new());
if s.is_ok() {
try!(self.out.write_all(&s.unwrap()));
return Ok(true)
return Ok(true);
}
}
Ok(false)
@ -116,12 +116,10 @@ impl<T: Write+Send+'static> Terminal<T> for TerminfoTerminal<T> {
let cap = cap_for_attr(attr);
let parm = self.ti.strings.get(cap);
if parm.is_some() {
let s = expand(parm.unwrap(),
&[],
&mut Variables::new());
let s = expand(parm.unwrap(), &[], &mut Variables::new());
if s.is_ok() {
try!(self.out.write_all(&s.unwrap()));
return Ok(true)
return Ok(true);
}
}
Ok(false)
@ -131,9 +129,7 @@ impl<T: Write+Send+'static> Terminal<T> for TerminfoTerminal<T> {
fn supports_attr(&self, attr: attr::Attr) -> bool {
match attr {
attr::ForegroundColor(_) | attr::BackgroundColor(_) => {
self.num_colors > 0
}
attr::ForegroundColor(_) | attr::BackgroundColor(_) => self.num_colors > 0,
_ => {
let cap = cap_for_attr(attr);
self.ti.strings.get(cap).is_some()
@ -151,28 +147,33 @@ impl<T: Write+Send+'static> Terminal<T> for TerminfoTerminal<T> {
cap = self.ti.strings.get("op");
}
}
let s = cap.map_or(Err("can't find terminfo capability `sgr0`".to_owned()), |op| {
expand(op, &[], &mut Variables::new())
});
let s = cap.map_or(Err("can't find terminfo capability `sgr0`".to_owned()),
|op| expand(op, &[], &mut Variables::new()));
if s.is_ok() {
return self.out.write_all(&s.unwrap())
return self.out.write_all(&s.unwrap());
}
Ok(())
}
fn get_ref<'a>(&'a self) -> &'a 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 }
fn get_mut<'a>(&'a mut self) -> &'a mut T {
&mut self.out
}
}
impl<T: Write+Send+'static> UnwrappableTerminal<T> for TerminfoTerminal<T> {
fn unwrap(self) -> T { self.out }
fn unwrap(self) -> T {
self.out
}
}
impl<T: Write+Send+'static> TerminfoTerminal<T> {
/// Returns `None` whenever the terminal cannot be created for some
/// reason.
pub fn new(out: T) -> Option<Box<Terminal<T>+Send+'static>> {
pub fn new(out: T) -> Option<Box<Terminal<T> + Send + 'static>> {
let term = match env::var("TERM") {
Ok(t) => t,
Err(..) => {
@ -183,20 +184,22 @@ impl<T: Write+Send+'static> TerminfoTerminal<T> {
let mut file = match open(&term[..]) {
Ok(f) => f,
Err(err) => return match env::var("MSYSCON") {
Ok(ref val) if &val[..] == "mintty.exe" => {
// msys terminal
Some(box TerminfoTerminal{
out: out,
ti: msys_terminfo(),
num_colors: 8,
})
},
_ => {
debug!("error finding terminfo entry: {:?}", err);
None
},
},
Err(err) => {
return match env::var("MSYSCON") {
Ok(ref val) if &val[..] == "mintty.exe" => {
// msys terminal
Some(box TerminfoTerminal {
out: out,
ti: msys_terminfo(),
num_colors: 8,
})
}
_ => {
debug!("error finding terminfo entry: {:?}", err);
None
}
};
}
};
let ti = parse(&mut file, false);
@ -206,20 +209,25 @@ impl<T: Write+Send+'static> TerminfoTerminal<T> {
}
let inf = ti.unwrap();
let nc = if inf.strings.get("setaf").is_some()
&& inf.strings.get("setab").is_some() {
inf.numbers.get("colors").map_or(0, |&n| n)
} else { 0 };
let nc = if inf.strings.get("setaf").is_some() && inf.strings.get("setab").is_some() {
inf.numbers.get("colors").map_or(0, |&n| n)
} else {
0
};
Some(box TerminfoTerminal {out: out,
ti: inf,
num_colors: nc})
Some(box TerminfoTerminal {
out: out,
ti: inf,
num_colors: nc,
})
}
fn dim_if_necessary(&self, color: color::Color) -> color::Color {
if color >= self.num_colors && color >= 8 && color < 16 {
color-8
} else { color }
color - 8
} else {
color
}
}
}

View File

@ -32,14 +32,14 @@ enum States {
SeekIfElse(isize),
SeekIfElsePercent(isize),
SeekIfEnd(isize),
SeekIfEndPercent(isize)
SeekIfEndPercent(isize),
}
#[derive(Copy, Clone, PartialEq)]
enum FormatState {
FormatStateFlags,
FormatStateWidth,
FormatStatePrecision
FormatStatePrecision,
}
/// Types of parameters a capability can use
@ -47,7 +47,7 @@ enum FormatState {
#[derive(Clone)]
pub enum Param {
Words(String),
Number(isize)
Number(isize),
}
/// Container for static and dynamic variable arrays
@ -55,29 +55,21 @@ pub struct Variables {
/// Static variables A-Z
sta: [Param; 26],
/// Dynamic variables a-z
dyn: [Param; 26]
dyn: [Param; 26],
}
impl Variables {
/// Return a new zero-initialized Variables
pub fn new() -> Variables {
Variables {
sta: [
Number(0), Number(0), Number(0), Number(0), Number(0),
Number(0), Number(0), Number(0), Number(0), Number(0),
Number(0), Number(0), Number(0), Number(0), Number(0),
Number(0), Number(0), Number(0), Number(0), Number(0),
Number(0), Number(0), Number(0), Number(0), Number(0),
Number(0),
],
dyn: [
Number(0), Number(0), Number(0), Number(0), Number(0),
Number(0), Number(0), Number(0), Number(0), Number(0),
Number(0), Number(0), Number(0), Number(0), Number(0),
Number(0), Number(0), Number(0), Number(0), Number(0),
Number(0), Number(0), Number(0), Number(0), Number(0),
Number(0),
],
sta: [Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0),
Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0),
Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0),
Number(0), Number(0), Number(0), Number(0), Number(0)],
dyn: [Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0),
Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0),
Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0),
Number(0), Number(0), Number(0), Number(0), Number(0)],
}
}
}
@ -91,8 +83,7 @@ impl Variables {
///
/// To be compatible with ncurses, `vars` should be the same between calls to `expand` for
/// multiple capabilities for the same terminal.
pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
-> Result<Vec<u8> , String> {
pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<u8>, String> {
let mut state = Nothing;
// expanded cap will only rarely be larger than the cap itself
@ -101,10 +92,8 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
let mut stack: Vec<Param> = Vec::new();
// Copy parameters into a local vector for mutability
let mut mparams = [
Number(0), Number(0), Number(0), Number(0), Number(0),
Number(0), Number(0), Number(0), Number(0),
];
let mut mparams = [Number(0), Number(0), Number(0), Number(0), Number(0), Number(0),
Number(0), Number(0), Number(0)];
for (dst, src) in mparams.iter_mut().zip(params) {
*dst = (*src).clone();
}
@ -119,147 +108,241 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
} else {
output.push(c);
}
},
}
Percent => {
match cur {
'%' => { output.push(c); state = Nothing },
'c' => if !stack.is_empty() {
match stack.pop().unwrap() {
// if c is 0, use 0200 (128) for ncurses compatibility
Number(c) => {
output.push(if c == 0 {
128
} else {
c as u8
})
'%' => {
output.push(c);
state = Nothing
}
'c' => {
if !stack.is_empty() {
match stack.pop().unwrap() {
// if c is 0, use 0200 (128) for ncurses compatibility
Number(c) => {
output.push(if c == 0 {
128
} else {
c as u8
})
}
_ => return Err("a non-char was used with %c".to_owned()),
}
_ => return Err("a non-char was used with %c".to_owned())
} else {
return Err("stack is empty".to_owned());
}
} else { return Err("stack is empty".to_owned()) },
}
'p' => state = PushParam,
'P' => state = SetVar,
'g' => state = GetVar,
'\'' => state = CharConstant,
'{' => state = IntConstant(0),
'l' => if !stack.is_empty() {
match stack.pop().unwrap() {
Words(s) => stack.push(Number(s.len() as isize)),
_ => return Err("a non-str was used with %l".to_owned())
'l' => {
if !stack.is_empty() {
match stack.pop().unwrap() {
Words(s) => stack.push(Number(s.len() as isize)),
_ => return Err("a non-str was used with %l".to_owned()),
}
} else {
return Err("stack is empty".to_owned());
}
} else { return Err("stack is empty".to_owned()) },
'+' => if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => stack.push(Number(x + y)),
_ => return Err("non-numbers on stack with +".to_owned())
}
'+' => {
if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => stack.push(Number(x + y)),
_ => return Err("non-numbers on stack with +".to_owned()),
}
} else {
return Err("stack is empty".to_owned());
}
} else { return Err("stack is empty".to_owned()) },
'-' => if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => stack.push(Number(x - y)),
_ => return Err("non-numbers on stack with -".to_owned())
}
'-' => {
if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => stack.push(Number(x - y)),
_ => return Err("non-numbers on stack with -".to_owned()),
}
} else {
return Err("stack is empty".to_owned());
}
} else { return Err("stack is empty".to_owned()) },
'*' => if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => stack.push(Number(x * y)),
_ => return Err("non-numbers on stack with *".to_owned())
}
'*' => {
if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => stack.push(Number(x * y)),
_ => return Err("non-numbers on stack with *".to_owned()),
}
} else {
return Err("stack is empty".to_owned());
}
} else { return Err("stack is empty".to_owned()) },
'/' => if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => stack.push(Number(x / y)),
_ => return Err("non-numbers on stack with /".to_owned())
}
'/' => {
if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => stack.push(Number(x / y)),
_ => return Err("non-numbers on stack with /".to_owned()),
}
} else {
return Err("stack is empty".to_owned());
}
} else { return Err("stack is empty".to_owned()) },
'm' => if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => stack.push(Number(x % y)),
_ => return Err("non-numbers on stack with %".to_owned())
}
'm' => {
if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => stack.push(Number(x % y)),
_ => return Err("non-numbers on stack with %".to_owned()),
}
} else {
return Err("stack is empty".to_owned());
}
} else { return Err("stack is empty".to_owned()) },
'&' => if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => stack.push(Number(x & y)),
_ => return Err("non-numbers on stack with &".to_owned())
}
'&' => {
if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => stack.push(Number(x & y)),
_ => return Err("non-numbers on stack with &".to_owned()),
}
} else {
return Err("stack is empty".to_owned());
}
} else { return Err("stack is empty".to_owned()) },
'|' => if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => stack.push(Number(x | y)),
_ => return Err("non-numbers on stack with |".to_owned())
}
'|' => {
if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => stack.push(Number(x | y)),
_ => return Err("non-numbers on stack with |".to_owned()),
}
} else {
return Err("stack is empty".to_owned());
}
} else { return Err("stack is empty".to_owned()) },
'^' => if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => stack.push(Number(x ^ y)),
_ => return Err("non-numbers on stack with ^".to_owned())
}
'^' => {
if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => stack.push(Number(x ^ y)),
_ => return Err("non-numbers on stack with ^".to_owned()),
}
} else {
return Err("stack is empty".to_owned());
}
} else { return Err("stack is empty".to_owned()) },
'=' => if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => stack.push(Number(if x == y { 1 }
else { 0 })),
_ => return Err("non-numbers on stack with =".to_owned())
}
'=' => {
if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => {
stack.push(Number(if x == y {
1
} else {
0
}))
}
_ => return Err("non-numbers on stack with =".to_owned()),
}
} else {
return Err("stack is empty".to_owned());
}
} else { return Err("stack is empty".to_owned()) },
'>' => if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => stack.push(Number(if x > y { 1 }
else { 0 })),
_ => return Err("non-numbers on stack with >".to_owned())
}
'>' => {
if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => {
stack.push(Number(if x > y {
1
} else {
0
}))
}
_ => return Err("non-numbers on stack with >".to_owned()),
}
} else {
return Err("stack is empty".to_owned());
}
} else { return Err("stack is empty".to_owned()) },
'<' => if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => stack.push(Number(if x < y { 1 }
else { 0 })),
_ => return Err("non-numbers on stack with <".to_owned())
}
'<' => {
if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(y), Number(x)) => {
stack.push(Number(if x < y {
1
} else {
0
}))
}
_ => return Err("non-numbers on stack with <".to_owned()),
}
} else {
return Err("stack is empty".to_owned());
}
} else { return Err("stack is empty".to_owned()) },
'A' => if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(0), Number(_)) => stack.push(Number(0)),
(Number(_), Number(0)) => stack.push(Number(0)),
(Number(_), Number(_)) => stack.push(Number(1)),
_ => return Err("non-numbers on stack with logical and".to_owned())
}
'A' => {
if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(0), Number(_)) => stack.push(Number(0)),
(Number(_), Number(0)) => stack.push(Number(0)),
(Number(_), Number(_)) => stack.push(Number(1)),
_ => return Err("non-numbers on stack with logical and".to_owned()),
}
} else {
return Err("stack is empty".to_owned());
}
} else { return Err("stack is empty".to_owned()) },
'O' => if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(0), Number(0)) => stack.push(Number(0)),
(Number(_), Number(_)) => stack.push(Number(1)),
_ => return Err("non-numbers on stack with logical or".to_owned())
}
'O' => {
if stack.len() > 1 {
match (stack.pop().unwrap(), stack.pop().unwrap()) {
(Number(0), Number(0)) => stack.push(Number(0)),
(Number(_), Number(_)) => stack.push(Number(1)),
_ => return Err("non-numbers on stack with logical or".to_owned()),
}
} else {
return Err("stack is empty".to_owned());
}
} else { return Err("stack is empty".to_owned()) },
'!' => if !stack.is_empty() {
match stack.pop().unwrap() {
Number(0) => stack.push(Number(1)),
Number(_) => stack.push(Number(0)),
_ => return Err("non-number on stack with logical not".to_owned())
}
'!' => {
if !stack.is_empty() {
match stack.pop().unwrap() {
Number(0) => stack.push(Number(1)),
Number(_) => stack.push(Number(0)),
_ => return Err("non-number on stack with logical not".to_owned()),
}
} else {
return Err("stack is empty".to_owned());
}
} else { return Err("stack is empty".to_owned()) },
'~' => if !stack.is_empty() {
match stack.pop().unwrap() {
Number(x) => stack.push(Number(!x)),
_ => return Err("non-number on stack with %~".to_owned())
}
'~' => {
if !stack.is_empty() {
match stack.pop().unwrap() {
Number(x) => stack.push(Number(!x)),
_ => return Err("non-number on stack with %~".to_owned()),
}
} else {
return Err("stack is empty".to_owned());
}
} else { return Err("stack is empty".to_owned()) },
'i' => match (mparams[0].clone(), mparams[1].clone()) {
(Number(x), Number(y)) => {
mparams[0] = Number(x+1);
mparams[1] = Number(y+1);
},
(_, _) => return Err("first two params not numbers with %i".to_owned())
},
}
'i' => {
match (mparams[0].clone(), mparams[1].clone()) {
(Number(x), Number(y)) => {
mparams[0] = Number(x + 1);
mparams[1] = Number(y + 1);
}
(_, _) => return Err("first two params not numbers with %i".to_owned()),
}
}
// printf-style support for %doxXs
'd'|'o'|'x'|'X'|'s' => if !stack.is_empty() {
let flags = Flags::new();
let res = format(stack.pop().unwrap(), FormatOp::from_char(cur), flags);
if res.is_err() { return res }
output.push_all(&res.unwrap())
} else { return Err("stack is empty".to_owned()) },
':'|'#'|' '|'.'|'0'...'9' => {
'd' | 'o' | 'x' | 'X' | 's' => {
if !stack.is_empty() {
let flags = Flags::new();
let res = format(stack.pop().unwrap(), FormatOp::from_char(cur), flags);
if res.is_err() {
return res;
}
output.push_all(&res.unwrap())
} else {
return Err("stack is empty".to_owned());
}
}
':' | '#' | ' ' | '.' | '0'...'9' => {
let mut flags = Flags::new();
let mut fstate = FormatStateFlags;
match cur {
@ -271,51 +354,57 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
flags.width = cur as usize - '0' as usize;
fstate = FormatStateWidth;
}
_ => unreachable!()
_ => unreachable!(),
}
state = FormatPattern(flags, fstate);
}
// conditionals
'?' => (),
't' => if !stack.is_empty() {
match stack.pop().unwrap() {
Number(0) => state = SeekIfElse(0),
Number(_) => (),
_ => return Err("non-number on stack \
with conditional".to_owned())
't' => {
if !stack.is_empty() {
match stack.pop().unwrap() {
Number(0) => state = SeekIfElse(0),
Number(_) => (),
_ => return Err("non-number on stack with conditional".to_owned()),
}
} else {
return Err("stack is empty".to_owned());
}
} else { return Err("stack is empty".to_owned()) },
}
'e' => state = SeekIfEnd(0),
';' => (),
_ => {
return Err(format!("unrecognized format option {:?}", cur))
}
_ => return Err(format!("unrecognized format option {:?}", cur)),
}
},
}
PushParam => {
// params are 1-indexed
stack.push(mparams[match cur.to_digit(10) {
Some(d) => d as usize - 1,
None => return Err("bad param number".to_owned())
}].clone());
},
Some(d) => d as usize - 1,
None => return Err("bad param number".to_owned()),
}]
.clone());
}
SetVar => {
if cur >= 'A' && cur <= 'Z' {
if !stack.is_empty() {
let idx = (cur as u8) - b'A';
vars.sta[idx as usize] = stack.pop().unwrap();
} else { return Err("stack is empty".to_owned()) }
} else {
return Err("stack is empty".to_owned());
}
} else if cur >= 'a' && cur <= 'z' {
if !stack.is_empty() {
let idx = (cur as u8) - b'a';
vars.dyn[idx as usize] = stack.pop().unwrap();
} else { return Err("stack is empty".to_owned()) }
} else {
return Err("stack is empty".to_owned());
}
} else {
return Err("bad variable name in %P".to_owned());
}
},
}
GetVar => {
if cur >= 'A' && cur <= 'Z' {
let idx = (cur as u8) - b'A';
@ -326,16 +415,16 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
} else {
return Err("bad variable name in %g".to_owned());
}
},
}
CharConstant => {
stack.push(Number(c as isize));
state = CharClose;
},
}
CharClose => {
if cur != '\'' {
return Err("malformed character constant".to_owned());
}
},
}
IntConstant(i) => {
match cur {
'}' => {
@ -343,57 +432,67 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
state = Nothing;
}
'0'...'9' => {
state = IntConstant(i*10 + (cur as isize - '0' as isize));
state = IntConstant(i * 10 + (cur as isize - '0' as isize));
old_state = Nothing;
}
_ => return Err("bad isize constant".to_owned())
_ => return Err("bad isize constant".to_owned()),
}
}
FormatPattern(ref mut flags, ref mut fstate) => {
old_state = Nothing;
match (*fstate, cur) {
(_,'d')|(_,'o')|(_,'x')|(_,'X')|(_,'s') => if !stack.is_empty() {
let res = format(stack.pop().unwrap(), FormatOp::from_char(cur), *flags);
if res.is_err() { return res }
output.push_all(&res.unwrap());
// will cause state to go to Nothing
old_state = FormatPattern(*flags, *fstate);
} else { return Err("stack is empty".to_owned()) },
(FormatStateFlags,'#') => {
(_, 'd') | (_, 'o') | (_, 'x') | (_, 'X') | (_, 's') => {
if !stack.is_empty() {
let res = format(stack.pop().unwrap(),
FormatOp::from_char(cur),
*flags);
if res.is_err() {
return res;
}
output.push_all(&res.unwrap());
// will cause state to go to Nothing
old_state = FormatPattern(*flags, *fstate);
} else {
return Err("stack is empty".to_owned());
}
}
(FormatStateFlags, '#') => {
flags.alternate = true;
}
(FormatStateFlags,'-') => {
(FormatStateFlags, '-') => {
flags.left = true;
}
(FormatStateFlags,'+') => {
(FormatStateFlags, '+') => {
flags.sign = true;
}
(FormatStateFlags,' ') => {
(FormatStateFlags, ' ') => {
flags.space = true;
}
(FormatStateFlags,'0'...'9') => {
(FormatStateFlags, '0'...'9') => {
flags.width = cur as usize - '0' as usize;
*fstate = FormatStateWidth;
}
(FormatStateFlags,'.') => {
(FormatStateFlags, '.') => {
*fstate = FormatStatePrecision;
}
(FormatStateWidth,'0'...'9') => {
(FormatStateWidth, '0'...'9') => {
let old = flags.width;
flags.width = flags.width * 10 + (cur as usize - '0' as usize);
if flags.width < old { return Err("format width overflow".to_owned()) }
if flags.width < old {
return Err("format width overflow".to_owned());
}
}
(FormatStateWidth,'.') => {
(FormatStateWidth, '.') => {
*fstate = FormatStatePrecision;
}
(FormatStatePrecision,'0'...'9') => {
(FormatStatePrecision, '0'...'9') => {
let old = flags.precision;
flags.precision = flags.precision * 10 + (cur as usize - '0' as usize);
if flags.precision < old {
return Err("format precision overflow".to_owned())
return Err("format precision overflow".to_owned());
}
}
_ => return Err("invalid format specifier".to_owned())
_ => return Err("invalid format specifier".to_owned()),
}
}
SeekIfElse(level) => {
@ -407,12 +506,12 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
if level == 0 {
state = Nothing;
} else {
state = SeekIfElse(level-1);
state = SeekIfElse(level - 1);
}
} else if cur == 'e' && level == 0 {
state = Nothing;
} else if cur == '?' {
state = SeekIfElse(level+1);
state = SeekIfElse(level + 1);
} else {
state = SeekIfElse(level);
}
@ -428,10 +527,10 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables)
if level == 0 {
state = Nothing;
} else {
state = SeekIfEnd(level-1);
state = SeekIfEnd(level - 1);
}
} else if cur == '?' {
state = SeekIfEnd(level+1);
state = SeekIfEnd(level + 1);
} else {
state = SeekIfEnd(level);
}
@ -451,13 +550,19 @@ struct Flags {
alternate: bool,
left: bool,
sign: bool,
space: bool
space: bool,
}
impl Flags {
fn new() -> Flags {
Flags{ width: 0, precision: 0, alternate: false,
left: false, sign: false, space: false }
Flags {
width: 0,
precision: 0,
alternate: false,
left: false,
sign: false,
space: false,
}
}
}
@ -467,7 +572,7 @@ enum FormatOp {
FormatOctal,
FormatHex,
FormatHEX,
FormatString
FormatString,
}
impl FormatOp {
@ -478,7 +583,7 @@ impl FormatOp {
'x' => FormatHex,
'X' => FormatHEX,
's' => FormatString,
_ => panic!("bad FormatOp char")
_ => panic!("bad FormatOp char"),
}
}
fn to_char(self) -> char {
@ -487,23 +592,21 @@ impl FormatOp {
FormatOctal => 'o',
FormatHex => 'x',
FormatHEX => 'X',
FormatString => 's'
FormatString => '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> {
let mut s = match val {
Number(d) => {
let s = match (op, flags.sign) {
(FormatDigit, true) => format!("{:+}", d).into_bytes(),
(FormatDigit, true) => format!("{:+}", d).into_bytes(),
(FormatDigit, false) => format!("{}", d).into_bytes(),
(FormatOctal, _) => format!("{:o}", d).into_bytes(),
(FormatHex, _) => format!("{:x}", d).into_bytes(),
(FormatHEX, _) => format!("{:X}", d).into_bytes(),
(FormatString, _) => {
return Err("non-number on stack with %s".to_owned())
}
(FormatOctal, _) => format!("{:o}", d).into_bytes(),
(FormatHex, _) => format!("{:x}", d).into_bytes(),
(FormatHEX, _) => format!("{:X}", d).into_bytes(),
(FormatString, _) => return Err("non-number on stack with %s".to_owned()),
};
let mut s: Vec<u8> = s.into_iter().collect();
if flags.precision > s.len() {
@ -516,7 +619,7 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8> ,String> {
assert!(!s.is_empty(), "string conversion produced empty result");
match op {
FormatDigit => {
if flags.space && !(s[0] == b'-' || s[0] == b'+' ) {
if flags.space && !(s[0] == b'-' || s[0] == b'+') {
s.insert(0, b' ');
}
}
@ -527,18 +630,18 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8> ,String> {
}
FormatHex => {
if flags.alternate {
let s_ = replace(&mut s, vec!(b'0', b'x'));
let s_ = replace(&mut s, vec![b'0', b'x']);
s.extend(s_);
}
}
FormatHEX => {
s = s.to_ascii_uppercase();
if flags.alternate {
let s_ = replace(&mut s, vec!(b'0', b'X'));
let s_ = replace(&mut s, vec![b'0', b'X']);
s.extend(s_);
}
}
FormatString => unreachable!()
FormatString => unreachable!(),
}
s
}
@ -551,10 +654,7 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8> ,String> {
}
s
}
_ => {
return Err(format!("non-string on stack with %{:?}",
op.to_char()))
}
_ => return Err(format!("non-string on stack with %{:?}", op.to_char())),
}
}
};
@ -574,7 +674,7 @@ fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8> ,String> {
#[cfg(test)]
mod tests {
use super::{expand,Param,Words,Variables,Number};
use super::{expand, Param, Words, Variables, Number};
use std::result::Result::Ok;
#[test]
@ -594,7 +694,8 @@ mod tests {
fn test_op_i() {
let mut vars = Variables::new();
assert_eq!(expand(b"%p1%d%p2%d%p3%d%i%p1%d%p2%d%p3%d",
&[Number(1),Number(2),Number(3)], &mut vars),
&[Number(1), Number(2), Number(3)],
&mut vars),
Ok("123233".bytes().collect::<Vec<_>>()));
assert_eq!(expand(b"%p1%d%p2%d%i%p1%d%p2%d", &[], &mut vars),
Ok("0011".bytes().collect::<Vec<_>>()));
@ -604,9 +705,11 @@ mod tests {
fn test_param_stack_failure_conditions() {
let mut varstruct = Variables::new();
let vars = &mut varstruct;
fn get_res(fmt: &str, cap: &str, params: &[Param], vars: &mut Variables) ->
Result<Vec<u8>, String>
{
fn get_res(fmt: &str,
cap: &str,
params: &[Param],
vars: &mut Variables)
-> Result<Vec<u8>, String> {
let mut u8v: Vec<_> = fmt.bytes().collect();
u8v.extend(cap.bytes());
expand(&u8v, params, vars)
@ -616,7 +719,8 @@ mod tests {
for &cap in &caps {
let res = get_res("", cap, &[], vars);
assert!(res.is_err(),
"Op {} succeeded incorrectly with 0 stack entries", cap);
"Op {} succeeded incorrectly with 0 stack entries",
cap);
let p = if cap == "%s" || cap == "%l" {
Words("foo".to_string())
} else {
@ -624,19 +728,25 @@ mod tests {
};
let res = get_res("%p1", cap, &[p], vars);
assert!(res.is_ok(),
"Op {} failed with 1 stack entry: {}", cap, res.err().unwrap());
"Op {} failed with 1 stack entry: {}",
cap,
res.err().unwrap());
}
let caps = ["%+", "%-", "%*", "%/", "%m", "%&", "%|", "%A", "%O"];
for &cap in &caps {
let res = expand(cap.as_bytes(), &[], vars);
assert!(res.is_err(),
"Binop {} succeeded incorrectly with 0 stack entries", cap);
"Binop {} succeeded incorrectly with 0 stack entries",
cap);
let res = get_res("%{1}", cap, &[], vars);
assert!(res.is_err(),
"Binop {} succeeded incorrectly with 1 stack entry", cap);
"Binop {} succeeded incorrectly with 1 stack entry",
cap);
let res = get_res("%{1}%{2}", cap, &[], vars);
assert!(res.is_ok(),
"Binop {} failed with 2 stack entries: {:?}", cap, res.err().unwrap());
"Binop {} failed with 2 stack entries: {:?}",
cap,
res.err().unwrap());
}
}
@ -670,16 +780,13 @@ mod tests {
let s = b"\\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m";
let res = expand(s, &[Number(1)], &mut vars);
assert!(res.is_ok(), res.err().unwrap());
assert_eq!(res.unwrap(),
"\\E[31m".bytes().collect::<Vec<_>>());
assert_eq!(res.unwrap(), "\\E[31m".bytes().collect::<Vec<_>>());
let res = expand(s, &[Number(8)], &mut vars);
assert!(res.is_ok(), res.err().unwrap());
assert_eq!(res.unwrap(),
"\\E[90m".bytes().collect::<Vec<_>>());
assert_eq!(res.unwrap(), "\\E[90m".bytes().collect::<Vec<_>>());
let res = expand(s, &[Number(42)], &mut vars);
assert!(res.is_ok(), res.err().unwrap());
assert_eq!(res.unwrap(),
"\\E[38;5;42m".bytes().collect::<Vec<_>>());
assert_eq!(res.unwrap(), "\\E[38;5;42m".bytes().collect::<Vec<_>>());
}
#[test]
@ -690,14 +797,17 @@ mod tests {
&[Words("foo".to_string()),
Words("foo".to_string()),
Words("f".to_string()),
Words("foo".to_string())], vars),
Words("foo".to_string())],
vars),
Ok("foofoo ffo".bytes().collect::<Vec<_>>()));
assert_eq!(expand(b"%p1%:-4.2s", &[Words("foo".to_owned())], vars),
Ok("fo ".bytes().collect::<Vec<_>>()));
assert_eq!(expand(b"%p1%d%p1%.3d%p1%5d%p1%:+d", &[Number(1)], vars),
Ok("1001 1+1".bytes().collect::<Vec<_>>()));
assert_eq!(expand(b"%p1%o%p1%#o%p2%6.4x%p2%#6.4X", &[Number(15), Number(27)], vars),
assert_eq!(expand(b"%p1%o%p1%#o%p2%6.4x%p2%#6.4X",
&[Number(15), Number(27)],
vars),
Ok("17017 001b0X001B".bytes().collect::<Vec<_>>()));
}
}

View File

@ -19,6 +19,7 @@ use super::super::TermInfo;
// These are the orders ncurses uses in its compiled format (as of 5.9). Not sure if portable.
#[rustfmt_skip]
#[allow(missing_docs)]
pub static boolfnames: &'static[&'static str] = &["auto_left_margin", "auto_right_margin",
"no_esc_ctlc", "ceol_standout_glitch", "eat_newline_glitch", "erase_overstrike", "generic_type",
@ -32,12 +33,14 @@ pub static boolfnames: &'static[&'static str] = &["auto_left_margin", "auto_righ
"no_correctly_working_cr", "gnu_has_meta_key", "linefeed_is_newline", "has_hardware_tabs",
"return_does_clr_eol"];
#[rustfmt_skip]
#[allow(missing_docs)]
pub static boolnames: &'static[&'static str] = &["bw", "am", "xsb", "xhp", "xenl", "eo",
"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",
"xvpa", "sam", "cpix", "lpix", "OTbs", "OTns", "OTnc", "OTMT", "OTNL", "OTpt", "OTxr"];
#[rustfmt_skip]
#[allow(missing_docs)]
pub static numfnames: &'static[&'static str] = &[ "columns", "init_tabs", "lines",
"lines_of_memory", "magic_cookie_glitch", "padding_baud_rate", "virtual_terminal",
@ -49,12 +52,14 @@ pub static numfnames: &'static[&'static str] = &[ "columns", "init_tabs", "lines
"bit_image_entwining", "bit_image_type", "magic_cookie_glitch_ul", "carriage_return_delay",
"new_line_delay", "backspace_delay", "horizontal_tab_delay", "number_of_function_keys"];
#[rustfmt_skip]
#[allow(missing_docs)]
pub static numnames: &'static[&'static str] = &[ "cols", "it", "lines", "lm", "xmc", "pb",
"vt", "wsl", "nlab", "lh", "lw", "ma", "wnum", "colors", "pairs", "ncv", "bufsz", "spinv",
"spinh", "maddr", "mjump", "mcs", "mls", "npins", "orc", "orl", "orhi", "orvi", "cps", "widcs",
"btns", "bitwin", "bitype", "UTug", "OTdC", "OTdN", "OTdB", "OTdT", "OTkn"];
#[rustfmt_skip]
#[allow(missing_docs)]
pub static stringfnames: &'static[&'static str] = &[ "back_tab", "bell", "carriage_return",
"change_scroll_region", "clear_all_tabs", "clear_screen", "clr_eol", "clr_eos",
@ -129,6 +134,7 @@ pub static stringfnames: &'static[&'static str] = &[ "back_tab", "bell", "carria
"acs_lrcorner", "acs_ltee", "acs_rtee", "acs_btee", "acs_ttee", "acs_hline", "acs_vline",
"acs_plus", "memory_lock", "memory_unlock", "box_chars_1"];
#[rustfmt_skip]
#[allow(missing_docs)]
pub static stringnames: &'static[&'static str] = &[ "cbt", "_", "cr", "csr", "tbc", "clear",
"_", "_", "hpa", "cmdch", "cup", "cud1", "home", "civis", "cub1", "mrcup", "cnorm", "cuf1",
@ -165,8 +171,7 @@ pub static stringnames: &'static[&'static str] = &[ "cbt", "_", "cr", "csr", "tb
"box1"];
/// Parse a compiled terminfo entry, using long capability names if `longnames` is true
pub fn parse(file: &mut Read, longnames: bool)
-> Result<Box<TermInfo>, String> {
pub fn parse(file: &mut Read, longnames: bool) -> Result<Box<TermInfo>, String> {
macro_rules! try { ($e:expr) => (
match $e {
Ok(e) => e,
@ -192,36 +197,34 @@ pub fn parse(file: &mut Read, longnames: bool)
let magic = try!(read_le_u16(file));
if magic != 0x011A {
return Err(format!("invalid magic number: expected {:x}, found {:x}",
0x011A_usize, magic as usize));
0x011A_usize,
magic as usize));
}
let names_bytes = try!(read_le_u16(file)) as isize;
let bools_bytes = try!(read_le_u16(file)) as isize;
let numbers_count = try!(read_le_u16(file)) as isize;
let names_bytes = try!(read_le_u16(file)) as isize;
let bools_bytes = try!(read_le_u16(file)) as isize;
let numbers_count = try!(read_le_u16(file)) as isize;
let string_offsets_count = try!(read_le_u16(file)) as isize;
let string_table_bytes = try!(read_le_u16(file)) as isize;
let string_table_bytes = try!(read_le_u16(file)) as isize;
assert!(names_bytes > 0);
assert!(names_bytes > 0);
if (bools_bytes as usize) > boolnames.len() {
return Err("incompatible file: more booleans than \
expected".to_owned());
return Err("incompatible file: more booleans than expected".to_owned());
}
if (numbers_count as usize) > numnames.len() {
return Err("incompatible file: more numbers than \
expected".to_owned());
return Err("incompatible file: more numbers than expected".to_owned());
}
if (string_offsets_count as usize) > stringnames.len() {
return Err("incompatible file: more string offsets than \
expected".to_owned());
return Err("incompatible file: more string offsets than expected".to_owned());
}
// don't read NUL
let bytes = try!(read_exact(file, names_bytes as usize - 1));
let names_str = match String::from_utf8(bytes) {
Ok(s) => s,
Ok(s) => s,
Err(_) => return Err("input not utf-8".to_owned()),
};
@ -266,13 +269,13 @@ pub fn parse(file: &mut Read, longnames: bool)
let string_table = try!(read_exact(file, string_table_bytes as usize));
if string_table.len() != string_table_bytes as usize {
return Err("error: hit EOF before end of string \
table".to_owned());
return Err("error: hit EOF before end of string table".to_owned());
}
for (i, v) in string_offsets.iter().enumerate() {
let offset = *v;
if offset == 0xFFFF { // non-entry
if offset == 0xFFFF {
// non-entry
continue;
}
@ -291,17 +294,17 @@ pub fn parse(file: &mut Read, longnames: bool)
// Find the offset of the NUL we want to go to
let nulpos = string_table[offset as usize .. string_table_bytes as usize]
.iter().position(|&b| b == 0);
let nulpos = string_table[offset as usize..string_table_bytes as usize]
.iter()
.position(|&b| b == 0);
match nulpos {
Some(len) => {
string_map.insert(name.to_string(),
string_table[offset as usize ..
(offset as usize + len)].to_vec())
},
string_table[offset as usize..(offset as usize + len)]
.to_vec())
}
None => {
return Err("invalid file: missing NUL in \
string_table".to_owned());
return Err("invalid file: missing NUL in string_table".to_owned());
}
};
}
@ -312,7 +315,7 @@ pub fn parse(file: &mut Read, longnames: bool)
names: term_names,
bools: bools_map,
numbers: numbers_map,
strings: string_map
strings: string_map,
})
}
@ -343,10 +346,10 @@ pub fn msys_terminfo() -> Box<TermInfo> {
strings.insert("setaf".to_owned(), b"\x1B[3%p1%dm".to_vec());
strings.insert("setab".to_owned(), b"\x1B[4%p1%dm".to_vec());
box TermInfo {
names: vec!("cygwin".to_owned()), // msys is a fork of an older cygwin version
names: vec!["cygwin".to_owned()], // msys is a fork of an older cygwin version
bools: HashMap::new(),
numbers: HashMap::new(),
strings: strings
strings: strings,
}
}

View File

@ -38,13 +38,15 @@ pub fn get_dbpath_for_term(term: &str) -> Option<Box<PathBuf>> {
dirs_to_search.push(homedir.unwrap().join(".terminfo"))
}
match env::var("TERMINFO_DIRS") {
Ok(dirs) => for i in dirs.split(':') {
if i == "" {
dirs_to_search.push(PathBuf::from("/usr/share/terminfo"));
} else {
dirs_to_search.push(PathBuf::from(i));
Ok(dirs) => {
for i in dirs.split(':') {
if i == "" {
dirs_to_search.push(PathBuf::from("/usr/share/terminfo"));
} else {
dirs_to_search.push(PathBuf::from(i));
}
}
},
}
// Found nothing in TERMINFO_DIRS, use the default paths:
// According to /etc/terminfo/README, after looking at
// ~/.terminfo, ncurses will search /etc/terminfo, then
@ -86,9 +88,7 @@ pub fn open(term: &str) -> Result<File, String> {
Err(e) => Err(format!("error opening file: {:?}", e)),
}
}
None => {
Err(format!("could not find terminfo entry for {:?}", term))
}
None => Err(format!("could not find terminfo entry for {:?}", term)),
}
}

View File

@ -19,7 +19,7 @@ use std::io::prelude::*;
use attr;
use color;
use {Terminal,UnwrappableTerminal};
use {Terminal, UnwrappableTerminal};
/// A Terminal implementation which uses the Win32 Console API.
pub struct WinConsole<T> {
@ -50,23 +50,22 @@ struct CONSOLE_SCREEN_BUFFER_INFO {
extern "system" {
fn SetConsoleTextAttribute(handle: HANDLE, attr: WORD) -> BOOL;
fn GetStdHandle(which: DWORD) -> HANDLE;
fn GetConsoleScreenBufferInfo(handle: HANDLE,
info: *mut CONSOLE_SCREEN_BUFFER_INFO) -> BOOL;
fn GetConsoleScreenBufferInfo(handle: HANDLE, info: *mut CONSOLE_SCREEN_BUFFER_INFO) -> BOOL;
}
fn color_to_bits(color: color::Color) -> u16 {
// magic numbers from mingw-w64's wincon.h
let bits = match color % 8 {
color::BLACK => 0,
color::BLUE => 0x1,
color::GREEN => 0x2,
color::RED => 0x4,
color::YELLOW => 0x2 | 0x4,
color::BLACK => 0,
color::BLUE => 0x1,
color::GREEN => 0x2,
color::RED => 0x4,
color::YELLOW => 0x2 | 0x4,
color::MAGENTA => 0x1 | 0x4,
color::CYAN => 0x1 | 0x2,
color::WHITE => 0x1 | 0x2 | 0x4,
_ => unreachable!()
color::CYAN => 0x1 | 0x2,
color::WHITE => 0x1 | 0x2 | 0x4,
_ => unreachable!(),
};
if color >= 8 {
@ -86,7 +85,7 @@ fn bits_to_color(bits: u16) -> color::Color {
0x5 => color::MAGENTA,
0x3 => color::CYAN,
0x7 => color::WHITE,
_ => unreachable!()
_ => unreachable!(),
};
color | (bits & 0x8) // copy the hi-intensity bit
@ -116,13 +115,12 @@ impl<T: Write+Send+'static> WinConsole<T> {
/// Returns `None` whenever the terminal cannot be created for some
/// reason.
pub fn new(out: T) -> Option<Box<Terminal<T>+Send+'static>> {
pub fn new(out: T) -> Option<Box<Terminal<T> + Send + 'static>> {
let fg;
let bg;
unsafe {
let mut buffer_info = ::std::mem::uninitialized();
if GetConsoleScreenBufferInfo(GetStdHandle(-11i32 as DWORD),
&mut buffer_info) != 0 {
if GetConsoleScreenBufferInfo(GetStdHandle(-11i32 as DWORD), &mut buffer_info) != 0 {
fg = bits_to_color(buffer_info.wAttributes);
bg = bits_to_color(buffer_info.wAttributes >> 4);
} else {
@ -130,9 +128,13 @@ impl<T: Write+Send+'static> WinConsole<T> {
bg = color::BLACK;
}
}
Some(box WinConsole { buf: out,
def_foreground: fg, def_background: bg,
foreground: fg, background: bg })
Some(box WinConsole {
buf: out,
def_foreground: fg,
def_background: bg,
foreground: fg,
background: bg,
})
}
}
@ -167,13 +169,13 @@ impl<T: Write+Send+'static> Terminal<T> for WinConsole<T> {
self.foreground = f;
self.apply();
Ok(true)
},
}
attr::BackgroundColor(b) => {
self.background = b;
self.apply();
Ok(true)
},
_ => Ok(false)
}
_ => Ok(false),
}
}
@ -182,7 +184,7 @@ impl<T: Write+Send+'static> Terminal<T> for WinConsole<T> {
// it to do anything -cmr
match attr {
attr::ForegroundColor(_) | attr::BackgroundColor(_) => true,
_ => false
_ => false,
}
}
@ -194,11 +196,17 @@ impl<T: Write+Send+'static> Terminal<T> for WinConsole<T> {
Ok(())
}
fn get_ref<'a>(&'a self) -> &'a T { &self.buf }
fn get_ref<'a>(&'a self) -> &'a T {
&self.buf
}
fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.buf }
fn get_mut<'a>(&'a mut self) -> &'a mut T {
&mut self.buf
}
}
impl<T: Write+Send+'static> UnwrappableTerminal<T> for WinConsole<T> {
fn unwrap(self) -> T { self.buf }
fn unwrap(self) -> T {
self.buf
}
}