1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
//! Module with ansi escape codes.
//!
//! Most of them are taken from:
//! <https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797>
//!
//! There are several types of codes here:
//! - **Sequences:** string/char used to introduce escape sequence, most of the
//! other codes use them
//! - **General ascii codes:** single char sequences some of them have escape
//! codes in rust string/char literals (such as '\n')
//! - **Macro codes:** these escape codes have one or more parameters. Here
//! they are in form of a macro that takes the parameters. If the macro is
//! invoked with literals, it expands to `&'static str`. If the arguments
//! are not literals it expands to a call to the `format!` macro. Because
//! these codes may expand either to `&'static str` or `String` you can use
//! the [`GetString::get_string`] method to get `String`, or you can use
//! `AsRef<str>::as_ref` method to get `&str`, or you can use
//! `Into<Cow<'static, str>>::into` to get the possibly owned string.
//! - **String codes:** these codes are just strings that can be just printed
//! to terminal to do what they say they do. This is the majority of the
//! codes.
use place_macro::place;
/// Creates the given sequence, this is used internally, you should use
/// the macro [`csi`]
#[macro_export]
macro_rules! seq {
($sq:literal, $i:literal, $f:literal, $($a:literal),*) => {
concat!($sq, $f $(, ';', $a)*, $i)
};
($sq:literal, $i:literal, $f:expr $(,$a:expr)*) => {
$crate::seq!($sq, $i, $f, $(";{}"; $a),*)
};
($sq:literal, $i:literal, $f:expr, $($l:literal; $e:expr),*) => {
format!(concat!($sq, "{}" $(,$l)*, $i), $f $(,$e)*)
}
}
// Sequences:
/// The escape character
pub const ESC: char = '\x1b';
/// Control Sequence Introducer: Start of CSI sequence
pub const CSI: &str = "\x1b[";
/// Device Control String: Start of DCS sequence
pub const DCS: &str = "\x1bP";
/// Operating System Command: Start of OCS sequence
pub const OCS: &str = "\x1b]";
/// Creates escape sequence, the first literal is the end of the sequence,
/// the other arguments are the values in the sequence
#[macro_export]
macro_rules! csi {
($i:literal, $($a:expr),+) => {
$crate::seq!("\x1b[", $i, $($a),+)
};
}
// General ASCII codes
/// Produces terminal bell
pub const BELL: char = '\x07';
/// Moves the cursor left by one positoin
pub const BACKSPACE: char = '\x08';
/// Horizontal tabulator, moves cursor to the next stop
pub const HTAB: char = '\t';
/// Moves the cursor to the start of the next line
pub const NEWLINE: char = '\n';
/// Vertical tabulator, moves the cursor to the next vertical stop
pub const VTAB: char = '\x0b';
/// Indicates new page, usualy has no use in terminal
pub const FORMFEED: char = '\x0c';
/// Moves cursor to the start of the line
pub const CARRIAGE_RETURN: char = '\r';
/// Does nothing
pub const DELETE: char = '\x7f';
// Cursor controls
// For the macros is true that:
// If you use literals it returns `&str`,
// if you use expressions, it returns [`String`]. You can use the
// `.get_string()` method from the trait [`GetString`] to get [`String`] in
// both cases
macro_rules! csi_macro {
($(
$name:ident
$(, $($nam:ident)? $($lit:literal)?)+ ;
$i:literal $(?$doc:literal)?),+ $(,)?
) => {
place! {$(
$(#[doc = __repnl__($doc, " ")])?
#[macro_export]
macro_rules! $name {
(__start__($($(__s__ $nam:expr,)?)+)) => {
__s__ crate::csi!($i, $($(__s__ $nam)? $($lit)?),+)
}
}
pub (crate) use $name;
)+}
};
}
/// Moves cursor to the given position.
#[macro_export]
macro_rules! move_to {
($x:expr, $y:expr) => {
$crate::csi!('H', $y, $x)
};
}
csi_macro!(
move_up, n; 'A' ? "Moves cursor up by N positions",
move_down, n; 'B' ? "Moves cursor down by N positions",
move_right, n; 'C' ? "Moves cursor right by N positions",
move_left, n; 'D' ? "Moves cursor left by N positions",
set_down, n; 'E' ? "Moves cursor to the start of line N lines down",
set_up, n; 'E' ? "Moves cursor to the start of line N lines up",
column, n; 'G' ? "Moves cursor to the given column",
);
/// Moves cursor one line up, scrolling if needed
pub const UP_SCRL: &str = "\x1bM";
/// Saves the cursor position (this is single save slot, not stack)
pub const CUR_SAVE: &str = "\x1b7";
/// Restores the cursor position to the last saved position (this is single
/// save slot, not stack)
pub const CUR_LOAD: &str = "\x1b8";
// Erase codes
/// Erases from the cursor to the end of the screen
pub const ERASE_TO_END: &str = "\x1b[J";
/// Erases from the start of the screen to the cursor
pub const ERASE_FROM_START: &str = "\x1b[1J";
/// Erases the entire screen
pub const ERASE_SCREEN: &str = "\x1b[2J";
/// Erases the whole screen and the scrollback buffer
pub const ERASE_ALL: &str = "\x1b[3J";
/// Erases from cursor to the end of the line
pub const ERASE_TO_LN_END: &str = "\x1b[K";
/// Erases from the start of the line to the cursor
pub const ERASE_FROM_LN_START: &str = "\x1b[1K";
/// Erases the entire line
pub const ERASE_LINE: &str = "\x1b[2K";
// Text modes
/// Resets all the text modes (colors and styles)
pub const RESET: &str = "\x1b[0m";
/// Set bold text mode (on some terminals may be just brighter color)
pub const BOLD: &str = "\x1b[1m";
/// Set dim/faint text mode
pub const FAINT: &str = "\x1b[2m";
/// Set italic mode
pub const ITALIC: &str = "\x1b[3m";
/// Set underline mode
pub const UNDERLINE: &str = "\x1b[4m";
/// Set blinking mode
pub const BLINKING: &str = "\x1b[5m";
/// Set inverse mode (inverse foreground and background)
pub const INVERSE: &str = "\x1b[7m";
/// Set invisible mode (foreground is same as background)
pub const INVISIBLE: &str = "\x1b[8m";
/// Set striketrough mode
pub const STRIKETROUGH: &str = "\x1b[9m";
/// Set double underline mode
pub const DOUBLE_UNDERLINE: &str = "\x1b[21";
/// Reset [`BOLD`] and [`FAINT`] mode
pub const RESET_BOLD: &str = "\x1b[22m";
/// Reset [`ITALIC`] mode
pub const RESET_ITALIC: &str = "\x1b[23m";
/// Reset [`UNDERLINE`] and [`DOUBLE_UNDERLINE`] mode
pub const RESET_UNDERLINE: &str = "\x1b[24m";
/// Reset [`BLINKING`] mode
pub const RESET_BLINKING: &str = "\x1b[25m";
/// Reset [`INVERSE`] mode
pub const RESET_INVERSE: &str = "\x1b[27m";
/// Reset [`INVISIBLE`] mode
pub const RESET_INVISIBLE: &str = "\x1b[28m";
/// Reset [`STRIKETROUGH`] mode
pub const RESET_STRIKETROUGH: &str = "\x1b[29m";
/// Set the foreground color to black (dark black)
pub const BLACK_FG: &str = "\x1b[30m";
/// Set the foreground color to white (bright white)
pub const WHITE_FG: &str = "\x1b[97m";
/// Set the foreground color to gray (bright black)
pub const GRAY_FG: &str = "\x1b[90m";
/// Set to foreground color to bright gray (dark white)
pub const GRAY_BRIGHT_FG: &str = "\x1b[37m";
/// Set the foreground color to red (bright red)
pub const RED_FG: &str = "\x1b[91m";
/// Set the foreground color to green (bright green)
pub const GREEN_FG: &str = "\x1b[92m";
/// Set the foreground color to yellow (bright yellow)
pub const YELLOW_FG: &str = "\x1b[93m";
/// Set the foreground color to blue (bright blue)
pub const BLUE_FG: &str = "\x1b[94m";
/// Set the foreground color to magenta (bright magenta)
pub const MAGENTA_FG: &str = "\x1b[95m";
/// Set the foreground color to cyan (bright cyan)
pub const CYAN_FG: &str = "\x1b[96m";
/// Set the foreground color to dark red
pub const RED_DARK_FG: &str = "\x1b[31m";
/// Set the foreground color to dark green
pub const GREEN_DARK_FG: &str = "\x1b[32m";
/// Set the foreground color to dark yellow
pub const YELLOW_DARK_FG: &str = "\x1b[33m";
/// Set the foreground color to dark blue
pub const BLUE_DARK_FG: &str = "\x1b[34m";
/// Set the foreground color to dark magenta
pub const MAGENTA_DARK_FG: &str = "\x1b[35m";
/// Set the foreground color to dark cyan
pub const CYAN_DARK_FG: &str = "\x1b[36m";
/// Reset the foreground color
pub const RESET_FG: &str = "\x1b[39m";
/// Set the background color to black (dark black)
pub const BLACK_BG: &str = "\x1b[40m";
/// Set the background color to white (bright white)
pub const WHITE_BG: &str = "\x1b[107m";
/// Set the background color to gray (bright black)
pub const GRAY_BG: &str = "\x1b[100m";
/// Set to background color to bright gray (dark white)
pub const GRAY_BRIGHT_BG: &str = "\x1b[47m";
/// Set the background color to red (bright red)
pub const RED_BG: &str = "\x1b[101m";
/// Set the background color to green (bright green)
pub const GREEN_BG: &str = "\x1b[102m";
/// Set the background color to yellow (bright yellow)
pub const YELLOW_BG: &str = "\x1b[103m";
/// Set the background color to blue (bright blue)
pub const BLUE_BG: &str = "\x1b[104m";
/// Set the background color to magenta (bright magenta)
pub const MAGENTA_BG: &str = "\x1b[105m";
/// Set the background color to cyan (bright cyan)
pub const CYAN_BG: &str = "\x1b[106m";
/// Set the background color to dark red
pub const RED_DARK_BG: &str = "\x1b[41m";
/// Set the background color to dark green
pub const GREEN_DARK_BG: &str = "\x1b[42m";
/// Set the background color to dark yellow
pub const YELLOW_DARK_BG: &str = "\x1b[43m";
/// Set the background color to dark blue
pub const BLUE_DARK_BG: &str = "\x1b[44m";
/// Set the background color to dark magenta
pub const MAGENTA_DARK_BG: &str = "\x1b[45m";
/// Set the background color to dark cyan
pub const CYAN_DARK_BG: &str = "\x1b[46m";
/// Reset the background color
pub const RESET_BG: &str = "\x1b[49m";
csi_macro! {
fg256, 38, 5, c; 'm'
? "creates a foreground color, color is value in range 0..256",
bg256, 48, 5, c; 'm'
? "creates a background color, color is value in range 0..256",
fg, 38, 2, r, g, b; 'm'
? "creates a true rgb foreground color. R, G and B must be values in
range 0..256",
bg, 48, 2, r, g, b; 'm'
? "creates a true rgb background color. R, G and B must be values in
range 0..256",
}
// Screen modes
/// Enables line wrapping
pub const ENABLE_LINE_WRAP: &str = "\x1b[=7h";
/// Disables line wrapping
pub const DISABLE_LINE_WRAP: &str = "\x1b[=7l";
// Private modes
/// Makes the cursor invisible
pub const HIDE_CURSOR: &str = "\x1b[?25l";
/// Makes the cursor visible
pub const SHOW_CURSOR: &str = "\x1b[?25h";
/// Saves the visible part of the screen buffer
pub const SAVE_SCREEN: &str = "\x1b[?47l";
/// Loads the last saved screen
pub const LOAD_SCREEN: &str = "\x1b[?47h";
/// Enables alternative buffer
pub const ENABLE_ALTERNATIVE_BUFFER: &str = "\x1b[?1049h";
/// Disables the laternative buffer
pub const DISABLE_ALTERNATIVE_BUFFER: &str = "\x1b[?1049l";
// Other
/*#[macro_export]
macro_rules! resize_window {
($x:expr, $y:expr) => {
$crate::csi!('t', 8, $y, $x)
};
}*/
/// Trait for getting string from &str and String
pub trait GetString {
/// If [`self`] is `&str` uses `.to_owned()`, if [`self`] is [`String`] returns
/// [`self`]
fn get_string(self) -> String;
}
impl GetString for &str {
fn get_string(self) -> String {
self.to_owned()
}
}
impl GetString for String {
fn get_string(self) -> String {
self
}
}
#[cfg(test)]
mod tests {
use std::any::TypeId;
fn type_id_of<T: 'static>(_: T) -> TypeId {
TypeId::of::<T>()
}
#[test]
fn test_macros() {
assert_eq!(csi!('a', 1, 2, 3, 4, 5), "\x1b[1;2;3;4;5a");
assert_eq!(csi!('a', 1 + 0, 2, 3, 4, 5), "\x1b[1;2;3;4;5a");
assert_eq!(type_id_of(csi!('a', 1, 2, 3, 4, 5)), TypeId::of::<&str>());
assert_eq!(
type_id_of(csi!('a', 1 + 0, 2, 3, 4, 5)),
TypeId::of::<String>()
);
}
}