1#![feature(default_field_values)]
7
8mod console;
10mod layout;
11#[cfg(test)]
12mod tests;
13
14use std::{
16 env::{
17 args,
18 vars
19 },
20 io::{
21 stderr,
22 Write
23 },
24 time::Instant
25};
26
27use hashbrown::HashMap as Map;
29
30use libutils_cage::Cage;
32
33use libutils_problem::{
35 Problem,
36 Threat,
37 Threaten
38};
39
40use libutils_diff::Diff;
42
43use libutils_issue::Issue;
45
46use layout::Layout;
48
49pub use console::Console;
51
52
53pub static TERMINAL: Cage<Terminal> = Cage::new(Terminal {
59 layout: Layout {..},
60 stderr: String::new()
61});
62
63pub struct Terminal {
65 layout: Layout,
66 stderr: String
67}
68
69impl Threaten for Terminal {
71 #[inline]
72 fn convert<Object: Into<Issue>, const N: usize>(&mut self, threat: Threat<Object, N>) -> Problem {return Problem {
73 chain: threat.chain.into(),
74 at: Instant::now(),
75 issue: threat.object.into(),
76 severity: threat.severity
77 }}
78}
79
80impl Console for Terminal {
82 #[inline]
83 fn arguments(&self) -> Vec<String> {args().collect()}
84 #[inline]
85 fn environment(&self) -> Map<String, String> {vars().collect()}
86 #[inline]
87 fn sync(&mut self) -> () {
88 let content = self.layout.view();
89 stderr().lock().write(<Diff as Into<Vec<u8>>>::into(Diff::new(self.stderr.as_bytes(), content.as_bytes())).as_ref()).unwrap();
90 self.stderr = content;
91 }
92 #[inline]
93 fn problem<Object: Into<Issue>, const N: usize>(&mut self, threat: Threat<Object, N>) -> () {
94 let problem = self.convert(threat);
95 self.layout.problems.push(problem);
96 self.sync();
97 }
98}