Skip to content

Commit 8f0e433

Browse files
committed
Initial version
0 parents  commit 8f0e433

File tree

10 files changed

+832
-0
lines changed

10 files changed

+832
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
target
2+
Cargo.lock

Cargo.toml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[package]
2+
name = "console"
3+
description = "A terminal and console abstraction for Rust"
4+
version = "0.1.0"
5+
keywords = ["cli", "terminal", "colors", "console", "ansi"]
6+
authors = ["Armin Ronacher <[email protected]>"]
7+
license = "MIT"
8+
homepage = "https://github.com/mitsuhiko/console"
9+
documentation = "https://docs.rs/console"
10+
readme = "README.md"
11+
12+
[dependencies]
13+
clicolors-control = "0"
14+
lazy_static = "0.2"
15+
libc = "0"
16+
parking_lot = "0"
17+
regex = "0.2"
18+
unicode-width = "0.1"
19+
20+
[target.'cfg(windows)'.dependencies]
21+
winapi = "0"
22+
kernel32-sys = "0"

LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2017 Armin Ronacher <[email protected]>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
22+

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# indicatif
2+
3+
A rust library for indicating progress in command line applications to users.
4+
5+
This currently primarily provides progress bars and spinners as well as basic
6+
color support, but there are bigger plans for the future of this!
7+
8+
## Examples
9+
10+
<img src="https://github.com/mitsuhiko/indicatif/blob/master/screenshots/yarn.gif?raw=true">
11+
12+
<img src="https://github.com/mitsuhiko/indicatif/blob/master/screenshots/download.gif?raw=true">
13+
14+
<img src="https://github.com/mitsuhiko/indicatif/blob/master/screenshots/multi-progress.gif?raw=true">
15+
16+
<img src="https://github.com/mitsuhiko/indicatif/blob/master/screenshots/single.gif?raw=true">

examples/colors.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
extern crate console;
2+
3+
use console::style;
4+
5+
fn main() {
6+
println!("This is red on black: {:010x}", style(42).red().on_black().bold());
7+
println!("This is reversed: [{}]", style("whatever").reverse());
8+
println!("This is cyan: {}", style("whatever").cyan());
9+
}

src/lib.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//! console is a library for Rust that provides access to various terminal
2+
//! features so you can build nicer looking command line interfaces. It
3+
//! comes with various tools and utilities for working with Terminals and
4+
//! formatting text.
5+
//!
6+
//! Best paired with other libraries in the family:
7+
//!
8+
//! * [indicatif](https://crates.io/crates/indicatif)
9+
//!
10+
//! # Terminal Access
11+
//!
12+
//! The terminal is abstracted through the `console::Term` type. It can
13+
//! either directly provide access to the connected terminal or by buffering
14+
//! up commands. A buffered terminal will however not be completely buffered
15+
//! on windows where cursor movements are currently directly passed through.
16+
//!
17+
//! Example usage:
18+
//!
19+
//! ```
20+
//! # fn test() -> Result<(), Box<std::error::Error>> {
21+
//! use std::thread;
22+
//! use std::time::Duration;
23+
//!
24+
//! use console::Term;
25+
//!
26+
//! let term = Term::stdout();
27+
//! term.write_line("Hello World!")?;
28+
//! thread::sleep(Duration::from_millis(2000));
29+
//! term.clear_line()?;
30+
//! # Ok(()) } fn main() { test().unwrap(); }
31+
//! ```
32+
//!
33+
//! # Colors and Styles
34+
//!
35+
//! `console` uses `clicolors-control` to control colors. It also
36+
//! provides higher level wrappers for styling text and other things
37+
//! that can be displayed with the `style` function and utility types.
38+
//!
39+
//! Example usage:
40+
//!
41+
//! ```
42+
//! use console::style;
43+
//!
44+
//! println!("This is {} neat", style("quite").cyan());
45+
//! ```
46+
//!
47+
//! You can also store styles and apply them to text later:
48+
//!
49+
//! ```
50+
//! use console::Style;
51+
//!
52+
//! let cyan = Style::new().cyan();
53+
//! println!("This is {} neat", cyan.apply_to("quite"));
54+
//! ```
55+
//!
56+
//! # Working with ANSI Codes
57+
//!
58+
//! The crate provids the function `strip_ansi_codes` to remove ANSI codes
59+
//! from a string as well as `measure_text_width` to calculate the width of a
60+
//! string as it would be displayed by the terminal. Both of those together
61+
//! are useful for more complex formatting.
62+
#[cfg(unix)] extern crate libc;
63+
#[cfg(windows)] extern crate winapi;
64+
#[cfg(windows)] extern crate kernel32;
65+
#[macro_use] extern crate lazy_static;
66+
extern crate regex;
67+
extern crate parking_lot;
68+
extern crate unicode_width;
69+
extern crate clicolors_control;
70+
71+
pub use term::{Term, user_attended};
72+
pub use utils::{style, Style, StyledObject, Color, Attribute,
73+
strip_ansi_codes, measure_text_width,
74+
colors_enabled, set_colors_enabled};
75+
76+
mod term;
77+
mod utils;
78+
#[cfg(unix)] mod unix_term;
79+
#[cfg(windows)] mod windows_term;

