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