parent
8ac61db3c1
commit
f068ae69b1
@ -3,7 +3,7 @@
|
||||
//!
|
||||
extern crate crossterm;
|
||||
|
||||
use self::crossterm::style::{Color, style, color};
|
||||
use self::crossterm::style::{color, style, Color};
|
||||
use self::crossterm::{terminal, Screen};
|
||||
|
||||
/// print some red font | demonstration.
|
||||
@ -16,7 +16,10 @@ pub fn paint_foreground() {
|
||||
println!("Colored text: {}", styledobject);
|
||||
|
||||
// Or print inline
|
||||
println!("Colored text: {}", style("Red foreground").with(Color::Blue));
|
||||
println!(
|
||||
"Colored text: {}",
|
||||
style("Red foreground").with(Color::Blue)
|
||||
);
|
||||
}
|
||||
|
||||
/// print some font on red background | demonstration.
|
||||
@ -34,85 +37,185 @@ pub fn paint_background() {
|
||||
|
||||
/// Print all available foreground colors | demonstration.
|
||||
pub fn print_all_foreground_colors() {
|
||||
println!("{}", style(format!("Black : \t\t {} \n", "■")).with(Color::Black));
|
||||
println!("{}", style(format!("Red : \t\t {} \n", "■")).with(Color::Red));
|
||||
println!("{}", style(format!("Cyan : \t\t {} \n", "■")).with(Color::Cyan));
|
||||
println!("{}", style(format!("DarkCyan : \t {} \n", "■")).with(Color::DarkCyan));
|
||||
println!("{}", style(format!("DarkRed : \t {} \n", "■")).with(Color::DarkRed));
|
||||
println!("{}", style(format!("Green : \t {} \n", "■")).with(Color::Green));
|
||||
println!("{}", style(format!("DarkGreen : \t {} \n", "■")).with(Color::DarkGreen));
|
||||
println!("{}", style(format!("Blue : \t\t {} \n", "■")).with(Color::Blue));
|
||||
println!("{}", style(format!("DarkBlue : \t {} \n", "■")).with(Color::DarkBlue));
|
||||
println!("{}", style(format!("Magenta : \t {} \n", "■")).with(Color::Magenta));
|
||||
println!("{}", style(format!("DarkMagenta : \t {} \n", "■")).with(Color::DarkMagenta));
|
||||
println!("{}", style(format!("Yellow : \t {} \n", "■")).with(Color::Yellow));
|
||||
println!("{}", style(format!("DarkYellow : \t {} \n", "■")).with(Color::DarkYellow));
|
||||
println!("{}", style(format!("Grey : \t\t {} \n", "■")).with(Color::Grey));
|
||||
println!("{}", style(format!("White : \t {} \n", "■")).with(Color::White));
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("Black : \t\t {} \n", "■")).with(Color::Black)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("Red : \t\t {} \n", "■")).with(Color::Red)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("Cyan : \t\t {} \n", "■")).with(Color::Cyan)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("DarkCyan : \t {} \n", "■")).with(Color::DarkCyan)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("DarkRed : \t {} \n", "■")).with(Color::DarkRed)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("Green : \t {} \n", "■")).with(Color::Green)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("DarkGreen : \t {} \n", "■")).with(Color::DarkGreen)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("Blue : \t\t {} \n", "■")).with(Color::Blue)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("DarkBlue : \t {} \n", "■")).with(Color::DarkBlue)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("Magenta : \t {} \n", "■")).with(Color::Magenta)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("DarkMagenta : \t {} \n", "■")).with(Color::DarkMagenta)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("Yellow : \t {} \n", "■")).with(Color::Yellow)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("DarkYellow : \t {} \n", "■")).with(Color::DarkYellow)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("Grey : \t\t {} \n", "■")).with(Color::Grey)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("White : \t {} \n", "■")).with(Color::White)
|
||||
);
|
||||
|
||||
#[cfg(unix)]
|
||||
println!("{}", style("RGB color (10,10,10) ").with(Color::Rgb {
|
||||
println!(
|
||||
"{}",
|
||||
style("RGB color (10,10,10) ").with(Color::Rgb {
|
||||
r: 10,
|
||||
g: 10,
|
||||
b: 10
|
||||
}));
|
||||
})
|
||||
);
|
||||
|
||||
#[cfg(unix)]
|
||||
println!("{}",style("RGB color (10,10,10) ")).with(Color::AnsiValue(50));
|
||||
println!("{}", style("RGB color (10,10,10) ")).with(Color::AnsiValue(50));
|
||||
}
|
||||
|
||||
/// Print all available foreground colors | demonstration.
|
||||
pub fn print_all_background_colors() {
|
||||
println!("{}", style(format!("Black : \t {} \n", "■")).on(Color::Black));
|
||||
println!("{}", style(format!("Red : \t\t {} \n", "■")).on(Color::Red));
|
||||
println!("{}", style(format!("Cyan : \t\t {} \n", "■")).on(Color::Cyan));
|
||||
println!("{}", style(format!("DarkCyan : \t {} \n", "■")).on(Color::DarkCyan));
|
||||
println!("{}", style(format!("DarkRed : \t {} \n", "■")).on(Color::DarkRed));
|
||||
println!("{}", style(format!("Green : \t {} \n", "■")).on(Color::Green));
|
||||
println!("{}", style(format!("DarkGreen : \t {} \n", "■")).on(Color::DarkGreen));
|
||||
println!("{}", style(format!("Blue : \t\t {} \n", "■")).on(Color::Blue));
|
||||
println!("{}", style(format!("DarkBlue : \t {} \n", "■")).on(Color::DarkBlue));
|
||||
println!("{}", style(format!("Magenta : \t {} \n", "■")).on(Color::Magenta));
|
||||
println!("{}", style(format!("DarkMagenta : \t {} \n", "■")).on(Color::DarkMagenta));
|
||||
println!("{}", style(format!("Yellow : \t {} \n", "■")).on(Color::Yellow));
|
||||
println!("{}", style(format!("DarkYellow : \t {} \n", "■")).on(Color::DarkYellow));
|
||||
println!("{}", style(format!("Grey : \t\t {} \n", "■")).on(Color::Grey));
|
||||
println!("{}", style(format!("White : \t {} \n", "■")).on(Color::White));
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("Black : \t {} \n", "■")).on(Color::Black)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("Red : \t\t {} \n", "■")).on(Color::Red)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("Cyan : \t\t {} \n", "■")).on(Color::Cyan)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("DarkCyan : \t {} \n", "■")).on(Color::DarkCyan)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("DarkRed : \t {} \n", "■")).on(Color::DarkRed)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("Green : \t {} \n", "■")).on(Color::Green)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("DarkGreen : \t {} \n", "■")).on(Color::DarkGreen)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("Blue : \t\t {} \n", "■")).on(Color::Blue)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("DarkBlue : \t {} \n", "■")).on(Color::DarkBlue)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("Magenta : \t {} \n", "■")).on(Color::Magenta)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("DarkMagenta : \t {} \n", "■")).on(Color::DarkMagenta)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("Yellow : \t {} \n", "■")).on(Color::Yellow)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("DarkYellow : \t {} \n", "■")).on(Color::DarkYellow)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("Grey : \t\t {} \n", "■")).on(Color::Grey)
|
||||
);
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("White : \t {} \n", "■")).on(Color::White)
|
||||
);
|
||||
|
||||
#[cfg(unix)]
|
||||
println!("{}", style("RGB color (10,10,10) ").on(Color::Rgb {
|
||||
println!(
|
||||
"{}",
|
||||
style("RGB color (10,10,10) ").on(Color::Rgb {
|
||||
r: 10,
|
||||
g: 10,
|
||||
b: 10
|
||||
}));
|
||||
})
|
||||
);
|
||||
|
||||
#[cfg(unix)]
|
||||
println!("{}",style("RGB color (10,10,10) ").on(Color::AnsiValue(50)));
|
||||
println!(
|
||||
"{}",
|
||||
style("RGB color (10,10,10) ").on(Color::AnsiValue(50))
|
||||
);
|
||||
}
|
||||
|
||||
/// Print font with all available attributes. Note that this can only be used at unix systems and that some are not supported widely | demonstration..
|
||||
#[cfg(unix)]
|
||||
pub fn print_font_with_attributes() {
|
||||
println!("{}",style("Normal text"));
|
||||
println!("{}",style("Bold text").bold());
|
||||
println!("{}",style("Italic text").italic());
|
||||
println!("{}",style("Slow blinking text").slow_blink());
|
||||
println!("{}",style("Rapid blinking text").rapid_blink());
|
||||
println!("{}",style("Hidden text").hidden());
|
||||
println!("{}",style("Underlined text").underlined());
|
||||
println!("{}",style("Reversed text").reverse());
|
||||
println!("{}",style("Dim text").dim());
|
||||
println!("{}",style("Crossed out font").crossed_out());
|
||||
println!("{}", style("Normal text"));
|
||||
println!("{}", style("Bold text").bold());
|
||||
println!("{}", style("Italic text").italic());
|
||||
println!("{}", style("Slow blinking text").slow_blink());
|
||||
println!("{}", style("Rapid blinking text").rapid_blink());
|
||||
println!("{}", style("Hidden text").hidden());
|
||||
println!("{}", style("Underlined text").underlined());
|
||||
println!("{}", style("Reversed text").reverse());
|
||||
println!("{}", style("Dim text").dim());
|
||||
println!("{}", style("Crossed out font").crossed_out());
|
||||
}
|
||||
|
||||
/// Print all supported RGB colors | demonstration.
|
||||
#[cfg(unix)]
|
||||
pub fn print_supported_colors() {
|
||||
let count = color()
|
||||
.get_available_color_count()
|
||||
.unwrap();
|
||||
let count = color().get_available_color_count().unwrap();
|
||||
|
||||
for i in 0..count {
|
||||
println!("{}", style(format!("White : \t {}", i)).on(Color::AnsiValue(i as u8)));
|
||||
println!(
|
||||
"{}",
|
||||
style(format!("White : \t {}", i)).on(Color::AnsiValue(i as u8))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
//! This bin folder can be used to try the examples out located in the examples directory.
|
||||
//!
|
||||
//! All you need to do is:
|
||||
@ -9,12 +8,10 @@
|
||||
extern crate crossterm;
|
||||
|
||||
// modules that could be test
|
||||
mod terminal;
|
||||
mod color;
|
||||
mod cursor;
|
||||
mod some_types;
|
||||
mod input;
|
||||
mod some_types;
|
||||
mod terminal;
|
||||
|
||||
fn main()
|
||||
{
|
||||
}
|
||||
fn main() {}
|
||||
|
@ -1,12 +1,12 @@
|
||||
extern crate crossterm;
|
||||
|
||||
use self::crossterm::{Crossterm, Screen};
|
||||
use self::crossterm::terminal::ClearType;
|
||||
use self::crossterm::input::input;
|
||||
use self::crossterm::terminal::ClearType;
|
||||
use self::crossterm::{Crossterm, Screen};
|
||||
|
||||
use std::{thread, time};
|
||||
use std::io::{stdout, Read, Write};
|
||||
use std::time::Duration;
|
||||
use std::{thread, time};
|
||||
|
||||
/// this will capture the input until the given key.
|
||||
pub fn read_async_until() {
|
||||
@ -100,8 +100,7 @@ pub fn async_reading_on_alternate_screen() {
|
||||
let screen = Screen::new(false);
|
||||
|
||||
// switch to alternate screen
|
||||
if let Ok(alternate) = screen.enable_alternate_modes(true)
|
||||
{
|
||||
if let Ok(alternate) = screen.enable_alternate_modes(true) {
|
||||
let crossterm = Crossterm::from_screen(&alternate.screen);
|
||||
// init some modules we use for this demo
|
||||
let input = crossterm.input();
|
||||
|
@ -1,12 +1,12 @@
|
||||
extern crate crossterm;
|
||||
|
||||
use crossterm::{Screen, Crossterm};
|
||||
use crossterm::terminal::{from_screen,Terminal, ClearType};
|
||||
use crossterm::cursor::{TerminalCursor, cursor};
|
||||
use crossterm::cursor::{cursor, TerminalCursor};
|
||||
use crossterm::input::input;
|
||||
use std::sync::{Arc,Mutex};
|
||||
use crossterm::terminal::{from_screen, ClearType, Terminal};
|
||||
use crossterm::{Crossterm, Screen};
|
||||
use std::io::Read;
|
||||
use std::{thread,time};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{thread, time};
|
||||
|
||||
fn main() {
|
||||
use crossterm::color;
|
||||
@ -18,7 +18,7 @@ fn main() {
|
||||
|
||||
let mut input_buf = Arc::new(Mutex::new(String::new()));
|
||||
|
||||
let threads = log(input_buf.clone(),&screen);
|
||||
let threads = log(input_buf.clone(), &screen);
|
||||
|
||||
let mut count = 0;
|
||||
|
||||
@ -26,17 +26,14 @@ fn main() {
|
||||
let input = input();
|
||||
let mut stdin = input.read_async().bytes();
|
||||
|
||||
loop
|
||||
{
|
||||
loop {
|
||||
let a = stdin.next();
|
||||
|
||||
match a {
|
||||
Some(Ok(13)) =>
|
||||
{
|
||||
Some(Ok(13)) => {
|
||||
input_buf.lock().unwrap().clear();
|
||||
}
|
||||
Some(Ok(val)) =>
|
||||
{
|
||||
Some(Ok(val)) => {
|
||||
input_buf.lock().unwrap().push(val as char);
|
||||
}
|
||||
_ => {}
|
||||
@ -47,35 +44,36 @@ fn main() {
|
||||
}
|
||||
}).join();
|
||||
|
||||
|
||||
for thread in threads
|
||||
{
|
||||
for thread in threads {
|
||||
thread.join();
|
||||
}
|
||||
|
||||
cursor.show();
|
||||
}
|
||||
|
||||
fn log(input_buf: Arc<Mutex<String>>, screen: &Screen) -> Vec<thread::JoinHandle<()>>
|
||||
{
|
||||
fn log(input_buf: Arc<Mutex<String>>, screen: &Screen) -> Vec<thread::JoinHandle<()>> {
|
||||
let mut threads = Vec::with_capacity(10);
|
||||
|
||||
let (_, term_height) = from_screen(screen).terminal_size();
|
||||
|
||||
for i in 0..1
|
||||
{
|
||||
for i in 0..1 {
|
||||
let input_buffer = input_buf.clone();
|
||||
let clone_stdout = screen.stdout.clone();
|
||||
|
||||
let crossterm = Crossterm::from(screen.stdout.clone());
|
||||
|
||||
let join = thread::spawn( move || {
|
||||
let join = thread::spawn(move || {
|
||||
let cursor = crossterm.cursor();
|
||||
let terminal = crossterm.terminal();
|
||||
|
||||
for j in 0..1000
|
||||
{
|
||||
swap_write(format!("Some output: {} from thread: {}", j, i).as_ref(), &input_buffer.lock().unwrap(), &terminal, &cursor, term_height);
|
||||
for j in 0..1000 {
|
||||
swap_write(
|
||||
format!("Some output: {} from thread: {}", j, i).as_ref(),
|
||||
&input_buffer.lock().unwrap(),
|
||||
&terminal,
|
||||
&cursor,
|
||||
term_height,
|
||||
);
|
||||
thread::sleep(time::Duration::from_millis(300));
|
||||
}
|
||||
});
|
||||
@ -86,7 +84,13 @@ fn log(input_buf: Arc<Mutex<String>>, screen: &Screen) -> Vec<thread::JoinHandle
|
||||
return threads;
|
||||
}
|
||||
|
||||
pub fn swap_write(msg: &str, input_buf: &String, terminal: &Terminal, cursor: &TerminalCursor, term_height: u16) {
|
||||
pub fn swap_write(
|
||||
msg: &str,
|
||||
input_buf: &String,
|
||||
terminal: &Terminal,
|
||||
cursor: &TerminalCursor,
|
||||
term_height: u16,
|
||||
) {
|
||||
cursor.goto(0, term_height);
|
||||
terminal.clear(ClearType::CurrentLine);
|
||||
terminal.write(format!("{}\r\n", msg));
|
||||
|
@ -1,12 +1,12 @@
|
||||
extern crate crossterm;
|
||||
|
||||
use crossterm::Screen;
|
||||
use std::sync::Mutex;
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::Arc;
|
||||
use std::io::Write;
|
||||
use std::sync::mpsc::{self, Receiver, Sender};
|
||||
use std::thread::{JoinHandle, self};
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use std::thread::{self, JoinHandle};
|
||||
|
||||
/// This is an que that could be shared between threads safely.
|
||||
#[derive(Clone)]
|
||||
@ -16,7 +16,9 @@ struct WorkQueue<T: Send + Clone> {
|
||||
|
||||
impl<T: Send + Clone> WorkQueue<T> {
|
||||
fn new() -> Self {
|
||||
Self { inner: Arc::new(Mutex::new(VecDeque::new())) }
|
||||
Self {
|
||||
inner: Arc::new(Mutex::new(VecDeque::new())),
|
||||
}
|
||||
}
|
||||
|
||||
// get an item from the que if exists
|
||||
@ -74,14 +76,17 @@ impl SyncFlagRx {
|
||||
|
||||
fn new_sync_flag(initial_state: bool) -> (SyncFlagTx, SyncFlagRx) {
|
||||
let state = Arc::new(Mutex::new(initial_state));
|
||||
let tx = SyncFlagTx { inner: state.clone() };
|
||||
let rx = SyncFlagRx { inner: state.clone() };
|
||||
let tx = SyncFlagTx {
|
||||
inner: state.clone(),
|
||||
};
|
||||
let rx = SyncFlagRx {
|
||||
inner: state.clone(),
|
||||
};
|
||||
|
||||
return (tx, rx);
|
||||
}
|
||||
|
||||
fn main()
|
||||
{
|
||||
fn main() {
|
||||
let (_results_tx, _results_rx): (Sender<String>, Receiver<String>) = mpsc::channel();
|
||||
let (mut more_jobs_tx, more_jobs_rx) = new_sync_flag(true);
|
||||
|
||||
@ -94,15 +99,14 @@ fn main()
|
||||
// a thread that will log all logs in the queue.
|
||||
handle_incoming_logs(more_jobs_rx.clone(), queue.clone());
|
||||
|
||||
// for handle in thread_handles
|
||||
// {
|
||||
// handle.join();
|
||||
// }
|
||||
// for handle in thread_handles
|
||||
// {
|
||||
// handle.join();
|
||||
// }
|
||||
}
|
||||
|
||||
fn handle_incoming_logs(more_jobs_rx: SyncFlagRx, queue: WorkQueue<String>)
|
||||
{
|
||||
thread::spawn( move || {
|
||||
fn handle_incoming_logs(more_jobs_rx: SyncFlagRx, queue: WorkQueue<String>) {
|
||||
thread::spawn(move || {
|
||||
let mut screen: Screen = Screen::default();
|
||||
|
||||
// Loop while there's expected to be work, looking for work.
|
||||
@ -121,23 +125,25 @@ fn handle_incoming_logs(more_jobs_rx: SyncFlagRx, queue: WorkQueue<String>)
|
||||
}
|
||||
|
||||
// start different threads that log contiguously.
|
||||
fn log_with_different_threads(more_jobs_tx: SyncFlagTx, queue: WorkQueue<String>) -> Vec<JoinHandle<()>>
|
||||
{
|
||||
fn log_with_different_threads(
|
||||
more_jobs_tx: SyncFlagTx,
|
||||
queue: WorkQueue<String>,
|
||||
) -> Vec<JoinHandle<()>> {
|
||||
// one vector that will have the thread handles in it.
|
||||
let mut threads = Vec::new();
|
||||
|
||||
for thread_num in 1..5
|
||||
{
|
||||
for thread_num in 1..5 {
|
||||
let mut more_jobs = more_jobs_tx.clone();
|
||||
let thread_queue = queue.clone();
|
||||
|
||||
// create new thread
|
||||
let thread = thread::spawn(move || {
|
||||
|
||||
// log 400 messages
|
||||
for log_entry_count in 1..400
|
||||
{
|
||||
thread_queue.add_work(format!("Log {} from thread {} ",log_entry_count, thread_num));
|
||||
for log_entry_count in 1..400 {
|
||||
thread_queue.add_work(format!(
|
||||
"Log {} from thread {} ",
|
||||
log_entry_count, thread_num
|
||||
));
|
||||
more_jobs.set(true);
|
||||
}
|
||||
});
|
||||
|
@ -1,11 +1,10 @@
|
||||
extern crate crossterm;
|
||||
|
||||
use crossterm::{Crossterm, Screen};
|
||||
use crossterm::style::Color;
|
||||
use crossterm::{Crossterm, Screen};
|
||||
|
||||
/// use the `Crossterm` to get an instance to the cursor module | demonstration.
|
||||
pub fn crossterm()
|
||||
{
|
||||
pub fn crossterm() {
|
||||
// Create the crossterm type to access different modules.
|
||||
let crossterm = Crossterm::new();
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
extern crate crossterm;
|
||||
|
||||
use crossterm::style::{Color, style};
|
||||
use crossterm::style::{style, Color};
|
||||
use crossterm::terminal::{self, ClearType};
|
||||
use crossterm::{Crossterm, Screen};
|
||||
|
||||
@ -26,7 +26,10 @@ fn print_wait_screen(screen: &Screen) {
|
||||
for i in 1..5 {
|
||||
// print the current counter at the line of `Seconds to Go: {counter}`
|
||||
cursor.goto(10, 2);
|
||||
style(format!("{} of the 5 items processed", i)).with(Color::Red).on(Color::Blue).paint(&screen);
|
||||
style(format!("{} of the 5 items processed", i))
|
||||
.with(Color::Red)
|
||||
.on(Color::Blue)
|
||||
.paint(&screen);
|
||||
|
||||
// 1 second delay
|
||||
thread::sleep(time::Duration::from_secs(1));
|
||||
@ -35,11 +38,9 @@ fn print_wait_screen(screen: &Screen) {
|
||||
|
||||
/// print wait screen on alternate screen, then switch back.
|
||||
pub fn print_wait_screen_on_alternate_window() {
|
||||
|
||||
let screen = Screen::default();
|
||||
|
||||
if let Ok(alternate) = screen.enable_alternate_modes(false)
|
||||
{
|
||||
if let Ok(alternate) = screen.enable_alternate_modes(false) {
|
||||
print_wait_screen(&alternate.screen);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
extern crate crossterm;
|
||||
|
||||
use crossterm::{Crossterm, Screen};
|
||||
use crossterm::terminal::{self, ClearType};
|
||||
use crossterm::style::{style, Color};
|
||||
use crossterm::terminal::{self, ClearType};
|
||||
use crossterm::{Crossterm, Screen};
|
||||
|
||||
use std::io::{stdout, Write};
|
||||
use std::{thread, time};
|
||||
@ -27,7 +27,10 @@ fn print_wait_screen(screen: &mut Screen) {
|
||||
for i in 1..5 {
|
||||
// print the current counter at the line of `Seconds to Go: {counter}`
|
||||
cursor.goto(10, 2);
|
||||
style(format!("{} of the 5 items processed", i)).with(Color::Red).on(Color::Blue).paint(&screen);
|
||||
style(format!("{} of the 5 items processed", i))
|
||||
.with(Color::Red)
|
||||
.on(Color::Blue)
|
||||
.paint(&screen);
|
||||
screen.stdout.flush();
|
||||
|
||||
// 1 second delay
|
||||
@ -38,8 +41,7 @@ fn print_wait_screen(screen: &mut Screen) {
|
||||
pub fn print_wait_screen_on_alternate_window() {
|
||||
let screen = Screen::default();
|
||||
|
||||
if let Ok(ref mut alternate) = screen.enable_alternate_modes(true)
|
||||
{
|
||||
if let Ok(ref mut alternate) = screen.enable_alternate_modes(true) {
|
||||
print_wait_screen(&mut alternate.screen);
|
||||
}
|
||||
drop(screen);
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
extern crate crossterm;
|
||||
|
||||
use crossterm::terminal::{ClearType, terminal};
|
||||
use crossterm::cursor;
|
||||
use crossterm::terminal::{terminal, ClearType};
|
||||
fn print_test_data() {
|
||||
for i in 0..100 {
|
||||
println!("Test data to test terminal: {}", i);
|
||||
@ -87,7 +87,6 @@ pub fn print_terminal_size() {
|
||||
|
||||
/// Set the terminal size to width 10, height: 10 | demonstration.
|
||||
pub fn set_terminal_size() {
|
||||
|
||||
let mut terminal = terminal();
|
||||
|
||||
terminal.set_size(10, 10);
|
||||
@ -95,7 +94,6 @@ pub fn set_terminal_size() {
|
||||
|
||||
/// Scroll down 10 lines | demonstration.
|
||||
pub fn scroll_down() {
|
||||
|
||||
let mut terminal = terminal();
|
||||
|
||||
print_test_data();
|
||||
@ -106,7 +104,6 @@ pub fn scroll_down() {
|
||||
|
||||
/// Scroll down 10 lines | demonstration.
|
||||
pub fn scroll_up() {
|
||||
|
||||
let mut terminal = terminal();
|
||||
|
||||
print_test_data();
|
||||
@ -117,7 +114,6 @@ pub fn scroll_up() {
|
||||
|
||||
/// Resize the terminal to X: 10, Y: 10 | demonstration.
|
||||
pub fn resize_terminal() {
|
||||
|
||||
let mut terminal = terminal();
|
||||
|
||||
// Get terminal size
|
||||
@ -126,7 +122,6 @@ pub fn resize_terminal() {
|
||||
|
||||
/// exit the current proccess.
|
||||
pub fn exit() {
|
||||
|
||||
let mut terminal = terminal();
|
||||
terminal.exit();
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ pub trait IAlternateScreenCommand: Sync + Send {
|
||||
}
|
||||
|
||||
// This trait provides an interface for switching to raw mode and back.
|
||||
pub trait IRawScreenCommand: Sync + Send{
|
||||
pub trait IRawScreenCommand: Sync + Send {
|
||||
fn enable(&mut self) -> io::Result<()>;
|
||||
fn disable(&self) -> io::Result<()>;
|
||||
}
|
||||
|
@ -2,28 +2,27 @@
|
||||
|
||||
use super::{IAlternateScreenCommand, TerminalOutput};
|
||||
|
||||
use std::io::{ Result};
|
||||
use std::io::Result;
|
||||
|
||||
/// This command is used for switching to alternate screen and back to main screen.
|
||||
pub struct ToAlternateScreenCommand;
|
||||
|
||||
impl ToAlternateScreenCommand {
|
||||
pub fn new() -> ToAlternateScreenCommand {
|
||||
return ToAlternateScreenCommand;
|
||||
ToAlternateScreenCommand
|
||||
}
|
||||
}
|
||||
|
||||
impl IAlternateScreenCommand for ToAlternateScreenCommand {
|
||||
|
||||
/// enable alternate screen.
|
||||
fn enable(&self, stdout: &mut TerminalOutput) -> Result<()> {
|
||||
stdout.write_str(csi!("?1049h"));
|
||||
stdout.write_str(csi!("?1049h"))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// disable alternate screen.
|
||||
fn disable(&self, stdout: &TerminalOutput) -> Result<()> {
|
||||
stdout.write_str(csi!("?1049l"));
|
||||
stdout.write_str(csi!("?1049l"))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,67 +1,7 @@
|
||||
//! This module contains the commands that can be used for unix systems.
|
||||
|
||||
use super::{ IStateCommand};
|
||||
use kernel::unix_kernel::terminal;
|
||||
use termios::{tcsetattr, Termios, CREAD, ECHO, ICANON, TCSAFLUSH, BRKINT, ICRNL, INPCK, ISTRIP, IXON, OPOST, CS8, IEXTEN, ISIG,VTIME, VMIN};
|
||||
use libc::STDIN_FILENO;
|
||||
use std::sync::{Once, ONCE_INIT};
|
||||
static TERMINAL_MODE: Once = ONCE_INIT;
|
||||
|
||||
|
||||
use std::io::{Error, ErrorKind, Result};
|
||||
|
||||
/// This command is used for switching to NoncanonicalMode.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct NoncanonicalModeCommand;
|
||||
|
||||
impl NoncanonicalModeCommand {
|
||||
pub fn new() -> NoncanonicalModeCommand {
|
||||
NoncanonicalModeCommand {}
|
||||
}
|
||||
}
|
||||
static mut ORIGINAL: Option<Termios> = None;
|
||||
|
||||
impl NoncanonicalModeCommand {
|
||||
pub fn enable(&mut self) -> Result<()> {
|
||||
// Set noncanonical mode
|
||||
if let Ok(orig) = Termios::from_fd(STDIN_FILENO) {
|
||||
TERMINAL_MODE.call_once(|| {
|
||||
unsafe { ORIGINAL = Some(orig.clone()); }
|
||||
});
|
||||
|
||||
let mut noncan = orig.clone();
|
||||
noncan.c_iflag &= !(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
||||
noncan.c_oflag &= !(OPOST);
|
||||
noncan.c_cflag |= (CS8);
|
||||
noncan.c_lflag &= !(ECHO | ICANON | IEXTEN | ISIG);
|
||||
noncan.c_cc[VMIN] = 0;
|
||||
noncan.c_cc[VTIME] = 1;
|
||||
|
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &noncan)?;
|
||||
} else {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
"Could not set console mode when enabling raw mode",
|
||||
));
|
||||
}
|
||||
|
||||
unsafe { terminal::RAW_MODE_ENABLED_BY_USER = true }
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn disable(&self) -> Result<()> {
|
||||
|
||||
unsafe {
|
||||
if let Some(original) = ORIGINAL
|
||||
{
|
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &original)?;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { terminal::RAW_MODE_ENABLED_BY_USER = false }
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
use std::io::Result;
|
||||
|
||||
// This command is used for enabling and disabling raw mode for the terminal.
|
||||
/// This command is used for enabling and disabling raw mode for the terminal.
|
||||
@ -69,12 +9,12 @@ pub struct RawModeCommand;
|
||||
|
||||
impl RawModeCommand {
|
||||
pub fn new() -> Self {
|
||||
return RawModeCommand {}
|
||||
RawModeCommand
|
||||
}
|
||||
|
||||
/// Enables raw mode.
|
||||
pub fn enable(&mut self) -> Result<()> {
|
||||
terminal::into_raw_mode();
|
||||
terminal::into_raw_mode()?;
|
||||
|
||||
unsafe { terminal::RAW_MODE_ENABLED_BY_USER = true }
|
||||
Ok(())
|
||||
@ -82,10 +22,9 @@ impl RawModeCommand {
|
||||
|
||||
/// Disables raw mode.
|
||||
pub fn disable(&mut self) -> Result<()> {
|
||||
terminal::disable_raw_mode();
|
||||
terminal::disable_raw_mode()?;
|
||||
|
||||
unsafe { terminal::RAW_MODE_ENABLED_BY_USER = false }
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,13 +3,13 @@
|
||||
use super::{IAlternateScreenCommand, IEnableAnsiCommand, TerminalOutput};
|
||||
|
||||
use kernel::windows_kernel::{ansi_support, csbi, handle, kernel};
|
||||
use winapi::um::wincon;
|
||||
use winapi::shared::minwindef::DWORD;
|
||||
use winapi::um::wincon::{ENABLE_VIRTUAL_TERMINAL_PROCESSING};
|
||||
use winapi::um::wincon;
|
||||
use winapi::um::wincon::ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
|
||||
use winapi::um::winnt::HANDLE;
|
||||
use std::io::{Error, ErrorKind, Result};
|
||||
use std::sync::Arc;
|
||||
use winapi::um::winnt::HANDLE;
|
||||
|
||||
/// This command is used for enabling and disabling ANSI code support for windows systems,
|
||||
/// For more info check: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences.
|
||||
@ -74,12 +74,11 @@ impl IEnableAnsiCommand for EnableAnsiCommand {
|
||||
pub struct RawModeCommand {
|
||||
mask: DWORD,
|
||||
}
|
||||
use self::wincon::{ ENABLE_LINE_INPUT, ENABLE_WRAP_AT_EOL_OUTPUT};
|
||||
impl RawModeCommand
|
||||
{
|
||||
use self::wincon::{ENABLE_LINE_INPUT, ENABLE_WRAP_AT_EOL_OUTPUT};
|
||||
impl RawModeCommand {
|
||||
pub fn new() -> Self {
|
||||
RawModeCommand {
|
||||
mask: ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_LINE_INPUT
|
||||
mask: ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_LINE_INPUT,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -146,7 +145,6 @@ impl ToAlternateScreenCommand {
|
||||
|
||||
impl IAlternateScreenCommand for ToAlternateScreenCommand {
|
||||
fn enable(&self, stdout: &mut TerminalOutput) -> Result<()> {
|
||||
|
||||
let handle = handle::get_output_handle()?;
|
||||
|
||||
// create a new screen buffer to copy to.
|
||||
|
@ -36,7 +36,7 @@ use std::sync::Arc;
|
||||
/// }
|
||||
/// ```
|
||||
pub struct Crossterm {
|
||||
stdout: Option<Arc<TerminalOutput>>
|
||||
stdout: Option<Arc<TerminalOutput>>,
|
||||
}
|
||||
|
||||
impl<'crossterm> Crossterm {
|
||||
@ -47,7 +47,9 @@ impl<'crossterm> Crossterm {
|
||||
|
||||
/// Create a new instance of `Crossterm`
|
||||
pub fn from_screen(screen: &Screen) -> Crossterm {
|
||||
Crossterm { stdout: Some(screen.stdout.clone()) }
|
||||
Crossterm {
|
||||
stdout: Some(screen.stdout.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an `TerminalCursor` implementation whereon cursor related actions can be performed.
|
||||
@ -61,8 +63,8 @@ impl<'crossterm> Crossterm {
|
||||
/// ```
|
||||
pub fn cursor(&self) -> cursor::TerminalCursor {
|
||||
match &self.stdout {
|
||||
None => { cursor::TerminalCursor::new()},
|
||||
Some(stdout) => { cursor::TerminalCursor::on_screen(&stdout) },
|
||||
None => cursor::TerminalCursor::new(),
|
||||
Some(stdout) => cursor::TerminalCursor::on_screen(&stdout),
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,21 +137,24 @@ impl<'crossterm> Crossterm {
|
||||
/// ```
|
||||
pub fn style<D>(&self, val: D) -> style::StyledObject<D>
|
||||
where
|
||||
D: Display, {
|
||||
D: Display,
|
||||
{
|
||||
style::ObjectStyle::new().apply_to(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Arc<TerminalOutput>> for Crossterm
|
||||
{
|
||||
impl From<Arc<TerminalOutput>> for Crossterm {
|
||||
fn from(stdout: Arc<TerminalOutput>) -> Self {
|
||||
Crossterm { stdout: Some(stdout) }
|
||||
Crossterm {
|
||||
stdout: Some(stdout),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Screen> for Crossterm
|
||||
{
|
||||
impl From<Screen> for Crossterm {
|
||||
fn from(screen: Screen) -> Self {
|
||||
Crossterm { stdout: Some(screen.stdout.clone()) }
|
||||
Crossterm {
|
||||
stdout: Some(screen.stdout.clone()),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +1,14 @@
|
||||
//! Some actions need to preformed platform independently since they can not be solved `ANSI escape codes`.
|
||||
|
||||
use super::TerminalOutput;
|
||||
use std::sync::Arc;
|
||||
use std::io::{self, Write};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(windows)]
|
||||
use kernel::windows_kernel::ansi_support::{try_enable_ansi_support, windows_supportable};
|
||||
|
||||
#[cfg(windows)]
|
||||
use kernel::windows_kernel::terminal::{ exit, terminal_size};
|
||||
use kernel::windows_kernel::terminal::{exit, terminal_size};
|
||||
|
||||
#[cfg(windows)]
|
||||
use kernel::windows_kernel::cursor::pos;
|
||||
@ -18,14 +18,13 @@ use kernel::unix_kernel::terminal::{exit, pos, terminal_size};
|
||||
|
||||
/// Get the terminal size based on the current platform.
|
||||
pub fn get_terminal_size() -> (u16, u16) {
|
||||
return terminal_size();
|
||||
terminal_size()
|
||||
}
|
||||
|
||||
/// Get the cursor position based on the current platform.
|
||||
pub fn get_cursor_position() -> (u16, u16) {
|
||||
#[cfg(unix)]
|
||||
return pos().expect("Valide position");
|
||||
// return pos().unwrap_or_else(|x| { return (0,0) });
|
||||
#[cfg(windows)]
|
||||
return pos();
|
||||
}
|
||||
@ -43,13 +42,12 @@ pub fn get_module<T>(winapi_impl: T, unix_impl: T) -> Option<T> {
|
||||
let mut term: Option<T> = None;
|
||||
let mut does_support = true;
|
||||
|
||||
if !windows_supportable()
|
||||
{
|
||||
if !windows_supportable() {
|
||||
// Try to enable ansi on windows if not than use WINAPI.
|
||||
does_support = try_enable_ansi_support();
|
||||
|
||||
// uncomment this line when you want to use the winapi implementation.
|
||||
// does_support = false;
|
||||
// does_support = false;
|
||||
if !does_support {
|
||||
term = Some(winapi_impl);
|
||||
}
|
||||
@ -62,16 +60,26 @@ pub fn get_module<T>(winapi_impl: T, unix_impl: T) -> Option<T> {
|
||||
term
|
||||
}
|
||||
|
||||
pub fn write(stdout: &Option<&Arc<TerminalOutput>>, string: String) {
|
||||
pub fn write(stdout: &Option<&Arc<TerminalOutput>>, string: String) -> io::Result<usize> {
|
||||
match stdout {
|
||||
None => { print!("{}", string.as_str()); io::stdout().flush(); },
|
||||
Some(output) => { output.write_string(string); },
|
||||
None => {
|
||||
print!("{}", string.as_str());
|
||||
|
||||
match io::stdout().flush() {
|
||||
Ok(_) => Ok(string.len()),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
Some(output) => output.write_string(string),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_str(stdout: &Option<&Arc<TerminalOutput>>, string: &str) {
|
||||
pub fn write_str(stdout: &Option<&Arc<TerminalOutput>>, string: &str) -> io::Result<usize> {
|
||||
match stdout {
|
||||
None => { print!("{}", string); io::stdout().flush(); },
|
||||
Some(output) => { output.write_str(string); },
|
||||
None => match io::stdout().flush() {
|
||||
Ok(_) => Ok(string.len()),
|
||||
Err(e) => Err(e),
|
||||
},
|
||||
Some(output) => output.write_str(string),
|
||||
}
|
||||
}
|
||||
|
@ -10,4 +10,4 @@ pub mod traits;
|
||||
mod crossterm;
|
||||
|
||||
pub use self::crossterm::Crossterm;
|
||||
use {Screen, TerminalOutput};
|
||||
use TerminalOutput;
|
||||
|
@ -6,27 +6,24 @@
|
||||
//! Vim uses the entirety of the screen to edit the file, then returning to bash leaves the original buffer unchanged.
|
||||
|
||||
use super::commands::{self, IAlternateScreenCommand};
|
||||
use super::{functions, Screen, TerminalOutput,RawScreen};
|
||||
use super::{RawScreen, Screen, TerminalOutput};
|
||||
|
||||
use std::io;
|
||||
use std::convert::From;
|
||||
use std::io;
|
||||
|
||||
/// With this type you will be able to switch to alternate screen and back to main screen.
|
||||
/// Check also the Screen type for swishing to alternate mode.
|
||||
///
|
||||
/// Although this type is available for you to use I would recommend using `Screen` instead.
|
||||
pub struct AlternateScreen
|
||||
{
|
||||
pub struct AlternateScreen {
|
||||
command: Box<IAlternateScreenCommand + Sync + Send>,
|
||||
pub screen: Screen,
|
||||
}
|
||||
|
||||
impl AlternateScreen {
|
||||
|
||||
/// Create new instance of alternate screen.
|
||||
pub fn new(command: Box<IAlternateScreenCommand + Sync + Send>, screen: Screen) -> Self
|
||||
{
|
||||
return AlternateScreen { command, screen }
|
||||
pub fn new(command: Box<IAlternateScreenCommand + Sync + Send>, screen: Screen) -> Self {
|
||||
AlternateScreen { command, screen }
|
||||
}
|
||||
|
||||
/// Switch to alternate screen. This function will return an `AlternateScreen` instance if everything went well this type will give you control over the `AlternateScreen`.
|
||||
@ -38,10 +35,13 @@ impl AlternateScreen {
|
||||
/// The alternate buffer is exactly the dimensions of the window, without any scrollback region.
|
||||
/// For an example of this behavior, consider when vim is launched from bash.
|
||||
/// Vim uses the entirety of the screen to edit the file, then returning to bash leaves the original buffer unchanged.
|
||||
pub fn to_alternate_screen(stdout: TerminalOutput, raw_mode: bool) -> io::Result<AlternateScreen> {
|
||||
|
||||
pub fn to_alternate_screen(
|
||||
stdout: TerminalOutput,
|
||||
raw_mode: bool,
|
||||
) -> io::Result<AlternateScreen> {
|
||||
#[cfg(target_os = "windows")]
|
||||
let command = functions::get_module::<Box<commands::IAlternateScreenCommand + Sync + Send>>(
|
||||
let command =
|
||||
functions::get_module::<Box<commands::IAlternateScreenCommand + Sync + Send>>(
|
||||
Box::from(commands::win_commands::ToAlternateScreenCommand::new()),
|
||||
Box::from(commands::shared_commands::ToAlternateScreenCommand::new()),
|
||||
).unwrap();
|
||||
@ -54,12 +54,11 @@ impl AlternateScreen {
|
||||
|
||||
let screen = Screen::from(stdout);
|
||||
|
||||
if raw_mode
|
||||
{
|
||||
RawScreen::into_raw_mode();
|
||||
if raw_mode {
|
||||
RawScreen::into_raw_mode()?;
|
||||
}
|
||||
|
||||
return Ok(AlternateScreen::new(command, screen));
|
||||
Ok(AlternateScreen::new(command, screen))
|
||||
}
|
||||
|
||||
/// Switch the alternate screen back to main screen.
|
||||
@ -69,8 +68,7 @@ impl AlternateScreen {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AlternateScreen
|
||||
{
|
||||
impl Drop for AlternateScreen {
|
||||
/// This will switch back to main screen on drop.
|
||||
fn drop(&mut self) {
|
||||
self.to_main_screen();
|
||||
|
@ -5,8 +5,8 @@ mod alternate;
|
||||
mod raw;
|
||||
mod screen;
|
||||
|
||||
use super::{commands, functions, TerminalOutput};
|
||||
use super::{commands, TerminalOutput};
|
||||
|
||||
pub use self::raw::RawScreen;
|
||||
pub use self::alternate::AlternateScreen;
|
||||
pub use self::raw::RawScreen;
|
||||
pub use self::screen::Screen;
|
||||
|
@ -15,10 +15,8 @@
|
||||
//! With these modes you can easier design the terminal screen.
|
||||
|
||||
use super::commands::*;
|
||||
use TerminalOutput;
|
||||
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// A wrapper for the raw terminal state. Which can be used to write to.
|
||||
///
|
||||
@ -28,8 +26,7 @@ pub struct RawScreen;
|
||||
|
||||
impl RawScreen {
|
||||
/// Put terminal in raw mode.
|
||||
pub fn into_raw_mode() -> io::Result<()>
|
||||
{
|
||||
pub fn into_raw_mode() -> io::Result<()> {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let mut command = unix_command::RawModeCommand::new();
|
||||
#[cfg(target_os = "windows")]
|
||||
@ -41,14 +38,13 @@ impl RawScreen {
|
||||
}
|
||||
|
||||
/// Put terminal back in original modes.
|
||||
pub fn disable_raw_modes() -> io::Result<()>
|
||||
{
|
||||
pub fn disable_raw_modes() -> io::Result<()> {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let mut command = unix_command::RawModeCommand::new();
|
||||
#[cfg(target_os = "windows")]
|
||||
let mut command = win_commands::RawModeCommand::new();
|
||||
|
||||
command.disable()?;
|
||||
return Ok(())
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
use super::{AlternateScreen,RawScreen};
|
||||
use super::{AlternateScreen, RawScreen};
|
||||
use TerminalOutput;
|
||||
|
||||
use std::io::Write;
|
||||
use std::io::Result;
|
||||
use std::io::Write;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
/// This type represents an screen which could be in normal, raw and alternate modes.
|
||||
///
|
||||
@ -60,27 +59,27 @@ use std::sync::atomic::AtomicBool;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
pub struct Screen
|
||||
{
|
||||
pub struct Screen {
|
||||
buffer: Vec<u8>,
|
||||
pub stdout: Arc<TerminalOutput>,
|
||||
drop: bool,
|
||||
}
|
||||
|
||||
impl Screen
|
||||
{
|
||||
impl Screen {
|
||||
/// Create new instance of the Screen also specify if the current screen should be in raw mode or normal mode.
|
||||
/// If you are not sure what raw mode is then pass false or use the `Screen::default()` to create an instance.
|
||||
pub fn new(raw_mode: bool) -> Screen
|
||||
{
|
||||
if raw_mode
|
||||
{
|
||||
let screen = Screen { stdout: Arc::new(TerminalOutput::new(true)), buffer: Vec::new(), drop: true };
|
||||
pub fn new(raw_mode: bool) -> Screen {
|
||||
if raw_mode {
|
||||
let screen = Screen {
|
||||
stdout: Arc::new(TerminalOutput::new(true)),
|
||||
buffer: Vec::new(),
|
||||
drop: true,
|
||||
};
|
||||
RawScreen::into_raw_mode().unwrap();
|
||||
return screen;
|
||||
}
|
||||
|
||||
return Screen::default();
|
||||
Screen::default()
|
||||
}
|
||||
|
||||
/// Switch to alternate screen. This function will return an `AlternateScreen` instance. If everything went well this type will give you control over the `AlternateScreen`.
|
||||
@ -96,7 +95,7 @@ impl Screen
|
||||
let stdout = TerminalOutput::new(raw_mode);
|
||||
|
||||
let alternate_screen = AlternateScreen::to_alternate_screen(stdout, raw_mode)?;
|
||||
return Ok(alternate_screen);
|
||||
Ok(alternate_screen)
|
||||
}
|
||||
|
||||
/// Write buffer to an internal buffer. When you want to write the buffer to screen use `flush_buf()`.
|
||||
@ -112,8 +111,7 @@ impl Screen
|
||||
/// screen.write_buf(b"Some more text");
|
||||
/// ```
|
||||
pub fn write_buf(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
self.buffer.write(buf)?;
|
||||
Ok(buf.len())
|
||||
self.buffer.write(buf)
|
||||
}
|
||||
|
||||
/// Flush the internal buffer to the screen.
|
||||
@ -125,49 +123,54 @@ impl Screen
|
||||
}
|
||||
|
||||
/// This will disable the drop which will cause raw modes not to be undone on drop of `Screen`.
|
||||
pub fn disable_drop(&mut self)
|
||||
{
|
||||
pub fn disable_drop(&mut self) {
|
||||
self.drop = false;
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TerminalOutput> for Screen
|
||||
{
|
||||
impl From<TerminalOutput> for Screen {
|
||||
/// Create an screen with the given `Stdout`
|
||||
fn from(stdout: TerminalOutput) -> Self {
|
||||
return Screen { stdout: Arc::new(stdout), buffer: Vec::new(), drop: true};
|
||||
Screen {
|
||||
stdout: Arc::new(stdout),
|
||||
buffer: Vec::new(),
|
||||
drop: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Arc<TerminalOutput>> for Screen
|
||||
{
|
||||
impl From<Arc<TerminalOutput>> for Screen {
|
||||
/// Create an screen with the given 'Arc<Stdout>'
|
||||
fn from(stdout: Arc<TerminalOutput>) -> Self {
|
||||
return Screen { stdout: stdout, buffer: Vec::new(), drop: true};
|
||||
Screen {
|
||||
stdout,
|
||||
buffer: Vec::new(),
|
||||
drop: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Screen
|
||||
{
|
||||
impl Default for Screen {
|
||||
/// Create an new screen which will not be in raw mode or alternate mode.
|
||||
fn default() -> Self {
|
||||
return Screen { stdout: Arc::new(TerminalOutput::new(false)), buffer: Vec::new(), drop: true};
|
||||
Screen {
|
||||
stdout: Arc::new(TerminalOutput::new(false)),
|
||||
buffer: Vec::new(),
|
||||
drop: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Screen
|
||||
{
|
||||
impl Drop for Screen {
|
||||
/// If the current screen is in raw mode whe need to disable it when the instance goes out of scope.
|
||||
fn drop(&mut self) {
|
||||
if self.stdout.is_in_raw_mode && self.drop
|
||||
{
|
||||
if self.stdout.is_in_raw_mode && self.drop {
|
||||
RawScreen::disable_raw_modes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for Screen
|
||||
{
|
||||
impl Write for Screen {
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
self.stdout.write_buf(buf)
|
||||
}
|
||||
|
@ -1,22 +1,14 @@
|
||||
//! This module contains all `unix` specific terminal related logic.
|
||||
|
||||
use self::libc::{c_int, c_ushort, ioctl, STDOUT_FILENO, TIOCGWINSZ, TIOCSWINSZ, signal, SIG_IGN, SIGWINCH};
|
||||
use self::libc::{c_ushort, ioctl, STDOUT_FILENO, TCSADRAIN, TIOCGWINSZ};
|
||||
|
||||
use common::commands::unix_command::RawModeCommand;
|
||||
use {libc, TerminalOutput, Screen};
|
||||
pub use libc::termios;
|
||||
use {libc, Screen};
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::fs;
|
||||
use std::io::{self, Error, ErrorKind, Read, Write};
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::time::{Duration, SystemTime};
|
||||
use std::{fs, mem};
|
||||
use termios::{cfmakeraw, tcsetattr, Termios, TCSADRAIN, CREAD, ECHO, ICANON, TCSAFLUSH};
|
||||
|
||||
const FD_STDIN: ::std::os::unix::io::RawFd = 1;
|
||||
|
||||
use Crossterm;
|
||||
use input::input;
|
||||
use termios::{tcsetattr, Termios};
|
||||
|
||||
/// A representation of the size of the current terminal.
|
||||
#[repr(C)]
|
||||
@ -46,7 +38,7 @@ pub fn terminal_size() -> (u16, u16) {
|
||||
// because crossterm works starts counting at 0 and unix terminal starts at cell 1 you have subtract one to get 0-based results.
|
||||
(us.cols, us.rows)
|
||||
} else {
|
||||
(0,0)
|
||||
(0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,8 +63,7 @@ pub fn terminal_size() -> (u16, u16) {
|
||||
// }
|
||||
//}
|
||||
|
||||
pub fn pos() -> io::Result<(u16, u16)>
|
||||
{
|
||||
pub fn pos() -> io::Result<(u16, u16)> {
|
||||
let _screen = Screen::new(false);
|
||||
|
||||
// if we enable raw modes with screen, this could cause problems if raw mode is already enabled in applicaition.
|
||||
@ -82,7 +73,7 @@ pub fn pos() -> io::Result<(u16, u16)>
|
||||
if !RAW_MODE_ENABLED_BY_USER || !RAW_MODE_ENABLED_BY_SYSTEM {
|
||||
// set this boolean so that we know that the systems has enabled raw mode.
|
||||
RAW_MODE_ENABLED_BY_SYSTEM = true;
|
||||
into_raw_mode();
|
||||
into_raw_mode()?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,7 +82,7 @@ pub fn pos() -> io::Result<(u16, u16)>
|
||||
let mut stdout = io::stdout();
|
||||
|
||||
// Write command
|
||||
stdout.write(b"\x1B[6n")?;
|
||||
stdout.write_all(b"\x1B[6n")?;
|
||||
stdout.flush()?;
|
||||
|
||||
let mut buf = [0u8; 2];
|
||||
@ -133,7 +124,7 @@ pub fn pos() -> io::Result<(u16, u16)>
|
||||
|
||||
// Expect `R`
|
||||
let res = if c == 'R' {
|
||||
Ok(((cols -1) as u16, (rows -1) as u16))
|
||||
Ok(((cols - 1) as u16, (rows - 1) as u16))
|
||||
} else {
|
||||
return Err(Error::new(ErrorKind::Other, "test"));
|
||||
};
|
||||
@ -143,20 +134,16 @@ pub fn pos() -> io::Result<(u16, u16)>
|
||||
unsafe {
|
||||
if RAW_MODE_ENABLED_BY_SYSTEM && !RAW_MODE_ENABLED_BY_USER {
|
||||
RAW_MODE_ENABLED_BY_SYSTEM = false;
|
||||
disable_raw_mode();
|
||||
disable_raw_mode()?;
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
res
|
||||
}
|
||||
|
||||
/// Set the terminal mode to the given mode.
|
||||
pub fn set_terminal_mode(termios: &Termios) -> io::Result<()> {
|
||||
extern "C" {
|
||||
pub fn tcsetattr(fd: c_int, opt: c_int, termptr: *const Termios) -> c_int;
|
||||
}
|
||||
is_true(unsafe { tcsetattr(0, 0, termios) }).and(Ok(()))
|
||||
}
|
||||
static mut ORIGINAL_TERMINAL_MODE: Option<Termios> = None;
|
||||
static mut RAW_MODE_ENABLED_BY_SYSTEM: bool = false;
|
||||
pub static mut RAW_MODE_ENABLED_BY_USER: bool = false;
|
||||
|
||||
/// Transform the given mode into an raw mode (non-canonical) mode.
|
||||
pub fn make_raw(termios: &mut Termios) {
|
||||
@ -166,12 +153,7 @@ pub fn make_raw(termios: &mut Termios) {
|
||||
unsafe { cfmakeraw(termios) }
|
||||
}
|
||||
|
||||
static mut ORIGINAL_TERMINAL_MODE: Option<Termios> = None;
|
||||
static mut RAW_MODE_ENABLED_BY_SYSTEM: bool = false;
|
||||
pub static mut RAW_MODE_ENABLED_BY_USER: bool = false;
|
||||
|
||||
pub fn into_raw_mode() -> io::Result<()>
|
||||
{
|
||||
pub fn into_raw_mode() -> io::Result<()> {
|
||||
let tty_f;
|
||||
|
||||
let fd = unsafe {
|
||||
@ -187,8 +169,7 @@ pub fn into_raw_mode() -> io::Result<()>
|
||||
let original = termios.clone();
|
||||
|
||||
unsafe {
|
||||
if let None = ORIGINAL_TERMINAL_MODE
|
||||
{
|
||||
if ORIGINAL_TERMINAL_MODE.is_none() {
|
||||
ORIGINAL_TERMINAL_MODE = Some(original.clone())
|
||||
}
|
||||
}
|
||||
@ -196,12 +177,10 @@ pub fn into_raw_mode() -> io::Result<()>
|
||||
make_raw(&mut termios);
|
||||
tcsetattr(fd, TCSADRAIN, &termios)?;
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn disable_raw_mode() -> io::Result<()>
|
||||
{
|
||||
pub fn disable_raw_mode() -> io::Result<()> {
|
||||
let tty_f;
|
||||
|
||||
let fd = unsafe {
|
||||
@ -213,8 +192,7 @@ pub fn disable_raw_mode() -> io::Result<()>
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(original) = unsafe { ORIGINAL_TERMINAL_MODE }
|
||||
{
|
||||
if let Some(original) = unsafe { ORIGINAL_TERMINAL_MODE } {
|
||||
tcsetattr(fd, TCSADRAIN, &original)?;
|
||||
}
|
||||
Ok(())
|
||||
@ -235,7 +213,7 @@ pub fn get_tty() -> io::Result<fs::File> {
|
||||
}
|
||||
};
|
||||
|
||||
return Ok(tty_f);
|
||||
Ok(tty_f)
|
||||
}
|
||||
|
||||
pub fn read_char() -> io::Result<char> {
|
||||
@ -254,7 +232,7 @@ pub fn read_char() -> io::Result<char> {
|
||||
};
|
||||
|
||||
let mut termios = Termios::from_fd(fd)?;
|
||||
let original = termios.clone();
|
||||
let original = termios;
|
||||
|
||||
make_raw(&mut termios);
|
||||
tcsetattr(fd, TCSADRAIN, &termios)?;
|
||||
@ -305,12 +283,3 @@ pub fn read_char() -> io::Result<char> {
|
||||
pub fn exit() {
|
||||
::std::process::exit(0);
|
||||
}
|
||||
|
||||
/// Is the return value true?
|
||||
fn is_true(value: i32) -> Result<(), Error> {
|
||||
match value {
|
||||
-1 => Err(io::Error::last_os_error()),
|
||||
0 => Ok(()),
|
||||
_ => Err(io::Error::last_os_error()),
|
||||
}
|
||||
}
|
||||
|
@ -13,18 +13,16 @@ use winapi::um::winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC
|
||||
use super::{handle, kernel, Empty, TerminalOutput, HANDLE};
|
||||
|
||||
use std::io::{self, Result};
|
||||
use std::sync::{Once, ONCE_INIT};
|
||||
use std::mem::size_of;
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Once, ONCE_INIT};
|
||||
|
||||
/// Create a new console screen buffer info struct.
|
||||
pub fn get_csbi() -> Result<CONSOLE_SCREEN_BUFFER_INFO> {
|
||||
let mut csbi = CONSOLE_SCREEN_BUFFER_INFO::empty();
|
||||
let success;
|
||||
|
||||
unsafe {
|
||||
success = GetConsoleScreenBufferInfo(handle::get_current_handle()?, &mut csbi)
|
||||
}
|
||||
unsafe { success = GetConsoleScreenBufferInfo(handle::get_current_handle()?, &mut csbi) }
|
||||
|
||||
if success == 0 {
|
||||
return Err(io::Error::new(
|
||||
|
@ -7,19 +7,16 @@ use winapi::um::wincon::{
|
||||
|
||||
use super::{csbi, handle, kernel, TerminalOutput};
|
||||
|
||||
use kernel::windows_kernel::kernel::get_largest_console_window_size;
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
use kernel::windows_kernel::kernel::get_largest_console_window_size;
|
||||
/// This stores the cursor pos, at program level. So it can be recalled later.
|
||||
static mut SAVED_CURSOR_POS: (u16, u16) = (0, 0);
|
||||
|
||||
/// Reset to saved cursor position
|
||||
pub fn reset_to_saved_position() {
|
||||
unsafe {
|
||||
set_console_cursor_position(
|
||||
SAVED_CURSOR_POS.0 as i16,
|
||||
SAVED_CURSOR_POS.1 as i16,
|
||||
);
|
||||
set_console_cursor_position(SAVED_CURSOR_POS.0 as i16, SAVED_CURSOR_POS.1 as i16);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,17 +1,17 @@
|
||||
//! This module contains some logic for working with the console handle.
|
||||
|
||||
use super::*;
|
||||
use winapi::shared::minwindef::DWORD;
|
||||
use winapi::um::errhandlingapi::GetLastError;
|
||||
use winapi::um::fileapi::{CreateFileW, OPEN_EXISTING};
|
||||
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
|
||||
use winapi::um::processenv::GetStdHandle;
|
||||
use winapi::um::winbase::{STD_INPUT_HANDLE, STD_OUTPUT_HANDLE};
|
||||
use winapi::um::winnt::{GENERIC_READ, GENERIC_WRITE, GENERIC_ALL, FILE_SHARE_WRITE};
|
||||
use winapi::um::fileapi::{OPEN_EXISTING, CreateFileW};
|
||||
use winapi::shared::minwindef::DWORD;
|
||||
use winapi::um::errhandlingapi::GetLastError;
|
||||
use super::*;
|
||||
use winapi::um::winnt::{FILE_SHARE_WRITE, GENERIC_ALL, GENERIC_READ, GENERIC_WRITE};
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::io::{self, Result};
|
||||
use std::ptr::null_mut;
|
||||
use std::sync::Arc;
|
||||
|
||||
use winapi::ctypes::c_void;
|
||||
|
||||
@ -22,16 +22,25 @@ pub fn get_current_handle() -> Result<HANDLE> {
|
||||
let utf16: Vec<u16> = "CONOUT$\0".encode_utf16().collect();
|
||||
let utf16_ptr: *const u16 = utf16.as_ptr();
|
||||
|
||||
let handle = CreateFileW(utf16_ptr, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, null_mut(), OPEN_EXISTING, dw, null_mut());
|
||||
let handle = CreateFileW(
|
||||
utf16_ptr,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_WRITE,
|
||||
null_mut(),
|
||||
OPEN_EXISTING,
|
||||
dw,
|
||||
null_mut(),
|
||||
);
|
||||
|
||||
if !is_valid_handle(&handle) {
|
||||
|
||||
unsafe
|
||||
{
|
||||
unsafe {
|
||||
let error = GetLastError();
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("Could not get output handle current handle!, error code: {}", error).as_ref(),
|
||||
format!(
|
||||
"Could not get output handle current handle!, error code: {}",
|
||||
error
|
||||
).as_ref(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ use TerminalOutput;
|
||||
|
||||
use common::traits::Empty;
|
||||
|
||||
|
||||
impl Empty for COORD {
|
||||
fn empty() -> COORD {
|
||||
COORD { X: 0, Y: 0 }
|
||||
|
@ -7,9 +7,9 @@ use std::sync::Arc;
|
||||
pub fn terminal_size() -> (u16, u16) {
|
||||
let handle = handle::get_output_handle().unwrap();
|
||||
|
||||
// if let Ok(csbi) = csbi::get_csbi_by_handle(&handle) {
|
||||
// println!("right: {} left: {} bottom: {}, top: {} window top {} windows width {} csbi.dwCursorPosition.X {} csbi.dwCursorPosition.Y {}", csbi.srWindow.Right, csbi.srWindow.Left, csbi.srWindow.Bottom, csbi.srWindow.Top, csbi.dwSize.X,csbi.dwSize.Y, csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y);
|
||||
// }
|
||||
// if let Ok(csbi) = csbi::get_csbi_by_handle(&handle) {
|
||||
// println!("right: {} left: {} bottom: {}, top: {} window top {} windows width {} csbi.dwCursorPosition.X {} csbi.dwCursorPosition.Y {}", csbi.srWindow.Right, csbi.srWindow.Left, csbi.srWindow.Bottom, csbi.srWindow.Top, csbi.dwSize.X,csbi.dwSize.Y, csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y);
|
||||
// }
|
||||
|
||||
if let Ok(csbi) = csbi::get_csbi_by_handle(&handle) {
|
||||
(
|
||||
|
@ -4,8 +4,8 @@ use winapi::ctypes::c_void;
|
||||
use winapi::shared::ntdef::NULL;
|
||||
use winapi::um::consoleapi::WriteConsoleW;
|
||||
use winapi::um::wincon::{
|
||||
FillConsoleOutputAttribute, FillConsoleOutputCharacterA, WriteConsoleOutputA, CHAR_INFO,
|
||||
COORD, PSMALL_RECT,
|
||||
FillConsoleOutputAttribute, FillConsoleOutputCharacterA, WriteConsoleOutputA, CHAR_INFO, COORD,
|
||||
PSMALL_RECT,
|
||||
};
|
||||
|
||||
use super::{csbi, handle, kernel, TerminalOutput, HANDLE};
|
||||
@ -18,7 +18,7 @@ use std::sync::Arc;
|
||||
pub fn fill_console_output_character(
|
||||
cells_written: &mut u32,
|
||||
start_location: COORD,
|
||||
cells_to_write: u32
|
||||
cells_to_write: u32,
|
||||
) -> bool {
|
||||
let handle = handle::get_current_handle().unwrap();
|
||||
|
||||
@ -39,7 +39,7 @@ pub fn fill_console_output_character(
|
||||
pub fn fill_console_output_attribute(
|
||||
cells_written: &mut u32,
|
||||
start_location: COORD,
|
||||
cells_to_write: u32
|
||||
cells_to_write: u32,
|
||||
) -> bool {
|
||||
// Get the position of the current console window
|
||||
|
||||
|
@ -9,22 +9,19 @@ mod common;
|
||||
mod kernel;
|
||||
mod modules;
|
||||
|
||||
use common::screen;
|
||||
pub use modules::cursor;
|
||||
pub use modules::input;
|
||||
pub use modules::output;
|
||||
pub use modules::style;
|
||||
pub use modules::terminal;
|
||||
|
||||
pub use common::screen::{Screen, AlternateScreen};
|
||||
pub use common::Crossterm;
|
||||
pub use output::TerminalOutput;
|
||||
pub use self::cursor::*;
|
||||
pub use self::input::*;
|
||||
pub use self::output::*;
|
||||
pub use self::style::*;
|
||||
|
||||
use common::functions;
|
||||
pub use common::screen::{AlternateScreen, Screen};
|
||||
pub use common::Crossterm;
|
||||
pub use output::TerminalOutput;
|
||||
|
||||
#[cfg(unix)]
|
||||
extern crate libc;
|
||||
|
@ -3,16 +3,13 @@
|
||||
//! Note that the cursor position is 0 based. This means that we start counting at 0 when setting the cursor position ect.
|
||||
|
||||
use super::*;
|
||||
use std::io::Write;
|
||||
|
||||
|
||||
/// This struct is an ansi implementation for cursor related actions.
|
||||
pub struct AnsiCursor { }
|
||||
pub struct AnsiCursor {}
|
||||
|
||||
impl AnsiCursor
|
||||
{
|
||||
impl AnsiCursor {
|
||||
pub fn new() -> Box<AnsiCursor> {
|
||||
Box::from(AnsiCursor { })
|
||||
Box::from(AnsiCursor {})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,13 +33,14 @@ pub struct TerminalCursor<'stdout> {
|
||||
stdout: Option<&'stdout Arc<TerminalOutput>>,
|
||||
}
|
||||
|
||||
impl<'stdout> TerminalCursor <'stdout>{
|
||||
impl<'stdout> TerminalCursor<'stdout> {
|
||||
/// Create new cursor instance whereon cursor related actions can be performed.
|
||||
pub fn new() -> TerminalCursor<'stdout> {
|
||||
#[cfg(target_os = "windows")]
|
||||
let cursor =
|
||||
functions::get_module::<Box<ITerminalCursor + Sync + Send>>(WinApiCursor::new(), AnsiCursor::new())
|
||||
.unwrap();
|
||||
let cursor = functions::get_module::<Box<ITerminalCursor + Sync + Send>>(
|
||||
WinApiCursor::new(),
|
||||
AnsiCursor::new(),
|
||||
).unwrap();
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let cursor = AnsiCursor::new() as Box<ITerminalCursor + Sync + Send>;
|
||||
@ -52,9 +53,10 @@ impl<'stdout> TerminalCursor <'stdout>{
|
||||
|
||||
pub fn on_screen(stdout: &'stdout Arc<TerminalOutput>) -> TerminalCursor<'stdout> {
|
||||
#[cfg(target_os = "windows")]
|
||||
let cursor =
|
||||
functions::get_module::<Box<ITerminalCursor + Sync + Send>>(WinApiCursor::new(), AnsiCursor::new())
|
||||
.unwrap();
|
||||
let cursor = functions::get_module::<Box<ITerminalCursor + Sync + Send>>(
|
||||
WinApiCursor::new(),
|
||||
AnsiCursor::new(),
|
||||
).unwrap();
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let cursor = AnsiCursor::new() as Box<ITerminalCursor + Sync + Send>;
|
||||
@ -211,6 +213,6 @@ pub fn cursor() -> TerminalCursor<'static> {
|
||||
|
||||
/// Get an TerminalCursor implementation whereon cursor related actions can be performed.
|
||||
/// Pass the reference to any screen you want this type to perform actions on.
|
||||
pub fn from_screen<'stdout>(screen: &'stdout Screen) -> TerminalCursor<'stdout> {
|
||||
pub fn from_screen(screen: &Screen) -> TerminalCursor {
|
||||
TerminalCursor::on_screen(&screen.stdout)
|
||||
}
|
||||
|
@ -17,8 +17,8 @@ use self::winapi_cursor::WinApiCursor;
|
||||
pub use self::cursor::{cursor, from_screen, TerminalCursor};
|
||||
|
||||
use super::functions;
|
||||
use TerminalOutput;
|
||||
use std::sync::Arc;
|
||||
use TerminalOutput;
|
||||
|
||||
///! This trait defines the actions that can be preformed with the terminal cursor.
|
||||
///! This trait can be implemented so that an concrete implementation of the ITerminalCursor can forfill
|
||||
@ -28,27 +28,27 @@ use std::sync::Arc;
|
||||
///!
|
||||
///! This trait is implemented for `WINAPI` (Windows specific) and `ANSI` (Unix specific),
|
||||
///! so that cursor related actions can be preformed on both unix and windows systems.
|
||||
trait ITerminalCursor : Sync + Send {
|
||||
trait ITerminalCursor: Sync + Send {
|
||||
/// Goto some location (x,y) in the context.
|
||||
fn goto(&self, x: u16, y: u16, stdout: &Option<&Arc<TerminalOutput>>);
|
||||
/// Get the location (x,y) of the current cusror in the context
|
||||
fn pos(&self) -> (u16, u16);
|
||||
/// Move cursor n times up
|
||||
fn move_up(&self, count: u16,stdout: &Option<&Arc<TerminalOutput>>);
|
||||
fn move_up(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>);
|
||||
/// Move the cursor `n` times to the right.
|
||||
fn move_right(&self, count: u16,stdout: &Option<&Arc<TerminalOutput>>);
|
||||
fn move_right(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>);
|
||||
/// Move the cursor `n` times down.
|
||||
fn move_down(&self, count: u16,stdout: &Option<&Arc<TerminalOutput>>);
|
||||
fn move_down(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>);
|
||||
/// Move the cursor `n` times left.
|
||||
fn move_left(&self, count: u16,stdout: &Option<&Arc<TerminalOutput>>);
|
||||
fn move_left(&self, count: u16, stdout: &Option<&Arc<TerminalOutput>>);
|
||||
/// Save cursor position so that its saved position can be recalled later. Note that this position is stored program based not per instance of the cursor struct.
|
||||
fn save_position(&self,stdout: &Option<&Arc<TerminalOutput>>);
|
||||
fn save_position(&self, stdout: &Option<&Arc<TerminalOutput>>);
|
||||
/// Return to saved cursor position
|
||||
fn reset_position(&self,stdout: &Option<&Arc<TerminalOutput>>);
|
||||
fn reset_position(&self, stdout: &Option<&Arc<TerminalOutput>>);
|
||||
/// Hide the terminal cursor.
|
||||
fn hide(&self,stdout: &Option<&Arc<TerminalOutput>>);
|
||||
fn hide(&self, stdout: &Option<&Arc<TerminalOutput>>);
|
||||
/// Show the terminal cursor
|
||||
fn show(&self,stdout: &Option<&Arc<TerminalOutput>>);
|
||||
fn show(&self, stdout: &Option<&Arc<TerminalOutput>>);
|
||||
/// Enable or disable the blinking of the cursor.
|
||||
fn blink(&self, blink: bool,stdout: &Option<&Arc<TerminalOutput>>);
|
||||
fn blink(&self, blink: bool, stdout: &Option<&Arc<TerminalOutput>>);
|
||||
}
|
||||
|
@ -7,17 +7,16 @@ use Screen;
|
||||
/* ======================== WinApi =========================== */
|
||||
#[cfg(windows)]
|
||||
mod winapi_tests {
|
||||
use modules::cursor::winapi_cursor::WinApiCursor;
|
||||
use super::*;
|
||||
use modules::cursor::winapi_cursor::WinApiCursor;
|
||||
|
||||
#[test]
|
||||
fn goto_winapi()
|
||||
{
|
||||
fn goto_winapi() {
|
||||
let screen = Screen::default();
|
||||
let stdout = Some(&screen.stdout);
|
||||
let cursor = WinApiCursor::new();
|
||||
|
||||
cursor.goto(5, 5,&stdout);
|
||||
cursor.goto(5, 5, &stdout);
|
||||
let (x, y) = cursor.pos();
|
||||
|
||||
assert_eq!(x, 5);
|
||||
@ -25,15 +24,14 @@ mod winapi_tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_safe_winapi()
|
||||
{
|
||||
fn reset_safe_winapi() {
|
||||
let screen = Screen::default();
|
||||
let stdout = Some(&screen.stdout);
|
||||
let cursor = WinApiCursor::new();
|
||||
let (x, y) = cursor.pos();
|
||||
|
||||
cursor.save_position(&stdout);
|
||||
cursor.goto(5, 5,&stdout);
|
||||
cursor.goto(5, 5, &stdout);
|
||||
cursor.reset_position(&stdout);
|
||||
|
||||
let (x_saved, y_saved) = cursor.pos();
|
||||
@ -45,8 +43,7 @@ mod winapi_tests {
|
||||
|
||||
/* ======================== ANSI =========================== */
|
||||
#[test]
|
||||
fn reset_safe_ansi()
|
||||
{
|
||||
fn reset_safe_ansi() {
|
||||
if try_enable_ansi() {
|
||||
let screen = Screen::default();
|
||||
let stdout = Some(&screen.stdout);
|
||||
@ -54,7 +51,7 @@ fn reset_safe_ansi()
|
||||
let (x, y) = cursor.pos();
|
||||
|
||||
cursor.save_position(&stdout);
|
||||
cursor.goto(5, 5,&stdout);
|
||||
cursor.goto(5, 5, &stdout);
|
||||
cursor.reset_position(&stdout);
|
||||
|
||||
let (x_saved, y_saved) = cursor.pos();
|
||||
@ -65,14 +62,13 @@ fn reset_safe_ansi()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn goto_ansi()
|
||||
{
|
||||
fn goto_ansi() {
|
||||
if try_enable_ansi() {
|
||||
let screen = Screen::default();
|
||||
let stdout = Some(&screen.stdout);
|
||||
let cursor = AnsiCursor::new();
|
||||
|
||||
cursor.goto(5, 5,&stdout);
|
||||
cursor.goto(5, 5, &stdout);
|
||||
let (x, y) = cursor.pos();
|
||||
|
||||
assert_eq!(x, 5);
|
||||
@ -80,16 +76,15 @@ fn goto_ansi()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn try_enable_ansi() -> bool
|
||||
{
|
||||
fn try_enable_ansi() -> bool {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
if cfg!(target_os = "windows") {
|
||||
use kernel::windows_kernel::ansi_support::try_enable_ansi_support;
|
||||
|
||||
if !try_enable_ansi_support()
|
||||
{ return false; }
|
||||
if !try_enable_ansi_support() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ impl WinApiCursor {
|
||||
}
|
||||
|
||||
impl ITerminalCursor for WinApiCursor {
|
||||
fn goto(&self, x: u16, y: u16,_stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
fn goto(&self, x: u16, y: u16, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
cursor::set_console_cursor_position(x as i16, y as i16);
|
||||
}
|
||||
|
||||
@ -24,41 +24,41 @@ impl ITerminalCursor for WinApiCursor {
|
||||
cursor::pos()
|
||||
}
|
||||
|
||||
fn move_up(&self, count: u16,_stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
fn move_up(&self, count: u16, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
let (xpos, ypos) = self.pos();
|
||||
self.goto(xpos, ypos - count, _stdout);
|
||||
}
|
||||
|
||||
fn move_right(&self, count: u16,_stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
fn move_right(&self, count: u16, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
let (xpos, ypos) = self.pos();
|
||||
self.goto(xpos + count, ypos, _stdout);
|
||||
}
|
||||
|
||||
fn move_down(&self, count: u16,_stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
fn move_down(&self, count: u16, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
let (xpos, ypos) = self.pos();
|
||||
self.goto(xpos, ypos + count, _stdout);
|
||||
}
|
||||
|
||||
fn move_left(&self, count: u16,_stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
fn move_left(&self, count: u16, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
let (xpos, ypos) = self.pos();
|
||||
self.goto(xpos - count, ypos, _stdout);
|
||||
}
|
||||
|
||||
fn save_position(&self,_stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
fn save_position(&self, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
cursor::save_cursor_pos();
|
||||
}
|
||||
|
||||
fn reset_position(&self,_stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
fn reset_position(&self, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
cursor::reset_to_saved_position();
|
||||
}
|
||||
|
||||
fn hide(&self,_stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
fn hide(&self, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
cursor::cursor_visibility(false);
|
||||
}
|
||||
|
||||
fn show(&self,_stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
fn show(&self, _stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
cursor::cursor_visibility(true);
|
||||
}
|
||||
|
||||
fn blink(&self, blink: bool,_stdout: &Option<&Arc<TerminalOutput>>) {}
|
||||
fn blink(&self, blink: bool, _stdout: &Option<&Arc<TerminalOutput>>) {}
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ impl<'stdout> TerminalInput<'stdout> {
|
||||
/// }
|
||||
/// ```
|
||||
pub fn read_char(&self) -> io::Result<char> {
|
||||
return self.terminal_input.read_char(&self.stdout);
|
||||
self.terminal_input.read_char(&self.stdout)
|
||||
}
|
||||
|
||||
/// Read the input asynchronously from the user.
|
||||
@ -162,11 +162,11 @@ impl<'stdout> TerminalInput<'stdout> {
|
||||
|
||||
/// Get an Terminal Input implementation whereon input related actions can be performed.
|
||||
pub fn input<'stdout>() -> TerminalInput<'stdout> {
|
||||
return TerminalInput::new();
|
||||
TerminalInput::new()
|
||||
}
|
||||
|
||||
/// Get an Terminal Input implementation whereon input related actions can be performed.
|
||||
/// Pass the reference to any screen you want this type to perform actions on.
|
||||
pub fn from_screen<'stdout>(screen: &'stdout Screen) -> TerminalInput<'stdout> {
|
||||
pub fn from_screen(screen: &Screen) -> TerminalInput {
|
||||
TerminalInput::on_screen(&screen.stdout)
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ use self::windows_input::WindowsInput;
|
||||
|
||||
pub use self::input::{input, TerminalInput};
|
||||
|
||||
use std::io::{self, Read, Error, ErrorKind};
|
||||
use std::io::{self, Error, ErrorKind, Read};
|
||||
use std::sync::{mpsc, Arc};
|
||||
|
||||
use TerminalOutput;
|
||||
@ -36,7 +36,8 @@ trait ITerminalInput {
|
||||
/// Read the input asynchronously from the user.
|
||||
fn read_async(&self, stdout: &Option<&Arc<TerminalOutput>>) -> AsyncReader;
|
||||
/// Read the input asynchronously until a certain character is hit.
|
||||
fn read_until_async(&self, delimiter: u8, stdout: &Option<&Arc<TerminalOutput>>) -> AsyncReader;
|
||||
fn read_until_async(&self, delimiter: u8, stdout: &Option<&Arc<TerminalOutput>>)
|
||||
-> AsyncReader;
|
||||
}
|
||||
|
||||
/// This is a wrapper for reading from the input asynchronously.
|
||||
@ -64,7 +65,7 @@ impl Read for AsyncReader {
|
||||
Some(Ok(value)) => {
|
||||
buf[total] = value;
|
||||
total += 1;
|
||||
},
|
||||
}
|
||||
_ => return Err(Error::new(ErrorKind::Other, "No characters pressed.")),
|
||||
}
|
||||
}
|
||||
|
@ -38,17 +38,21 @@ impl ITerminalInput for UnixInput {
|
||||
}
|
||||
});
|
||||
|
||||
AsyncReader { recv: recv }
|
||||
AsyncReader { recv }
|
||||
}
|
||||
|
||||
fn read_until_async(&self, delimiter: u8, __stdout: &Option<&Arc<TerminalOutput>>) -> AsyncReader {
|
||||
fn read_until_async(
|
||||
&self,
|
||||
delimiter: u8,
|
||||
__stdout: &Option<&Arc<TerminalOutput>>,
|
||||
) -> AsyncReader {
|
||||
let (send, recv) = mpsc::channel();
|
||||
|
||||
thread::spawn(move || {
|
||||
for i in get_tty().unwrap().bytes() {
|
||||
match i {
|
||||
Ok(byte) => {
|
||||
let end_of_stream = &byte == &delimiter;
|
||||
let end_of_stream = byte == delimiter;
|
||||
let send_error = send.send(Ok(byte)).is_err();
|
||||
|
||||
if end_of_stream || send_error {
|
||||
@ -62,6 +66,6 @@ impl ITerminalInput for UnixInput {
|
||||
}
|
||||
});
|
||||
|
||||
AsyncReader { recv: recv }
|
||||
AsyncReader { recv }
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ impl ITerminalInput for WindowsInput {
|
||||
loop {
|
||||
let is_raw_screen = match stdout {
|
||||
Some(output) => output.is_in_raw_mode,
|
||||
None => false
|
||||
None => false,
|
||||
};
|
||||
|
||||
// _getwch is without echo and _getwche is with echo
|
||||
@ -55,7 +55,7 @@ impl ITerminalInput for WindowsInput {
|
||||
fn read_char(&self, stdout: &Option<&Arc<TerminalOutput>>) -> io::Result<char> {
|
||||
let is_raw_screen = match stdout {
|
||||
Some(output) => output.is_in_raw_mode,
|
||||
None => false
|
||||
None => false,
|
||||
};
|
||||
|
||||
// _getwch is without echo and _getwche is with echo
|
||||
@ -91,7 +91,7 @@ impl ITerminalInput for WindowsInput {
|
||||
|
||||
let is_raw_screen = match stdout {
|
||||
Some(output) => output.is_in_raw_mode,
|
||||
None => false
|
||||
None => false,
|
||||
};
|
||||
|
||||
thread::spawn(move || {
|
||||
@ -117,12 +117,16 @@ impl ITerminalInput for WindowsInput {
|
||||
AsyncReader { recv: rx }
|
||||
}
|
||||
|
||||
fn read_until_async(&self, delimiter: u8, stdout: &Option<&Arc<TerminalOutput>>) -> AsyncReader {
|
||||
fn read_until_async(
|
||||
&self,
|
||||
delimiter: u8,
|
||||
stdout: &Option<&Arc<TerminalOutput>>,
|
||||
) -> AsyncReader {
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
let is_raw_screen = match stdout {
|
||||
Some(output) => output.is_in_raw_mode,
|
||||
None => false
|
||||
None => false,
|
||||
};
|
||||
|
||||
thread::spawn(move || {
|
||||
|
@ -4,5 +4,4 @@ pub mod output;
|
||||
pub mod style;
|
||||
pub mod terminal;
|
||||
|
||||
use super::common::commands;
|
||||
use super::common::functions;
|
||||
|
@ -4,8 +4,7 @@
|
||||
|
||||
use super::IStdout;
|
||||
|
||||
use std::any::Any;
|
||||
use std::io::{self, Write,Stdout, stdout};
|
||||
use std::io::{self, stdout, Stdout, Write};
|
||||
|
||||
/// This struct is a wrapper for `Stdout`
|
||||
pub struct AnsiOutput {
|
||||
|
@ -15,11 +15,8 @@ use self::winapi_output::WinApiOutput;
|
||||
|
||||
pub use self::output::TerminalOutput;
|
||||
|
||||
use std::any::Any;
|
||||
use std::io;
|
||||
|
||||
use super::{functions};
|
||||
|
||||
/// This trait defines represents an stdout of an screen.
|
||||
/// This trait can be implemented so that an concrete implementation of the IStdout can forfill
|
||||
/// the wishes to work on an specific platform.
|
||||
@ -30,7 +27,7 @@ use super::{functions};
|
||||
/// so that color related actions can be preformed on both unix and windows systems.
|
||||
trait IStdout {
|
||||
/// Write an &str to the current stdout and flush the screen.
|
||||
fn write_str(&self, string: &str ) -> io::Result<usize>;
|
||||
fn write_str(&self, string: &str) -> io::Result<usize>;
|
||||
/// Write [u8] buffer to console.
|
||||
fn write(&self, buf: &[u8]) -> io::Result<usize>;
|
||||
/// Flush the current output.
|
||||
|
@ -20,10 +20,8 @@
|
||||
|
||||
use super::*;
|
||||
|
||||
use std::any::Any;
|
||||
use std::default::Default;
|
||||
use std::io::Write;
|
||||
use screen::RawScreen;
|
||||
|
||||
/// Struct that is an handle to an terminal screen.
|
||||
/// This handle could be used to write to the current screen
|
||||
@ -31,14 +29,15 @@ use screen::RawScreen;
|
||||
/// For unix and windows 10 `stdout()` will be used for handle when on windows systems with versions lower than 10 WinApi `HANDLE` will be used.
|
||||
pub struct TerminalOutput {
|
||||
stdout: Box<IStdout + Send + Sync>,
|
||||
pub is_in_raw_mode:bool,
|
||||
pub is_in_raw_mode: bool,
|
||||
}
|
||||
|
||||
impl TerminalOutput {
|
||||
/// Create new screen write instance whereon screen related actions can be performed.
|
||||
pub fn new(raw_mode: bool) -> Self {
|
||||
#[cfg(target_os = "windows")]
|
||||
let stdout: Box<IStdout + Send + Sync> = functions::get_module::<Box<IStdout + Send + Sync>>(
|
||||
let stdout: Box<IStdout + Send + Sync> =
|
||||
functions::get_module::<Box<IStdout + Send + Sync>>(
|
||||
Box::from(WinApiOutput::new()),
|
||||
Box::from(AnsiOutput::new()),
|
||||
).unwrap();
|
||||
@ -46,7 +45,10 @@ impl TerminalOutput {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let stdout = Box::from(AnsiOutput::new()) as Box<IStdout + Send + Sync>;
|
||||
|
||||
TerminalOutput { stdout , is_in_raw_mode: raw_mode}
|
||||
TerminalOutput {
|
||||
stdout,
|
||||
is_in_raw_mode: raw_mode,
|
||||
}
|
||||
}
|
||||
|
||||
/// Write String to the current screen.
|
||||
@ -76,12 +78,11 @@ impl Write for TerminalOutput {
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
self.flush()
|
||||
self.stdout.flush()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TerminalOutput
|
||||
{
|
||||
impl Default for TerminalOutput {
|
||||
/// Get the default handle to the current screen.
|
||||
fn default() -> Self {
|
||||
#[cfg(target_os = "windows")]
|
||||
@ -93,6 +94,9 @@ impl Default for TerminalOutput
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let stdout = Box::from(AnsiOutput::new()) as Box<IStdout + Send + Sync>;
|
||||
|
||||
TerminalOutput { stdout , is_in_raw_mode: false}
|
||||
TerminalOutput {
|
||||
stdout,
|
||||
is_in_raw_mode: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,12 +6,11 @@ use Screen;
|
||||
|
||||
#[cfg(windows)]
|
||||
mod winapi_tests {
|
||||
use modules::output::winapi_output::WinApiOutput;
|
||||
use super::*;
|
||||
use modules::output::winapi_output::WinApiOutput;
|
||||
/* ======================== WinApi =========================== */
|
||||
#[test]
|
||||
fn write_winapi()
|
||||
{
|
||||
fn write_winapi() {
|
||||
let screen = Screen::default();
|
||||
let output = WinApiOutput::new();
|
||||
|
||||
@ -21,8 +20,7 @@ mod winapi_tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_str_winapi()
|
||||
{
|
||||
fn write_str_winapi() {
|
||||
let screen = Screen::default();
|
||||
let output = WinApiOutput::new();
|
||||
|
||||
@ -34,8 +32,7 @@ mod winapi_tests {
|
||||
|
||||
/* ======================== ANSI =========================== */
|
||||
#[test]
|
||||
fn write_ansi()
|
||||
{
|
||||
fn write_ansi() {
|
||||
let _screen = Screen::default();
|
||||
let output = AnsiOutput::new();
|
||||
|
||||
@ -45,8 +42,7 @@ fn write_ansi()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_str_ansi()
|
||||
{
|
||||
fn write_str_ansi() {
|
||||
let _screen = Screen::default();
|
||||
let output = AnsiOutput::new();
|
||||
|
||||
@ -55,23 +51,26 @@ fn write_str_ansi()
|
||||
is_valid_write(result, bytes.len());
|
||||
}
|
||||
|
||||
fn is_valid_write(result: ::std::io::Result<usize>, str_length: usize)
|
||||
{
|
||||
fn is_valid_write(result: ::std::io::Result<usize>, str_length: usize) {
|
||||
match result {
|
||||
Err(_) => assert!(false),
|
||||
Ok(length) => if str_length == length { assert!(true) } else { assert!(false) }
|
||||
Ok(length) => if str_length == length {
|
||||
assert!(true)
|
||||
} else {
|
||||
assert!(false)
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn try_enable_ansi() -> bool
|
||||
{
|
||||
fn try_enable_ansi() -> bool {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
if cfg!(target_os = "windows") {
|
||||
use kernel::windows_kernel::ansi_support::try_enable_ansi_support;
|
||||
|
||||
if !try_enable_ansi_support()
|
||||
{ return false; }
|
||||
if !try_enable_ansi_support() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,26 +1,23 @@
|
||||
use super::IStdout;
|
||||
use screen::RawScreen;
|
||||
use common::commands::win_commands::RawModeCommand;
|
||||
use kernel::windows_kernel::{handle, writing};
|
||||
use screen::RawScreen;
|
||||
use winapi::um::winnt::HANDLE;
|
||||
|
||||
use std::sync::Mutex;
|
||||
use std::any::Any;
|
||||
use std::io;
|
||||
use std::sync::Mutex;
|
||||
|
||||
/// This struct is a wrapper for WINAPI `HANDLE`
|
||||
pub struct WinApiOutput;
|
||||
|
||||
impl WinApiOutput
|
||||
{
|
||||
pub fn new() -> WinApiOutput
|
||||
{
|
||||
impl WinApiOutput {
|
||||
pub fn new() -> WinApiOutput {
|
||||
WinApiOutput
|
||||
}
|
||||
}
|
||||
|
||||
impl IStdout for WinApiOutput {
|
||||
|
||||
fn write_str(&self, string: &str) -> io::Result<usize> {
|
||||
self.write(string.as_bytes())
|
||||
}
|
||||
|
@ -14,17 +14,23 @@ impl AnsiColor {
|
||||
|
||||
impl ITerminalColor for AnsiColor {
|
||||
fn set_fg(&self, fg_color: Color, stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
functions::write(stdout,format!(
|
||||
functions::write(
|
||||
stdout,
|
||||
format!(
|
||||
csi!("{}m"),
|
||||
self.color_value(fg_color, ColorType::Foreground)
|
||||
));
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
fn set_bg(&self, bg_color: Color, stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
functions::write(stdout,format!(
|
||||
functions::write(
|
||||
stdout,
|
||||
format!(
|
||||
csi!("{}m"),
|
||||
self.color_value(bg_color, ColorType::Background)
|
||||
));
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
fn reset(&self, stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
|
@ -63,7 +63,7 @@ impl<'stdout> TerminalColor<'stdout> {
|
||||
|
||||
TerminalColor {
|
||||
color,
|
||||
stdout: Some(stdout)
|
||||
stdout: Some(stdout),
|
||||
}
|
||||
}
|
||||
|
||||
@ -128,9 +128,8 @@ pub fn color<'stdout>() -> TerminalColor<'stdout> {
|
||||
TerminalColor::new()
|
||||
}
|
||||
|
||||
|
||||
/// Get an Terminal Color implementation whereon color related actions can be performed.
|
||||
/// Pass the reference to any screen you want this type to perform actions on.
|
||||
pub fn from_screen<'stdout>(screen: &'stdout Screen) -> TerminalColor<'stdout> {
|
||||
pub fn from_screen(screen: &Screen) -> TerminalColor {
|
||||
TerminalColor::on_screen(&screen.stdout)
|
||||
}
|
||||
|
@ -13,14 +13,14 @@ use self::ansi_color::AnsiColor;
|
||||
use self::winapi_color::WinApiColor;
|
||||
|
||||
use std::convert::From;
|
||||
use std::fmt::Display;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
use std::fmt::Display;
|
||||
|
||||
pub use self::color::{TerminalColor, color, from_screen};
|
||||
pub use self::color::{color, from_screen, TerminalColor};
|
||||
pub use self::objectstyle::ObjectStyle;
|
||||
pub use self::styledobject::StyledObject;
|
||||
pub use self::styledobject::DisplayableObject;
|
||||
pub use self::styledobject::StyledObject;
|
||||
use super::functions;
|
||||
|
||||
use TerminalOutput;
|
||||
@ -63,9 +63,10 @@ trait ITerminalColor {
|
||||
/// println!("{}", styled_object);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn style<'a,D: 'a>(val: D) -> StyledObject<D>
|
||||
where
|
||||
D: Display, {
|
||||
pub fn style<'a, D: 'a>(val: D) -> StyledObject<D>
|
||||
where
|
||||
D: Display,
|
||||
{
|
||||
ObjectStyle::new().apply_to(val)
|
||||
}
|
||||
|
||||
|
@ -30,10 +30,7 @@ impl Default for ObjectStyle {
|
||||
|
||||
impl ObjectStyle {
|
||||
/// Apply an `StyledObject` to the passed displayable object.
|
||||
pub fn apply_to<D: Display>(
|
||||
&self,
|
||||
val: D,
|
||||
) -> StyledObject<D> {
|
||||
pub fn apply_to<D: Display>(&self, val: D) -> StyledObject<D> {
|
||||
StyledObject {
|
||||
object_style: self.clone(),
|
||||
content: val,
|
||||
@ -42,12 +39,12 @@ impl ObjectStyle {
|
||||
|
||||
/// Get an new instance of `ObjectStyle`
|
||||
pub fn new() -> ObjectStyle {
|
||||
return ObjectStyle {
|
||||
ObjectStyle {
|
||||
fg_color: None,
|
||||
bg_color: None,
|
||||
#[cfg(unix)]
|
||||
attrs: Vec::new(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the background color of `ObjectStyle` to the passed color.
|
||||
|
@ -74,7 +74,7 @@ impl<'a, D: Display + 'a> StyledObject<D> {
|
||||
/// ```
|
||||
#[cfg(unix)]
|
||||
pub fn attr(mut self, attr: Attribute) -> StyledObject<D> {
|
||||
&self.object_style.add_attr(attr);
|
||||
self.object_style.add_attr(attr);
|
||||
self
|
||||
}
|
||||
|
||||
@ -144,8 +144,7 @@ impl<'a, D: Display + 'a> StyledObject<D> {
|
||||
///
|
||||
/// You should take not that `StyledObject` implements `Display`. You don't need to call paint unless you are on alternate screen.
|
||||
/// Checkout `into_displayable()` for more information about this.
|
||||
pub fn paint(&self, screen: &Screen)
|
||||
{
|
||||
pub fn paint(&self, screen: &Screen) {
|
||||
let colored_terminal = from_screen(&screen);
|
||||
let mut reset = true;
|
||||
|
||||
@ -161,7 +160,9 @@ impl<'a, D: Display + 'a> StyledObject<D> {
|
||||
|
||||
#[cfg(unix)]
|
||||
for attr in self.object_style.attrs.iter() {
|
||||
screen.stdout.write_string(format!(csi!("{}m"), *attr as i16));
|
||||
screen
|
||||
.stdout
|
||||
.write_string(format!(csi!("{}m"), *attr as i16));
|
||||
reset = true;
|
||||
}
|
||||
|
||||
@ -190,15 +191,14 @@ impl<'a, D: Display + 'a> StyledObject<D> {
|
||||
/// let display_object = styled_object.into_displayable(&screen);
|
||||
/// println!("Colored text: {}. Default color", display_object);
|
||||
/// ```
|
||||
pub fn into_displayable(self, screen: &'a Screen) -> DisplayableObject<'a, D>
|
||||
{
|
||||
return DisplayableObject::new(screen, self)
|
||||
pub fn into_displayable(self, screen: &'a Screen) -> DisplayableObject<'a, D> {
|
||||
DisplayableObject::new(screen, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Display> Display for StyledObject<D> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||
let mut colored_terminal = color();
|
||||
let colored_terminal = color();
|
||||
let mut reset = true;
|
||||
|
||||
if let Some(bg) = self.object_style.bg_color {
|
||||
@ -221,31 +221,29 @@ impl<D: Display> Display for StyledObject<D> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// This is a wrapper for a styled object on alternate screen so that the styled object could be printed on the alternate screen with the standard write functions in rust.
|
||||
///
|
||||
/// ```
|
||||
/// write! ("some normal text, {} <- some colored text", DisplayableObject::new(&screen, styled_object));
|
||||
/// println! ("some normal text, {} <- some colored text", DisplayableObject::new(&screen, styled_object));
|
||||
/// ```
|
||||
pub struct DisplayableObject<'a, D:Display + 'a>
|
||||
{
|
||||
pub struct DisplayableObject<'a, D: Display + 'a> {
|
||||
styled_object: StyledObject<D>,
|
||||
screen: &'a Screen,
|
||||
}
|
||||
|
||||
impl <'a, D: Display + 'a> DisplayableObject<'a, D>
|
||||
{
|
||||
pub fn new(screen: &'a Screen, styled_object: StyledObject<D>) -> DisplayableObject<'a, D>
|
||||
{
|
||||
DisplayableObject { screen, styled_object }
|
||||
impl<'a, D: Display + 'a> DisplayableObject<'a, D> {
|
||||
pub fn new(screen: &'a Screen, styled_object: StyledObject<D>) -> DisplayableObject<'a, D> {
|
||||
DisplayableObject {
|
||||
screen,
|
||||
styled_object,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, D: Display + 'a> Display for DisplayableObject<'a, D>
|
||||
{
|
||||
impl<'a, D: Display + 'a> Display for DisplayableObject<'a, D> {
|
||||
fn fmt(&self, _f: &mut Formatter) -> Result<(), fmt::Error> {
|
||||
self.styled_object.paint(&self.screen);
|
||||
return Ok(())
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -8,14 +8,15 @@ use kernel::windows_kernel::{csbi, kernel};
|
||||
use winapi::um::wincon;
|
||||
|
||||
/// This struct is an windows implementation for color related actions.
|
||||
pub struct WinApiColor
|
||||
{
|
||||
original_color: u16
|
||||
pub struct WinApiColor {
|
||||
original_color: u16,
|
||||
}
|
||||
|
||||
impl WinApiColor {
|
||||
pub fn new() -> WinApiColor {
|
||||
WinApiColor { original_color: csbi::get_original_console_color()}
|
||||
WinApiColor {
|
||||
original_color: csbi::get_original_console_color(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,6 @@ use super::*;
|
||||
pub struct AnsiTerminal;
|
||||
use cursor::TerminalCursor;
|
||||
|
||||
|
||||
impl AnsiTerminal {
|
||||
pub fn new() -> AnsiTerminal {
|
||||
AnsiTerminal {}
|
||||
@ -18,20 +17,20 @@ impl ITerminal for AnsiTerminal {
|
||||
fn clear(&self, clear_type: ClearType, stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
match clear_type {
|
||||
ClearType::All => {
|
||||
functions::write_str(&stdout,csi!("2J"));
|
||||
TerminalCursor::new().goto(0,0);
|
||||
functions::write_str(&stdout, csi!("2J"));
|
||||
TerminalCursor::new().goto(0, 0);
|
||||
}
|
||||
ClearType::FromCursorDown => {
|
||||
functions::write_str(&stdout,csi!("J"));
|
||||
functions::write_str(&stdout, csi!("J"));
|
||||
}
|
||||
ClearType::FromCursorUp => {
|
||||
functions::write_str(&stdout,csi!("1J"));
|
||||
functions::write_str(&stdout, csi!("1J"));
|
||||
}
|
||||
ClearType::CurrentLine => {
|
||||
functions::write_str(&stdout,csi!("2K"));
|
||||
functions::write_str(&stdout, csi!("2K"));
|
||||
}
|
||||
ClearType::UntilNewLine => {
|
||||
functions::write_str(&stdout,csi!("K"));
|
||||
functions::write_str(&stdout, csi!("K"));
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -41,18 +40,18 @@ impl ITerminal for AnsiTerminal {
|
||||
}
|
||||
|
||||
fn scroll_up(&self, count: i16, stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
functions::write(&stdout,format!(csi!("{}S"), count));
|
||||
functions::write(&stdout, format!(csi!("{}S"), count));
|
||||
}
|
||||
|
||||
fn scroll_down(&self, count: i16, stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
functions::write(&stdout,format!(csi!("{}T"), count));
|
||||
functions::write(&stdout, format!(csi!("{}T"), count));
|
||||
}
|
||||
|
||||
fn set_size(&self, width: i16, height: i16, stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
functions::write(&stdout,format!(csi!("8;{};{}t"), height, width));
|
||||
functions::write(&stdout, format!(csi!("8;{};{}t"), height, width));
|
||||
}
|
||||
|
||||
fn exit(&self,stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
fn exit(&self, stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
if let Some(output) = stdout {
|
||||
// drop the screen with the current stdout. This will make sure when in raw mode this will be disabled first.
|
||||
let screen = Screen::from(output.to_owned().clone());
|
||||
|
@ -13,10 +13,10 @@ use self::ansi_terminal::AnsiTerminal;
|
||||
#[cfg(target_os = "windows")]
|
||||
use self::winapi_terminal::WinApiTerminal;
|
||||
|
||||
pub use self::terminal::{terminal, from_screen, Terminal};
|
||||
pub use self::terminal::{from_screen, terminal, Terminal};
|
||||
|
||||
use std::sync::Arc;
|
||||
use super::functions;
|
||||
use std::sync::Arc;
|
||||
use {Screen, TerminalOutput};
|
||||
|
||||
/// Enum that specifies a way of clearing.
|
||||
@ -48,5 +48,5 @@ trait ITerminal {
|
||||
/// Resize terminal to the given width and height.
|
||||
fn set_size(&self, width: i16, height: i16, stdout: &Option<&Arc<TerminalOutput>>);
|
||||
/// Close the current terminal
|
||||
fn exit(&self,stdout: &Option<&Arc<TerminalOutput>>);
|
||||
fn exit(&self, stdout: &Option<&Arc<TerminalOutput>>);
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ impl<'stdout> Terminal<'stdout> {
|
||||
/// println!("{:?}", size);
|
||||
/// ```
|
||||
pub fn terminal_size(&self) -> (u16, u16) {
|
||||
return self.terminal.terminal_size(&self.screen);
|
||||
self.terminal.terminal_size(&self.screen)
|
||||
}
|
||||
|
||||
/// Scroll `n` lines up in the current terminal.
|
||||
|
@ -7,12 +7,11 @@ use Screen;
|
||||
/* ======================== WinApi =========================== */
|
||||
#[cfg(windows)]
|
||||
mod winapi_tests {
|
||||
use modules::terminal::winapi_terminal::WinApiTerminal;
|
||||
use super::*;
|
||||
use modules::terminal::winapi_terminal::WinApiTerminal;
|
||||
|
||||
#[test]
|
||||
fn resize_winapi()
|
||||
{
|
||||
fn resize_winapi() {
|
||||
let screen = Screen::default();
|
||||
let stdout = Some(&screen.stdout);
|
||||
let terminal = WinApiTerminal::new();
|
||||
@ -28,15 +27,14 @@ mod winapi_tests {
|
||||
|
||||
/* ======================== ANSI =========================== */
|
||||
#[test]
|
||||
fn resize_ansi()
|
||||
{
|
||||
fn resize_ansi() {
|
||||
use std::{thread, time};
|
||||
if try_enable_ansi() {
|
||||
let screen = Screen::default();
|
||||
let stdout = Some(&screen.stdout);
|
||||
let terminal = AnsiTerminal::new();
|
||||
|
||||
terminal.set_size(50,50, &stdout);
|
||||
terminal.set_size(50, 50, &stdout);
|
||||
|
||||
// see issue: https://github.com/eminence/terminal-size/issues/11
|
||||
thread::sleep(time::Duration::from_millis(30));
|
||||
@ -48,15 +46,15 @@ fn resize_ansi()
|
||||
}
|
||||
}
|
||||
|
||||
fn try_enable_ansi() -> bool
|
||||
{
|
||||
fn try_enable_ansi() -> bool {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
if cfg!(target_os = "windows") {
|
||||
use kernel::windows_kernel::ansi_support::try_enable_ansi_support;
|
||||
|
||||
if !try_enable_ansi_support()
|
||||
{ return false; }
|
||||
if !try_enable_ansi_support() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
//!
|
||||
//! Windows versions lower then windows 10 are not supporting ANSI codes. Those versions will use this implementation instead.
|
||||
|
||||
use cursor::TerminalCursor;
|
||||
use super::*;
|
||||
use cursor::TerminalCursor;
|
||||
|
||||
use kernel::windows_kernel::{csbi, kernel, terminal, writing};
|
||||
use winapi::um::wincon::{CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT};
|
||||
@ -151,8 +151,7 @@ impl ITerminal for WinApiTerminal {
|
||||
}
|
||||
|
||||
fn exit(&self, stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
if let Some(output) = stdout
|
||||
{
|
||||
if let Some(output) = stdout {
|
||||
// drop the screen with the current stdout. This will make sure when in raw mode this will be disabled first.
|
||||
let mut screen = Screen::from(output.to_owned().clone());
|
||||
drop(screen);
|
||||
@ -208,7 +207,10 @@ pub fn clear_before_cursor(
|
||||
clear(start_location, cells_to_write);
|
||||
}
|
||||
|
||||
pub fn clear_entire_screen(csbi: CONSOLE_SCREEN_BUFFER_INFO, stdout: &Option<&Arc<TerminalOutput>>) {
|
||||
pub fn clear_entire_screen(
|
||||
csbi: CONSOLE_SCREEN_BUFFER_INFO,
|
||||
stdout: &Option<&Arc<TerminalOutput>>,
|
||||
) {
|
||||
// position x at start
|
||||
let x = 0;
|
||||
// position y at start
|
||||
@ -305,11 +307,8 @@ fn clear(start_loaction: COORD, cells_to_write: u32) {
|
||||
let mut cells_written = 0;
|
||||
let mut success = false;
|
||||
|
||||
success = writing::fill_console_output_character(
|
||||
&mut cells_written,
|
||||
start_loaction,
|
||||
cells_to_write,
|
||||
);
|
||||
success =
|
||||
writing::fill_console_output_character(&mut cells_written, start_loaction, cells_to_write);
|
||||
|
||||
if !success {
|
||||
panic!("Could not clear screen after cursor");
|
||||
@ -317,11 +316,8 @@ fn clear(start_loaction: COORD, cells_to_write: u32) {
|
||||
|
||||
cells_written = 0;
|
||||
|
||||
success = writing::fill_console_output_attribute(
|
||||
&mut cells_written,
|
||||
start_loaction,
|
||||
cells_to_write,
|
||||
);
|
||||
success =
|
||||
writing::fill_console_output_attribute(&mut cells_written, start_loaction, cells_to_write);
|
||||
|
||||
if !success {
|
||||
panic!("Could not reset attributes after cursor");
|
||||
|
Loading…
Reference in New Issue
Block a user