Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
f923b936
R
Rust
项目概览
int
/
Rust
大约 1 年 前同步成功
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
Rust
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
f923b936
编写于
4月 08, 2014
作者:
C
Corey Richardson
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
term: add docs and windows support
Closes #2807
上级
e30198d9
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
440 addition
and
180 deletion
+440
-180
mk/crates.mk
mk/crates.mk
+1
-1
src/libterm/lib.rs
src/libterm/lib.rs
+107
-179
src/libterm/terminfo/mod.rs
src/libterm/terminfo/mod.rs
+186
-0
src/libterm/win.rs
src/libterm/win.rs
+146
-0
未找到文件。
mk/crates.mk
浏览文件 @
f923b936
...
...
@@ -73,7 +73,7 @@ DEPS_arena := std collections
DEPS_graphviz
:=
std
DEPS_glob
:=
std
DEPS_serialize
:=
std collections log
DEPS_term
:=
std collections
DEPS_term
:=
std collections
log
DEPS_semver
:=
std
DEPS_uuid
:=
std serialize rand
DEPS_sync
:=
std
...
...
src/libterm/lib.rs
浏览文件 @
f923b936
...
...
@@ -8,7 +8,32 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Simple ANSI color library
//! Terminal formatting library.
//!
//! This crate provides the `Terminal` trait, which abstracts over an [ANSI
//! Termina][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].
//!
//! ## Example
//!
//! ```rust
//! extern crate term;
//!
//! fn main() {
//! let mut t = term::stdout();
//! t.fg(term::color::GREEN);
//! println!("hello, ");
//! t.fg(term::color::RED);
//! println("world!");
//! t.reset();
//! }
//! ```
//!
//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code
//! [win]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682010%28v=vs.85%29.aspx
//! [ti]: https://en.wikipedia.org/wiki/Terminfo
#![crate_id
=
"term#0.11.0-pre"
]
#![comment
=
"Simple ANSI color library"
]
...
...
@@ -19,22 +44,76 @@
html_favicon_url
=
"http://www.rust-lang.org/favicon.ico"
,
html_root_url
=
"http://static.rust-lang.org/doc/master"
)]
#![feature(macro_rules)]
#![feature(macro_rules
,
phase
)]
#![deny(missing_doc)]
#[phase(syntax,
link)]
extern
crate
log
;
extern
crate
collections
;
use
std
::
io
;
use
std
::
os
;
use
terminfo
::
TermInfo
;
use
terminfo
::
searcher
::
open
;
use
terminfo
::
parser
::
compiled
::{
parse
,
msys_terminfo
};
use
terminfo
::
parm
::{
expand
,
Number
,
Variables
};
pub
use
terminfo
::
TerminfoTerminal
;
#[cfg(windows)]
pub
use
win
::
WinConsole
;
use
std
::
io
::
IoResult
;
pub
mod
terminfo
;
// FIXME (#2807): Windows support.
#[cfg(windows)]
mod
win
;
#[cfg(not(windows))]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub
fn
stdout
()
->
Option
<~
Terminal
<~
Writer
:
Send
>
:
Send
>
{
let
ti
:
Option
<
TerminfoTerminal
<~
Writer
:
Send
>>
=
Terminal
::
new
(
~
std
::
io
::
stdout
()
as
~
Writer
:
Send
);
ti
.map
(|
t
|
~
t
as
~
Terminal
<~
Writer
:
Send
>
:
Send
)
}
#[cfg(windows)]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub
fn
stdout
()
->
Option
<~
Terminal
<~
Writer
:
Send
>
:
Send
>
{
let
ti
:
Option
<
TerminfoTerminal
<~
Writer
:
Send
>>
=
Terminal
::
new
(
~
std
::
io
::
stdout
()
as
~
Writer
:
Send
);
match
ti
{
Some
(
t
)
=>
Some
(
~
t
as
~
Terminal
<~
Writer
:
Send
>
:
Send
),
None
=>
{
let
wc
:
Option
<
WinConsole
<~
Writer
:
Send
>>
=
Terminal
::
new
(
~
std
::
io
::
stdout
()
as
~
Writer
:
Send
);
wc
.map
(|
w
|
~
w
as
~
Terminal
<~
Writer
:
Send
>
:
Send
)
}
}
}
#[cfg(not(windows))]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub
fn
stderr
()
->
Option
<~
Terminal
<~
Writer
:
Send
>
:
Send
>
{
let
ti
:
Option
<
TerminfoTerminal
<~
Writer
:
Send
>>
=
Terminal
::
new
(
~
std
::
io
::
stderr
()
as
~
Writer
:
Send
);
ti
.map
(|
t
|
~
t
as
~
Terminal
<~
Writer
:
Send
>
:
Send
)
}
#[cfg(windows)]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub
fn
stderr
()
->
Option
<~
Terminal
<~
Writer
:
Send
>
:
Send
>
{
let
ti
:
Option
<
TerminfoTerminal
<~
Writer
:
Send
>>
=
Terminal
::
new
(
~
std
::
io
::
stderr
()
as
~
Writer
:
Send
);
match
ti
{
Some
(
t
)
=>
Some
(
~
t
as
~
Terminal
<~
Writer
:
Send
>
:
Send
),
None
=>
{
let
wc
:
Option
<
WinConsole
<~
Writer
:
Send
>>
=
Terminal
::
new
(
~
std
::
io
::
stderr
()
as
~
Writer
:
Send
);
wc
.map
(|
w
|
~
w
as
~
Terminal
<~
Writer
:
Send
>
:
Send
)
}
}
}
/// Terminal color definitions
pub
mod
color
{
...
...
@@ -91,72 +170,13 @@ pub enum Attr {
}
}
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
::
ForegroundColor
(
_
)
=>
"setaf"
,
attr
::
BackgroundColor
(
_
)
=>
"setab"
}
}
/// A Terminal that knows how many colors it supports, with a reference to its
/// parsed TermInfo database record.
pub
struct
Terminal
<
T
>
{
num_colors
:
u16
,
out
:
T
,
ti
:
Box
<
TermInfo
>
,
}
impl
<
T
:
Writer
>
Terminal
<
T
>
{
/// Returns a wrapped output stream (`Terminal<T>`) as a `Result`.
///
/// Returns `Err()` if the TERM environment variable is undefined.
/// TERM should be set to something like `xterm-color` or `screen-256color`.
///
/// Returns `Err()` on failure to open the terminfo database correctly.
/// Also, in the event that the individual terminfo database entry can not
/// be parsed.
pub
fn
new
(
out
:
T
)
->
Result
<
Terminal
<
T
>
,
StrBuf
>
{
let
term
=
match
os
::
getenv
(
"TERM"
)
{
Some
(
t
)
=>
t
,
None
=>
{
return
Err
(
"TERM environment variable undefined"
.to_strbuf
())
}
};
let
mut
file
=
match
open
(
term
)
{
Ok
(
file
)
=>
file
,
Err
(
err
)
=>
{
if
"cygwin"
==
term
{
// msys terminal
return
Ok
(
Terminal
{
out
:
out
,
ti
:
msys_terminfo
(),
num_colors
:
8
});
}
return
Err
(
err
);
}
};
/// A terminal with similar capabilities to an ANSI Terminal
/// (foreground/background colors etc).
pub
trait
Terminal
<
T
:
Writer
>
:
Writer
{
/// Returns `None` whenever the terminal cannot be created for some
/// reason.
fn
new
(
out
:
T
)
->
Option
<
Self
>
;
let
inf
=
try!
(
parse
(
&
mut
file
,
false
));
let
nc
=
if
inf
.strings
.find_equiv
(
&
(
"setaf"
))
.is_some
()
&&
inf
.strings
.find_equiv
(
&
(
"setab"
))
.is_some
()
{
inf
.numbers
.find_equiv
(
&
(
"colors"
))
.map_or
(
0
,
|
&
n
|
n
)
}
else
{
0
};
return
Ok
(
Terminal
{
out
:
out
,
ti
:
inf
,
num_colors
:
nc
});
}
/// Sets the foreground color to the given color.
///
/// If the color is a bright color, but the terminal only supports 8 colors,
...
...
@@ -164,22 +184,8 @@ pub fn new(out: T) -> Result<Terminal<T>, StrBuf> {
///
/// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
/// if there was an I/O error.
pub
fn
fg
(
&
mut
self
,
color
:
color
::
Color
)
->
io
::
IoResult
<
bool
>
{
let
color
=
self
.dim_if_necessary
(
color
);
if
self
.num_colors
>
color
{
let
s
=
expand
(
self
.ti
.strings
.find_equiv
(
&
(
"setaf"
))
.unwrap
()
.as_slice
(),
[
Number
(
color
as
int
)],
&
mut
Variables
::
new
());
if
s
.is_ok
()
{
try!
(
self
.out
.write
(
s
.unwrap
()
.as_slice
()));
return
Ok
(
true
)
}
}
Ok
(
false
)
}
fn
fg
(
&
mut
self
,
color
:
color
::
Color
)
->
IoResult
<
bool
>
;
/// Sets the background color to the given color.
///
/// If the color is a bright color, but the terminal only supports 8 colors,
...
...
@@ -187,104 +193,26 @@ pub fn fg(&mut self, color: color::Color) -> io::IoResult<bool> {
///
/// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
/// if there was an I/O error.
pub
fn
bg
(
&
mut
self
,
color
:
color
::
Color
)
->
io
::
IoResult
<
bool
>
{
let
color
=
self
.dim_if_necessary
(
color
);
if
self
.num_colors
>
color
{
let
s
=
expand
(
self
.ti
.strings
.find_equiv
(
&
(
"setab"
))
.unwrap
()
.as_slice
(),
[
Number
(
color
as
int
)],
&
mut
Variables
::
new
());
if
s
.is_ok
()
{
try!
(
self
.out
.write
(
s
.unwrap
()
.as_slice
()));
return
Ok
(
true
)
}
}
Ok
(
false
)
}
fn
bg
(
&
mut
self
,
color
:
color
::
Color
)
->
IoResult
<
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.
pub
fn
attr
(
&
mut
self
,
attr
:
attr
::
Attr
)
->
io
::
IoResult
<
bool
>
{
match
attr
{
attr
::
ForegroundColor
(
c
)
=>
self
.fg
(
c
),
attr
::
BackgroundColor
(
c
)
=>
self
.bg
(
c
),
_
=>
{
let
cap
=
cap_for_attr
(
attr
);
let
parm
=
self
.ti.strings
.find_equiv
(
&
cap
);
if
parm
.is_some
()
{
let
s
=
expand
(
parm
.unwrap
()
.as_slice
(),
[],
&
mut
Variables
::
new
());
if
s
.is_ok
()
{
try!
(
self
.out
.write
(
s
.unwrap
()
.as_slice
()));
return
Ok
(
true
)
}
}
Ok
(
false
)
}
}
}
/// 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
::
Attr
)
->
IoResult
<
bool
>
;
/// Returns whether the given terminal attribute is supported.
pub
fn
supports_attr
(
&
self
,
attr
:
attr
::
Attr
)
->
bool
{
match
attr
{
attr
::
ForegroundColor
(
_
)
|
attr
::
BackgroundColor
(
_
)
=>
{
self
.num_colors
>
0
}
_
=>
{
let
cap
=
cap_for_attr
(
attr
);
self
.ti.strings
.find_equiv
(
&
cap
)
.is_some
()
}
}
}
fn
supports_attr
(
&
self
,
attr
:
attr
::
Attr
)
->
bool
;
/// Resets all terminal attributes and color to the default.
/// Returns `Ok()`.
pub
fn
reset
(
&
mut
self
)
->
io
::
IoResult
<
()
>
{
let
mut
cap
=
self
.ti.strings
.find_equiv
(
&
(
"sgr0"
));
if
cap
.is_none
()
{
// are there any terminals that have color/attrs and not sgr0?
// Try falling back to sgr, then op
cap
=
self
.ti.strings
.find_equiv
(
&
(
"sgr"
));
if
cap
.is_none
()
{
cap
=
self
.ti.strings
.find_equiv
(
&
(
"op"
));
}
}
let
s
=
cap
.map_or
(
Err
(
"can't find terminfo capability
\
`sgr0`"
.to_strbuf
()),
|
op
|
{
expand
(
op
.as_slice
(),
[],
&
mut
Variables
::
new
())
});
if
s
.is_ok
()
{
return
self
.out
.write
(
s
.unwrap
()
.as_slice
())
}
Ok
(())
}
fn
dim_if_necessary
(
&
self
,
color
:
color
::
Color
)
->
color
::
Color
{
if
color
>=
self
.num_colors
&&
color
>=
8
&&
color
<
16
{
color
-
8
}
else
{
color
}
}
fn
reset
(
&
mut
self
)
->
IoResult
<
()
>
;
/// Returns the contained stream
pub
fn
unwrap
(
self
)
->
T
{
self
.out
}
/// Returns the contained stream
, destroying the `Terminal`
fn
unwrap
(
self
)
->
T
;
/// Gets an immutable reference to the stream inside
pub
fn
get_ref
<
'a
>
(
&
'a
self
)
->
&
'a
T
{
&
self
.out
}
fn
get_ref
<
'a
>
(
&
'a
self
)
->
&
'a
T
;
/// Gets a mutable reference to the stream inside
pub
fn
get_mut
<
'a
>
(
&
'a
mut
self
)
->
&
'a
mut
T
{
&
mut
self
.out
}
}
impl
<
T
:
Writer
>
Writer
for
Terminal
<
T
>
{
fn
write
(
&
mut
self
,
buf
:
&
[
u8
])
->
io
::
IoResult
<
()
>
{
self
.out
.write
(
buf
)
}
fn
flush
(
&
mut
self
)
->
io
::
IoResult
<
()
>
{
self
.out
.flush
()
}
fn
get_mut
<
'a
>
(
&
'a
mut
self
)
->
&
'a
mut
T
;
}
src/libterm/terminfo/mod.rs
浏览文件 @
f923b936
...
...
@@ -11,6 +11,16 @@
//! Terminfo database interface.
use
collections
::
HashMap
;
use
std
::
io
::
IoResult
;
use
std
::
os
;
use
attr
;
use
color
;
use
Terminal
;
use
self
::
searcher
::
open
;
use
self
::
parser
::
compiled
::{
parse
,
msys_terminfo
};
use
self
::
parm
::{
expand
,
Number
,
Variables
};
/// A parsed terminfo database entry.
pub
struct
TermInfo
{
...
...
@@ -32,3 +42,179 @@ pub mod parser {
pub
mod
compiled
;
}
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
::
ForegroundColor
(
_
)
=>
"setaf"
,
attr
::
BackgroundColor
(
_
)
=>
"setab"
}
}
/// A Terminal that knows how many colors it supports, with a reference to its
/// parsed Terminfo database record.
pub
struct
TerminfoTerminal
<
T
>
{
num_colors
:
u16
,
out
:
T
,
ti
:
~
TermInfo
}
impl
<
T
:
Writer
>
Terminal
<
T
>
for
TerminfoTerminal
<
T
>
{
fn
new
(
out
:
T
)
->
Option
<
TerminfoTerminal
<
T
>>
{
let
term
=
match
os
::
getenv
(
"TERM"
)
{
Some
(
t
)
=>
t
,
None
=>
{
debug!
(
"TERM environment variable not defined"
);
return
None
;
}
};
let
entry
=
open
(
term
);
if
entry
.is_err
()
{
if
os
::
getenv
(
"MSYSCON"
)
.map_or
(
false
,
|
s
|
"mintty.exe"
==
s
)
{
// msys terminal
return
Some
(
TerminfoTerminal
{
out
:
out
,
ti
:
msys_terminfo
(),
num_colors
:
8
});
}
debug!
(
"error finding terminfo entry: {}"
,
entry
.unwrap_err
());
return
None
;
}
let
mut
file
=
entry
.unwrap
();
let
ti
=
parse
(
&
mut
file
,
false
);
if
ti
.is_err
()
{
debug!
(
"error parsing terminfo entry: {}"
,
ti
.unwrap_err
());
return
None
;
}
let
inf
=
ti
.unwrap
();
let
nc
=
if
inf
.strings
.find_equiv
(
&
(
"setaf"
))
.is_some
()
&&
inf
.strings
.find_equiv
(
&
(
"setab"
))
.is_some
()
{
inf
.numbers
.find_equiv
(
&
(
"colors"
))
.map_or
(
0
,
|
&
n
|
n
)
}
else
{
0
};
return
Some
(
TerminfoTerminal
{
out
:
out
,
ti
:
inf
,
num_colors
:
nc
});
}
fn
fg
(
&
mut
self
,
color
:
color
::
Color
)
->
IoResult
<
bool
>
{
let
color
=
self
.dim_if_necessary
(
color
);
if
self
.num_colors
>
color
{
let
s
=
expand
(
self
.ti
.strings
.find_equiv
(
&
(
"setaf"
))
.unwrap
()
.as_slice
(),
[
Number
(
color
as
int
)],
&
mut
Variables
::
new
());
if
s
.is_ok
()
{
try!
(
self
.out
.write
(
s
.unwrap
()
.as_slice
()));
return
Ok
(
true
)
}
}
Ok
(
false
)
}
fn
bg
(
&
mut
self
,
color
:
color
::
Color
)
->
IoResult
<
bool
>
{
let
color
=
self
.dim_if_necessary
(
color
);
if
self
.num_colors
>
color
{
let
s
=
expand
(
self
.ti
.strings
.find_equiv
(
&
(
"setab"
))
.unwrap
()
.as_slice
(),
[
Number
(
color
as
int
)],
&
mut
Variables
::
new
());
if
s
.is_ok
()
{
try!
(
self
.out
.write
(
s
.unwrap
()
.as_slice
()));
return
Ok
(
true
)
}
}
Ok
(
false
)
}
fn
attr
(
&
mut
self
,
attr
:
attr
::
Attr
)
->
IoResult
<
bool
>
{
match
attr
{
attr
::
ForegroundColor
(
c
)
=>
self
.fg
(
c
),
attr
::
BackgroundColor
(
c
)
=>
self
.bg
(
c
),
_
=>
{
let
cap
=
cap_for_attr
(
attr
);
let
parm
=
self
.ti.strings
.find_equiv
(
&
cap
);
if
parm
.is_some
()
{
let
s
=
expand
(
parm
.unwrap
()
.as_slice
(),
[],
&
mut
Variables
::
new
());
if
s
.is_ok
()
{
try!
(
self
.out
.write
(
s
.unwrap
()
.as_slice
()));
return
Ok
(
true
)
}
}
Ok
(
false
)
}
}
}
fn
supports_attr
(
&
self
,
attr
:
attr
::
Attr
)
->
bool
{
match
attr
{
attr
::
ForegroundColor
(
_
)
|
attr
::
BackgroundColor
(
_
)
=>
{
self
.num_colors
>
0
}
_
=>
{
let
cap
=
cap_for_attr
(
attr
);
self
.ti.strings
.find_equiv
(
&
cap
)
.is_some
()
}
}
}
fn
reset
(
&
mut
self
)
->
IoResult
<
()
>
{
let
mut
cap
=
self
.ti.strings
.find_equiv
(
&
(
"sgr0"
));
if
cap
.is_none
()
{
// are there any terminals that have color/attrs and not sgr0?
// Try falling back to sgr, then op
cap
=
self
.ti.strings
.find_equiv
(
&
(
"sgr"
));
if
cap
.is_none
()
{
cap
=
self
.ti.strings
.find_equiv
(
&
(
"op"
));
}
}
let
s
=
cap
.map_or
(
Err
(
~
"can't find terminfo capability `sgr0`"
),
|
op
|
{
expand
(
op
.as_slice
(),
[],
&
mut
Variables
::
new
())
});
if
s
.is_ok
()
{
return
self
.out
.write
(
s
.unwrap
()
.as_slice
())
}
Ok
(())
}
fn
unwrap
(
self
)
->
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
}
}
impl
<
T
:
Writer
>
TerminfoTerminal
<
T
>
{
fn
dim_if_necessary
(
&
self
,
color
:
color
::
Color
)
->
color
::
Color
{
if
color
>=
self
.num_colors
&&
color
>=
8
&&
color
<
16
{
color
-
8
}
else
{
color
}
}
}
impl
<
T
:
Writer
>
Writer
for
TerminfoTerminal
<
T
>
{
fn
write
(
&
mut
self
,
buf
:
&
[
u8
])
->
IoResult
<
()
>
{
self
.out
.write
(
buf
)
}
fn
flush
(
&
mut
self
)
->
IoResult
<
()
>
{
self
.out
.flush
()
}
}
src/libterm/win.rs
0 → 100644
浏览文件 @
f923b936
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Windows console handling
// FIXME (#13400): this is only a tiny fraction of the win32 console api
extern
crate
libc
;
use
std
::
io
::
IoResult
;
use
attr
;
use
color
;
use
Terminal
;
pub
struct
WinConsole
<
T
>
{
buf
:
T
,
foreground
:
color
::
Color
,
background
:
color
::
Color
,
}
#[link(name
=
"kernel32"
)]
extern
"system"
{
fn
SetConsoleTextAttribute
(
handle
:
libc
::
HANDLE
,
attr
:
libc
::
WORD
)
->
libc
::
BOOL
;
fn
GetStdHandle
(
which
:
libc
::
DWORD
)
->
libc
::
HANDLE
;
}
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
::
MAGENTA
=>
0x1
|
0x4
,
color
::
CYAN
=>
0x1
|
0x2
,
color
::
WHITE
=>
0x1
|
0x2
|
0x4
,
_
=>
unreachable!
()
};
if
color
>=
8
{
bits
|
0x8
}
else
{
bits
}
}
impl
<
T
:
Writer
>
WinConsole
<
T
>
{
fn
apply
(
&
mut
self
)
{
let
mut
accum
:
libc
::
WORD
=
0
;
accum
|
=
color_to_bits
(
self
.foreground
);
accum
|
=
color_to_bits
(
self
.background
)
<<
4
;
unsafe
{
// Magic -11 means stdout, from
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231%28v=vs.85%29.aspx
//
// You may be wondering, "but what about stderr?", and the answer
// to that is that setting terminal attributes on the stdout
// handle also sets them for stderr, since they go to the same
// terminal! Admittedly, this is fragile, since stderr could be
// redirected to a different console. This is good enough for
// rustc though. See #13400.
let
out
=
GetStdHandle
(
-
11
);
SetConsoleTextAttribute
(
out
,
accum
);
}
}
}
impl
<
T
:
Writer
>
Writer
for
WinConsole
<
T
>
{
fn
write
(
&
mut
self
,
buf
:
&
[
u8
])
->
IoResult
<
()
>
{
self
.buf
.write
(
buf
)
}
fn
flush
(
&
mut
self
)
->
IoResult
<
()
>
{
self
.buf
.flush
()
}
}
impl
<
T
:
Writer
>
Terminal
<
T
>
for
WinConsole
<
T
>
{
fn
new
(
out
:
T
)
->
Option
<
WinConsole
<
T
>>
{
Some
(
WinConsole
{
buf
:
out
,
foreground
:
color
::
WHITE
,
background
:
color
::
BLACK
})
}
fn
fg
(
&
mut
self
,
color
:
color
::
Color
)
->
IoResult
<
bool
>
{
self
.foreground
=
color
;
self
.apply
();
Ok
(
true
)
}
fn
bg
(
&
mut
self
,
color
:
color
::
Color
)
->
IoResult
<
bool
>
{
self
.background
=
color
;
self
.apply
();
Ok
(
true
)
}
fn
attr
(
&
mut
self
,
attr
:
attr
::
Attr
)
->
IoResult
<
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
::
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
)
->
IoResult
<
()
>
{
self
.foreground
=
color
::
WHITE
;
self
.background
=
color
::
BLACK
;
self
.apply
();
Ok
(())
}
fn
unwrap
(
self
)
->
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
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录