use crate::{_ansi_consts, Digits, StringNonul, slice, write_at};
#[doc = crate::_tags!(term namespace)]
#[doc = crate::_doc_location!("sys/os/term")]
#[doc = crate::doclink!(custom devela "[`ansi!`]" "sys/os/term/macro.ansi.html")]
#[derive(Debug)]
pub struct Ansi;
impl Ansi {
_ansi_consts! {
pub const CSI: [u8; 2] = "\x1b[", *b"\x1b[";
}
#[must_use]
const fn write_ansi_code_n(buffer: &mut [u8], n: u16, final_byte: u8) -> &[u8] {
buffer[0] = b'\x1b';
buffer[1] = b'[';
let mut index = 2;
index += Digits(n).write_digits10(buffer, index);
buffer[index] = final_byte;
slice![buffer, ..=index]
}
}
impl Ansi {
_ansi_consts! {
pub const ENABLE_ALT_SCREEN: [u8; 8] = "\x1b[?1049h", *b"\x1b[?1049h";
pub const DISABLE_ALT_SCREEN: [u8; 8] = "\x1b[?1049l", *b"\x1b[?1049l";
}
}
impl Ansi {
_ansi_consts! {
pub const ERASE_LINE_END: [u8; 3] = "\x1b[K", *b"\x1b[K"; pub const ERASE_LINE_START: [u8; 4] = "\x1b[1K", *b"\x1b[1K";
pub const ERASE_LINE: [u8; 4] = "\x1b[2K", *b"\x1b[2K";
pub const ERASE_SCREEN_END: [u8; 3] = "\x1b[J", *b"\x1b[J"; pub const ERASE_SCREEN_START: [u8; 4] = "\x1b[1J", *b"\x1b[1J";
pub const ERASE_SCREEN: [u8; 4] = "\x1b[2J", *b"\x1b[2J";
}
}
impl Ansi {
_ansi_consts! {
pub const CURSOR_INVISIBLE: [u8; 6] = "\x1b[?25l", *b"\x1b[?25l";
pub const CURSOR_VISIBLE: [u8; 6] = "\x1b[?25h", *b"\x1b[?25h";
pub const CURSOR_SAVE: [u8; 3] = "\x1b[s", *b"\x1b[s";
pub const CURSOR_RESTORE: [u8; 3] = "\x1b[u", *b"\x1b[u";
pub const CURSOR_HOME: [u8; 3] = "\x1b[H", *b"\x1b[H";
}
_ansi_consts! {
pub const fn CURSOR_MOVE1(col: u8, row: u8) -> [u8; 6] {
[ b'\x1b', b'[', Digits(row).digits10_1(), b';', Digits(col).digits10_1(), b'H' ]
}
pub const fn CURSOR_MOVE2(col: u8, row: u8) -> [u8; 8] {
let r: [u8; 2] = Digits(row).digits10_2();
let c: [u8; 2] = Digits(col).digits10_2();
[b'\x1b', b'[', r[0], r[1], b';', c[0], c[1], b'H']
}
pub const fn CURSOR_MOVE3(col: u16, row: u16) -> [u8; 10] {
let r: [u8; 3] = Digits(row).digits10_3();
let c: [u8; 3] = Digits(col).digits10_3();
[b'\x1b', b'[', r[0], r[1], r[2], b';', c[0], c[1], c[2], b'H']
}
pub const fn CURSOR_MOVE4(col: u16, row: u16) -> [u8; 12] {
let r: [u8; 4] = Digits(row).digits10_4();
let c: [u8; 4] = Digits(col).digits10_4();
[b'\x1b', b'[', r[0], r[1], r[2], r[3], b';', c[0], c[1], c[2], c[3], b'H']
}
}
pub const fn CURSOR_MOVE(col: u16, row: u16) -> StringNonul<14> {
let mut buf = [0; 14];
let _ = Self::CURSOR_MOVE_N(&mut buf, col, row);
StringNonul::<14>::_from_array_trusted(buf)
}
_ansi_consts! {
pub const fn CURSOR_MOVE_N(buffer: &mut [u8], col: u16, row: u16) -> &[u8] {
buffer[0] = b'\x1b';
buffer[1] = b'[';
let mut index = 2;
index += Digits(row).write_digits10(buffer, index);
write_at![buffer, +=index, b';'];
index += Digits(col).write_digits10(buffer, index);
buffer[index] = b'H';
slice![buffer, ..=index]
}
}
_ansi_consts! {
pub const CURSOR_UP: [u8; 3] = "\x1b[A", *b"\x1b[A";
}
_ansi_consts! {
pub const fn CURSOR_UP1(n: u8) -> [u8; 4] {
[b'\x1b', b'[', Digits(n).digits10_1(), b'A']
}
pub const fn CURSOR_UP2(n: u8) -> [u8; 5] {
let n: [u8; 2] = Digits(n).digits10_2();
[b'\x1b', b'[', n[0], n[1], b'A']
}
pub const fn CURSOR_UP3(n: u16) -> [u8; 6] {
let n: [u8; 3] = Digits(n).digits10_3();
[b'\x1b', b'[', n[0], n[1], n[2], b'A']
}
pub const fn CURSOR_UP4(n: u16) -> [u8; 7] {
let n: [u8; 4] = Digits(n).digits10_4();
[b'\x1b', b'[', n[0], n[1], n[2], n[3], b'A']
}
}
_ansi_consts! {
pub const fn CURSOR_UP_N(buffer: &mut [u8], n: u16) -> &[u8] {
Self::write_ansi_code_n(buffer, n, b'A')
}
}
_ansi_consts! {
pub const CURSOR_DOWN: [u8; 3] = "\x1b[B", *b"\x1b[B";
}
_ansi_consts! {
pub const fn CURSOR_DOWN1(n: u8) -> [u8; 4] {
[b'\x1b', b'[', Digits(n).digits10_1(), b'B']
}
pub const fn CURSOR_DOWN2(n: u8) -> [u8; 5] {
let n: [u8; 2] = Digits(n).digits10_2();
[b'\x1b', b'[', n[0], n[1], b'B']
}
pub const fn CURSOR_DOWN3(n: u16) -> [u8; 6] {
let n: [u8; 3] = Digits(n).digits10_3();
[b'\x1b', b'[', n[0], n[1], n[2], b'B']
}
pub const fn CURSOR_DOWN4(n: u16) -> [u8; 7] {
let n: [u8; 4] = Digits(n).digits10_4();
[b'\x1b', b'[', n[0], n[1], n[2], n[3], b'B']
}
}
_ansi_consts! {
pub const fn CURSOR_DOWN_N(buffer: &mut [u8], n: u16) -> &[u8] {
Self::write_ansi_code_n(buffer, n, b'B')
}
}
_ansi_consts! {
pub const CURSOR_RIGHT: [u8; 3] = "\x1b[C", *b"\x1b[C";
}
_ansi_consts! {
pub const fn CURSOR_RIGHT1(n: u8) -> [u8; 4] {
[b'\x1b', b'[', Digits(n).digits10_1(), b'C']
}
pub const fn CURSOR_RIGHT2(n: u8) -> [u8; 5] {
let n: [u8; 2] = Digits(n).digits10_2();
[b'\x1b', b'[', n[0], n[1], b'C']
}
pub const fn CURSOR_RIGHT3(n: u16) -> [u8; 6] {
let n: [u8; 3] = Digits(n).digits10_3();
[b'\x1b', b'[', n[0], n[1], n[2], b'C']
}
pub const fn CURSOR_RIGHT4(n: u16) -> [u8; 7] {
let n: [u8; 4] = Digits(n).digits10_4();
[b'\x1b', b'[', n[0], n[1], n[2], n[3], b'C']
}
}
_ansi_consts! {
pub const fn CURSOR_RIGHT_N(buffer: &mut [u8], n: u16) -> &[u8] {
Self::write_ansi_code_n(buffer, n, b'C')
}
}
_ansi_consts! {
pub const CURSOR_LEFT: [u8; 3] = "\x1b[D", *b"\x1b[D";
}
_ansi_consts! {
pub const fn CURSOR_LEFT1(n: u8) -> [u8; 4] {
[b'\x1b', b'[', Digits(n).digits10_1(), b'D']
}
pub const fn CURSOR_LEFT2(n: u8) -> [u8; 5] {
let n: [u8; 2] = Digits(n).digits10_2();
[b'\x1b', b'[', n[0], n[1], b'D']
}
pub const fn CURSOR_LEFT3(n: u16) -> [u8; 6] {
let n: [u8; 3] = Digits(n).digits10_3();
[b'\x1b', b'[', n[0], n[1], n[2], b'D']
}
pub const fn CURSOR_LEFT4(n: u16) -> [u8; 7] {
let n: [u8; 4] = Digits(n).digits10_4();
[b'\x1b', b'[', n[0], n[1], n[2], n[3], b'D']
}
}
_ansi_consts! {
pub const fn CURSOR_LEFT_N(buffer: &mut [u8], n: u16) -> &[u8] {
Self::write_ansi_code_n(buffer, n, b'D')
}
}
_ansi_consts! {
pub const CURSOR_NEXT_LINE: [u8; 3] = "\x1b[E", *b"\x1b[E";
}
_ansi_consts! {
pub const fn CURSOR_NEXT_LINE1(n: u8) -> [u8; 4] {
[b'\x1b', b'[', Digits(n).digits10_1(), b'E']
}
pub const fn CURSOR_NEXT_LINE2(n: u8) -> [u8; 5] {
let n: [u8; 2] = Digits(n).digits10_2();
[b'\x1b', b'[', n[0], n[1], b'E']
}
pub const fn CURSOR_NEXT_LINE3(n: u16) -> [u8; 6] {
let n: [u8; 3] = Digits(n).digits10_3();
[b'\x1b', b'[', n[0], n[1], n[2], b'E']
}
pub const fn CURSOR_NEXT_LINE4(n: u16) -> [u8; 7] {
let n: [u8; 4] = Digits(n).digits10_4();
[b'\x1b', b'[', n[0], n[1], n[2], n[3], b'E']
}
}
_ansi_consts! {
pub const fn CURSOR_NEXT_LINE_N(buffer: &mut [u8], n: u16) -> &[u8] {
Self::write_ansi_code_n(buffer, n, b'F')
}
}
_ansi_consts! {
pub const CURSOR_PREV_LINE: [u8; 3] = "\x1b[E", *b"\x1b[E";
}
_ansi_consts! {
pub const fn CURSOR_PREV_LINE1(n: u8) -> [u8; 4] {
[b'\x1b', b'[', Digits(n).digits10_1(), b'E']
}
pub const fn CURSOR_PREV_LINE2(n: u8) -> [u8; 5] {
let n: [u8; 2] = Digits(n).digits10_2();
[b'\x1b', b'[', n[0], n[1], b'E']
}
pub const fn CURSOR_PREV_LINE3(n: u16) -> [u8; 6] {
let n: [u8; 3] = Digits(n).digits10_3();
[b'\x1b', b'[', n[0], n[1], n[2], b'E']
}
pub const fn CURSOR_PREV_LINE4(n: u16) -> [u8; 7] {
let n: [u8; 4] = Digits(n).digits10_4();
[b'\x1b', b'[', n[0], n[1], n[2], n[3], b'E']
}
}
_ansi_consts! {
pub const fn CURSOR_PREV_LINE_N(buffer: &mut [u8], n: u16) -> &[u8] {
Self::write_ansi_code_n(buffer, n, b'E')
}}
}
impl Ansi {
_ansi_consts! {
pub const MOUSE_X10_ENABLE: [u8; 5] = "\x1b[?9h", *b"\x1b[?9h";
pub const MOUSE_X10_DISABLE: [u8; 5] = "\x1b[?9l", *b"\x1b[?9l";
pub const MOUSE_UTF8: [u8; 8] = "\x1b[?1005h", *b"\x1b[?1005h";
pub const MOUSE_SGR: [u8; 8] = "\x1b[?1006h", *b"\x1b[?1006h";
pub const MOUSE_SGR_PIXELS: [u8; 8] = "\x1b[?1016h", *b"\x1b[?1016h"; }
}
impl Ansi {
_ansi_consts! {
pub const RESET: [u8; 4] = "\x1b[0m", *b"\x1b[0m";
pub const BOLD: [u8; 4] = "\x1b[1m", *b"\x1b[1m";
pub const BOLD_OFF: [u8; 5] = "\x1b[22m", *b"\x1b[22m";
pub const ITALIC: [u8; 4] = "\x1b[3m", *b"\x1b[3m";
pub const ITALIC_OFF: [u8; 5] = "\x1b[23m", *b"\x1b[23m";
pub const DIM: [u8; 4] = "\x1b[2m", *b"\x1b[2m";
pub const DIM_OFF: [u8; 5] = "\x1b[22m", *b"\x1b[22m";
pub const UNDERLINE: [u8; 4] = "\x1b[4m", *b"\x1b[4m";
pub const UNDERLINE_OFF: [u8; 5] = "\x1b[24m", *b"\x1b[24m";
pub const BLINK: [u8; 4] = "\x1b[5m", *b"\x1b[5m";
pub const BLINK_OFF: [u8; 5] = "\x1b[25m", *b"\x1b[25m";
pub const INVERSE: [u8; 4] = "\x1b[7m", *b"\x1b[7m";
pub const INVERSE_OFF: [u8; 5] = "\x1b[27m", *b"\x1b[27m";
pub const CROSSED: [u8; 4] = "\x1b[9m", *b"\x1b[9m";
pub const CROSSED_OFF: [u8; 5] = "\x1b[29m", *b"\x1b[29m";
}
}
#[cfg(test)]
mod tests {
use super::Ansi;
#[test]
fn write_ansi_code_n() {
let mut buffer = [0u8; 16];
let result = Ansi::write_ansi_code_n(&mut buffer, 0, b'J');
assert_eq!(result, b"\x1b[0J");
let result = Ansi::write_ansi_code_n(&mut buffer, 5, b'm');
assert_eq!(result, b"\x1b[5m");
let result = Ansi::write_ansi_code_n(&mut buffer, 255, b'B');
assert_eq!(result, b"\x1b[255B");
let result = Ansi::write_ansi_code_n(&mut buffer, 15000, b'C');
assert_eq!(result, b"\x1b[15000C");
}
#[test]
fn cursor_move_n() {
let mut buffer = [0u8; 32];
let result = Ansi::CURSOR_MOVE_N_B(&mut buffer, 0, 0);
assert_eq!(result, b"\x1b[0;0H");
let result = Ansi::CURSOR_MOVE_N_B(&mut buffer, 1, 2);
assert_eq!(result, b"\x1b[2;1H");
let result = Ansi::CURSOR_MOVE_N_B(&mut buffer, 5, 10);
assert_eq!(result, b"\x1b[10;5H");
let result = Ansi::CURSOR_MOVE_N_B(&mut buffer, 123, 456);
assert_eq!(result, b"\x1b[456;123H");
let result = Ansi::CURSOR_MOVE_N_B(&mut buffer, 1999, 10999);
assert_eq!(result, b"\x1b[10999;1999H");
let result = Ansi::CURSOR_MOVE(30_000, 20_000); assert_eq!(result, "\x1b[20000;30000H");
}
}