terminal-framework 0.0.2

A simple library to manage the terminal via ANSI escape sequences
Documentation
use std::io::{self, Write};

use self::{clearing::Clearable, colors::Colorable, cursor::Cursor};

pub mod clearing;
pub mod colors;
pub mod cursor;

// Cursor movements:
// ESC[H 	moves cursor to home position (0, 0)
// ESC[{line};{column}H
// ESC[{line};{column}f 	moves cursor to line #, column #
// ESC[#A 	moves cursor up # lines
// ESC[#B 	moves cursor down # lines
// ESC[#C 	moves cursor right # columns
// ESC[#D 	moves cursor left # columns

// Colors table:
// Color    FG  BG
// Black    30  40
// Red      31  41
// Green    32  42
// Yellow   33  43
// Blue     34  43
// Magenta  35  45
// Cyan     36  46
// White    37  47
// Default  39  49
// Reset    0   0

// Screen Clearing:
// ToEndOfScreen       0J
// ToBeginingOfScreen  1J
// EntrieScreen        2J
// ToBeginingOfLine    0K
// ToEndOfLine         1K
// EntrieLine          2K

const CSI: &str = "\x1b[";

pub struct Point {
    pub x: usize,
    pub y: usize
}

pub struct AnsiDisplay {
    origin: Point,
    width: usize,
    height: usize,
    cursor: Point
}

impl AnsiDisplay {
    pub fn new(width: usize, height: usize, origin: Option<Point>) ->Self {
        let cursor = Point {
            x: 0,
            y: 0
        };
        let origin = match origin {
            Some(o) => o,
            None => Point {
                x: 0,
                y: 0
            }
        };
        AnsiDisplay {
            width,
            height,
            cursor,
            origin
        }
    }
    pub fn resize(&mut self, new_width: Option<usize>, new_height: Option<usize>) {
        self.width = match new_width {
            Some(w) => w,
            None => self.width
        };
        self.height = match new_height {
            Some(h) => h,
            None => self.height
        };
    }
    pub fn print(){}
}

impl Cursor for AnsiDisplay {
    fn move_up(&mut self, lines: Option<usize>) {
        let lines = match lines {
            Some(l) => l,
            None => 1
        };

        if lines + self.cursor.y >= self.height {
            return;
        }

        self.cursor.y -= lines;
        print!("{}{}A", CSI, lines);
        io::stdout().flush().unwrap();
    }
    fn move_down(&mut self, lines: Option<usize>) {
        let lines = match lines {
            Some(l) => l,
            None => 1
        };

        if lines + self.cursor.y >= self.height {
            return;
        }

        self.cursor.y += lines;
        print!("{}{}B", CSI, lines);
        io::stdout().flush().unwrap();
    }
    fn move_right(&mut self, cols: Option<usize>) {
        let cols = match cols {
            Some(l) => l,
            None => 1
        };

        if cols + self.cursor.x >= self.width {
            return;
        }

        self.cursor.x += cols;
        print!("{}{}C", CSI, cols);
        io::stdout().flush().unwrap();
    }
    fn move_left(&mut self, cols: Option<usize>) {
        let cols = match cols {
            Some(l) => l,
            None => 1
        };

        if cols + self.cursor.x >= self.width {
            return;
        }

        print!("{}{}A", CSI, cols);
        io::stdout().flush().unwrap();
    }
    fn position(&mut self, x: usize, y: usize) {

        if x >= self.width || y >= self.height {
            return;
        }

        print!("{}{};{}H", CSI, y, x);
        io::stdout().flush().unwrap();
    }
}

impl Colorable for AnsiDisplay {
    fn set_bg_color(&mut self, color: Option<colors::Color>) {
        let color: &str = match color {
            Some(c) => {
                match c {
                    colors::Color::Black => "40",
                    colors::Color::Red => "41",
                    colors::Color::Green => "42",
                    colors::Color::Yellow => "43",
                    colors::Color::Blue => "44",
                    colors::Color::Magenta => "45",
                    colors::Color::Cyan => "46",
                    colors::Color::White => "47",
                    colors::Color::Default => "49",
                    colors::Color::Reset => "0"
                }
            },
            None => "49"
        };
        print!("{}{}m", CSI, color);
        io::stdout().flush().unwrap();
    }
    fn set_fg_color(&mut self, color: Option<colors::Color>) {
        let color: &str = match color {
            Some(c) => {
                match c {
                    colors::Color::Black => "30",
                    colors::Color::Red => "31",
                    colors::Color::Green => "32",
                    colors::Color::Yellow => "33",
                    colors::Color::Blue => "34",
                    colors::Color::Magenta => "35",
                    colors::Color::Cyan => "36",
                    colors::Color::White => "37",
                    colors::Color::Default => "39",
                    colors::Color::Reset => "0"
                }
            },
            None => "49"
        };
        print!("{}{}m", CSI, color);
        io::stdout().flush().unwrap();
    }
}

impl Clearable for AnsiDisplay {
    fn clear_line(&self) {
        print!("{}2K", CSI);
        io::stdout().flush().unwrap();
    }
    fn clear_screen(&self) {
        print!("{}2J", CSI);
        io::stdout().flush().unwrap();
    }
    fn clear_to_end_of_screen(&self) {
        print!("{}0J", CSI);
        io::stdout().flush().unwrap();
    }
    fn clear_to_begin_of_screen(&self) {
        print!("{}1J", CSI);
        io::stdout().flush().unwrap();
    }
    fn clear_to_end_of_line(&self) {
        print!("{}0K", CSI);
        io::stdout().flush().unwrap();
    }
    fn clear_to_begin_of_line(&self) {
        print!("{}1K", CSI);
        io::stdout().flush().unwrap();
    }
}