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