endbasic_std/console/
trivial.rs1use crate::console::{
19 CharsXY, ClearType, Console, Key, get_env_var_as_u16, read_key_from_stdin, remove_control_chars,
20};
21use crate::sound::BEEP_TONE;
22use async_trait::async_trait;
23use std::collections::VecDeque;
24use std::io::{self, StdoutLock, Write};
25use std::thread;
26
27const DEFAULT_COLUMNS: u16 = 80;
29
30const DEFAULT_LINES: u16 = 24;
32
33#[derive(Default)]
35pub struct TrivialConsole {
36 buffer: VecDeque<Key>,
38
39 sync_enabled: bool,
41}
42
43impl TrivialConsole {
44 fn maybe_flush(&self, mut lock: StdoutLock<'_>) -> io::Result<()> {
46 if self.sync_enabled { lock.flush() } else { Ok(()) }
47 }
48}
49
50#[async_trait(?Send)]
51impl Console for TrivialConsole {
52 fn clear(&mut self, _how: ClearType) -> io::Result<()> {
53 Ok(())
54 }
55
56 fn color(&self) -> (Option<u8>, Option<u8>) {
57 (None, None)
58 }
59
60 fn set_color(&mut self, _fg: Option<u8>, _bg: Option<u8>) -> io::Result<()> {
61 Ok(())
62 }
63
64 fn enter_alt(&mut self) -> io::Result<()> {
65 Ok(())
66 }
67
68 fn hide_cursor(&mut self) -> io::Result<()> {
69 Ok(())
70 }
71
72 fn is_interactive(&self) -> bool {
73 true
74 }
75
76 fn leave_alt(&mut self) -> io::Result<()> {
77 Ok(())
78 }
79
80 #[cfg_attr(not(debug_assertions), allow(unused))]
81 fn locate(&mut self, pos: CharsXY) -> io::Result<()> {
82 #[cfg(debug_assertions)]
83 {
84 let size = self.size_chars()?;
85 assert!(pos.x < size.x);
86 assert!(pos.y < size.y);
87 }
88 Ok(())
89 }
90
91 fn move_within_line(&mut self, _off: i16) -> io::Result<()> {
92 Ok(())
93 }
94
95 fn print(&mut self, text: &str) -> io::Result<()> {
96 let text = remove_control_chars(text);
97
98 let stdout = io::stdout();
99 let mut stdout = stdout.lock();
100 stdout.write_all(text.as_bytes())?;
101 stdout.write_all(b"\n")?;
102 Ok(())
103 }
104
105 async fn poll_key(&mut self) -> io::Result<Option<Key>> {
106 Ok(None)
107 }
108
109 async fn read_key(&mut self) -> io::Result<Key> {
110 read_key_from_stdin(&mut self.buffer)
111 }
112
113 fn show_cursor(&mut self) -> io::Result<()> {
114 Ok(())
115 }
116
117 fn size_chars(&self) -> io::Result<CharsXY> {
118 let lines = get_env_var_as_u16("LINES").unwrap_or(DEFAULT_LINES);
119 let columns = get_env_var_as_u16("COLUMNS").unwrap_or(DEFAULT_COLUMNS);
120 Ok(CharsXY::new(columns, lines))
121 }
122
123 fn write(&mut self, text: &str) -> io::Result<()> {
124 let text = remove_control_chars(text);
125
126 let stdout = io::stdout();
127 let mut stdout = stdout.lock();
128 stdout.write_all(text.as_bytes())?;
129 self.maybe_flush(stdout)
130 }
131
132 fn sync_now(&mut self) -> io::Result<()> {
133 if self.sync_enabled { Ok(()) } else { io::stdout().flush() }
134 }
135
136 fn set_sync(&mut self, enabled: bool) -> io::Result<bool> {
137 if !self.sync_enabled {
138 io::stdout().flush()?;
139 }
140 let previous = self.sync_enabled;
141 self.sync_enabled = enabled;
142 Ok(previous)
143 }
144
145 async fn beep(&mut self) -> io::Result<()> {
146 let stdout = io::stdout();
147 let mut stdout = stdout.lock();
148 stdout.write_all(b"\x07")?;
149 stdout.flush()?;
150 thread::sleep(BEEP_TONE.duration);
151 Ok(())
152 }
153}