1#![warn(clippy::pedantic)]
3#![warn(missing_docs)]
4
5use std::io::{stdout, Write};
6
7#[cfg(feature = "crossterm")]
8pub use crossterm;
9
10pub mod clear;
11pub mod color;
12pub mod goto;
13pub mod guard;
14pub mod prelude;
15pub mod rect;
16pub mod style;
17pub mod term;
18
19mod line;
20mod println;
21
22#[cfg(feature = "crossterm")]
23pub mod read;
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub struct NonOrthogonal;
29
30fn escape<T: std::fmt::Display>(code: T) {
32 print!("{}[{}", 27 as char, code);
33}
34
35pub fn normal() {
37 escape("0m");
38}
39
40pub fn pixel(c: char, x: u32, y: u32) {
42 escape(format!("{};{}H{}", y + 1, x + 1, c));
43}
44
45pub fn orth_line(c: char, x1: u32, y1: u32, x2: u32, y2: u32) -> Result<(), NonOrthogonal> {
51 if x1 != x2 && y1 != y2 {
52 return Err(NonOrthogonal);
53 }
54
55 if x1 == x2 {
56 let mut y = y1.min(y2);
57
58 while y != y1.max(y2) + 1 {
59 pixel(c, x1, y);
60
61 y += 1;
62 }
63 } else {
64 let mut x = x1.min(x2);
65
66 while x != x1.max(x2) + 1 {
67 pixel(c, x, y1);
68
69 x += 1;
70 }
71 }
72
73 Ok(())
74}
75
76#[allow(clippy::missing_panics_doc)]
78pub fn line(c: char, x1: u32, y1: u32, x2: u32, y2: u32) {
79 if x1 == x2 || y1 == y2 {
80 orth_line(c, x1, x2, y1, y2).unwrap();
81 return;
82 }
83
84 for (x, y) in line::Iter::new(x1, y1, x2, y2) {
85 pixel(c, x, y);
86 }
87}
88
89pub fn blit<S: AsRef<str>>(src: S, mut x: u32, mut y: u32) {
91 let src = src.as_ref();
92 let rows = src.split('\n').map(|s| s.chars());
93
94 let ox = x;
95 for row in rows {
96 for c in row {
97 pixel(c, x, y);
98 x += 1;
99 }
100 x = ox;
101 y += 1;
102 }
103}
104
105pub fn blit_transparent<S: AsRef<str>>(src: S, blank: char, mut x: u32, mut y: u32) {
119 let src = src.as_ref();
120 let rows = src.split('\n').map(|s| s.chars());
121
122 let ox = x;
123 for row in rows {
124 for c in row {
125 match c {
126 ' ' => goto::right(1),
127 ch if ch == blank => pixel(' ', x, y),
128 _ => pixel(c, x, y),
129 }
130 x += 1;
131 }
132 x = ox;
133 y += 1;
134 }
135}
136
137pub fn triangle(c: char, x1: u32, y1: u32, x2: u32, y2: u32, x3: u32, y3: u32) {
139 line(c, x1, y1, x2, y2);
140 line(c, x2, y2, x3, y3);
141 line(c, x1, y1, x3, y3);
142}
143
144pub fn text<S: AsRef<str>>(s: S, x: u32, mut y: u32) {
152 let chars = s.as_ref().chars();
153 let mut nx = x;
154 for ch in chars {
155 if ch == '\n' {
156 nx = x;
157 y += 1;
158 }
159
160 pixel(ch, nx, y);
161 nx += 1;
162 }
163}
164
165pub fn flush() {
171 stdout().flush().expect("Failed to flush stdout");
172}