mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-14 01:25:54 +00:00
extra::term: better error handling and win32 compat
This commit is contained in:
parent
100ee84097
commit
5311d59023
@ -43,12 +43,20 @@ pub static color_bright_magenta: u8 = 13u8;
|
||||
pub static color_bright_cyan: u8 = 14u8;
|
||||
pub static color_bright_white: u8 = 15u8;
|
||||
|
||||
#[cfg(not(target_os = "win32"))]
|
||||
pub struct Terminal {
|
||||
color_supported: bool,
|
||||
priv out: @io::Writer,
|
||||
priv ti: ~TermInfo
|
||||
}
|
||||
|
||||
#[cfg(target_os = "win32")]
|
||||
pub struct Terminal {
|
||||
color_supported: bool,
|
||||
priv out: @io::Writer,
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "win32"))]
|
||||
pub impl Terminal {
|
||||
pub fn new(out: @io::Writer) -> Result<Terminal, ~str> {
|
||||
let term = os::getenv("TERM");
|
||||
@ -74,19 +82,50 @@ pub impl Terminal {
|
||||
}
|
||||
fn fg(&self, color: u8) {
|
||||
if self.color_supported {
|
||||
self.out.write(expand(*self.ti.strings.find_equiv(&("setaf")).unwrap(),
|
||||
[Number(color as int)], [], []));
|
||||
let s = expand(*self.ti.strings.find_equiv(&("setaf")).unwrap(),
|
||||
[Number(color as int)], [], []);
|
||||
if s.is_ok() {
|
||||
self.out.write(s.get());
|
||||
} else {
|
||||
warn!(s.get_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
fn bg(&self, color: u8) {
|
||||
if self.color_supported {
|
||||
self.out.write(expand(*self.ti.strings.find_equiv(&("setab")).unwrap(),
|
||||
[Number(color as int)], [], []));
|
||||
let s = expand(*self.ti.strings.find_equiv(&("setab")).unwrap(),
|
||||
[Number(color as int)], [], []);
|
||||
if s.is_ok() {
|
||||
self.out.write(s.get());
|
||||
} else {
|
||||
warn!(s.get_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
fn reset(&self) {
|
||||
if self.color_supported {
|
||||
self.out.write(expand(*self.ti.strings.find_equiv(&("op")).unwrap(), [], [], []));
|
||||
let s = expand(*self.ti.strings.find_equiv(&("op")).unwrap(), [], [], []);
|
||||
if s.is_ok() {
|
||||
self.out.write(s.get());
|
||||
} else {
|
||||
warn!(s.get_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "win32")]
|
||||
pub impl Terminal {
|
||||
pub fn new(out: @io::Writer) -> Result<Terminal, ~str> {
|
||||
return Ok(Terminal {out: out, color_supported: false});
|
||||
}
|
||||
|
||||
fn fg(&self, color: u8) {
|
||||
}
|
||||
|
||||
fn bg(&self, color: u8) {
|
||||
}
|
||||
|
||||
fn reset(&self) {
|
||||
}
|
||||
}
|
||||
|
@ -27,13 +27,27 @@ enum States {
|
||||
IfBody
|
||||
}
|
||||
|
||||
/// Types of parameters a capability can use
|
||||
pub enum Param {
|
||||
String(~str),
|
||||
Char(char),
|
||||
Number(int)
|
||||
}
|
||||
|
||||
pub fn expand(cap: &[u8], params: &mut [Param], sta: &mut [Param], dyn: &mut [Param]) -> ~[u8] {
|
||||
/**
|
||||
Expand a parameterized capability
|
||||
|
||||
# Arguments
|
||||
* `cap` - string to expand
|
||||
* `params` - vector of params for %p1 etc
|
||||
* `sta` - vector of params corresponding to static variables
|
||||
* `dyn` - vector of params corresponding to stativ variables
|
||||
|
||||
To be compatible with ncurses, `sta` and `dyn` should be the same between calls to `expand` for
|
||||
multiple capabilities for the same terminal.
|
||||
*/
|
||||
pub fn expand(cap: &[u8], params: &mut [Param], sta: &mut [Param], dyn: &mut [Param])
|
||||
-> Result<~[u8], ~str> {
|
||||
assert!(cap.len() != 0, "expanding an empty capability makes no sense");
|
||||
assert!(params.len() <= 9, "only 9 parameters are supported by capability strings");
|
||||
|
||||
@ -68,15 +82,15 @@ pub fn expand(cap: &[u8], params: &mut [Param], sta: &mut [Param], dyn: &mut [Pa
|
||||
'%' => { output.push(cap[i]); state = Nothing },
|
||||
'c' => match stack.pop() {
|
||||
Char(c) => output.push(c as u8),
|
||||
_ => fail!("a non-char was used with %c")
|
||||
_ => return Err(~"a non-char was used with %c")
|
||||
},
|
||||
's' => match stack.pop() {
|
||||
String(s) => output.push_all(s.to_bytes()),
|
||||
_ => fail!("a non-str was used with %s")
|
||||
_ => return Err(~"a non-str was used with %s")
|
||||
},
|
||||
'd' => match stack.pop() {
|
||||
Number(x) => output.push_all(x.to_str().to_bytes()),
|
||||
_ => fail!("a non-number was used with %d")
|
||||
_ => return Err(~"a non-number was used with %d")
|
||||
},
|
||||
'p' => state = PushParam,
|
||||
'P' => state = SetVar,
|
||||
@ -85,52 +99,52 @@ pub fn expand(cap: &[u8], params: &mut [Param], sta: &mut [Param], dyn: &mut [Pa
|
||||
'{' => state = IntConstant,
|
||||
'l' => match stack.pop() {
|
||||
String(s) => stack.push(Number(s.len() as int)),
|
||||
_ => fail!("a non-str was used with %l")
|
||||
_ => return Err(~"a non-str was used with %l")
|
||||
},
|
||||
'+' => match (stack.pop(), stack.pop()) {
|
||||
(Number(x), Number(y)) => stack.push(Number(x + y)),
|
||||
(_, _) => fail!("non-numbers on stack with +")
|
||||
(_, _) => return Err(~"non-numbers on stack with +")
|
||||
},
|
||||
'-' => match (stack.pop(), stack.pop()) {
|
||||
(Number(x), Number(y)) => stack.push(Number(x - y)),
|
||||
(_, _) => fail!("non-numbers on stack with -")
|
||||
(_, _) => return Err(~"non-numbers on stack with -")
|
||||
},
|
||||
'*' => match (stack.pop(), stack.pop()) {
|
||||
(Number(x), Number(y)) => stack.push(Number(x * y)),
|
||||
(_, _) => fail!("non-numbers on stack with *")
|
||||
(_, _) => return Err(~"non-numbers on stack with *")
|
||||
},
|
||||
'/' => match (stack.pop(), stack.pop()) {
|
||||
(Number(x), Number(y)) => stack.push(Number(x / y)),
|
||||
(_, _) => fail!("non-numbers on stack with /")
|
||||
(_, _) => return Err(~"non-numbers on stack with /")
|
||||
},
|
||||
'm' => match (stack.pop(), stack.pop()) {
|
||||
(Number(x), Number(y)) => stack.push(Number(x % y)),
|
||||
(_, _) => fail!("non-numbers on stack with %")
|
||||
(_, _) => return Err(~"non-numbers on stack with %")
|
||||
},
|
||||
'&' => match (stack.pop(), stack.pop()) {
|
||||
(Number(x), Number(y)) => stack.push(Number(x & y)),
|
||||
(_, _) => fail!("non-numbers on stack with &")
|
||||
(_, _) => return Err(~"non-numbers on stack with &")
|
||||
},
|
||||
'|' => match (stack.pop(), stack.pop()) {
|
||||
(Number(x), Number(y)) => stack.push(Number(x | y)),
|
||||
(_, _) => fail!("non-numbers on stack with |")
|
||||
(_, _) => return Err(~"non-numbers on stack with |")
|
||||
},
|
||||
'A' => fail!("logical operations unimplemented"),
|
||||
'O' => fail!("logical operations unimplemented"),
|
||||
'!' => fail!("logical operations unimplemented"),
|
||||
'A' => return Err(~"logical operations unimplemented"),
|
||||
'O' => return Err(~"logical operations unimplemented"),
|
||||
'!' => return Err(~"logical operations unimplemented"),
|
||||
'~' => match stack.pop() {
|
||||
Number(x) => stack.push(Number(!x)),
|
||||
_ => fail!("non-number on stack with %~")
|
||||
_ => return Err(~"non-number on stack with %~")
|
||||
},
|
||||
'i' => match (copy params[0], copy params[1]) {
|
||||
(Number(x), Number(y)) => {
|
||||
params[0] = Number(x + 1);
|
||||
params[1] = Number(y + 1);
|
||||
},
|
||||
(_, _) => fail!("first two params not numbers with %i")
|
||||
(_, _) => return Err(~"first two params not numbers with %i")
|
||||
},
|
||||
'?' => state = fail!("if expressions unimplemented"),
|
||||
_ => fail!("unrecognized format option %c", cur)
|
||||
'?' => state = return Err(fmt!("if expressions unimplemented (%?)", cap)),
|
||||
_ => return Err(fmt!("unrecognized format option %c", cur))
|
||||
}
|
||||
},
|
||||
PushParam => {
|
||||
@ -145,7 +159,7 @@ pub fn expand(cap: &[u8], params: &mut [Param], sta: &mut [Param], dyn: &mut [Pa
|
||||
let idx = (cur as u8) - ('a' as u8);
|
||||
dyn[idx] = stack.pop();
|
||||
} else {
|
||||
fail!("bad variable name in %P");
|
||||
return Err(~"bad variable name in %P");
|
||||
}
|
||||
},
|
||||
GetVar => {
|
||||
@ -156,7 +170,7 @@ pub fn expand(cap: &[u8], params: &mut [Param], sta: &mut [Param], dyn: &mut [Pa
|
||||
let idx = (cur as u8) - ('a' as u8);
|
||||
stack.push(copy dyn[idx]);
|
||||
} else {
|
||||
fail!("bad variable name in %g");
|
||||
return Err(~"bad variable name in %g");
|
||||
}
|
||||
},
|
||||
CharConstant => {
|
||||
@ -174,14 +188,14 @@ pub fn expand(cap: &[u8], params: &mut [Param], sta: &mut [Param], dyn: &mut [Pa
|
||||
intstate.push(cur as u8);
|
||||
old_state = Nothing;
|
||||
}
|
||||
_ => fail!("unimplemented state")
|
||||
_ => return Err(~"unimplemented state")
|
||||
}
|
||||
if state == old_state {
|
||||
state = Nothing;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
output
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1,6 +1,4 @@
|
||||
/// ncurses-compatible compiled terminfo format parsing (term(5))
|
||||
///
|
||||
/// does *not* handle obsolete termcap capabilities!
|
||||
|
||||
use core::prelude::*;
|
||||
|
||||
@ -150,6 +148,7 @@ pub static stringnames: &'static[&'static str] = &'static[ "cbt", "_", "cr", "cs
|
||||
"OTG3", "OTG1", "OTG4", "OTGR", "OTGL", "OTGU", "OTGD", "OTGH", "OTGV", "OTGC", "meml", "memu",
|
||||
"box1"];
|
||||
|
||||
/// Parse a compiled terminfo entry, using long capability names if `longnames` is true
|
||||
pub fn parse(file: @Reader, longnames: bool) -> Result<~TermInfo, ~str> {
|
||||
let bnames, snames, nnames;
|
||||
|
||||
|
@ -12,10 +12,10 @@
|
||||
/// Does not support hashed database, only filesystem!
|
||||
|
||||
use core::prelude::*;
|
||||
use core::{os, str, vec};
|
||||
use core::{os, str};
|
||||
use core::os::getenv;
|
||||
use core::io::{file_reader, Reader};
|
||||
use path = core::path::PosixPath;
|
||||
use path = core::path::Path;
|
||||
|
||||
/// Return path to database entry for `term`
|
||||
pub fn get_dbpath_for_term(term: &str) -> Option<~path> {
|
||||
|
@ -10,10 +10,15 @@
|
||||
|
||||
use core::hashmap::HashMap;
|
||||
|
||||
/// A parsed terminfo entry.
|
||||
pub struct TermInfo {
|
||||
/// Names for the terminal
|
||||
names: ~[~str],
|
||||
/// Map of capability name to boolean value
|
||||
bools: HashMap<~str, bool>,
|
||||
/// Map of capability name to numeric value
|
||||
numbers: HashMap<~str, u16>,
|
||||
/// Map of capability name to raw (unexpanded) string
|
||||
strings: HashMap<~str, ~[u8]>
|
||||
}
|
||||
|
||||
|
@ -280,7 +280,7 @@ pub fn need_dir(s: &Path) {
|
||||
fn pretty_message<'a>(msg: &'a str, prefix: &'a str, color: u8, out: @io::Writer) {
|
||||
let term = term::Terminal::new(out);
|
||||
match term {
|
||||
Ok(ref t) if t.color_supported => {
|
||||
Ok(ref t) => {
|
||||
t.fg(color);
|
||||
out.write_str(prefix);
|
||||
t.reset();
|
||||
|
@ -191,7 +191,7 @@ fn diagnosticcolor(lvl: level) -> u8 {
|
||||
}
|
||||
|
||||
fn print_diagnostic(topic: &str, lvl: level, msg: &str) {
|
||||
let term = term::Terminal::new(io::stderr());
|
||||
let t = term::Terminal::new(io::stderr());
|
||||
|
||||
let stderr = io::stderr();
|
||||
|
||||
@ -199,18 +199,18 @@ fn print_diagnostic(topic: &str, lvl: level, msg: &str) {
|
||||
stderr.write_str(fmt!("%s ", topic));
|
||||
}
|
||||
|
||||
match term {
|
||||
Ok(t) => {
|
||||
match t {
|
||||
Ok(term) => {
|
||||
if stderr.get_type() == io::Screen {
|
||||
t.fg(diagnosticcolor(lvl));
|
||||
term.fg(diagnosticcolor(lvl));
|
||||
stderr.write_str(fmt!("%s: ", diagnosticstr(lvl)));
|
||||
t.reset();
|
||||
term.reset();
|
||||
stderr.write_str(fmt!("%s\n", msg));
|
||||
} else {
|
||||
stderr.write_str(fmt!("%s: %s\n", diagnosticstr(lvl), msg));
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
stderr.write_str(fmt!("%s: %s\n", diagnosticstr(lvl), msg));
|
||||
}
|
||||
},
|
||||
_ => stderr.write_str(fmt!("%s: %s\n", diagnosticstr(lvl), msg))
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user