1#![feature(const_trait_impl)]
7#![feature(const_default)]
8
9mod problem;
11#[cfg(test)]
12mod tests;
13
14use std::{
16 env::args,
17 io::{
18 Write,
19 stdout
20 },
21 sync::LazyLock,
22 fs::read_to_string,
23 path::PathBuf
24};
25
26use libutils_cage::Cage;
28
29use libutils_threat::Threat;
31
32use libutils_diff::Diff;
34
35use libutils_issue::{
37 Issue,
38 Severity
39};
40
41use libutils_console::{
43 Console,
44 Argument
45};
46
47use problem::Problem;
49
50
51pub static TERMINAL: Terminal = Terminal {
57 arguments: LazyLock::new(|| args().map(Argument::from).collect()),
58 layout: Cage::default(),
59 output: Cage::default()
60};
61
62pub struct Terminal {
64 arguments: LazyLock<Vec<Argument>>,
65 layout: Cage<Vec<Problem>>,
66 output: Cage<String>
67}
68
69impl Console for Terminal {
71 #[inline]
72 fn arguments<'valid>(&'valid self) -> &'valid [Argument] {return self.arguments.as_slice()}
73 #[inline]
74 fn read(&self, filename: &str) -> Result<String, Issue> {return read_to_string(PathBuf::from(filename)).map_err(|error| Issue {
75 name: "Failed to read file",
76 description: Some(error.to_string()),
77 severity: Severity::Error
78 })}
79 #[inline]
80 fn sync(&self) -> () {
81 let content = self.layout.read().iter().map(ToString::to_string).collect::<Vec<String>>().join("\n\n");
82 self.output.with_mut(|output| {
83 let mut lock = stdout().lock();
84 lock.write(<Diff as Into<Vec<u8>>>::into(Diff::new(
85 output.as_bytes(),
86 content.as_bytes()
87 )).as_ref()).unwrap();
88 lock.flush().unwrap();
89 *output = content;
90 });
91 }
92 #[inline]
93 fn problem(&self, threat: Threat) -> () {self.layout.write().push(threat.into())}
94}