Skip to main content

libutils_terminal/
mod.rs

1//^
2//^ HEAD
3//^
4
5//> HEAD -> FEATURES
6#![feature(const_trait_impl)]
7#![feature(const_default)]
8
9//> HEAD -> MODULES
10mod problem;
11#[cfg(test)]
12mod tests;
13
14//> HEAD -> STD
15use std::{
16    env::args, 
17    io::{
18        Write, 
19        stdout
20    }, 
21    sync::LazyLock,
22    fs::read_to_string,
23    path::PathBuf
24};
25
26//> HEAD -> CAGE
27use libutils_cage::Cage;
28
29//> HEAD -> PROBLEM
30use libutils_threat::Threat;
31
32//> HEAD -> DIFF
33use libutils_diff::Diff;
34
35//> HEAD -> ISSUE
36use libutils_issue::{
37    Issue,
38    Severity
39};
40
41//> HEAD -> CONSOLE
42use libutils_console::{
43    Console,
44    Argument
45};
46
47//> HEAD -> PROBLEM
48use problem::Problem;
49
50
51//^
52//^ TERMINAL
53//^
54
55//> TERMINAL -> INSTANCE
56pub static TERMINAL: Terminal = Terminal {
57    arguments: LazyLock::new(|| args().map(Argument::from).collect()),
58    layout: Cage::default(),
59    output: Cage::default()
60};
61
62//> TERMINAL -> STRUCT
63pub struct Terminal {
64    arguments: LazyLock<Vec<Argument>>,
65    layout: Cage<Vec<Problem>>,
66    output: Cage<String>
67}
68
69//> TERMINAL -> IMPLEMENTATION
70impl 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}