Updated all examples and comments tested unix logic
This commit is contained in:
parent
f31bb1a656
commit
d23ef22a58
@ -15,12 +15,13 @@ extern crate crossterm;
|
|||||||
mod some_types;
|
mod some_types;
|
||||||
mod input;
|
mod input;
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// call some test module function
|
// call some test module function
|
||||||
|
|
||||||
terminal::terminal::resize_terminal();
|
// terminal::terminal::resize_terminal();
|
||||||
|
input::keyboard::async_input::read_async_demo();
|
||||||
use crossterm::screen::RawScreen;
|
// use crossterm::screen::RawScreen;
|
||||||
// RawScreen::into_raw_mode();
|
// RawScreen::into_raw_mode();
|
||||||
// RawScreen::disable_raw_modes();
|
// RawScreen::disable_raw_modes();
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ pub fn read_async_until() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// this will read pressed characters async until `x` is typed .
|
/// this will read pressed characters async until `x` is typed.
|
||||||
pub fn read_async() {
|
pub fn read_async() {
|
||||||
let input = input(&Screen::default());
|
let input = input(&Screen::default());
|
||||||
|
|
||||||
|
@ -127,10 +127,10 @@ impl<'screen> FirstDepthSearch<'screen>
|
|||||||
fn find_first_possible_direction(&mut self)
|
fn find_first_possible_direction(&mut self)
|
||||||
{
|
{
|
||||||
// if there are no elements left in the stack that means we have visited all cell and we van terminate the program.
|
// if there are no elements left in the stack that means we have visited all cell and we van terminate the program.
|
||||||
if let Some(previous_cell) = &self.stack.pop()
|
if let &Some(previous_cell) = &self.stack.pop()
|
||||||
{
|
{
|
||||||
// update root pos to previous cell and continue searching for new neighbours
|
// update root pos to previous cell and continue searching for new neighbours
|
||||||
self.root_pos = *previous_cell;
|
self.root_pos = previous_cell;
|
||||||
self.choose_random_neighbor();
|
self.choose_random_neighbor();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -33,7 +33,7 @@ fn print_wait_screen(screen: &Screen) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// print wait screen on alternate screen, then swich back.
|
/// print wait screen on alternate screen, then switch back.
|
||||||
pub fn print_wait_screen_on_alternate_window() {
|
pub fn print_wait_screen_on_alternate_window() {
|
||||||
|
|
||||||
let screen = Screen::default();
|
let screen = Screen::default();
|
||||||
|
@ -22,56 +22,139 @@ use common::commands::win_commands;
|
|||||||
|
|
||||||
use write::Stdout;
|
use write::Stdout;
|
||||||
|
|
||||||
|
/// This type could be used to access the `cursor, terminal, color, input, styling` module more easily.
|
||||||
|
/// You need to pass a reference to the screen where on you want to perform the actions.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
/// If you want to use the default screen you could do it like this:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
///
|
||||||
|
/// extern crate crossterm;
|
||||||
|
/// use crossterm::{Crossterm, Screen};
|
||||||
|
///
|
||||||
|
/// let crossterm = Crossterm::new();
|
||||||
|
/// let cursor = crossterm.cursor(&Screen::default());
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// If you want to perform actions on the `AlternateScreen` make sure to pass a refrence to the screen of the `AlternateScreen`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// /// extern crate crossterm;
|
||||||
|
/// use crossterm::{Crossterm, Screen};
|
||||||
|
///
|
||||||
|
/// let main_screen = Screen::default();
|
||||||
|
///
|
||||||
|
/// if let Ok(alternate_srceen) = main_screen.enable_alternate_modes(false)
|
||||||
|
/// {
|
||||||
|
/// let crossterm = Crossterm::new();
|
||||||
|
/// let cursor = crossterm.cursor(&alternate_screen.screen);
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
pub struct Crossterm { }
|
pub struct Crossterm { }
|
||||||
|
|
||||||
impl<'crossterm> Crossterm {
|
impl<'crossterm> Crossterm {
|
||||||
|
|
||||||
|
/// Create a new instance of `Crossterm`
|
||||||
pub fn new() -> Crossterm {
|
pub fn new() -> Crossterm {
|
||||||
Crossterm {}
|
Crossterm {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get an TerminalCursor implementation whereon cursor related actions can be performed.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
///
|
||||||
|
/// extern crate crossterm;
|
||||||
|
/// use crossterm::{Crossterm, Screen};
|
||||||
|
///
|
||||||
|
/// let crossterm = Crossterm::new();
|
||||||
|
/// let cursor = crossterm.cursor(&Screen::default());
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
pub fn cursor(&self, screen: &'crossterm Screen) -> cursor::TerminalCursor {
|
pub fn cursor(&self, screen: &'crossterm Screen) -> cursor::TerminalCursor {
|
||||||
cursor::TerminalCursor::new(&screen.stdout.clone())
|
cursor::TerminalCursor::new(&screen.stdout.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get an TerminalInput implementation whereon terminal related actions can be performed.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
///
|
||||||
|
/// extern crate crossterm;
|
||||||
|
/// use crossterm::{Crossterm, Screen};
|
||||||
|
/// use crossterm::terminal;
|
||||||
|
///
|
||||||
|
/// let crossterm = Crossterm::new();
|
||||||
|
/// let input = crossterm.input(&Screen::default());
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
pub fn input(&self, screen: &'crossterm Screen) -> input::TerminalInput {
|
pub fn input(&self, screen: &'crossterm Screen) -> input::TerminalInput {
|
||||||
return input::TerminalInput::new(&screen.stdout);
|
return input::TerminalInput::new(&screen.stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get an Terminal implementation whereon terminal related actions can be performed.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
///
|
||||||
|
/// extern crate crossterm;
|
||||||
|
/// use crossterm::{Crossterm, Screen};
|
||||||
|
///
|
||||||
|
/// let crossterm = Crossterm::new();
|
||||||
|
/// let mut terminal = crossterm.terminal(&Screen::default());
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
pub fn terminal(&self, screen: &'crossterm Screen) -> terminal::Terminal {
|
pub fn terminal(&self, screen: &'crossterm Screen) -> terminal::Terminal {
|
||||||
return terminal::Terminal::new(&screen.stdout);
|
return terminal::Terminal::new(&screen.stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get an TerminalColor implementation whereon color related actions can be performed.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
///
|
||||||
|
/// extern crate crossterm;
|
||||||
|
/// use crossterm::{Crossterm, Screen};
|
||||||
|
///
|
||||||
|
/// let crossterm = Crossterm::new();
|
||||||
|
/// let mut terminal = crossterm.terminal(&Screen::default());
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
pub fn color(&self, screen: &'crossterm Screen) -> style::TerminalColor {
|
pub fn color(&self, screen: &'crossterm Screen) -> style::TerminalColor {
|
||||||
return style::TerminalColor::new(&screen.stdout);
|
return style::TerminalColor::new(&screen.stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wraps an displayable object so it can be formatted with colors and attributes.
|
/// This could be used to style an Displayable with colors and attributes.
|
||||||
//
|
///
|
||||||
// Check `/examples/color` in the libary for more spesific examples.
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
///
|
||||||
|
/// use crossterm::{ Screen };
|
||||||
|
///
|
||||||
|
/// // get an styled object which could be painted to the terminal.
|
||||||
|
/// let styled_object = style("Some Blue colored text on black background").with(Color::Blue).on(Color::Black);
|
||||||
|
///
|
||||||
|
/// // create an default screen.
|
||||||
|
/// let screen = Screen::default();
|
||||||
|
///
|
||||||
|
/// // print the styled font * times to the current screen.
|
||||||
|
/// for i in 1..10
|
||||||
|
/// {
|
||||||
|
/// styled_object.paint(&screen);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub fn style<D>(&self, val: D) -> style::StyledObject<D>
|
pub fn style<D>(&self, val: D) -> style::StyledObject<D>
|
||||||
where
|
where
|
||||||
D: Display, {
|
D: Display, {
|
||||||
style::ObjectStyle::new().apply_to(val)
|
style::ObjectStyle::new().apply_to(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//impl Write for Crossterm {M
|
|
||||||
// fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
|
||||||
// self.active_screen.write_buf(buf)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fn flush(&mut self) -> Result<()> {
|
|
||||||
// self.active_screen.flush()
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//impl Drop for Crossterm {
|
|
||||||
// fn drop(&mut self) {
|
|
||||||
// if let Some(ref mut screen) = self.alternate_screen {
|
|
||||||
// screen.disable(&mut self.active_screen);
|
|
||||||
// }
|
|
||||||
// if let Some(ref mut raw_terminal) = self.raw_terminal {
|
|
||||||
// raw_terminal.disable();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
@ -49,16 +49,19 @@ pub fn get_module<T>(winapi_impl: T, unix_impl: T) -> Option<T> {
|
|||||||
|
|
||||||
if cfg!(target_os = "windows") {
|
if cfg!(target_os = "windows") {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use kernel::windows_kernel::ansi_support::try_enable_ansi_support;
|
use kernel::windows_kernel::ansi_support::{try_enable_ansi_support, windows_supportable};
|
||||||
|
|
||||||
// Try to enable ansi on windows if not than use WINAPI.
|
if !windows_supportable()
|
||||||
does_support = try_enable_ansi_support();
|
{
|
||||||
|
// 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.
|
// uncomment this line when you want to use the winapi implementation.
|
||||||
does_support = false;
|
// does_support = false;
|
||||||
if !does_support {
|
if !does_support {
|
||||||
term = Some(winapi_impl);
|
term = Some(winapi_impl);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if does_support {
|
if does_support {
|
||||||
|
@ -5,22 +5,6 @@
|
|||||||
//! The alternate buffer is exactly the dimensions of the window, without any scrollback region.
|
//! 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.
|
//! 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.
|
//! Vim uses the entirety of the screen to edit the file, then returning to bash leaves the original buffer unchanged.
|
||||||
//!
|
|
||||||
//!
|
|
||||||
//! When using alternate screen there is one thing to keep in mind.
|
|
||||||
//! To get the functionalities of `cursor, color, terminal` also working on alternate screen.
|
|
||||||
//! You need to pass it the same `Context` as you have passed to the previous three functions,
|
|
||||||
//! If you don't use the same `Context` the `cursor(), color(), terminal()` these modules will be using main screen to write to.
|
|
||||||
//! So you will see nothing on alternate screen.
|
|
||||||
//!
|
|
||||||
//!
|
|
||||||
//! When you want to switch to alternate screen there are a couple of things to keep in mind for it to work correctly.
|
|
||||||
//! First off some code of how to switch to Alternate screen, for more info check the example folder at github
|
|
||||||
//! Create alternate screen from `Crossterm`:
|
|
||||||
//!
|
|
||||||
//!
|
|
||||||
//! Todo: example
|
|
||||||
//!
|
|
||||||
|
|
||||||
use super::commands::{self, IAlternateScreenCommand};
|
use super::commands::{self, IAlternateScreenCommand};
|
||||||
use super::{functions, Screen, Stdout, RawScreen};
|
use super::{functions, Screen, Stdout, RawScreen};
|
||||||
@ -29,6 +13,7 @@ use std::convert::From;
|
|||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
/// With this type you will be able to switch to alternate screen and back to main screen.
|
||||||
pub struct AlternateScreen
|
pub struct AlternateScreen
|
||||||
{
|
{
|
||||||
command: Box<IAlternateScreenCommand + Send>,
|
command: Box<IAlternateScreenCommand + Send>,
|
||||||
@ -37,11 +22,19 @@ pub struct AlternateScreen
|
|||||||
|
|
||||||
impl AlternateScreen {
|
impl AlternateScreen {
|
||||||
|
|
||||||
|
/// Create new instance of alternate screen.
|
||||||
pub fn new(command: Box<IAlternateScreenCommand + Send>, screen: Screen) -> Self
|
pub fn new(command: Box<IAlternateScreenCommand + Send>, screen: Screen) -> Self
|
||||||
{
|
{
|
||||||
return AlternateScreen { command, screen }
|
return 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`.
|
||||||
|
///
|
||||||
|
/// # What is Alternate screen?
|
||||||
|
/// *Nix style applications often utilize an alternate screen buffer, so that they can modify the entire contents of the buffer, without affecting the application that started them.
|
||||||
|
/// 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(screen_manager: Stdout) -> io::Result<AlternateScreen> {
|
pub fn to_alternate_screen(screen_manager: Stdout) -> io::Result<AlternateScreen> {
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
let command = functions::get_module::<Box<commands::IAlternateScreenCommand + Send>>(
|
let command = functions::get_module::<Box<commands::IAlternateScreenCommand + Send>>(
|
||||||
@ -57,6 +50,7 @@ impl AlternateScreen {
|
|||||||
return Ok(AlternateScreen::new(command, Screen::from(stdout)));
|
return Ok(AlternateScreen::new(command, Screen::from(stdout)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Switch the alternate screen back to main screen.
|
||||||
pub fn to_main_screen(&self) -> io::Result<()> {
|
pub fn to_main_screen(&self) -> io::Result<()> {
|
||||||
self.command.disable(&self.screen.stdout)?;
|
self.command.disable(&self.screen.stdout)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -65,8 +59,8 @@ impl AlternateScreen {
|
|||||||
|
|
||||||
impl Drop for AlternateScreen
|
impl Drop for AlternateScreen
|
||||||
{
|
{
|
||||||
|
/// This will switch back to main screen on drop.
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.to_main_screen();
|
self.to_main_screen();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
//! - Characters
|
//! - Characters
|
||||||
//! The characters are not processed by the terminal driver, but are sent straight through.
|
//! The characters are not processed by the terminal driver, but are sent straight through.
|
||||||
//! Special character have no meaning, like backspace will not be interpret as backspace but instead will be directly send to the terminal.
|
//! Special character have no meaning, like backspace will not be interpret as backspace but instead will be directly send to the terminal.
|
||||||
|
//! - Escape characters
|
||||||
|
//! Note that in raw modes `\n` will move to the new line but the cursor will be at the same position as before on the new line therefor use `\n\r` to start at the new line at the first cell.
|
||||||
//!
|
//!
|
||||||
//! With these modes you can easier design the terminal screen.
|
//! With these modes you can easier design the terminal screen.
|
||||||
|
|
||||||
@ -18,16 +20,10 @@ use super::{functions, Screen, Stdout};
|
|||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
|
||||||
/// A wrapper for the raw terminal state. Which can be used to write to.
|
/// A wrapper for the raw terminal state. Which can be used to write to.
|
||||||
pub struct RawScreen
|
pub struct RawScreen;
|
||||||
{
|
|
||||||
// #[cfg(not(target_os = "windows"))]
|
|
||||||
// command: unix_command::RawModeCommand,
|
|
||||||
// #[cfg(not(target_os = "windows"))]
|
|
||||||
// command: win_commands::RawModeCommand,
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl 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"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
@ -35,12 +31,11 @@ impl RawScreen {
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
let mut command = win_commands::RawModeCommand::new();
|
let mut command = win_commands::RawModeCommand::new();
|
||||||
|
|
||||||
// command::new();
|
|
||||||
command.enable()?;
|
command.enable()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
@ -48,9 +43,7 @@ impl RawScreen {
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
let mut command = win_commands::RawModeCommand::new();
|
let mut command = win_commands::RawModeCommand::new();
|
||||||
|
|
||||||
let a = command.disable();
|
command.disable()?;
|
||||||
|
|
||||||
|
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,42 @@ use std::io::Write;
|
|||||||
use std::io::Result;
|
use std::io::Result;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// This type represents an screen.
|
||||||
|
/// This screen has an stdout which is used by the program to write to or to execute commands with.
|
||||||
|
///
|
||||||
|
/// You have to make sure that you pass the correct `Screen` to the modules `cursor, terminal, color, input, style`.
|
||||||
|
/// Most of the time you just have one screen so you could get an instance of that screen with: `Screen::default()`.
|
||||||
|
///
|
||||||
|
/// Also this screen has an buffer where you can write to. When you want to write the buffer to the screen you could flush the screen.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// // create default screen.
|
||||||
|
/// let screen = Screen::default();
|
||||||
|
/// // create raw screen.
|
||||||
|
/// let mut screen = Screen::new(true);
|
||||||
|
///
|
||||||
|
/// // write some text to the internal buffer of this type.
|
||||||
|
/// screen.write(b"Some text");
|
||||||
|
/// screen.write(b"Some more text");
|
||||||
|
/// screen.write(b"Some more text");
|
||||||
|
///
|
||||||
|
/// // write the above text by flushing the internal buffer of this type.
|
||||||
|
/// screen.flush();
|
||||||
|
///
|
||||||
|
/// // create raw alternate screen from normal screen.
|
||||||
|
/// let screen = Screen::new();
|
||||||
|
///
|
||||||
|
/// if let Ok(alternate_screen) = screen.enable_alternate_modes(true)
|
||||||
|
/// {
|
||||||
|
/// let crossterm = Crossterm::new();
|
||||||
|
///
|
||||||
|
/// // make sure to pass in the screen of the AlternateScreen.
|
||||||
|
/// crossterm.cursor(&alternate_screen.screen);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
pub struct Screen
|
pub struct Screen
|
||||||
{
|
{
|
||||||
buffer: Vec<u8>,
|
buffer: Vec<u8>,
|
||||||
@ -21,6 +57,8 @@ pub struct Screen
|
|||||||
|
|
||||||
impl Screen
|
impl Screen
|
||||||
{
|
{
|
||||||
|
/// Create new instance of the Screen also specify if the current screen should be in raw mode or normal mode. Check out `RawScreen` type for more info.
|
||||||
|
/// 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
|
pub fn new(raw_mode: bool) -> Screen
|
||||||
{
|
{
|
||||||
if raw_mode
|
if raw_mode
|
||||||
@ -32,16 +70,33 @@ impl Screen
|
|||||||
return Screen::default();
|
return Screen::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from(stdout: Stdout) -> Screen
|
/// This method could be used for enabling raw mode for the terminal.
|
||||||
{
|
///
|
||||||
return Screen { stdout: Arc::new(stdout), buffer: Vec::new() };
|
/// What exactly is raw state:
|
||||||
}
|
/// - No line buffering.
|
||||||
|
/// Normally the terminals uses line buffering. This means that the input will be send to the terminal line by line.
|
||||||
|
/// With raw mode the input will be send one byte at a time.
|
||||||
|
/// - Input
|
||||||
|
/// All input has to be written manually by the programmer.
|
||||||
|
/// - Characters
|
||||||
|
/// The characters are not processed by the terminal driver, but are sent straight through.
|
||||||
|
/// Special character have no meaning, like backspace will not be interpret as backspace but instead will be directly send to the terminal.
|
||||||
|
/// - Escape characters
|
||||||
|
/// Note that in raw modes `\n` will move to the new line but the cursor will be at the same position as before on the new line therefor use `\n\r` to start at the new line at the first cell.
|
||||||
|
///
|
||||||
|
/// With these modes you can easier design the terminal screen.
|
||||||
pub fn enable_raw_modes(&self) -> Result<()> {
|
pub fn enable_raw_modes(&self) -> Result<()> {
|
||||||
RawScreen::into_raw_mode()?;
|
RawScreen::into_raw_mode()?;
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Switch to alternate screen. This function will return an `AlternateScreen` instance if everything went well this type will give you control over the `AlternateScreen`.
|
||||||
|
///
|
||||||
|
/// # What is Alternate screen?
|
||||||
|
/// *Nix style applications often utilize an alternate screen buffer, so that they can modify the entire contents of the buffer, without affecting the application that started them.
|
||||||
|
/// 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 enable_alternate_modes(&self, raw_mode: bool) -> Result<AlternateScreen> {
|
pub fn enable_alternate_modes(&self, raw_mode: bool) -> Result<AlternateScreen> {
|
||||||
let mut stdout = Stdout::new(raw_mode);
|
let mut stdout = Stdout::new(raw_mode);
|
||||||
|
|
||||||
@ -55,8 +110,25 @@ impl Screen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Stdout> for Screen
|
||||||
|
{
|
||||||
|
/// Create an screen with the given `Stdout`
|
||||||
|
fn from(stdout: Stdout) -> Self {
|
||||||
|
return Screen { stdout: Arc::new(stdout), buffer: Vec::new() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Arc<Stdout>> for Screen
|
||||||
|
{
|
||||||
|
/// Create an screen with the given 'Arc<Stdout>'
|
||||||
|
fn from(stdout: Arc<Stdout>) -> Self {
|
||||||
|
return Screen { stdout: stdout, buffer: Vec::new() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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 {
|
fn default() -> Self {
|
||||||
return Screen { stdout: Arc::new(Stdout::new(false)), buffer: Vec::new() };
|
return Screen { stdout: Arc::new(Stdout::new(false)), buffer: Vec::new() };
|
||||||
}
|
}
|
||||||
@ -64,6 +136,7 @@ impl Default for Screen
|
|||||||
|
|
||||||
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) {
|
fn drop(&mut self) {
|
||||||
if self.stdout.is_in_raw_mode
|
if self.stdout.is_in_raw_mode
|
||||||
{
|
{
|
||||||
@ -74,11 +147,15 @@ impl Drop for Screen
|
|||||||
|
|
||||||
impl Write for Screen
|
impl Write for Screen
|
||||||
{
|
{
|
||||||
|
/// Write buffer to an internal buffer. When you want to write the buffer to screen use `flush()`.
|
||||||
|
///
|
||||||
|
/// This function is useful if you want to build up some output and when you are ready you could flush the output to the screen.
|
||||||
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
||||||
self.buffer.write(buf);
|
self.buffer.write(buf);
|
||||||
Ok(buf.len())
|
Ok(buf.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Flush the internal buffer to the screen.
|
||||||
fn flush(&mut self) -> Result<()> {
|
fn flush(&mut self) -> Result<()> {
|
||||||
self.stdout.write_buf(&self.buffer);
|
self.stdout.write_buf(&self.buffer);
|
||||||
self.stdout.flush()
|
self.stdout.flush()
|
||||||
|
@ -9,6 +9,7 @@ use std::fmt::Display;
|
|||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Struct that stores an specific platform implementation for cursor related actions.
|
/// Struct that stores an specific platform implementation for cursor related actions.
|
||||||
///
|
///
|
||||||
/// Check `/examples/version/cursor` in the library for more specific examples.
|
/// Check `/examples/version/cursor` in the library for more specific examples.
|
||||||
@ -17,11 +18,10 @@ use std::sync::Arc;
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// extern crate crossterm;
|
/// extern crate crossterm;
|
||||||
/// use self::crossterm::Crossterm;
|
/// use self::crossterm::cursor::cursor;
|
||||||
///
|
///
|
||||||
/// let term = Crossterm::new();
|
/// let mut cursor = cursor();
|
||||||
/// let mut cursor = term.cursor();
|
|
||||||
///
|
///
|
||||||
/// // Get cursor and goto pos X: 5, Y: 10
|
/// // Get cursor and goto pos X: 5, Y: 10
|
||||||
/// cursor.goto(5,10);
|
/// cursor.goto(5,10);
|
||||||
@ -31,8 +31,6 @@ use std::sync::Arc;
|
|||||||
/// cursor.blink(true);
|
/// cursor.blink(true);
|
||||||
/// cursor.move_left(2);
|
/// cursor.move_left(2);
|
||||||
///
|
///
|
||||||
/// // or in one line
|
|
||||||
/// cursor.goto(5,5).move_left(2).move_right(2).print("10");
|
|
||||||
/// ```
|
/// ```
|
||||||
pub struct TerminalCursor {
|
pub struct TerminalCursor {
|
||||||
screen: Arc<Stdout>,
|
screen: Arc<Stdout>,
|
||||||
@ -62,11 +60,10 @@ impl TerminalCursor {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// let cursor = cursor(&Screen::default());
|
||||||
/// let cursor = crossterm.cursor();
|
|
||||||
///
|
///
|
||||||
/// // change the cursor to position, x: 4 and y: 5
|
/// // change the cursor to position, x: 4 and y: 5
|
||||||
/// cursor.goto(4,5);
|
/// cursor.goto(4,5);
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
pub fn goto(&self, x: u16, y: u16) {
|
pub fn goto(&self, x: u16, y: u16) {
|
||||||
@ -79,11 +76,10 @@ impl TerminalCursor {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// let cursor = cursor(&Screen::default());
|
||||||
/// let cursor = crossterm.cursor();
|
|
||||||
///
|
///
|
||||||
/// // get the current cursor pos
|
/// // get the current cursor pos
|
||||||
/// let (x,y) = cursor.pos();
|
/// let (x,y) = cursor.pos();
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
pub fn pos(&self) -> (u16, u16) {
|
pub fn pos(&self) -> (u16, u16) {
|
||||||
@ -95,11 +91,9 @@ impl TerminalCursor {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// let cursor = cursor(&Screen::default());
|
||||||
/// let cursor = crossterm.cursor();
|
/// // Move the cursor to position 3 times to the up in the terminal
|
||||||
///
|
/// cursor.move_up(3);
|
||||||
/// // Move the cursor to position 3 times to the up in the terminal
|
|
||||||
/// cursor.move_up(3);
|
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
pub fn move_up(&mut self, count: u16) -> &mut TerminalCursor {
|
pub fn move_up(&mut self, count: u16) -> &mut TerminalCursor {
|
||||||
@ -113,10 +107,10 @@ impl TerminalCursor {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// let cursor = cursor(&Screen::default());
|
||||||
/// let cursor = crossterm.cursor();
|
///
|
||||||
/// // Move the cursor to position 3 times to the right in the terminal
|
/// // Move the cursor to position 3 times to the right in the terminal
|
||||||
/// cursor.move_right(3);
|
/// cursor.move_right(3);
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
pub fn move_right(&mut self, count: u16) -> &mut TerminalCursor {
|
pub fn move_right(&mut self, count: u16) -> &mut TerminalCursor {
|
||||||
@ -130,11 +124,10 @@ impl TerminalCursor {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// let cursor = cursor(&Screen::default());
|
||||||
/// let cursor = crossterm.cursor();
|
|
||||||
///
|
///
|
||||||
/// // Move the cursor to position 3 times to the down in the terminal
|
/// // Move the cursor to position 3 times to the down in the terminal
|
||||||
/// cursor.move_down(3);
|
/// cursor.move_down(3);
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
pub fn move_down(&mut self, count: u16) -> &mut TerminalCursor {
|
pub fn move_down(&mut self, count: u16) -> &mut TerminalCursor {
|
||||||
@ -148,8 +141,7 @@ impl TerminalCursor {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// let cursor = cursor(&Screen::default());
|
||||||
/// let cursor = crossterm.cursor();
|
|
||||||
///
|
///
|
||||||
/// // Move the cursor to position 3 times to the left in the terminal
|
/// // Move the cursor to position 3 times to the left in the terminal
|
||||||
/// cursor.move_left(3);
|
/// cursor.move_left(3);
|
||||||
@ -168,9 +160,7 @@ impl TerminalCursor {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// let cursor = cursor(&Screen::default());
|
||||||
/// let cursor = crossterm.cursor();
|
|
||||||
///
|
|
||||||
/// cursor.safe_position();
|
/// cursor.safe_position();
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
@ -186,9 +176,7 @@ impl TerminalCursor {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// let cursor = cursor(&Screen::default());
|
||||||
/// let cursor = crossterm.cursor();
|
|
||||||
///
|
|
||||||
/// cursor.reset_position();
|
/// cursor.reset_position();
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
@ -202,9 +190,7 @@ impl TerminalCursor {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// let cursor = cursor(&Screen::default());
|
||||||
/// let cursor = crossterm.cursor();
|
|
||||||
///
|
|
||||||
/// cursor.hide();
|
/// cursor.hide();
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
@ -218,9 +204,7 @@ impl TerminalCursor {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// let cursor = cursor(&Screen::default());
|
||||||
/// let cursor = crossterm.cursor();
|
|
||||||
///
|
|
||||||
/// cursor.show();
|
/// cursor.show();
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
@ -236,9 +220,7 @@ impl TerminalCursor {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// let cursor = cursor(&Screen::default());
|
||||||
/// let cursor = crossterm.cursor();
|
|
||||||
///
|
|
||||||
/// cursor.blink(true);
|
/// cursor.blink(true);
|
||||||
/// cursor.blink(false);
|
/// cursor.blink(false);
|
||||||
///
|
///
|
||||||
@ -249,6 +231,7 @@ impl TerminalCursor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get an TerminalCursor implementation whereon cursor related actions can be performed.
|
/// 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 cursor(screen_manager: &Screen) -> TerminalCursor {
|
pub fn cursor(screen_manager: &Screen) -> TerminalCursor {
|
||||||
TerminalCursor::new(&screen_manager.stdout)
|
TerminalCursor::new(&screen_manager.stdout)
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,6 @@ pub trait ITerminalCursor {
|
|||||||
fn hide(&self, screen_manager: &Arc<Stdout>);
|
fn hide(&self, screen_manager: &Arc<Stdout>);
|
||||||
/// Show the terminal cursor
|
/// Show the terminal cursor
|
||||||
fn show(&self, screen_manager: &Arc<Stdout>);
|
fn show(&self, screen_manager: &Arc<Stdout>);
|
||||||
/// enable or disable the blinking of the cursor.
|
/// Enable or disable the blinking of the cursor.
|
||||||
fn blink(&self, blink: bool, screen_manager: &Arc<Stdout>);
|
fn blink(&self, blink: bool, screen_manager: &Arc<Stdout>);
|
||||||
}
|
}
|
||||||
|
@ -7,18 +7,16 @@ use super::*;
|
|||||||
|
|
||||||
/// Struct that stores an specific platform implementation for input related actions.
|
/// Struct that stores an specific platform implementation for input related actions.
|
||||||
///
|
///
|
||||||
/// Check `/examples/version/input` the examples folder on github for more info.
|
/// Check `/examples/input` the examples folder on github for more info.
|
||||||
///
|
///
|
||||||
/// #Example
|
/// #Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// extern crate crossterm;
|
/// extern crate crossterm;
|
||||||
/// use self::crossterm::Crossterm;
|
/// use self::crossterm::input::input;
|
||||||
///
|
|
||||||
/// let crossterm = Crossterm::new();
|
|
||||||
/// let input = crossterm.input();
|
|
||||||
///
|
///
|
||||||
|
/// let input = input(&Screen::default());
|
||||||
/// let result = input.read_line();
|
/// let result = input.read_line();
|
||||||
/// let pressed_char = input.read_char();
|
/// let pressed_char = input.read_char();
|
||||||
///
|
///
|
||||||
@ -48,8 +46,8 @@ impl TerminalInput{
|
|||||||
/// #Example
|
/// #Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// let crossterm = Crossterm::new();
|
///
|
||||||
/// match crossterm.input().read_line() {
|
/// match input(&Screen::default()).read_line() {
|
||||||
/// Ok(s) => println!("string typed: {}", s),
|
/// Ok(s) => println!("string typed: {}", s),
|
||||||
/// Err(e) => println!("error: {}", e),
|
/// Err(e) => println!("error: {}", e),
|
||||||
/// }
|
/// }
|
||||||
@ -64,11 +62,11 @@ impl TerminalInput{
|
|||||||
/// #Example
|
/// #Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// let crossterm = Crossterm::new();
|
///
|
||||||
/// match crossterm.input().read_char() {
|
/// match crossterm.input(&Screen::default()).read_char() {
|
||||||
/// Ok(c) => println!("character pressed: {}", c),
|
/// Ok(c) => println!("character pressed: {}", c),
|
||||||
/// Err(e) => println!("error: {}", e),
|
/// Err(e) => println!("error: {}", e),
|
||||||
// }
|
/// }
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
pub fn read_char(&self) -> io::Result<char> {
|
pub fn read_char(&self) -> io::Result<char> {
|
||||||
@ -80,12 +78,14 @@ impl TerminalInput{
|
|||||||
/// #Example
|
/// #Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// let crossterm = Crossterm::new();
|
///
|
||||||
|
/// use crossterm::{Crossterm, Screen}
|
||||||
///
|
///
|
||||||
/// // we need to enable raw mode otherwise the characters will be outputted by default before we are able to read them.
|
/// // we need to enable raw mode otherwise the characters will be outputted by default before we are able to read them.
|
||||||
/// crossterm.enable_raw_mode();
|
/// let screen = Screen::new(true);
|
||||||
|
/// let crossterm = Crossterm::new();
|
||||||
///
|
///
|
||||||
/// let mut stdin = crossterm.input().read_async().bytes();
|
/// let mut stdin = crossterm.input(&screen).read_async().bytes();
|
||||||
///
|
///
|
||||||
/// for i in 0..100 {
|
/// for i in 0..100 {
|
||||||
///
|
///
|
||||||
@ -112,13 +112,14 @@ impl TerminalInput{
|
|||||||
/// #Example
|
/// #Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// let crossterm = Crossterm::new();
|
|
||||||
/// let input = crossterm.input();
|
|
||||||
/// let terminal = crossterm.terminal();
|
|
||||||
/// let mut cursor = crossterm.cursor();
|
|
||||||
///
|
|
||||||
/// // we need to enable raw mode otherwise the characters will be outputted by default before we are able to read them.
|
/// // we need to enable raw mode otherwise the characters will be outputted by default before we are able to read them.
|
||||||
/// crossterm.enable_raw_mode();
|
/// let screen = Screen::new(true);
|
||||||
|
///
|
||||||
|
/// let crossterm = Crossterm::new();
|
||||||
|
/// let input = crossterm.input(&screen);
|
||||||
|
/// let terminal = crossterm.terminal(&screen);
|
||||||
|
/// let mut cursor = crossterm.cursor(&screen);
|
||||||
|
///
|
||||||
///
|
///
|
||||||
/// let mut stdin = input.read_until_async(b'\r').bytes();
|
/// let mut stdin = input.read_until_async(b'\r').bytes();
|
||||||
///
|
///
|
||||||
@ -149,6 +150,7 @@ impl TerminalInput{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get an Terminal Input implementation whereon input related actions can be performed.
|
/// 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 input(stdout: &Screen) -> TerminalInput {
|
pub fn input(stdout: &Screen) -> TerminalInput {
|
||||||
return TerminalInput::new(&stdout.stdout);
|
return TerminalInput::new(&stdout.stdout);
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ use self::windows_input::WindowsInput;
|
|||||||
pub use self::input::{input, TerminalInput};
|
pub use self::input::{input, TerminalInput};
|
||||||
use super::Stdout;
|
use super::Stdout;
|
||||||
|
|
||||||
use std::io::{self, Read};
|
use std::io::{self, Read, Error, ErrorKind};
|
||||||
use std::sync::{mpsc, Arc};
|
use std::sync::{mpsc, Arc};
|
||||||
use Screen;
|
use Screen;
|
||||||
|
|
||||||
@ -60,13 +60,13 @@ impl Read for AsyncReader {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.recv.try_recv() {
|
match self.recv.try_iter().next() {
|
||||||
Ok(Ok(b)) => {
|
Some(Ok(value)) => {
|
||||||
buf[total] = b;
|
buf[total] = value;
|
||||||
total += 1;
|
total += 1;
|
||||||
}
|
},
|
||||||
Ok(Err(e)) => return Err(e),
|
_ => return Err(Error::new(ErrorKind::Other, "No characters pressed.")),
|
||||||
Err(_) => break,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,8 +13,8 @@ use Screen;
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// use crossterm::{Screen, Crossterm}
|
||||||
/// let colored_terminal = crossterm.color();
|
/// let colored_terminal = crossterm.color(&Screen::default());
|
||||||
///
|
///
|
||||||
/// // set foreground color
|
/// // set foreground color
|
||||||
/// colored_terminal.set_fg(Color::Red);
|
/// colored_terminal.set_fg(Color::Red);
|
||||||
@ -52,8 +52,7 @@ impl<'terminal> TerminalColor {
|
|||||||
/// #Example
|
/// #Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// let crossterm = Crossterm::new();
|
/// let colored_terminal = crossterm.color(&Screen::default());
|
||||||
/// let colored_terminal = crossterm.color();
|
|
||||||
///
|
///
|
||||||
/// // Set foreground color of the font
|
/// // Set foreground color of the font
|
||||||
/// colored_terminal.set_fg(Color::Red);
|
/// colored_terminal.set_fg(Color::Red);
|
||||||
@ -71,8 +70,7 @@ impl<'terminal> TerminalColor {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// let colored_terminal = crossterm.color(&Screen::default());
|
||||||
/// let colored_terminal = crossterm.color();
|
|
||||||
///
|
///
|
||||||
/// // Set background color of the font
|
/// // Set background color of the font
|
||||||
/// colored_terminal.set_bg(Color::Red);
|
/// colored_terminal.set_bg(Color::Red);
|
||||||
@ -89,9 +87,7 @@ impl<'terminal> TerminalColor {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// let colored_terminal = crossterm.color(&Screen::default());
|
||||||
/// let colored_terminal = crossterm.color();
|
|
||||||
///
|
|
||||||
/// colored_terminal.reset();
|
/// colored_terminal.reset();
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
@ -117,6 +113,7 @@ impl<'terminal> TerminalColor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get an Terminal Color implementation whereon color related actions can be performed.
|
/// 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 color(screen: &Screen) -> TerminalColor {
|
pub fn color(screen: &Screen) -> TerminalColor {
|
||||||
TerminalColor::new(&screen.stdout)
|
TerminalColor::new(&screen.stdout)
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,26 @@ pub trait ITerminalColor {
|
|||||||
fn color_value(&self, color: Color, color_type: ColorType) -> String;
|
fn color_value(&self, color: Color, color_type: ColorType) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This could be used to style an Displayable with colors and attributes.
|
||||||
|
///
|
||||||
|
/// #Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
///
|
||||||
|
/// use crossterm::Screen;
|
||||||
|
///
|
||||||
|
/// // get an styled object which could be painted to the terminal.
|
||||||
|
/// let styled_object = style("Some Blue colored text on black background").with(Color::Blue).on(Color::Black);
|
||||||
|
///
|
||||||
|
/// // create an default screen.
|
||||||
|
/// let screen = Screen::default();
|
||||||
|
///
|
||||||
|
/// // print the styled font * times to the current screen.
|
||||||
|
/// for i in 1..10
|
||||||
|
/// {
|
||||||
|
/// styled_object.paint(&screen);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub fn style<D>(val: D) -> StyledObject<D>
|
pub fn style<D>(val: D) -> StyledObject<D>
|
||||||
where
|
where
|
||||||
D: Display, {
|
D: Display, {
|
||||||
@ -105,12 +125,14 @@ pub enum ColorType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a str> for Color {
|
impl<'a> From<&'a str> for Color {
|
||||||
|
/// Get an color from an &str like `Color::from("blue")`
|
||||||
fn from(src: &str) -> Self {
|
fn from(src: &str) -> Self {
|
||||||
src.parse().unwrap_or(Color::White)
|
src.parse().unwrap_or(Color::White)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for Color {
|
impl From<String> for Color {
|
||||||
|
/// Get an color from an &str like `Color::from(String::from(blue))`
|
||||||
fn from(src: String) -> Self {
|
fn from(src: String) -> Self {
|
||||||
src.parse().unwrap_or(Color::White)
|
src.parse().unwrap_or(Color::White)
|
||||||
}
|
}
|
||||||
@ -119,6 +141,7 @@ impl From<String> for Color {
|
|||||||
impl FromStr for Color {
|
impl FromStr for Color {
|
||||||
type Err = ();
|
type Err = ();
|
||||||
|
|
||||||
|
/// Convert a string to an Color value
|
||||||
fn from_str(src: &str) -> Result<Self, Self::Err> {
|
fn from_str(src: &str) -> Result<Self, Self::Err> {
|
||||||
let src = src.to_lowercase();
|
let src = src.to_lowercase();
|
||||||
|
|
||||||
|
@ -24,19 +24,21 @@ impl<D: Display> StyledObject<D> {
|
|||||||
/// #Example
|
/// #Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// extern crate crossterm;
|
/// use self::crossterm::style::{style,Color};
|
||||||
/// use self::crossterm::style::{paint,Color};
|
|
||||||
///
|
///
|
||||||
/// // create an styled object with the foreground color red.
|
/// // create an styled object with the foreground color red.
|
||||||
/// let styledobject = paint("I am colored red").with(Color::Red);
|
/// let styledobject = style("Some colored text").with(Color::Blue);
|
||||||
/// // create an styled object with the foreground color blue.
|
/// // create an styled object with the foreground color blue.
|
||||||
/// let styledobject1 = paint("I am colored blue").with(Color::Blue);
|
/// let styledobject1 = style("Some colored text").with(Color::Blue);
|
||||||
|
///
|
||||||
|
/// let screen = Screen::default();
|
||||||
///
|
///
|
||||||
/// // print the styledobject to see the result
|
/// // print the styledobject to see the result
|
||||||
/// println!("{}", styledobject);
|
/// styledobject.paint(&screen);
|
||||||
/// println!("{}", styledobject1);
|
/// styledobject1.paint(&screen);
|
||||||
|
///
|
||||||
/// // print an styled object directly.
|
/// // print an styled object directly.
|
||||||
/// println!("{}", paint("I am colored green").with(Color::Green));
|
/// style("Some colored text").with(Color::Blue).paint(&screen);
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
pub fn with(mut self, foreground_color: Color) -> StyledObject<D> {
|
pub fn with(mut self, foreground_color: Color) -> StyledObject<D> {
|
||||||
@ -49,19 +51,21 @@ impl<D: Display> StyledObject<D> {
|
|||||||
/// #Example
|
/// #Example
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// extern crate crossterm;
|
/// use self::crossterm::style::{style,Color};
|
||||||
/// use self::crossterm::style::{paint,Color};
|
|
||||||
///
|
///
|
||||||
/// // create an styled object with the background color red.
|
/// // create an styled object with the background color red.
|
||||||
/// let styledobject = paint("I am colored red").on(Color::Red);
|
/// let styledobject = style("Some colored text").on(Color::Blue);
|
||||||
/// // create an styled object with the background color blue.
|
/// // create an styled object with the foreground color blue.
|
||||||
/// let styledobject1 = paint("I am colored blue").on(Color::Blue);
|
/// let styledobject1 = style("Some colored text").on(Color::Blue);
|
||||||
|
///
|
||||||
|
/// let screen = Screen::default();
|
||||||
|
///
|
||||||
|
/// // print the styledobject to see the result
|
||||||
|
/// styledobject.paint(&screen);
|
||||||
|
/// styledobject1.paint(&screen);
|
||||||
///
|
///
|
||||||
/// // print the styledobjects
|
|
||||||
/// println!("{}", styledobject);
|
|
||||||
/// println!("{}", styledobject1);
|
|
||||||
/// // print an styled object directly.
|
/// // print an styled object directly.
|
||||||
/// println!("{}", paint("I am colored green").on(Color::Green))
|
/// style("Some colored text").on(Color::Blue).paint(&screen);
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
pub fn on(mut self, background_color: Color) -> StyledObject<D> {
|
pub fn on(mut self, background_color: Color) -> StyledObject<D> {
|
||||||
@ -76,9 +80,9 @@ impl<D: Display> StyledObject<D> {
|
|||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// extern crate crossterm;
|
/// extern crate crossterm;
|
||||||
/// use self::crossterm::style::{paint,Attribute};
|
/// use self::crossterm::style::{style,Attribute};
|
||||||
///
|
///
|
||||||
/// println!("{}", paint("Bold").attr(Attribute::Bold));
|
/// style("Some colored text").attr(Attribute::Bold).paint(&screen);
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
@ -142,6 +146,14 @@ impl<D: Display> StyledObject<D> {
|
|||||||
self.attr(Attribute::CrossedOut)
|
self.attr(Attribute::CrossedOut)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This could be used to paint the styled object on the screen. Pass a refrence to the screen whereon you want to perform the painting.
|
||||||
|
///
|
||||||
|
/// ``` rust
|
||||||
|
/// style("Some colored text")
|
||||||
|
/// .with(Color::Blue)
|
||||||
|
/// .on(Color::Black)
|
||||||
|
/// .paint(&screen);
|
||||||
|
/// ```
|
||||||
pub fn paint(&self, screen: &Screen)
|
pub fn paint(&self, screen: &Screen)
|
||||||
{
|
{
|
||||||
let mut colored_terminal = super::super::super::style::color::color(&screen);
|
let mut colored_terminal = super::super::super::style::color::color(&screen);
|
||||||
|
@ -50,7 +50,10 @@ impl ITerminal for AnsiTerminal {
|
|||||||
screen_manager.write_string(format!(csi!("8;{};{}t"), width, height));
|
screen_manager.write_string(format!(csi!("8;{};{}t"), width, height));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exit(&self) {
|
fn exit(&self,screen_manager: &Arc<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(screen_manager.clone());
|
||||||
|
drop(screen);
|
||||||
functions::exit_terminal();
|
functions::exit_terminal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,5 +44,5 @@ pub trait ITerminal {
|
|||||||
/// Resize terminal to the given width and height.
|
/// Resize terminal to the given width and height.
|
||||||
fn set_size(&self, width: i16, height: i16, screen_manager: &Arc<Stdout>);
|
fn set_size(&self, width: i16, height: i16, screen_manager: &Arc<Stdout>);
|
||||||
/// Close the current terminal
|
/// Close the current terminal
|
||||||
fn exit(&self);
|
fn exit(&self,screen_manager: &Arc<Stdout>);
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,9 @@ use std::io::Write;
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// use crossterm::terminal::terminal;
|
||||||
/// let term = crossterm.terminal();
|
///
|
||||||
|
/// let term = terminal();
|
||||||
///
|
///
|
||||||
/// term.scroll_down(5);
|
/// term.scroll_down(5);
|
||||||
/// term.scroll_up(4);
|
/// term.scroll_up(4);
|
||||||
@ -51,8 +52,7 @@ impl Terminal {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// let term = terminal();
|
||||||
/// let term = crossterm.terminal();
|
|
||||||
///
|
///
|
||||||
/// // clear all cells in terminal.
|
/// // clear all cells in terminal.
|
||||||
/// term.clear(terminal::ClearType::All);
|
/// term.clear(terminal::ClearType::All);
|
||||||
@ -76,12 +76,7 @@ impl Terminal {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// extern crate crossterm;
|
/// let term = terminal();
|
||||||
/// use crossterm::terminal;
|
|
||||||
/// use crossterm::Context;
|
|
||||||
///
|
|
||||||
/// let crossterm = Crossterm::new();
|
|
||||||
/// let term = crossterm.terminal();
|
|
||||||
///
|
///
|
||||||
/// let size = term.terminal_size();
|
/// let size = term.terminal_size();
|
||||||
/// println!("{:?}", size);
|
/// println!("{:?}", size);
|
||||||
@ -97,8 +92,7 @@ impl Terminal {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// let term = terminal();
|
||||||
/// let term = crossterm.terminal();
|
|
||||||
///
|
///
|
||||||
/// // scroll up by 5 lines
|
/// // scroll up by 5 lines
|
||||||
/// let size = term.scroll_up(5);
|
/// let size = term.scroll_up(5);
|
||||||
@ -114,8 +108,7 @@ impl Terminal {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// let term = terminal();
|
||||||
/// let term = crossterm.terminal();
|
|
||||||
///
|
///
|
||||||
/// // scroll down by 5 lines
|
/// // scroll down by 5 lines
|
||||||
/// let size = term.scroll_down(5);
|
/// let size = term.scroll_down(5);
|
||||||
@ -131,8 +124,7 @@ impl Terminal {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// let term = terminal();
|
||||||
/// let term = crossterm.terminal();
|
|
||||||
///
|
///
|
||||||
/// // Set of the size to X: 10 and Y: 10
|
/// // Set of the size to X: 10 and Y: 10
|
||||||
/// let size = term.set_size(10,10);
|
/// let size = term.set_size(10,10);
|
||||||
@ -148,14 +140,13 @@ impl Terminal {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// let term = terminal();
|
||||||
/// let term = crossterm.terminal();
|
|
||||||
///
|
///
|
||||||
/// let size = term.exit();
|
/// let size = term.exit();
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
pub fn exit(&self) {
|
pub fn exit(&self) {
|
||||||
self.terminal.exit();
|
self.terminal.exit(&self.screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write any displayable content to the current terminal screen.
|
/// Write any displayable content to the current terminal screen.
|
||||||
@ -164,8 +155,7 @@ impl Terminal {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
///
|
///
|
||||||
/// let crossterm = Crossterm::new();
|
/// let term = terminal();
|
||||||
/// let term = crossterm.terminal();
|
|
||||||
///
|
///
|
||||||
/// let size = term.write("Some text \n Some text on new line");
|
/// let size = term.write("Some text \n Some text on new line");
|
||||||
///
|
///
|
||||||
@ -178,7 +168,8 @@ impl Terminal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an terminal implementation whereon terminal related actions could performed
|
/// Get an terminal implementation whereon terminal related actions could performed.
|
||||||
|
/// Pass the reference to any screen you want this type to perform actions on.
|
||||||
pub fn terminal(screen: &Screen) -> Terminal {
|
pub fn terminal(screen: &Screen) -> Terminal {
|
||||||
Terminal::new(&screen.stdout)
|
Terminal::new(&screen.stdout)
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,10 @@ impl ITerminal for WinApiTerminal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exit(&self) {
|
fn exit(&self, screen_manager: &Arc<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(screen_manager.clone());
|
||||||
|
drop(screen);
|
||||||
functions::exit_terminal();
|
functions::exit_terminal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ use std::sync::{Arc,Mutex};
|
|||||||
use std::io::{self, Read, Write,Stdout, stdout};
|
use std::io::{self, Read, Write,Stdout, stdout};
|
||||||
use std::str::from_utf8;
|
use std::str::from_utf8;
|
||||||
|
|
||||||
/// This struct is an ANSI escape code implementation for screen related actions.
|
/// This struct is a wrapper for `Stdout`
|
||||||
pub struct AnsiStdout {
|
pub struct AnsiStdout {
|
||||||
pub handle: Stdout,
|
pub handle: Stdout,
|
||||||
}
|
}
|
||||||
@ -35,7 +35,6 @@ impl IStdout for AnsiStdout {
|
|||||||
let out = &self.handle;
|
let out = &self.handle;
|
||||||
let mut handle = out.lock();
|
let mut handle = out.lock();
|
||||||
handle.flush();
|
handle.flush();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,22 +1,4 @@
|
|||||||
//! This module provides one place to work with the screen.
|
//! This module provides a way to work with an handle to an screen on different platforms.
|
||||||
//!
|
|
||||||
//! In Rust we can call `stdout()` to get an handle to the current default console handle.
|
|
||||||
//! For example when in unix systems you want to print something to the main screen you can use the following code:
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//! write!(std::io::stdout(), "{}", "some text").
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! But things change when we are in alternate screen modes.
|
|
||||||
//! We can not simply use `stdout()` to get a handle to the alternate screen, since this call returns the current default console handle (mainscreen).
|
|
||||||
//!
|
|
||||||
//! Instead we need to store an handle to the screen output.
|
|
||||||
//! This handle could be used to put into alternate screen modes and back into main screen modes.
|
|
||||||
//! Through this stored handle Crossterm can execute its command on the current screen whether it be alternate screen or main screen.
|
|
||||||
//!
|
|
||||||
//! For unix systems we store the handle gotten from `stdout()` for windows systems that are not supporting ANSI escape codes we store WinApi `HANDLE` struct witch will provide access to the current screen.
|
|
||||||
//!
|
|
||||||
//! This is the reason why this module exits: it is to provide access to the current terminal screen whether it will be the alternate screen and main screen.
|
|
||||||
|
|
||||||
mod stdout;
|
mod stdout;
|
||||||
|
|
||||||
@ -35,8 +17,8 @@ use std::io;
|
|||||||
|
|
||||||
use super::{functions};
|
use super::{functions};
|
||||||
|
|
||||||
/// This trait defines the actions that could be preformed on the current screen.
|
/// This trait defines represents an stdout of an screen.
|
||||||
/// This trait can be implemented so that an concrete implementation of the IScreenManager can forfill
|
/// This trait can be implemented so that an concrete implementation of the IStdout can forfill
|
||||||
/// the wishes to work on an specific platform.
|
/// the wishes to work on an specific platform.
|
||||||
///
|
///
|
||||||
/// ## For example:
|
/// ## For example:
|
||||||
@ -44,7 +26,7 @@ use super::{functions};
|
|||||||
/// This trait is implemented for `WINAPI` (Windows specific) and `ANSI` (Unix specific),
|
/// This trait is implemented for `WINAPI` (Windows specific) and `ANSI` (Unix specific),
|
||||||
/// so that color related actions can be preformed on both unix and windows systems.
|
/// so that color related actions can be preformed on both unix and windows systems.
|
||||||
pub trait IStdout {
|
pub trait IStdout {
|
||||||
/// Write a &str to the current stdout.
|
/// 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.
|
/// Write [u8] buffer to console.
|
||||||
fn write(&self, buf: &[u8]) -> io::Result<usize>;
|
fn write(&self, buf: &[u8]) -> io::Result<usize>;
|
||||||
@ -52,6 +34,5 @@ pub trait IStdout {
|
|||||||
fn flush(&self) -> io::Result<()>;
|
fn flush(&self) -> io::Result<()>;
|
||||||
|
|
||||||
fn as_any(&self) -> &Any;
|
fn as_any(&self) -> &Any;
|
||||||
|
|
||||||
fn as_any_mut(&mut self) -> &mut Any;
|
fn as_any_mut(&mut self) -> &mut Any;
|
||||||
}
|
}
|
||||||
|
@ -23,13 +23,17 @@ use super::*;
|
|||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
use std::default::Default;
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
use winapi::um::winnt::HANDLE;
|
use winapi::um::winnt::HANDLE;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Struct that stores an specific platform implementation for screen related actions.
|
/// Struct that is an handle to an terminal screen.
|
||||||
|
/// This handle could be used to write to the current screen
|
||||||
|
///
|
||||||
|
/// 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 Stdout {
|
pub struct Stdout {
|
||||||
screen_manager: Box<IStdout + Send>,
|
screen_manager: Box<IStdout + Send>,
|
||||||
pub is_in_raw_mode:bool,
|
pub is_in_raw_mode:bool,
|
||||||
@ -67,6 +71,7 @@ impl Stdout {
|
|||||||
self.screen_manager.write_str(string)
|
self.screen_manager.write_str(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write buffer to the screen
|
||||||
pub fn write_buf(&self, buf: &[u8]) -> io::Result<usize> {
|
pub fn write_buf(&self, buf: &[u8]) -> io::Result<usize> {
|
||||||
self.screen_manager.write(buf)
|
self.screen_manager.write(buf)
|
||||||
}
|
}
|
||||||
@ -74,8 +79,24 @@ impl Stdout {
|
|||||||
pub fn as_any(&self) -> &Any {
|
pub fn as_any(&self) -> &Any {
|
||||||
self.screen_manager.as_any()
|
self.screen_manager.as_any()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_any_mut(&mut self) -> &mut Any {
|
pub fn as_any_mut(&mut self) -> &mut Any {
|
||||||
self.screen_manager.as_any_mut()
|
self.screen_manager.as_any_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Stdout
|
||||||
|
{
|
||||||
|
/// Get the default handle to the current screen.
|
||||||
|
fn default() -> Self {
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
let screen_manager = functions::get_module::<Box<IStdout + Send>>(
|
||||||
|
Box::from(WinApiStdout::new()),
|
||||||
|
Box::from(AnsiStdout::new()),
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
let screen_manager = Box::from(AnsiStdout::new()) as Box<IStdout + Send>;
|
||||||
|
|
||||||
|
Stdout { screen_manager , is_in_raw_mode: false}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -8,7 +8,7 @@ use std::any::Any;
|
|||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// This struct is an WINAPI implementation for screen related actions.
|
/// This struct is a wrapper for WINAPI `HANDLE`
|
||||||
pub struct WinApiStdout {
|
pub struct WinApiStdout {
|
||||||
pub handle: HANDLE,
|
pub handle: HANDLE,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user