1#![feature(default_field_values)]
7#![feature(const_trait_impl)]
8
9mod layout;
11mod problem;
12#[cfg(test)]
13mod tests;
14
15use std::{
17 env::args,
18 io::{
19 Write,
20 stderr
21 },
22 sync::LazyLock,
23 fs::read_to_string,
24 path::PathBuf
25};
26
27use libutils_cage::Cage;
29
30use libutils_threat::Threat;
32
33use libutils_diff::Diff;
35
36use layout::Layout;
38
39use libutils_issue::{
41 Issue,
42 Severity
43};
44
45use libutils_console::{
47 Console,
48 Argument
49};
50
51
52pub static TERMINAL: Cage<Terminal> = Cage::new(Terminal {..});
58
59pub struct Terminal {
61 layout: Layout = Layout {..},
62 arguments: LazyLock<Vec<Argument>> = LazyLock::new(|| args().map(Argument::from).collect()),
63 stderr: String = String::new()
64}
65
66impl Console for Terminal {
68 #[inline]
69 fn arguments(&self) -> &[Argument] {return self.arguments.as_slice()}
70 #[inline]
71 fn read(&self, filename: &str) -> Result<String, Issue> {return read_to_string(PathBuf::from(filename)).map_err(|error| Issue {
72 name: "Failed to read file",
73 description: Some(error.to_string()),
74 severity: Severity::Error
75 })}
76 #[inline]
77 fn sync(&mut self) -> () {
78 let content = self.layout.view();
79 stderr().lock().write(<Diff as Into<Vec<u8>>>::into(Diff::new(
80 self.stderr.as_bytes(),
81 content.as_bytes())
82 ).as_ref()).unwrap();
83 stderr().lock().flush().unwrap();
84 self.stderr = content;
85 }
86 #[inline]
87 fn problem(&mut self, threat: Threat) -> () {self.layout.problems.push(threat.into())}
88}