diff --git a/examples/bin.rs b/examples/bin.rs index 2292925..a0fbd51 100644 --- a/examples/bin.rs +++ b/examples/bin.rs @@ -1,26 +1,41 @@ extern crate crossterm; -use self::crossterm::terminal_style::{paint,Color}; -use self::crossterm::terminal_cursor::cursor; -use std::io::Write; +use self::crossterm::terminal_style::*; +use self::crossterm::terminal_cursor::*; +use self::crossterm::terminal::*; +use std::io::{stdin, stdout, Write}; +fn main() { + terminal::get().clear(ClearType::All); -fn main() -{ - cursor::get().move_down(1); - print!("2"); - std::io::stdout().flush().expect("asdf"); + for y in 0..21 { + for x in 0..21 { + if (x == 0 || y == 0) || (x == 20 || y == 20) { + print!("{}", paint("■").with(Color::Red)); + } else { + print!("{}", paint(" ").with(Color::Blue).on(Color::Blue)); + } + } + println!(); + } - cursor::get().move_down(1); - print!("3"); - std::io::stdout().flush().expect("asdf"); + let mut curs = cursor::get(); + { + curs.goto(10, 10); + curs.print("@"); + curs.move_up(1); + curs.print("1"); - cursor::get().move_down(1); - print!("4"); - std::io::stdout().flush().expect("asdf"); + curs.move_right(1); + curs.print("2"); - cursor::get().move_down(1); - print!("5"); - std::io::stdout().flush().expect("asdf"); + curs.move_down(1); + curs.print("3"); -} \ No newline at end of file + curs.move_left(2); + curs.print("4"); + + curs.goto(0, 30); + println!("{:?}", curs.pos()); + } +} diff --git a/examples/cursor_example.rs b/examples/cursor_example.rs index e737699..4db5a26 100644 --- a/examples/cursor_example.rs +++ b/examples/cursor_example.rs @@ -1,8 +1,8 @@ -extern crate crossterm; +// extern crate crossterm; -use self::crossterm::cursor; +// use self::crossterm::cursor; -pub fn goto(x: i16, y: i16) -{ - cursor::get().goto(x,y); -} \ No newline at end of file +// pub fn goto(x: i16, y: i16) +// { +// cursor::get().goto(x,y); +// } diff --git a/src/kernel/linux_kernel/mod.rs b/src/kernel/linux_kernel/mod.rs new file mode 100644 index 0000000..a566381 --- /dev/null +++ b/src/kernel/linux_kernel/mod.rs @@ -0,0 +1 @@ +pub mod terminal; diff --git a/src/kernel/linux_kernel/terminal.rs b/src/kernel/linux_kernel/terminal.rs new file mode 100644 index 0000000..f0244be --- /dev/null +++ b/src/kernel/linux_kernel/terminal.rs @@ -0,0 +1,28 @@ +use std::{io, mem}; + +use super::cvt; +use super::libc; + +#[repr(C)] +struct TermSize { + row: libc::c_ushort, + col: libc::c_ushort, + _x: libc::c_ushort, + _y: libc::c_ushort, +} + +pub fn terminal_size() -> Option<(u16, u16)> { + unsafe { + if libc::isatty(libc::STDOUT_FILENO) != 1 { + return None; + } + + let mut winsize: libc::winsize = mem::zeroed(); + libc::ioctl(libc::STDOUT_FILENO, libc::TIOCGWINSZ, &mut winsize); + if winsize.ws_row > 0 && winsize.ws_col > 0 { + Some((winsize.ws_row as u16, winsize.ws_col as u16)) + } else { + None + } + } +} diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index 02b260d..2ae7b25 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -1,4 +1,4 @@ #[cfg(windows)] pub mod windows_kernel; -#[cfg(linux)] -pub mod linux_kernel; \ No newline at end of file +#[cfg(unix)] +pub mod linux_kernel; diff --git a/src/kernel/windows_kernel/ansi_support.rs b/src/kernel/windows_kernel/ansi_support.rs index b487a04..f16e43e 100644 --- a/src/kernel/windows_kernel/ansi_support.rs +++ b/src/kernel/windows_kernel/ansi_support.rs @@ -1,29 +1,17 @@ -extern crate kernel32; -extern crate winapi; - -use self::winapi::HANDLE; - +use winapi; +use kernel32; use super::handle; -/// Enables ansi for windows terminals. -pub fn enable_ansi_support() -> Result<(), u64> -{ - const ENABLE_ANSI_CODES: u32 = 7; - - let std_out_handle = handle::get_output_handle(); - - match std_out_handle - { - Some(handle) => { set_console_mode(handle, ENABLE_ANSI_CODES); Ok(()) }, - None => return Err(0) - } +/// Enables ansi for windows terminals. +pub fn enable_ansi_support() { + let enable_ansi_code: u32 = 7; + let output_handle = handle::get_output_handle(); + set_console_mode(output_handle, enable_ansi_code) } /// Set the console mode of the windows terminal. -fn set_console_mode(handle: HANDLE, enable_ansi_code: u32) -{ - unsafe - { - kernel32::SetConsoleMode(handle, enable_ansi_code); +fn set_console_mode(handle: winapi::HANDLE, console_mode: u32) { + unsafe { + kernel32::SetConsoleMode(handle, console_mode); } } diff --git a/src/kernel/windows_kernel/color.rs b/src/kernel/windows_kernel/color.rs index 3918e9b..31d9d06 100644 --- a/src/kernel/windows_kernel/color.rs +++ b/src/kernel/windows_kernel/color.rs @@ -1,138 +1,117 @@ -extern crate winapi; -extern crate kernel32; - -use super::handle; -use super::kernel; +use winapi; +use kernel32; +use super::{handle, kernel}; use terminal_style as style; /// This will set the forground color by the given winapi color value parsed to u16. -pub fn set_fg_color(fg_color: u16) -{ - if let Some(buffer_info) = kernel::get_console_screen_buffer_info() - { - // Notice that the color values are stored in wAttribute. - // So wee need to use bitwise operators to check if the values exists or to get current console colors. - let mut color: u16; - let attrs = buffer_info.wAttributes; - let bg_color = attrs & 0x0070; - color = fg_color | bg_color; +pub fn set_fg_color(fg_color: u16) { + let csbi = kernel::get_console_screen_buffer_info(); - // background intensity is a seperate value in attrs, - // wee need to check if this was applied to the current bg color. - if (attrs & winapi::BACKGROUND_INTENSITY as u16) != 0 - { - color = color | winapi::BACKGROUND_INTENSITY as u16; - } + // Notice that the color values are stored in wAttribute. + // So wee need to use bitwise operators to check if the values exists or to get current console colors. + let mut color: u16; + let attrs = csbi.wAttributes; + let bg_color = attrs & 0x0070; + color = fg_color | bg_color; - set_console_text_attribute(color); + // background intensity is a seperate value in attrs, + // wee need to check if this was applied to the current bg color. + if (attrs & winapi::BACKGROUND_INTENSITY as u16) != 0 { + color = color | winapi::BACKGROUND_INTENSITY as u16; } -} + + set_console_text_attribute(color); +} /// This will set the forground color by the given winapi color value parsed to u16. -pub fn set_bg_color(bg_color: u16) -{ - if let Some(buffer_info) = kernel::get_console_screen_buffer_info() - { - // Notice that the color values are stored in wAttribute. - // So wee need to use bitwise operators to check if the values exists or to get current console colors. - let mut color: u16; - let attrs = buffer_info.wAttributes; - let fg_color = attrs & 0x0007; - color = fg_color | bg_color; +pub fn set_bg_color(bg_color: u16) { + let csbi = kernel::get_console_screen_buffer_info(); + // Notice that the color values are stored in wAttribute. + // So wee need to use bitwise operators to check if the values exists or to get current console colors. + let mut color: u16; + let attrs = csbi.wAttributes; + let fg_color = attrs & 0x0007; + color = fg_color | bg_color; - // foreground intensity is a seperate value in attrs, - // wee need to check if this was applied to the current fg color. - if (attrs & winapi::FOREGROUND_INTENSITY as u16) != 0 - { - color = color | winapi::FOREGROUND_INTENSITY as u16; - } - set_console_text_attribute(color); + // foreground intensity is a seperate value in attrs, + // wee need to check if this was applied to the current fg color. + if (attrs & winapi::FOREGROUND_INTENSITY as u16) != 0 { + color = color | winapi::FOREGROUND_INTENSITY as u16; } + + set_console_text_attribute(color); } /// This will reset the colors to the value given in u16. -pub fn reset(original_color: u16) -{ +pub fn reset(original_color: u16) { set_console_text_attribute(original_color); } /// This will get the winapi color value from the Color struct -pub fn winapi_color_val(color: style::Color, color_type: style::ColorType) -> u16 -{ - use terminal_style::{ColorType, Color}; +pub fn winapi_color_val(color: style::Color, color_type: style::ColorType) -> u16 { + use terminal_style::{Color, ColorType}; let winapi_color: u32; - let fg_green = winapi::FOREGROUND_GREEN; - let fg_red = winapi::FOREGROUND_RED; - let fg_blue = winapi::FOREGROUND_BLUE; - let fg_intensity = winapi::FOREGROUND_INTENSITY; + let fg_green = winapi::FOREGROUND_GREEN; + let fg_red = winapi::FOREGROUND_RED; + let fg_blue = winapi::FOREGROUND_BLUE; + let fg_intensity = winapi::FOREGROUND_INTENSITY; - let bg_green = winapi::BACKGROUND_GREEN; - let bg_red = winapi::BACKGROUND_RED; - let bg_blue = winapi::BACKGROUND_BLUE; - let bg_intensity = winapi::BACKGROUND_INTENSITY; + let bg_green = winapi::BACKGROUND_GREEN; + let bg_red = winapi::BACKGROUND_RED; + let bg_blue = winapi::BACKGROUND_BLUE; + let bg_intensity = winapi::BACKGROUND_INTENSITY; - match color_type - { - ColorType::Foreground => - { - winapi_color = match color - { - Color::Black => 0, - Color::Red => fg_intensity | fg_red, - Color::DarkRed => fg_red, - Color::Green => fg_intensity | fg_green, - Color::DarkGreen => fg_green, - Color::Yellow => fg_intensity | fg_green | fg_red, - Color::DarkYellow => fg_green | fg_red, - Color::Blue => fg_intensity | fg_blue, - Color::DarkBlue => fg_blue, - Color::Magenta => fg_intensity | fg_red | fg_blue, - Color::DarkMagenta => fg_red | fg_blue, - Color::Cyan => fg_intensity | fg_green | fg_blue, - Color::DarkCyan => fg_green | fg_blue, - Color::Grey => fg_intensity, - Color::White => fg_intensity | fg_red | fg_green | fg_blue, - }; - }, - ColorType::Background => - { - winapi_color = match color - { - Color::Black => 0, - Color::Red => bg_intensity | bg_red, - Color::DarkRed => bg_red, - Color::Green => bg_intensity | bg_green, - Color::DarkGreen => bg_green, - Color::Yellow => bg_intensity | bg_green | bg_red, - Color::DarkYellow => bg_green | bg_red, - Color::Blue => bg_intensity | bg_blue, - Color::DarkBlue => bg_blue, - Color::Magenta => bg_intensity | bg_red | bg_blue, - Color::DarkMagenta => bg_red | bg_blue, - Color::Cyan => bg_intensity | bg_green | bg_blue, - Color::DarkCyan => bg_green | bg_blue, - Color::Grey => bg_intensity, - Color::White => bg_intensity | bg_red | bg_green | bg_blue, - }; - } - }; + match color_type { + ColorType::Foreground => { + winapi_color = match color { + Color::Black => 0, + Color::Red => fg_intensity | fg_red, + Color::DarkRed => fg_red, + Color::Green => fg_intensity | fg_green, + Color::DarkGreen => fg_green, + Color::Yellow => fg_intensity | fg_green | fg_red, + Color::DarkYellow => fg_green | fg_red, + Color::Blue => fg_intensity | fg_blue, + Color::DarkBlue => fg_blue, + Color::Magenta => fg_intensity | fg_red | fg_blue, + Color::DarkMagenta => fg_red | fg_blue, + Color::Cyan => fg_intensity | fg_green | fg_blue, + Color::DarkCyan => fg_green | fg_blue, + Color::Grey => fg_intensity, + Color::White => fg_intensity | fg_red | fg_green | fg_blue, + }; + } + ColorType::Background => { + winapi_color = match color { + Color::Black => 0, + Color::Red => bg_intensity | bg_red, + Color::DarkRed => bg_red, + Color::Green => bg_intensity | bg_green, + Color::DarkGreen => bg_green, + Color::Yellow => bg_intensity | bg_green | bg_red, + Color::DarkYellow => bg_green | bg_red, + Color::Blue => bg_intensity | bg_blue, + Color::DarkBlue => bg_blue, + Color::Magenta => bg_intensity | bg_red | bg_blue, + Color::DarkMagenta => bg_red | bg_blue, + Color::Cyan => bg_intensity | bg_green | bg_blue, + Color::DarkCyan => bg_green | bg_blue, + Color::Grey => bg_intensity, + Color::White => bg_intensity | bg_red | bg_green | bg_blue, + }; + } + }; - winapi_color as u16 + winapi_color as u16 } /// This will set the console attributes by the given value -fn set_console_text_attribute(value: u16) -{ +fn set_console_text_attribute(value: u16) { let output_handle = handle::get_output_handle(); - if let Some(handle) = output_handle - { - unsafe - { - kernel32::SetConsoleTextAttribute(handle, value); - } + unsafe { + kernel32::SetConsoleTextAttribute(output_handle, value); } } - diff --git a/src/kernel/windows_kernel/cursor.rs b/src/kernel/windows_kernel/cursor.rs index 95ca122..aa23aac 100644 --- a/src/kernel/windows_kernel/cursor.rs +++ b/src/kernel/windows_kernel/cursor.rs @@ -1,13 +1,11 @@ -extern crate winapi; -extern crate kernel32; +use winapi; +use kernel32; +use super::{handle, kernel}; +use shared::functions; -use self::winapi::{COORD}; -use super::{handle,kernel}; - -/// These are the movement directions of an cursor +/// These are the movement directions of an cursor #[derive(Debug)] -pub enum CursorDirection -{ +pub enum CursorDirection { Top, Right, Down, @@ -15,79 +13,48 @@ pub enum CursorDirection } /// Set the cursor position to an coordinate (x,y). -pub fn set(x: u16, y:u16) -{ - set_cursor_pos(x as i16,y as i16); +pub fn set(x: u16, y: u16) { + set_cursor_pos(x as i16, y as i16); } /// Get the current cursor x position. -pub fn xpos() -> u16 -{ - if let Some(csbi) = kernel::get_console_screen_buffer_info() - { - csbi.dwCursorPosition.Y as u16 - }else{ - println!("xpos verkeerd"); - 0 - } +pub fn xpos() -> u16 { + let csbi = kernel::get_console_screen_buffer_info(); + csbi.dwCursorPosition.X as u16 } /// Get the current cursor y position. -pub fn ypos() -> u16 -{ - if let Some(csbi) = kernel::get_console_screen_buffer_info() - { - csbi.dwCursorPosition.Y as u16 - }else{ - println!("ypos verkeerd"); - 0 +pub fn ypos() -> u16 { + let csbi = kernel::get_console_screen_buffer_info(); + csbi.dwCursorPosition.Y as u16 +} + +pub fn move_down(count: u16) { + let csbi = kernel::get_console_screen_buffer_info(); + unsafe { + let output_handle = handle::get_output_handle(); + kernel32::SetConsoleCursorPosition( + output_handle, + winapi::COORD { + X: csbi.dwCursorPosition.X, + Y: csbi.dwCursorPosition.Y + count as i16, + }, + ); } } -pub fn move_down(count: u16) -{ - if let Some(buffer) = kernel::get_console_screen_buffer_info() - { - unsafe - { - let handle = kernel32::GetStdHandle(winapi::STD_OUTPUT_HANDLE); - kernel32::SetConsoleCursorPosition(handle, COORD { - X: buffer.dwCursorPosition.X, - Y: buffer.dwCursorPosition.Y + count as i16, - }); - } - } -} - - -// pub fn move_direction(count: i16, cursor_direction: CursorDirection) -// { -// - -// println!("{}, {}, {:?}",x,y, cursor_direction); - -// match cursor_direction -// { -// CursorDirection::Top => set_cursor_pos(x,y - count) , -// CursorDirection::Right => set_cursor_pos(x + count, y) , -// CursorDirection::Down => set_cursor_pos(x, y + count), -// CursorDirection::Left => set_cursor_pos(x - count,y), -// }; -// }else{ -// println!("{}", "Not found"); -// } - -// } - /// Set the cursor position to an coordinate (x,y). -fn set_cursor_pos(x: i16, y: i16) -{ - if let Some(handle) = handle::get_output_handle() - { - unsafe - { - let position = COORD{X: x, Y:y}; - kernel32::SetConsoleCursorPosition(handle, position); +fn set_cursor_pos(x: i16, y: i16) { + functions::is_cursor_out_of_range(x, y); + + let output_handle = handle::get_output_handle(); + let position = winapi::COORD { X: x, Y: y }; + + unsafe { + let success = kernel32::SetConsoleCursorPosition(output_handle, position); + + if success == 0 { + panic!("Cannot set console cursor position"); } } -} \ No newline at end of file +} diff --git a/src/kernel/windows_kernel/handle.rs b/src/kernel/windows_kernel/handle.rs index 2e6c472..96150e4 100644 --- a/src/kernel/windows_kernel/handle.rs +++ b/src/kernel/windows_kernel/handle.rs @@ -1,98 +1,27 @@ -extern crate winapi; -extern crate kernel32; -use std::os::windows::io::{AsRawHandle, RawHandle}; -use self::winapi::{HANDLE, STD_OUTPUT_HANDLE, STD_INPUT_HANDLE}; -use std::mem; +use winapi; +use kernel32; -static mut CONSOLE_INPUT_HANDLE:Option = None; - -static mut CONSOLE_OUTPUT_HANDLE:Option = None; +// static mut CONSOLE_INPUT_HANDLE:Option = None; +static mut CONSOLE_OUTPUT_HANDLE: Option = None; /// Get the std_output_handle of the console -pub fn get_output_handle() -> Option -{ - unsafe - { - // if let Some(handle) = CONSOLE_OUTPUT_HANDLE - // { - // match handle_check(&handle) - // { - // true => { - // CONSOLE_OUTPUT_HANDLE = Some(handle); - // CONSOLE_OUTPUT_HANDLE - // }, - // false => None - // } - - // } else { - let handle = kernel32::GetStdHandle(STD_OUTPUT_HANDLE); - - match handle_check(&handle) - { - true => { - // CONSOLE_OUTPUT_HANDLE = Some(handle); - Some(handle) - }, - false => None - } - } - // } -} - -/// Get the std_input_handle of the console -pub fn get_input_handle() -> Option -{ - unsafe - { - if let Some(handle) = CONSOLE_INPUT_HANDLE - { - match handle_check(&handle) - { - true => { - CONSOLE_INPUT_HANDLE = Some(handle); - CONSOLE_INPUT_HANDLE - }, - false => None - } - } - else - { - let handle = kernel32::GetStdHandle(STD_INPUT_HANDLE); - match handle_check(&handle) - { - true => { - CONSOLE_INPUT_HANDLE = Some(handle); - CONSOLE_INPUT_HANDLE - }, - false => None - } - } - } -} - -pub fn as_raw_handle() -> Option<(HANDLE, winapi::CONSOLE_SCREEN_BUFFER_INFO)> -{ - unsafe - { - let hand = kernel32::GetStdHandle(STD_OUTPUT_HANDLE) as RawHandle; - - let mut csbi: winapi::CONSOLE_SCREEN_BUFFER_INFO = mem::zeroed() ; - - match kernel32::GetConsoleScreenBufferInfo(hand, &mut csbi) - { - 0 => None, - _ => Some((hand, csbi)), +pub fn get_output_handle() -> winapi::HANDLE { + unsafe { + if let Some(handle) = CONSOLE_OUTPUT_HANDLE { + handle + } else { + let handle = kernel32::GetStdHandle(winapi::STD_OUTPUT_HANDLE); + CONSOLE_OUTPUT_HANDLE = Some(handle); + handle } } } /// Checks if the console handle is an invalid handle value. -fn handle_check(handle: &HANDLE) -> bool -{ - if *handle == winapi::INVALID_HANDLE_VALUE - { - false - }else{ +pub fn is_valid_handle(handle: &winapi::HANDLE) -> bool { + if *handle == winapi::INVALID_HANDLE_VALUE { true + } else { + false } } diff --git a/src/kernel/windows_kernel/kernel.rs b/src/kernel/windows_kernel/kernel.rs index 7e43d14..8d3685d 100644 --- a/src/kernel/windows_kernel/kernel.rs +++ b/src/kernel/windows_kernel/kernel.rs @@ -1,43 +1,28 @@ -extern crate winapi; -extern crate kernel32; - -use super::handle; -use self::winapi::CONSOLE_SCREEN_BUFFER_INFO; - -use std::mem; +use winapi; +use kernel32; +use super::{handle, Empty}; /// Get console screen buffer info. -pub fn get_console_screen_buffer_info() -> Option -{ - let handle = handle::get_output_handle(); - let mut csbi: CONSOLE_SCREEN_BUFFER_INFO = unsafe { mem::zeroed() }; - - unsafe - { - if let Some(x) = handle - { - match kernel32::GetConsoleScreenBufferInfo(x, &mut csbi) - { - 0 => None, - _ => Some(csbi), - } - } - else { - None - } +pub fn get_console_screen_buffer_info() -> winapi::CONSOLE_SCREEN_BUFFER_INFO { + let output_handle = handle::get_output_handle(); + let mut csbi = winapi::CONSOLE_SCREEN_BUFFER_INFO::empty(); + let success; + + if handle::is_valid_handle(&output_handle) { + return winapi::CONSOLE_SCREEN_BUFFER_INFO::empty(); } + + unsafe { success = kernel32::GetConsoleScreenBufferInfo(output_handle, &mut csbi) } + + if success == 0 { + panic!("Cannot get console screen buffer info"); + } + + csbi } /// Get the current console colors. -pub fn get_original_console_color() -> u16 -{ +pub fn get_original_console_color() -> u16 { let console_buffer_info = get_console_screen_buffer_info(); - - if let Some(buffer_info) = console_buffer_info - { - buffer_info.wAttributes as u16 - } - else{ - 300 - } + console_buffer_info.wAttributes as u16 } diff --git a/src/kernel/windows_kernel/mod.rs b/src/kernel/windows_kernel/mod.rs index d0eb8fe..4e132bb 100644 --- a/src/kernel/windows_kernel/mod.rs +++ b/src/kernel/windows_kernel/mod.rs @@ -2,4 +2,8 @@ pub mod cursor; pub mod color; pub mod ansi_support; pub mod handle; -pub mod kernel; \ No newline at end of file +pub mod kernel; +pub mod terminal; +mod winapi_extentions; + +use shared::traits::Empty; diff --git a/src/kernel/windows_kernel/terminal.rs b/src/kernel/windows_kernel/terminal.rs new file mode 100644 index 0000000..96f6ee9 --- /dev/null +++ b/src/kernel/windows_kernel/terminal.rs @@ -0,0 +1,129 @@ +use winapi; +use kernel32; +use super::{cursor, handle, kernel, Empty}; + +/// Get the terminal size (y,x) +pub fn terminal_size() -> Option<(u16, u16)> { + let csbi = kernel::get_console_screen_buffer_info(); + + Some(( + (csbi.srWindow.Bottom - csbi.srWindow.Top) as u16, + (csbi.srWindow.Right - csbi.srWindow.Left) as u16, + )) +} + +/// Scroll down `n` rows +pub fn scroll_down(rows: i16) { + let output_handle = handle::get_output_handle(); + let csbi = kernel::get_console_screen_buffer_info(); + let mut srct_window; + + // Set srctWindow to the current window size and location. + srct_window = csbi.srWindow; + + // Check whether the window is too close to the screen buffer top + if srct_window.Bottom < csbi.dwSize.Y - rows { + srct_window.Top += rows; // move top down + srct_window.Bottom += rows; // move bottom down + + unsafe { + if kernel32::SetConsoleWindowInfo(output_handle, winapi::TRUE, &mut srct_window) != 1 { + panic!("Something whent wrong when scrolling down"); + } + } + } +} + +pub fn clear_after_cursor() { + let output_handle = handle::get_output_handle(); + let csbi = kernel::get_console_screen_buffer_info(); + + // one cell after cursor position + let mut x = cursor::xpos() as i16 + 1; + // one at row of cursor position + let mut y = cursor::ypos() as i16; + + // if cursor position is at the outer right position + if x > csbi.srWindow.Right + { + y += 1; + x = 0; + } + + // location where to start clearing + let start_loaction = winapi::COORD { X: x, Y: y }; + clear(output_handle, csbi, start_loaction); +} + +// pub fn before_after_cursor() { +// let output_handle = handle::get_output_handle(); +// let csbi = kernel::get_console_screen_buffer_info(); + +// // one cell after cursor position +// let x = cursor::xpos() as i16 - 1; +// // one at row of cursor position +// let y = cursor::ypos() as i16; + +// // location where to start clearing +// let start_loaction = winapi::COORD { X: x, Y: y }; +// clear(output_handle, csbi, start_loaction); +// } + +pub fn clear_entire_screen() { + let output_handle = handle::get_output_handle(); + let csbi = kernel::get_console_screen_buffer_info(); + + // position x at start + let x = 0; + // position y at start + let y = 0; + + // location where to start clearing + let start_loaction = winapi::COORD { X: x, Y: y }; + + clear(output_handle, csbi, start_loaction); + + // put the cursor back at (0, 0) + cursor::set(0, 0); +} + +fn clear( + handle: winapi::HANDLE, + csbi: winapi::CONSOLE_SCREEN_BUFFER_INFO, + start_loaction: winapi::COORD, +) { + let console_size = (csbi.dwSize.X as u32 * csbi.dwSize.Y as u32) as u32; + let mut cells_written = 0; + let mut success; + + unsafe { + // fill the entire screen with blanks + success = kernel32::FillConsoleOutputCharacterA( + handle, + ' ' as i8, + console_size, + start_loaction, + &mut cells_written, + ); + } + + if success == 0 { + panic!("Couldnot clear screen after cursor"); + } + + cells_written = 0; + + unsafe { + success = kernel32::FillConsoleOutputAttribute( + handle, + csbi.wAttributes, + console_size, + start_loaction, + &mut cells_written, + ); + } + + if success == 0 { + panic!("Couldnot reset attributes after cursor"); + } +} diff --git a/src/kernel/windows_kernel/winapi_extentions.rs b/src/kernel/windows_kernel/winapi_extentions.rs new file mode 100644 index 0000000..e58825f --- /dev/null +++ b/src/kernel/windows_kernel/winapi_extentions.rs @@ -0,0 +1,31 @@ +use winapi; +use super::Empty; + +impl Empty for winapi::COORD { + fn empty() -> winapi::COORD { + winapi::COORD { X: 0, Y: 0 } + } +} + +impl Empty for winapi::SMALL_RECT { + fn empty() -> winapi::SMALL_RECT { + winapi::SMALL_RECT { + Top: 0, + Right: 0, + Bottom: 0, + Left: 0, + } + } +} + +impl Empty for winapi::CONSOLE_SCREEN_BUFFER_INFO { + fn empty() -> winapi::CONSOLE_SCREEN_BUFFER_INFO { + winapi::CONSOLE_SCREEN_BUFFER_INFO { + dwSize: winapi::COORD::empty(), + dwCursorPosition: winapi::COORD::empty(), + wAttributes: 0, + srWindow: winapi::SMALL_RECT::empty(), + dwMaximumWindowSize: winapi::COORD::empty(), + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 45bcdac..80f2d01 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,15 @@ #[macro_use] pub mod shared; - pub mod terminal_cursor; pub mod terminal_style; +pub mod terminal; mod kernel; -pub use shared::traits::Construct; +use shared::traits::{Construct, Empty}; pub use terminal_cursor::cursor; pub use terminal_style::paint; - - +#[cfg(windows)] +extern crate kernel32; +#[cfg(windows)] +extern crate winapi; diff --git a/src/shared/enums.rs b/src/shared/enums.rs new file mode 100644 index 0000000..153ef8f --- /dev/null +++ b/src/shared/enums.rs @@ -0,0 +1,8 @@ +/// Contains directions that can be used for diffrent reasons. +#[derive(Debug)] +pub enum Direction { + Up, + Down, + Left, + Right, +} diff --git a/src/shared/functions.rs b/src/shared/functions.rs new file mode 100644 index 0000000..6229242 --- /dev/null +++ b/src/shared/functions.rs @@ -0,0 +1,9 @@ +pub fn is_cursor_out_of_range(x: i16, y: i16) { + if x < 0 || x >= ::max_value() { + panic!("Argument Out of Range Exception"); + } + + if y < 0 || y >= ::max_value() { + panic!("Argument Out of Range Exception"); + } +} diff --git a/src/shared/macros.rs b/src/shared/macros.rs index 1e4b6d1..3659217 100644 --- a/src/shared/macros.rs +++ b/src/shared/macros.rs @@ -1,56 +1,5 @@ -use std; -use std::fmt; -use std::io::Write; - -use terminal_style as style; - -/// This is used to make StyledObject able to be displayed. -/// This macro will set the styled stored in Styled Object -#[macro_export] -macro_rules! impl_fmt -{ - ($name:ident) => { - impl fmt::$name for style::StyledObject { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result - { - let mut colored_terminal = style::colored_terminal(); - let mut reset = true; - - if let Some(bg) = self.object_style.bg_color - { - colored_terminal.set_bg(bg); - reset = true; - } - if let Some(fg) = self.object_style.fg_color - { - colored_terminal.set_fg(fg); - reset = true; - } - - write!(f, "{}", &self.content); - std::io::stdout().flush().expect("Flush stdout failed"); - - if reset - { - colored_terminal.reset(); - } - - Ok(()) - } - } - } -} - /// This macro will take an ANSI input and combines it with some default ANSI characters and returns the result -#[macro_export] +#[macro_export] macro_rules! csi { ($( $l:expr ),*) => { concat!("\x1B[", $( $l ),*) }; } - -/// This inplements Display for StyledObject -/// Notice that more implementations can be maked. -/// # Example -/// ```rust -/// example impl_fmt!(Debug); -/// ``` -impl_fmt!(Display); \ No newline at end of file diff --git a/src/shared/mod.rs b/src/shared/mod.rs index 0e6bc87..283d8a9 100644 --- a/src/shared/mod.rs +++ b/src/shared/mod.rs @@ -1,3 +1,5 @@ #[macro_use] pub mod macros; -pub mod traits; \ No newline at end of file +pub mod traits; +pub mod enums; +pub mod functions; diff --git a/src/shared/traits.rs b/src/shared/traits.rs index 9852c9b..0861ab4 100644 --- a/src/shared/traits.rs +++ b/src/shared/traits.rs @@ -1,6 +1,12 @@ -/// This trait is used for creating an instance of an concrete implementation from an base trait. +/// This trait is used for creating an instance of an concrete implementation from an base trait. /// This trait allows the output to be different in size. -pub trait Construct -{ - fn new() -> Box where Self: Sized; -} \ No newline at end of file +pub trait Construct { + fn new() -> Box + where + Self: Sized; +} + +/// This trait is used to create an empty instance of an struct. +pub trait Empty { + fn empty() -> Self; +} diff --git a/src/terminal/ansi_terminal.rs b/src/terminal/ansi_terminal.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/terminal/base_terminal.rs b/src/terminal/base_terminal.rs index e69de29..7612820 100644 --- a/src/terminal/base_terminal.rs +++ b/src/terminal/base_terminal.rs @@ -0,0 +1,14 @@ +pub enum ClearType { + All, + AfterCursor, + BeforeCursor, + CurrentLine, + UntilNewLine, +} + +pub trait ITerminal { + fn clear(&self, clear_type: ClearType); + fn terminal_size(&self) -> Option<(u16, u16)>; + fn scroll_up(&self, count: i16); + fn scroll_down(&self, count: u16); +} diff --git a/src/terminal/mod.rs b/src/terminal/mod.rs new file mode 100644 index 0000000..482b5fb --- /dev/null +++ b/src/terminal/mod.rs @@ -0,0 +1,12 @@ +mod base_terminal; +mod no_terminal; +mod unix_terminal; +mod winapi_terminal; +pub mod terminal; + +pub use self::terminal::{get, Terminal}; +pub use self::base_terminal::ClearType; + +use self::unix_terminal::UnixTerminal; +use self::winapi_terminal::WinApiTerminal; +use self::no_terminal::NoTerminal; diff --git a/src/terminal/no_terminal.rs b/src/terminal/no_terminal.rs new file mode 100644 index 0000000..46cae34 --- /dev/null +++ b/src/terminal/no_terminal.rs @@ -0,0 +1,22 @@ +use Construct; +use super::base_terminal::{ClearType, ITerminal}; +/// This struct will be used for ansi terminals and unix systems. +pub struct NoTerminal; + +impl Construct for NoTerminal { + fn new() -> Box { + Box::from(NoTerminal {}) + } +} + +impl ITerminal for NoTerminal { + fn clear(&self, clear_type: ClearType) {} + + fn terminal_size(&self) -> Option<(u16, u16)> { + None + } + + fn scroll_up(&self, count: i16) {} + + fn scroll_down(&self, count: u16) {} +} diff --git a/src/terminal/terminal.rs b/src/terminal/terminal.rs new file mode 100644 index 0000000..7287562 --- /dev/null +++ b/src/terminal/terminal.rs @@ -0,0 +1,65 @@ +use Construct; +use super::base_terminal::{ClearType, ITerminal}; +use super::{NoTerminal, UnixTerminal, WinApiTerminal}; + +/// Struct with the terminal on wits terminal realated actions can be performed. +pub struct Terminal { + terminal: Option>, +} + +impl Terminal { + /// Instantiate an color implementation whereon color related actions can be performed. + pub fn init(&mut self) { + if let None = self.terminal { + self.terminal = get_terminal(); + } + } + + pub fn clear(&mut self, clear_type: ClearType) { + &self.init(); + if let Some(ref terminal) = self.terminal { + terminal.clear(clear_type); + } + } + + pub fn terminal_size(&mut self) -> Option<(u16, u16)> { + &self.init(); + if let Some(ref terminal) = self.terminal { + let a = terminal.terminal_size(); + a + } else { + None + } + } + + pub fn scroll_up(&mut self, count: i16) { + for i in 0..100 { + println!("Ik ben timon en dit is een test {}", i) + } + + &self.init(); + if let Some(ref terminal) = self.terminal { + terminal.scroll_up(count); + } + } + + pub fn scroll_down(&self) {} +} + +/// Get the concrete ITerminal implementation based on the current operating system. +fn get_terminal() -> Option> { + if cfg!(target_os = "linux") { + Some(UnixTerminal::new()) + } else if cfg!(target_os = "windows") { + Some(WinApiTerminal::new()) + } else { + Some(NoTerminal::new()) + } +} + +/// Get terminal whereon terminal related actions can be performed. +pub fn get() -> Box { + Box::from(Terminal { + terminal: get_terminal(), + }) +} diff --git a/src/terminal/unix_terminal.rs b/src/terminal/unix_terminal.rs new file mode 100644 index 0000000..24935f0 --- /dev/null +++ b/src/terminal/unix_terminal.rs @@ -0,0 +1,40 @@ +use Construct; +use super::base_terminal::{ClearType, ITerminal}; + +#[cfg(unix)] +use kernel::linux_kernel::terminal::*; +#[cfg(windows)] +use kernel::windows_kernel::terminal::*; + +/// This struct will be used for ansi terminals and unix systems. +pub struct UnixTerminal; + +impl Construct for UnixTerminal { + fn new() -> Box { + Box::from(UnixTerminal {}) + } +} + +impl ITerminal for UnixTerminal { + fn clear(&self, clear_type: ClearType) { + match clear_type { + ClearType::All => format!(csi!("2J")), + ClearType::AfterCursor => format!(csi!("J")), + ClearType::BeforeCursor => format!(csi!("1J")), + ClearType::CurrentLine => format!(csi!("2K")), + ClearType::UntilNewLine => format!(csi!("K")), + }; + } + + fn terminal_size(&self) -> Option<(u16, u16)> { + terminal_size() + } + + fn scroll_up(&self, count: i16) { + format!(csi!("{}S"), count); + } + + fn scroll_down(&self, count: u16) { + format!(csi!("{}T"), count); + } +} diff --git a/src/terminal/winapi_terminal.rs b/src/terminal/winapi_terminal.rs index e69de29..2fb5f87 100644 --- a/src/terminal/winapi_terminal.rs +++ b/src/terminal/winapi_terminal.rs @@ -0,0 +1,39 @@ +use Construct; +use super::base_terminal::{ClearType, ITerminal}; + +#[cfg(windows)] +use kernel::windows_kernel::terminal; +/// This struct will be used for ansi terminals and unix systems. +pub struct WinApiTerminal; + +impl Construct for WinApiTerminal { + fn new() -> Box { + Box::from(WinApiTerminal {}) + } +} + +impl ITerminal for WinApiTerminal { + fn clear(&self, clear_type: ClearType) { + match clear_type + { + ClearType::All => terminal::clear_entire_screen(), + ClearType::AfterCursor => terminal::clear_after_cursor(), + _ => print!("") + // ClearType::BeforeCursor => format!(csi!("1J")), + // ClearType::CurrentLine => format!(csi!("2K")), + // ClearType::UntilNewLine => format!(csi!("K")), + }; + } + + fn terminal_size(&self) -> Option<(u16, u16)> { + terminal::terminal_size() + } + + fn scroll_up(&self, count: i16) { + // yet to be inplemented + } + + fn scroll_down(&self, count: u16) { + terminal::scroll_down(count as i16); + } +} diff --git a/src/terminal_cursor/ansi_cursor.rs b/src/terminal_cursor/ansi_cursor.rs index 87691f9..32949e9 100644 --- a/src/terminal_cursor/ansi_cursor.rs +++ b/src/terminal_cursor/ansi_cursor.rs @@ -1,41 +1,37 @@ use Construct; use super::base_cursor::ITerminalCursor; -/// This struct will be used for ansi terminals and unix systems. +/// This struct will be used for ansi terminals and unix systems. pub struct AnsiCursor; -impl Construct for AnsiCursor -{ - fn new() -> Box - { - Box::from(AnsiCursor {}) +impl Construct for AnsiCursor { + fn new() -> Box { + Box::from(AnsiCursor {}) } } -impl ITerminalCursor for AnsiCursor -{ - fn goto(&self, x: i16 , y: i16) - { - format!(csi!("{};{}H"), x,y); - } +impl ITerminalCursor for AnsiCursor { + fn goto(&self, x: u16, y: u16) { + format!(csi!("{};{}H"), x, y); + } - fn move_up(&self,count: u16) - { + fn pos(&self) -> (u16, u16) { + (0, 0) + } + + fn move_up(&self, count: u16) { format!(csi!("{}A"), count); } - fn move_right(&self, count: u16) - { + fn move_right(&self, count: u16) { format!(csi!("{}C"), count); } - fn move_down(&self, count: u16) - { - format!(csi!("{}B"), count); + fn move_down(&self, count: u16) { + format!(csi!("{}B"), count); } - fn move_left(&self, count: u16) - { + fn move_left(&self, count: u16) { format!(csi!("{}D"), count); - } + } } diff --git a/src/terminal_cursor/base_cursor.rs b/src/terminal_cursor/base_cursor.rs index ad3ef45..46b80bb 100644 --- a/src/terminal_cursor/base_cursor.rs +++ b/src/terminal_cursor/base_cursor.rs @@ -1,19 +1,17 @@ /// This trait defines the actions that can be preformed on the termial cursor. /// This trait can be inplemented so that an concrete inplementation of the ITerminalCursor can forfill -/// the wishes to work on an specific platform. -/// +/// the wishes to work on an specific platform. +/// /// ## For example: -/// +/// /// This trait is inplemented for winapi (Windows specific) and ansi (Unix specific), -/// so that the cursor related actions can be preformed on both unix and windows systems. -pub trait ITerminalCursor -{ +/// so that the cursor related actions can be preformed on both unix and windows systems. +pub trait ITerminalCursor { /// Goto some location (x,y) in the terminal. - fn goto(&self, x: i16, y: i16); + fn goto(&self, x: u16, y: u16); + fn pos(&self) -> (u16, u16); fn move_up(&self, count: u16); fn move_right(&self, count: u16); fn move_down(&self, count: u16); fn move_left(&self, count: u16); } - - diff --git a/src/terminal_cursor/cursor.rs b/src/terminal_cursor/cursor.rs index 07e3738..1c4a71b 100644 --- a/src/terminal_cursor/cursor.rs +++ b/src/terminal_cursor/cursor.rs @@ -1,32 +1,29 @@ use std::fmt::Display; -use std; -use std::io::Write; - use Construct; use super::base_cursor::ITerminalCursor; -use super::{AnsiCursor, WinApiCursor, NoCursor}; +use super::{AnsiCursor, NoCursor, WinApiCursor}; /// Struct with the cursor on wits cursor realated actions can be performed. -pub struct TerminalCursor -{ +pub struct TerminalCursor { terminal_cursor: Option>, } -impl TerminalCursor -{ +// impl Clone for TerminalCursor { +// fn clone(&self) -> TerminalCursor { *self } +// } + +impl TerminalCursor { /// Instantiate an cursor implementation whereon cursor related actions can be performed. - pub fn init(&mut self) - { - if let None = self.terminal_cursor - { + pub fn init(&mut self) { + if let None = self.terminal_cursor { self.terminal_cursor = get_cursor_options(); } } /// Goto some location (x,y) in the terminal. - /// - /// #Example - /// + /// + /// #Example + /// /// ```rust /// extern crate crossterm; /// @@ -37,20 +34,27 @@ impl TerminalCursor /// cursor::get().goto(10,10); /// } /// ``` - pub fn goto(mut self, x: i16 , y: i16) -> TerminalCursor - { + pub fn goto(&mut self, x: u16, y: u16) -> &mut TerminalCursor { &self.init(); - if let Some(ref terminal_cursor) = self.terminal_cursor - { - terminal_cursor.goto(x,y); + if let Some(ref terminal_cursor) = self.terminal_cursor { + terminal_cursor.goto(x, y); } self } + pub fn pos(mut self) -> (u16, u16) { + &self.init(); + if let Some(ref terminal_cursor) = self.terminal_cursor { + terminal_cursor.pos() + } else { + (0, 0) + } + } + /// Print an value at the current cursor location. - /// - /// #Example - /// + /// + /// #Example + /// /// ```rust /// extern crate crossterm; /// @@ -65,69 +69,62 @@ impl TerminalCursor /// .goto(10,10) /// .print("@"); /// } - /// ``` - pub fn move_up(mut self, count: u16) -> TerminalCursor - { + /// ``` + pub fn move_up(&mut self, count: u16) -> &mut TerminalCursor { &self.init(); - if let Some(ref terminal_cursor) = self.terminal_cursor - { - terminal_cursor.move_up(count); + if let Some(ref terminal_cursor) = self.terminal_cursor { + terminal_cursor.move_up(count); } - self + self } - pub fn move_right(mut self, count: u16) -> TerminalCursor - { + pub fn move_right(&mut self, count: u16) -> &mut TerminalCursor { &self.init(); - if let Some(ref terminal_cursor) = self.terminal_cursor - { - terminal_cursor.move_right(count); + if let Some(ref terminal_cursor) = self.terminal_cursor { + terminal_cursor.move_right(count); } - self + self } - pub fn move_down(mut self, count: u16) -> TerminalCursor - { + pub fn move_down(&mut self, count: u16) -> &mut TerminalCursor { &self.init(); - if let Some(ref terminal_cursor) = self.terminal_cursor - { - terminal_cursor.move_down(count); + if let Some(ref terminal_cursor) = self.terminal_cursor { + terminal_cursor.move_down(count); } - self + self } - pub fn move_left(mut self, count: u16) -> TerminalCursor - { + pub fn move_left(&mut self, count: u16) -> &mut TerminalCursor { &self.init(); - if let Some(ref terminal_cursor) = self.terminal_cursor - { - terminal_cursor.move_left(count); + if let Some(ref terminal_cursor) = self.terminal_cursor { + terminal_cursor.move_left(count); } - self + self } - pub fn print(self, value:D) -> TerminalCursor - { - print!("{}", value); + pub fn print(&mut self, value: D) -> &mut TerminalCursor { + print!("{}", value); + use std; + use std::io::Write; + std::io::stdout().flush(); self } } /// Get the concrete ITerminalCursor implementation based on the current operating system. -fn get_cursor_options() -> Option> -{ +fn get_cursor_options() -> Option> { if cfg!(target_os = "linux") { Some(AnsiCursor::new()) - } - else if cfg!(target_os = "windows") { + } else if cfg!(target_os = "windows") { Some(WinApiCursor::new()) - }else{ + } else { Some(NoCursor::new()) } } /// Get terminal cursor options whereon cursor related actions can be performed. -pub fn get() -> Box -{ - Box::from(TerminalCursor { terminal_cursor: get_cursor_options() }) +pub fn get() -> Box { + Box::from(TerminalCursor { + terminal_cursor: get_cursor_options(), + }) } diff --git a/src/terminal_cursor/mod.rs b/src/terminal_cursor/mod.rs index 790e867..eb3789a 100644 --- a/src/terminal_cursor/mod.rs +++ b/src/terminal_cursor/mod.rs @@ -8,4 +8,4 @@ use self::no_cursor::NoCursor; use self::ansi_cursor::AnsiCursor; use self::winapi_cursor::WinApiCursor; -pub use cursor::{get, TerminalCursor}; \ No newline at end of file +pub use cursor::{get, TerminalCursor}; diff --git a/src/terminal_cursor/no_cursor.rs b/src/terminal_cursor/no_cursor.rs index 4f4faf2..3e78036 100644 --- a/src/terminal_cursor/no_cursor.rs +++ b/src/terminal_cursor/no_cursor.rs @@ -1,31 +1,28 @@ use Construct; use super::base_cursor::ITerminalCursor; -/// Struct that will be instantiated when something went wrong or when an platform does not suport +/// Struct that will be instantiated when something went wrong or when an platform does not suport /// the current concrete cursor inplementations. pub struct NoCursor; -impl Construct for NoCursor -{ +impl Construct for NoCursor { fn new() -> Box { Box::new(NoCursor {}) } } -impl ITerminalCursor for NoCursor -{ - fn goto(&self, x: i16 , y: i16) - { } +impl ITerminalCursor for NoCursor { + fn goto(&self, x: u16, y: u16) {} - fn move_up(&self, count: u16) - { } + fn pos(&self) -> (u16, u16) { + (0, 0) + } - fn move_right(&self, count: u16) - { } + fn move_up(&self, count: u16) {} - fn move_down(&self, count: u16) - { } + fn move_right(&self, count: u16) {} - fn move_left(&self, count: u16) - { } + fn move_down(&self, count: u16) {} + + fn move_left(&self, count: u16) {} } diff --git a/src/terminal_cursor/winapi_cursor.rs b/src/terminal_cursor/winapi_cursor.rs index 644cfa5..f1ab706 100644 --- a/src/terminal_cursor/winapi_cursor.rs +++ b/src/terminal_cursor/winapi_cursor.rs @@ -2,56 +2,51 @@ use Construct; use kernel::windows_kernel::cursor; use super::base_cursor::ITerminalCursor; -/// This struct will be used for cursor actions in windows terminals performed by winapi. -pub struct WinApiCursor -{ +/// This struct will be used for cursor actions in windows terminals performed by winapi. +pub struct WinApiCursor { has_moved: bool, } -impl Construct for WinApiCursor -{ - fn new() -> Box - { - Box::from(WinApiCursor {has_moved: false}) +impl Construct for WinApiCursor { + fn new() -> Box { + Box::from(WinApiCursor { has_moved: false }) } } -impl ITerminalCursor for WinApiCursor -{ - fn goto(&self, x: i16 , y: i16) - { - // cursor::set(x,y); - } - - fn move_up(&self, count: u16) - { - let xpos = cursor::xpos(); - let ypos = cursor::ypos(); - - cursor::set(xpos, ypos -1); +impl ITerminalCursor for WinApiCursor { + fn goto(&self, x: u16, y: u16) { + cursor::set(x, y); } - fn move_right(&self, count: u16) - { + fn pos(&self) -> (u16, u16) { + (cursor::xpos(), cursor::ypos()) + } + + fn move_up(&self, count: u16) { + let xpos = cursor::xpos(); + let ypos = cursor::ypos(); + + cursor::set(xpos, ypos - 1); + } + + fn move_right(&self, count: u16) { let xpos = cursor::xpos(); let ypos = cursor::ypos(); cursor::set(xpos + 1, ypos); } - fn move_down(&self, count: u16) - { + fn move_down(&self, count: u16) { let xpos = cursor::xpos(); let ypos = cursor::ypos(); cursor::set(xpos, ypos + count); } - fn move_left(&self, count: u16) - { + fn move_left(&self, count: u16) { let xpos = cursor::xpos(); let ypos = cursor::ypos(); - cursor::set(xpos -1, ypos); + cursor::set(xpos - 1, ypos); } } diff --git a/src/terminal_style/color/ansi_color.rs b/src/terminal_style/color/ansi_color.rs index 1d5e781..6e6f68b 100644 --- a/src/terminal_style/color/ansi_color.rs +++ b/src/terminal_style/color/ansi_color.rs @@ -1,87 +1,85 @@ use std::string::String; use Construct; -use super::color::{Color,ColorType}; -use super::base_color::{ ITerminalColor, sum_u16_to_string }; +use super::color::{Color, ColorType}; +use super::base_color::{ITerminalColor, sum_u16_to_string}; -/// This struct will be used for coloring ansi terminals with ansi escape codes. +/// This struct will be used for coloring ansi terminals with ansi escape codes. #[derive(Debug)] pub struct ANSIColor; -impl Construct for ANSIColor -{ - fn new() -> Box - { - Box::from(ANSIColor {}) +impl Construct for ANSIColor { + fn new() -> Box { + Box::from(ANSIColor {}) } } -impl ITerminalColor for ANSIColor -{ - fn set_fg(&self, fg_color: Color) - { - format!(csi!("38;2;{}m"), self.color_value(fg_color,ColorType::Foreground)); - } +impl ITerminalColor for ANSIColor { + fn set_fg(&self, fg_color: Color) { + format!( + csi!("38;2;{}m"), + self.color_value(fg_color, ColorType::Foreground) + ); + } - fn set_bg(&self, bg_color: Color) - { - format!(csi!("38;2;{}m"), self.color_value(bg_color,ColorType::Background)); - } + fn set_bg(&self, bg_color: Color) { + format!( + csi!("38;2;{}m"), + self.color_value(bg_color, ColorType::Background) + ); + } - fn reset(&self) - { - format!(csi!("0m")); - } + fn reset(&self) { + format!(csi!("0m")); + } - fn color_value(&self, color: Color, color_type: ColorType) -> String - { - let mut ansi_color_code = String::new(); + fn color_value(&self, color: Color, color_type: ColorType) -> String { + let mut ansi_color_code = String::new(); // The ansi code for forground = 30 and background = 40; - match color_type - { - ColorType::Foreground => ansi_color_code.push_str("30"), - ColorType::Background => ansi_color_code.push_str("40"), - } + match color_type { + ColorType::Foreground => ansi_color_code.push_str("30"), + ColorType::Background => ansi_color_code.push_str("40"), + } // Construct ANSI escape color code string. ;1 is for the brightness - match color - { - Color::Black => { sum_u16_to_string(0, &mut ansi_color_code); }, - Color::Red => sum_u16_to_string(1, &mut ansi_color_code), - Color::DarkRed => { - sum_u16_to_string(1, &mut ansi_color_code); - &ansi_color_code.push_str(";1"); - }, - Color::Green => sum_u16_to_string(2, &mut ansi_color_code), - Color::DarkGreen => { - sum_u16_to_string(2, &mut ansi_color_code); - &ansi_color_code.push_str(";1"); - }, - Color::Yellow => sum_u16_to_string(3, &mut ansi_color_code), - Color::DarkYellow => { - sum_u16_to_string(3, &mut ansi_color_code); - &ansi_color_code.push_str(";1"); - }, - Color::Blue => sum_u16_to_string(4, &mut ansi_color_code), - Color::DarkBlue => { - sum_u16_to_string(4, &mut ansi_color_code); - &ansi_color_code.push_str(";1"); - }, - Color::Magenta => sum_u16_to_string(5, &mut ansi_color_code), - Color::DarkMagenta => { - sum_u16_to_string(5, &mut ansi_color_code); - &ansi_color_code.push_str(";1"); - }, - Color::Cyan => sum_u16_to_string(6, &mut ansi_color_code), - Color::DarkCyan => - { - sum_u16_to_string(6, &mut ansi_color_code); - &ansi_color_code.push_str(";1"); - }, - Color::Grey => sum_u16_to_string(7, &mut ansi_color_code), - Color::White => sum_u16_to_string(7, &mut ansi_color_code), + match color { + Color::Black => { + sum_u16_to_string(0, &mut ansi_color_code); + } + Color::Red => sum_u16_to_string(1, &mut ansi_color_code), + Color::DarkRed => { + sum_u16_to_string(1, &mut ansi_color_code); + &ansi_color_code.push_str(";1"); + } + Color::Green => sum_u16_to_string(2, &mut ansi_color_code), + Color::DarkGreen => { + sum_u16_to_string(2, &mut ansi_color_code); + &ansi_color_code.push_str(";1"); + } + Color::Yellow => sum_u16_to_string(3, &mut ansi_color_code), + Color::DarkYellow => { + sum_u16_to_string(3, &mut ansi_color_code); + &ansi_color_code.push_str(";1"); + } + Color::Blue => sum_u16_to_string(4, &mut ansi_color_code), + Color::DarkBlue => { + sum_u16_to_string(4, &mut ansi_color_code); + &ansi_color_code.push_str(";1"); + } + Color::Magenta => sum_u16_to_string(5, &mut ansi_color_code), + Color::DarkMagenta => { + sum_u16_to_string(5, &mut ansi_color_code); + &ansi_color_code.push_str(";1"); + } + Color::Cyan => sum_u16_to_string(6, &mut ansi_color_code), + Color::DarkCyan => { + sum_u16_to_string(6, &mut ansi_color_code); + &ansi_color_code.push_str(";1"); + } + Color::Grey => sum_u16_to_string(7, &mut ansi_color_code), + Color::White => sum_u16_to_string(7, &mut ansi_color_code), } ansi_color_code - } -} \ No newline at end of file + } +} diff --git a/src/terminal_style/color/base_color.rs b/src/terminal_style/color/base_color.rs index c5df557..35626d8 100644 --- a/src/terminal_style/color/base_color.rs +++ b/src/terminal_style/color/base_color.rs @@ -1,33 +1,29 @@ /// This trait defines the actions that can be preformed on the termial color. -/// This trait can be inplemented so that an concrete inplementation of the ITerminalColor can forfill -/// the wishes to work on an specific platform. -/// +/// This trait can be inplemented so that an concrete inplementation of the ITerminalColor can forfill +/// the wishes to work on an specific platform. +/// /// ## For example: -/// +/// /// This trait is inplemented for winapi (Windows specific) and ansi (Unix specific), -/// so that the color related actions can be preformed on both unix and windows systems. +/// so that the color related actions can be preformed on both unix and windows systems. -use super::color::{Color,ColorType}; +use super::color::{Color, ColorType}; -pub trait ITerminalColor -{ +pub trait ITerminalColor { /// Set the forground color to the given color. fn set_fg(&self, fg_color: Color); /// Set the background color to the given color. - fn set_bg(&self, fg_color: Color); + fn set_bg(&self, fg_color: Color); /// Reset the terminal color to default. - fn reset(&self); + fn reset(&self); /// Gets an value that represents an color from the given `Color` and `ColorType`. fn color_value(&self, color: Color, color_type: ColorType) -> String; - } /// Sum an u16 value with an string (also a numeric value). -pub fn sum_u16_to_string(value: u16, string: &mut String) -{ +pub fn sum_u16_to_string(value: u16, string: &mut String) { let parsed_string: u16 = string.parse().unwrap(); let new_value: u16 = parsed_string + value; *string = new_value.to_string(); } - diff --git a/src/terminal_style/color/color.rs b/src/terminal_style/color/color.rs index 860a11b..98f2fdb 100644 --- a/src/terminal_style/color/color.rs +++ b/src/terminal_style/color/color.rs @@ -3,16 +3,13 @@ use std::convert::From; use std::str::FromStr; use Construct; -use super::{WinApiColor, ANSIColor,NoTerminalColor}; +use super::{ANSIColor, NoTerminalColor, WinApiColor}; use super::base_color::ITerminalColor; -use terminal_style::{ObjectStyle,StyledObject}; - +use terminal_style::{ObjectStyle, StyledObject}; /// Colors that are available for coloring the termainal font. -#[derive(Debug)] -#[derive(Copy, Clone)] -pub enum Color -{ +#[derive(Debug, Copy, Clone)] +pub enum Color { Black, Red, @@ -32,29 +29,27 @@ pub enum Color Cyan, DarkCyan, - + Grey, - White, + White, } -/// Color types -#[derive(Debug)] -#[derive(Copy, Clone)] -pub enum ColorType -{ +/// Color types +#[derive(Debug, Copy, Clone)] +pub enum ColorType { Background, Foreground, } /// Enables an user to pass in an color as str. /// *Default color if cannot be parsed will be white.* -/// +/// /// # Example -/// -/// ``` rust +/// +/// ``` rust /// let fg_color = Color::from("red"); /// let bg_color = Color::from("blue"); -/// +/// /// println!("{}",paint("■").with(fg_color).on(bg_color)); /// ``` impl<'a> From<&'a str> for Color { @@ -65,13 +60,13 @@ impl<'a> From<&'a str> for Color { /// Enables an user to pass in an color as String. /// *Default color if cannot be parsed will be white.* -/// +/// /// # Example -/// -/// ``` rust +/// +/// ``` rust /// let fg_color = Color::from(String::from("red")); -/// let bg_color = Color::from(String::from("blue")); -/// +/// let bg_color = Color::from(String::from("blue")); +/// /// println!("{}",paint("■").with(fg_color).on(bg_color)); /// ``` impl From for Color { @@ -108,109 +103,98 @@ impl FromStr for Color { } /// Struct on wits the color realated actions can be performed. -pub struct TerminalColor -{ +pub struct TerminalColor { terminal_color: Option>, } -impl TerminalColor -{ +impl TerminalColor { /// Instantiate an color implementation whereon color related actions can be performed. - pub fn init(&mut self) - { - if let None = self.terminal_color - { + pub fn init(&mut self) { + if let None = self.terminal_color { self.terminal_color = get_color_options(); } } /// Set the forground color to the given color. - /// - /// #Example - /// + /// + /// #Example + /// /// ```rust - /// + /// /// let mut colored_terminal = colored_terminal(); /// colored_terminal.set_fg(Color::Red); - /// + /// /// ``` - pub fn set_fg(&mut self, color: Color) - { + pub fn set_fg(&mut self, color: Color) { &self.init(); - if let Some(ref terminal_color) = self.terminal_color - { + if let Some(ref terminal_color) = self.terminal_color { terminal_color.set_fg(color); } } /// Set the background color to the given color. - /// - /// #Example - /// + /// + /// #Example + /// /// ```rust - /// + /// /// let mut colored_terminal = colored_terminal(); /// colored_terminal.set_bg(Color::Red); - /// + /// /// ``` - pub fn set_bg(&mut self, color: Color) - { - &self.init(); - if let Some(ref terminal_color) = self.terminal_color - { + pub fn set_bg(&mut self, color: Color) { + &self.init(); + if let Some(ref terminal_color) = self.terminal_color { terminal_color.set_bg(color); } } /// Reset the terminal colors to default. - /// # Example - /// + /// # Example + /// /// ```rust - /// + /// /// let mut colored_terminal = colored_terminal(); /// colored_terminal.reset(); - /// + /// /// ``` - pub fn reset(&mut self) - { - &self.init(); - if let Some(ref terminal_color) = self.terminal_color - { + pub fn reset(&mut self) { + &self.init(); + if let Some(ref terminal_color) = self.terminal_color { terminal_color.reset(); } } } /// Get the concrete ITerminalColor implementation based on the current operating system. -fn get_color_options() -> Option> -{ +fn get_color_options() -> Option> { if cfg!(target_os = "linux") { Some(ANSIColor::new()) - } - else if cfg!(target_os = "windows") { + } else if cfg!(target_os = "windows") { Some(WinApiColor::new()) - }else{ + } else { Some(NoTerminalColor::new()) } } /// Get the terminal options for colors, whereon color related actions can be performed. -pub fn colored_terminal() -> Box -{ - Box::from(TerminalColor { terminal_color: get_color_options() }) +pub fn colored_terminal() -> Box { + Box::from(TerminalColor { + terminal_color: get_color_options(), + }) } /// Wraps an displayable object so it can be formatted with colors and attributes. -/// -/// #Example -/// +/// +/// #Example +/// /// ```rust /// extern crate crossterm; /// use self::crossterm::terminal_style::{paint,Color}; /// /// fn main() -/// { +/// { /// // default foregroundcolor and backgroundcolor. /// println!("{}",paint("■")); /// @@ -219,9 +203,9 @@ pub fn colored_terminal() -> Box /// println!("{}", styledobject); /// } /// ``` -pub fn paint(val: D) -> StyledObject where D: fmt::Display +pub fn paint(val: D) -> StyledObject +where + D: fmt::Display, { ObjectStyle::new().apply_to(val) } - - diff --git a/src/terminal_style/color/mod.rs b/src/terminal_style/color/mod.rs index 767f091..020207b 100644 --- a/src/terminal_style/color/mod.rs +++ b/src/terminal_style/color/mod.rs @@ -8,5 +8,3 @@ pub mod base_color; use self::no_color::NoTerminalColor; use self::ansi_color::ANSIColor; use self::winapi_color::WinApiColor; - - diff --git a/src/terminal_style/color/no_color.rs b/src/terminal_style/color/no_color.rs index f928300..e627ee2 100644 --- a/src/terminal_style/color/no_color.rs +++ b/src/terminal_style/color/no_color.rs @@ -1,33 +1,26 @@ use Construct; -use super::color::{Color,ColorType}; +use super::color::{Color, ColorType}; use super::base_color::ITerminalColor; -/// Struct that will be instantiated when something went wrong or when an platform does not suport +/// Struct that will be instantiated when something went wrong or when an platform does not suport /// the current concrete color inplementations. #[derive(Debug)] pub struct NoTerminalColor; -impl Construct for NoTerminalColor -{ - fn new() -> Box - { - Box::from(NoTerminalColor {}) +impl Construct for NoTerminalColor { + fn new() -> Box { + Box::from(NoTerminalColor {}) } } -impl ITerminalColor for NoTerminalColor -{ - fn set_fg(&self, fg_color: Color) - { } +impl ITerminalColor for NoTerminalColor { + fn set_fg(&self, fg_color: Color) {} - fn set_bg(&self, bg_color: Color) - { } + fn set_bg(&self, bg_color: Color) {} - fn reset(&self) - { } + fn reset(&self) {} - fn color_value(&self, color: Color, color_type: ColorType) -> String - { - String::from("0") - } -} \ No newline at end of file + fn color_value(&self, color: Color, color_type: ColorType) -> String { + String::from("0") + } +} diff --git a/src/terminal_style/color/winapi_color.rs b/src/terminal_style/color/winapi_color.rs index 8651ed1..4e096a1 100644 --- a/src/terminal_style/color/winapi_color.rs +++ b/src/terminal_style/color/winapi_color.rs @@ -1,45 +1,39 @@ extern crate winapi; use Construct; -use super::color::{Color,ColorType}; +use super::color::{Color, ColorType}; use super::base_color::ITerminalColor; -use kernel::windows_kernel::{kernel,color}; +use kernel::windows_kernel::{color, kernel}; -/// This struct will be used for coloring windows terminals with winapi. +/// This struct will be used for coloring windows terminals with winapi. #[derive(Debug)] -pub struct WinApiColor -{ - original_console_color: u16, +pub struct WinApiColor { + original_console_color: u16, } -impl Construct for WinApiColor -{ - fn new() -> Box - { - Box::from(WinApiColor { original_console_color: kernel::get_original_console_color()}) +impl Construct for WinApiColor { + fn new() -> Box { + Box::from(WinApiColor { + original_console_color: kernel::get_original_console_color(), + }) } } -impl ITerminalColor for WinApiColor -{ - fn set_fg(&self, fg_color: Color) - { - let color_value = &self.color_value(fg_color, ColorType::Foreground); - color::set_fg_color(color_value.parse().unwrap()); - } +impl ITerminalColor for WinApiColor { + fn set_fg(&self, fg_color: Color) { + let color_value = &self.color_value(fg_color, ColorType::Foreground); + color::set_fg_color(color_value.parse().unwrap()); + } - fn set_bg(&self, bg_color: Color) - { + fn set_bg(&self, bg_color: Color) { let color_value = &self.color_value(bg_color, ColorType::Background); - color::set_bg_color(color_value.parse().unwrap()); - } + color::set_bg_color(color_value.parse().unwrap()); + } - fn reset(&self) - { - color::reset(self.original_console_color); - } + fn reset(&self) { + color::reset(self.original_console_color); + } - fn color_value(&self, color: Color, color_type: ColorType) -> String - { - color::winapi_color_val(color,color_type).to_string() - } -} \ No newline at end of file + fn color_value(&self, color: Color, color_type: ColorType) -> String { + color::winapi_color_val(color, color_type).to_string() + } +} diff --git a/src/terminal_style/mod.rs b/src/terminal_style/mod.rs index 207737f..1249a26 100644 --- a/src/terminal_style/mod.rs +++ b/src/terminal_style/mod.rs @@ -1,8 +1,8 @@ mod color; mod styles; -pub use self::color::base_color::{ITerminalColor}; +pub use self::color::base_color::ITerminalColor; pub use self::color::color::*; pub use self::styles::objectstyle::ObjectStyle; -pub use self::styles::styledobject::StyledObject; \ No newline at end of file +pub use self::styles::styledobject::StyledObject; diff --git a/src/terminal_style/styles/mod.rs b/src/terminal_style/styles/mod.rs index b23be73..edefd52 100644 --- a/src/terminal_style/styles/mod.rs +++ b/src/terminal_style/styles/mod.rs @@ -1,2 +1,2 @@ pub mod objectstyle; -pub mod styledobject; \ No newline at end of file +pub mod styledobject; diff --git a/src/terminal_style/styles/objectstyle.rs b/src/terminal_style/styles/objectstyle.rs index 9e3f065..fc99b18 100644 --- a/src/terminal_style/styles/objectstyle.rs +++ b/src/terminal_style/styles/objectstyle.rs @@ -1,48 +1,50 @@ -use terminal_style::{ Color, StyledObject }; +use terminal_style::{Color, StyledObject}; use std::fmt::Display; /// This struct contains the style properties that can be applied to an displayable object. #[derive(Clone)] -pub struct ObjectStyle -{ +pub struct ObjectStyle { pub fg_color: Option, pub bg_color: Option, } -impl Default for ObjectStyle -{ - fn default() -> ObjectStyle - { - ObjectStyle { fg_color: Some(Color::White), bg_color: Some(Color::Black) } +impl Default for ObjectStyle { + fn default() -> ObjectStyle { + ObjectStyle { + fg_color: Some(Color::White), + bg_color: Some(Color::Black), + } } } -impl ObjectStyle -{ +impl ObjectStyle { /// Get an `StyledObject` from the passed displayable object. - pub fn apply_to(&self, val: D) -> StyledObject where D: Display { + pub fn apply_to(&self, val: D) -> StyledObject + where + D: Display, + { StyledObject { object_style: self.clone(), - content: val + content: val, } } /// Get an instance of `ObjectStyle` - pub fn new() -> ObjectStyle - { - return ObjectStyle {fg_color: None, bg_color: None } + pub fn new() -> ObjectStyle { + return ObjectStyle { + fg_color: None, + bg_color: None, + }; } /// Set the background color of `ObjectStyle` to the passed color. - pub fn bg(mut self, color: Color) -> ObjectStyle - { + pub fn bg(mut self, color: Color) -> ObjectStyle { self.bg_color = Some(color); self } /// Set the foreground color of `ObjectStyle` to the passed color. - pub fn fg(mut self, color: Color) -> ObjectStyle - { + pub fn fg(mut self, color: Color) -> ObjectStyle { self.fg_color = Some(color); self } diff --git a/src/terminal_style/styles/styledobject.rs b/src/terminal_style/styles/styledobject.rs index 829bd95..43e72ba 100644 --- a/src/terminal_style/styles/styledobject.rs +++ b/src/terminal_style/styles/styledobject.rs @@ -1,30 +1,32 @@ -use terminal_style::{ObjectStyle, Color}; +use std; +use std::fmt; +use std::io::Write; + +use terminal_style::{Color, ObjectStyle}; /// Struct that contains both the style and the content wits is styled. -pub struct StyledObject -{ +pub struct StyledObject { pub object_style: ObjectStyle, - pub content: V, + pub content: D, } -impl StyledObject -{ - /// Paints the foreground color with the passed `Color` - /// - /// #Example - /// +impl StyledObject { + /// Paints the foreground color with the passed `Color` + /// + /// #Example + /// /// ```rust /// extern crate crossterm; - /// + /// /// use self::crossterm::terminal_style::{paint,Color}; /// /// fn main() - /// { - /// // 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); /// // create an styled object with the foreground color blue. /// let styledobject1 = paint("I am colored blue").with(Color::Blue); - /// + /// /// // print the styled objects /// println!("{}", styledobject); /// println!("{}", styledobject1); @@ -32,29 +34,27 @@ impl StyledObject /// println!("{}", paint("I am colored green").with(Color::Green)) /// } /// ``` - pub fn with(mut self, foreground_color: Color) -> StyledObject - { + pub fn with(mut self, foreground_color: Color) -> StyledObject { self.object_style = self.object_style.fg(foreground_color); self } - /// Paints the background color with the passed `Color` - /// - /// #Example - /// + /// + /// #Example + /// /// ```rust /// extern crate crossterm; - /// + /// /// use self::crossterm::terminal_style::{paint,Color}; /// /// fn main() - /// { - /// // 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); /// // create an styled object with the background color blue. /// let styledobject1 = paint("I am colored blue").on(Color::Blue); - /// + /// /// // print the styled objects /// println!("{}", styledobject); /// println!("{}", styledobject1); @@ -62,11 +62,53 @@ impl StyledObject /// println!("{}", paint("I am colored green").on(Color::Green)) /// } /// ``` - pub fn on(mut self, background_color: Color) -> StyledObject - { + pub fn on(mut self, background_color: Color) -> StyledObject { self.object_style = self.object_style.bg(background_color); self } } +/// This is used to make StyledObject able to be displayed. +/// This macro will set the styled stored in Styled Object +macro_rules! impl_fmt +{ + ($name:ident) => { + impl fmt::$name for StyledObject { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result + { + let mut colored_terminal = super::super::colored_terminal(); + let mut reset = true; + + if let Some(bg) = self.object_style.bg_color + { + colored_terminal.set_bg(bg); + reset = true; + } + if let Some(fg) = self.object_style.fg_color + { + colored_terminal.set_fg(fg); + reset = true; + } + fmt::$name::fmt(&self.content, f)?; + std::io::stdout().flush().expect("Flush stdout failed"); + + if reset + { + colored_terminal.reset(); + } + + Ok(()) + } + } + } +} + +/// This inplements Display for StyledObject +/// Notice that more implementations can be maked. +/// # Example +/// ```rust +/// example impl_fmt!(Debug); +/// ``` +impl_fmt!(Debug); +impl_fmt!(Display);