diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 742b36f..90d5e9a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,19 +7,19 @@ before_script: stable: script: - cargo +stable build --verbose - - cargo +stable test --verbose - - cargo +stable test --release --verbose + - script -q -c "cargo +stable test --verbose" + - script -q -c "cargo +stable test --release --verbose" beta: script: - rustup toolchain add beta - cargo +beta build --verbose - - cargo +beta test --verbose - - cargo +beta test --release --verbose + - script -q -c "cargo +beta test --verbose" + - script -q -c "cargo +beta test --release --verbose" nightly: script: - rustup toolchain add nightly - - cargo +nightly build --verbose - - cargo +nightly test --verbose - - cargo +nightly test --release --verbose \ No newline at end of file + - cargo +nightly build --verbose + - script -q -c "cargo +nightly test --verbose" + - script -q -c "cargo +nightly test --release --verbose" diff --git a/Cargo.toml b/Cargo.toml index a4dca1d..6e88e81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,9 @@ license = "MIT" keywords = ["tty", "color", "terminal", "password", "tui"] exclude = ["target", "CHANGELOG.md", "image.png", "Cargo.lock"] +[dependencies] +numtoa = { version = "0.1.0", features = ["std"]} + [target.'cfg(not(target_os = "redox"))'.dependencies] libc = "0.2.8" diff --git a/src/color.rs b/src/color.rs index 6f3fd88..73776c2 100644 --- a/src/color.rs +++ b/src/color.rs @@ -18,6 +18,7 @@ use std::io::{self, Write, Read}; use std::time::{SystemTime, Duration}; use async::async_stdin; use std::env; +use numtoa::NumToA; /// A terminal color. pub trait Color { @@ -36,14 +37,24 @@ macro_rules! derive_color { impl Color for $name { #[inline] fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, csi!("38;5;", $value, "m")) + f.write_str(self.fg_str()) } #[inline] fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, csi!("48;5;", $value, "m")) + f.write_str(self.bg_str()) } } + + impl $name { + #[inline] + /// Returns the ANSI escape sequence as a string. + pub fn fg_str(&self) -> &'static str { csi!("38;5;", $value, "m") } + + #[inline] + /// Returns the ANSI escape sequences as a string. + pub fn bg_str(&self) -> &'static str { csi!("48;5;", $value, "m") } + } }; } @@ -110,15 +121,31 @@ impl AnsiValue { } } +impl AnsiValue { + /// Returns the ANSI sequence as a string. + pub fn fg_string(self) -> String { + let mut x = [0u8; 20]; + let x = self.0.numtoa_str(10, &mut x); + [csi!("38;5;"), x, "m"].concat() + } + + /// Returns the ANSI sequence as a string. + pub fn bg_string(self) -> String { + let mut x = [0u8; 20]; + let x = self.0.numtoa_str(10, &mut x); + [csi!("48;5;"), x, "m"].concat() + } +} + impl Color for AnsiValue { #[inline] fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, csi!("38;5;{}m"), self.0) + f.write_str(&self.fg_string()) } #[inline] fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, csi!("48;5;{}m"), self.0) + f.write_str(&self.bg_string()) } } @@ -126,15 +153,41 @@ impl Color for AnsiValue { #[derive(Debug, Clone, Copy, PartialEq)] pub struct Rgb(pub u8, pub u8, pub u8); +impl Rgb { + /// Returns the ANSI sequence as a string. + pub fn fg_string(self) -> String { + let (mut x, mut y, mut z) = ([0u8; 20], [0u8; 20], [0u8; 20]); + let (x, y, z) = ( + self.0.numtoa_str(10, &mut x), + self.1.numtoa_str(10, &mut y), + self.2.numtoa_str(10, &mut z), + ); + + [csi!("38;2;"), x, ";", y, ";", z, "m"].concat() + } + + /// Returns the ANSI sequence as a string. + pub fn bg_string(self) -> String { + let (mut x, mut y, mut z) = ([0u8; 20], [0u8; 20], [0u8; 20]); + let (x, y, z) = ( + self.0.numtoa_str(10, &mut x), + self.1.numtoa_str(10, &mut y), + self.2.numtoa_str(10, &mut z), + ); + + [csi!("48;2;"), x, ";", y, ";", z, "m"].concat() + } +} + impl Color for Rgb { #[inline] fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, csi!("38;2;{};{};{}m"), self.0, self.1, self.2) + f.write_str(&self.fg_string()) } #[inline] fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, csi!("48;2;{};{};{}m"), self.0, self.1, self.2) + f.write_str(&self.bg_string()) } } @@ -142,15 +195,25 @@ impl Color for Rgb { #[derive(Debug, Clone, Copy)] pub struct Reset; +const RESET_FG: &str = csi!("39m"); +const RESET_BG: &str = csi!("49m"); + +impl Reset { + /// Returns the ANSI sequence as a string. + pub fn fg_str(self) -> &'static str { RESET_FG } + /// Returns the ANSI sequence as a string. + pub fn bg_str(self) -> &'static str { RESET_BG } +} + impl Color for Reset { #[inline] fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, csi!("39m")) + f.write_str(RESET_FG) } #[inline] fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, csi!("49m")) + f.write_str(RESET_BG) } } diff --git a/src/cursor.rs b/src/cursor.rs index cf8dc86..b9791a2 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -5,6 +5,7 @@ use std::io::{self, Write, Error, ErrorKind, Read}; use async::async_stdin_until; use std::time::{SystemTime, Duration}; use raw::CONTROL_SEQUENCE_TIMEOUT; +use numtoa::NumToA; derive_csi_sequence!("Hide the cursor.", Hide, "?25l"); derive_csi_sequence!("Show the cursor.", Show, "?25h"); @@ -32,6 +33,13 @@ derive_csi_sequence!("Save the cursor.", Save, "s"); #[derive(Copy, Clone, PartialEq, Eq)] pub struct Goto(pub u16, pub u16); +impl From for String { + fn from(this: Goto) -> String { + let (mut x, mut y) = ([0u8; 20], [0u8; 20]); + ["\x1B[", this.1.numtoa_str(10, &mut x), ";", this.0.numtoa_str(10, &mut y), "H"].concat() + } +} + impl Default for Goto { fn default() -> Goto { Goto(1, 1) @@ -41,8 +49,7 @@ impl Default for Goto { impl fmt::Display for Goto { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { debug_assert!(self != &Goto(0, 0), "Goto is one-based."); - - write!(f, csi!("{};{}H"), self.1, self.0) + f.write_str(&String::from(*self)) } } @@ -50,9 +57,16 @@ impl fmt::Display for Goto { #[derive(Copy, Clone, PartialEq, Eq)] pub struct Left(pub u16); +impl From for String { + fn from(this: Left) -> String { + let mut buf = [0u8; 20]; + ["\x1B[", this.0.numtoa_str(10, &mut buf), "D"].concat() + } +} + impl fmt::Display for Left { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, csi!("{}D"), self.0) + f.write_str(&String::from(*self)) } } @@ -60,9 +74,16 @@ impl fmt::Display for Left { #[derive(Copy, Clone, PartialEq, Eq)] pub struct Right(pub u16); +impl From for String { + fn from(this: Right) -> String { + let mut buf = [0u8; 20]; + ["\x1B[", this.0.numtoa_str(10, &mut buf), "C"].concat() + } +} + impl fmt::Display for Right { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, csi!("{}C"), self.0) + f.write_str(&String::from(*self)) } } @@ -70,9 +91,16 @@ impl fmt::Display for Right { #[derive(Copy, Clone, PartialEq, Eq)] pub struct Up(pub u16); +impl From for String { + fn from(this: Up) -> String { + let mut buf = [0u8; 20]; + ["\x1B[", this.0.numtoa_str(10, &mut buf), "A"].concat() + } +} + impl fmt::Display for Up { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, csi!("{}A"), self.0) + f.write_str(&String::from(*self)) } } @@ -80,9 +108,16 @@ impl fmt::Display for Up { #[derive(Copy, Clone, PartialEq, Eq)] pub struct Down(pub u16); +impl From for String { + fn from(this: Down) -> String { + let mut buf = [0u8; 20]; + ["\x1B[", this.0.numtoa_str(10, &mut buf), "B"].concat() + } +} + impl fmt::Display for Down { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, csi!("{}B"), self.0) + f.write_str(&String::from(*self)) } } @@ -115,7 +150,7 @@ impl DetectCursorPos for W { } } - if read_chars.len() == 0 { + if read_chars.is_empty() { return Err(Error::new(ErrorKind::Other, "Cursor position detection timed out.")); } diff --git a/src/lib.rs b/src/lib.rs index 2cb49fa..1d8f66f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,6 +11,8 @@ //! For more information refer to the [README](https://github.com/redox-os/termion). #![warn(missing_docs)] +extern crate numtoa; + #[cfg(target_os = "redox")] #[path="sys/redox/mod.rs"] mod sys; diff --git a/src/macros.rs b/src/macros.rs index 28370e3..5fd70b9 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -15,5 +15,13 @@ macro_rules! derive_csi_sequence { write!(f, csi!($value)) } } + + impl AsRef<[u8]> for $name { + fn as_ref(&self) -> &'static [u8] { csi!($value).as_bytes() } + } + + impl AsRef for $name { + fn as_ref(&self) -> &'static str { csi!($value) } + } }; }