src/term.rs

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
use std::io;
2+
use std::io::Write;
3+
4+
#[cfg(unix)]
5+
use std::os::unix::io::{AsRawFd, RawFd};
6+
#[cfg(windows)]
7+
use std::os::windows::io::{AsRawHandle, RawHandle};
8+
9+
use parking_lot::Mutex;
10+
11+
enum TermTarget {
12+
Stdout,
13+
Stderr,
14+
}
15+
16+
/// Abstraction around a terminal.
17+
pub struct Term {
18+
target: TermTarget,
19+
buffer: Option<Mutex<Vec<u8>>>,
20+
}
21+
22+
impl Term {
23+
/// Return a new unbuffered terminal
24+
#[inline(always)]
25+
pub fn stdout() -> Term {
26+
Term {
27+
target: TermTarget::Stdout,
28+
buffer: None,
29+
}
30+
}
31+
32+
/// Return a new unbuffered terminal to stderr
33+
#[inline(always)]
34+
pub fn stderr() -> Term {
35+
Term {
36+
target: TermTarget::Stderr,
37+
buffer: None,
38+
}
39+
}
40+
41+
/// Return a new buffered terminal
42+
pub fn buffered_stdout() -> Term {
43+
Term {
44+
target: TermTarget::Stdout,
45+
buffer: Some(Mutex::new(vec![])),
46+
}
47+
}
48+
49+
/// Return a new buffered terminal to stderr
50+
pub fn buffered_stderr() -> Term {
51+
Term {
52+
target: TermTarget::Stderr,
53+
buffer: Some(Mutex::new(vec![])),
54+
}
55+
}
56+
57+
#[doc(hidden)]
58+
pub fn write_str(&self, s: &str) -> io::Result<()> {
59+
match self.buffer {
60+
Some(ref buffer) => buffer.lock().write_all(s.as_bytes()),
61+
None => self.write_through(s.as_bytes())
62+
}
63+
}
64+
65+
/// Writes a string to the terminal and adds a newline.
66+
pub fn write_line(&self, s: &str) -> io::Result<()> {
67+
match self.buffer {
68+
Some(ref mutex) => {
69+
let mut buffer = mutex.lock();
70+
buffer.extend_from_slice(s.as_bytes());
71+
buffer.push(b'\n');
72+
Ok(())
73+
}
74+
None => {
75+
self.write_through(format!("{}\n", s).as_bytes())
76+
}
77+
}
78+
}
79+
80+
/// Flushes
81+
pub fn flush(&self) -> io::Result<()> {
82+
match self.buffer {
83+
Some(ref buffer) => {
84+
let mut buffer = buffer.lock();
85+
if !buffer.is_empty() {
86+
self.write_through(&buffer[..])?;
87+
buffer.clear();
88+
}
89+
}
90+
None => {}
91+
}
92+
Ok(())
93+
}
94+
95+
/// Checks if the terminal is indeed a terminal.
96+
pub fn is_term(&self) -> bool {
97+
is_a_terminal(self)
98+
}
99+
100+
/// Returns the terminal size or gets sensible defaults.
101+
#[inline(always)]
102+
pub fn size(&self) -> (u16, u16) {
103+
self.size_checked().unwrap_or((24, DEFAULT_WIDTH))
104+
}
105+
106+
/// Returns the terminal size in rows and columns.
107+
///
108+
/// If the size cannot be reliably determined None is returned.
109+
#[inline(always)]
110+
pub fn size_checked(&self) -> Option<(u16, u16)> {
111+
terminal_size()
112+
}
113+
114+
/// Moves the cursor up `n` lines
115+
pub fn move_cursor_up(&self, n: usize) -> io::Result<()> {
116+
move_cursor_up(self, n)
117+
}
118+
119+
/// Moves the cursor down `n` lines
120+
pub fn move_cursor_down(&self, n: usize) -> io::Result<()> {
121+
move_cursor_down(self, n)
122+
}
123+
124+
/// Clears the current line.
125+
pub fn clear_line(&self) -> io::Result<()> {
126+
clear_line(self)
127+
}
128+
129+
/// Clear the last `n` lines.
130+
pub fn clear_last_lines(&self, n: usize) -> io::Result<()> {
131+
self.move_cursor_up(n)?;
132+
for _ in 0..n {
133+
self.clear_line()?;
134+
self.move_cursor_down(1)?;
135+
}
136+
self.move_cursor_up(n)?;
137+
Ok(())
138+
}
139+
140+
// helpers
141+
142+
fn write_through(&self, bytes: &[u8]) -> io::Result<()> {
143+
match self.target {
144+
TermTarget::Stdout => {
145+
io::stdout().write_all(bytes)?;
146+
io::stdout().flush()?;
147+
}
148+
TermTarget::Stderr => {
149+
io::stderr().write_all(bytes)?;
150+
io::stderr().flush()?;
151+
}
152+
}
153+
Ok(())
154+
}
155+
}
156+
157+
/// A fast way to check if the application has a user attended.
158+
///
159+
/// This means that stdout is connected to a terminal instead of a
160+
/// file or redirected by other means.
161+
pub fn user_attended() -> bool {
162+
Term::stdout().is_term()
163+
}
164+
165+
#[cfg(unix)]
166+
impl AsRawFd for Term {
167+
168+
fn as_raw_fd(&self) -> RawFd {
169+
use libc;
170+
match self.target {
171+
TermTarget::Stdout => libc::STDOUT_FILENO,
172+
TermTarget::Stderr => libc::STDERR_FILENO,
173+
}
174+
}
175+
}
176+
177+
#[cfg(windows)]
178+
impl AsRawHandle for Term {
179+
180+
fn as_raw_handle(&self) -> RawHandle {
181+
use winapi::{STD_OUTPUT_HANDLE, STD_ERROR_HANDLE};
182+
use kernel32::GetStdHandle;
183+
unsafe {
184+
GetStdHandle(match self.target {
185+
TermTarget::Stdout => STD_OUTPUT_HANDLE,
186+
TermTarget::Stderr => STD_ERROR_HANDLE,
187+
}) as RawHandle
188+
}
189+
}
190+
}
191+
192+
#[cfg(unix)] pub use unix_term::*;
193+
#[cfg(windows)] pub use windows_term::*;

0 commit comments

Comments
 (0)