nconsole/
lib.rs

1use crate::command::{Command, GenericCommand};
2use crate::error_handler::{ErrorHandler, NErrorHandler};
3use colored::Colorize;
4use std::io;
5use std::io::{stdout, Write};
6
7pub mod command;
8pub mod error_handler;
9
10pub fn log(log_type: LogTypes, message: String) {
11    match log_type {
12        LogTypes::INFO => println!("{} {}", "[INFO]".green(), message),
13        LogTypes::WARN => println!("{} {}", "[WARNING]".yellow(), message),
14        LogTypes::ERR => println!("{} {}", "[ERROR]".red(), message),
15    }
16}
17
18pub struct CommandsRegister<E> {
19    commands: Vec<GenericCommand>,
20    error_handler: E,
21    help_command: bool,
22}
23
24impl Default for CommandsRegister<NErrorHandler> {
25    fn default() -> Self {
26        Self::new(NErrorHandler::new(), true)
27    }
28}
29
30impl<E: ErrorHandler> CommandsRegister<E> {
31    pub fn new(error_handle: E, help_command: bool) -> Self {
32        Self {
33            commands: vec![],
34            error_handler: error_handle,
35            help_command,
36        }
37    }
38
39    pub fn get_error_handler(&self) -> &E {
40        &self.error_handler
41    }
42
43    pub fn get_command(&mut self, command_str: &str) -> Option<&mut GenericCommand> {
44        for command in self.commands.iter_mut() {
45            if command.get_command_name() == command_str {
46                return Some(command);
47            }
48            for alias in command.get_command_alias() {
49                if alias == command_str {
50                    return Some(command);
51                }
52            }
53        }
54
55        None
56    }
57
58    pub fn start(&mut self) {
59        self.commands.iter_mut().for_each(|command| {
60            command.start();
61        });
62    }
63
64    pub fn end(&mut self) {
65        self.commands.iter_mut().for_each(|command| {
66            command.end();
67        });
68    }
69
70    pub fn register_command(&mut self, command: GenericCommand) {
71        self.commands.push(command);
72    }
73
74    pub fn check_input(&mut self, input: String) -> bool {
75        let mut input = input.split_whitespace();
76        let command_or_alias = input.next().unwrap();
77
78        let mut args: Vec<&str> = vec![];
79        for arg in input {
80            args.push(arg);
81        }
82
83        if let Some(command) = self.get_command(command_or_alias) {
84            command.on_command(args);
85            true
86        } else if self.help_command && Self::is_help_command(command_or_alias) {
87            self.help(&args);
88            true
89        } else {
90            false
91        }
92    }
93
94    pub fn help(&mut self, args: &[&str]) {
95        match args.len() {
96            0 => {
97                let mut content = String::new();
98                for command in &self.commands {
99                    content.push_str(command.get_command_name());
100                    content.push('\n');
101                    content.push_str(command.get_help());
102                    content.push_str("\n\n");
103                }
104                println!("{content}");
105            }
106            1 => {
107                let command = if let Some(c) = self.get_command(args[0]) {
108                    c
109                } else {
110                    return;
111                };
112                let mut content = String::new();
113                content.push_str(command.get_command_name());
114                content.push('\n');
115                content.push_str(command.get_help());
116                content.push_str("\n\n");
117                println!("{content}");
118            }
119            _ => {}
120        }
121    }
122
123    fn is_help_command(command_str: &str) -> bool {
124        command_str == "help" || command_str == "h" || command_str == "?"
125    }
126}
127
128pub enum LogTypes {
129    INFO,
130    WARN,
131    ERR,
132}
133
134pub struct Console<E: ErrorHandler> {
135    prompt: String,
136    commands_register: CommandsRegister<E>,
137}
138
139impl<E: ErrorHandler> Console<E> {
140    pub fn new(prompt: String, commands_register: CommandsRegister<E>) -> Self {
141        Self {
142            prompt,
143            commands_register,
144        }
145    }
146
147    pub fn update(&mut self) {
148        let mut input = String::new();
149        print!("{}", self.prompt);
150        stdout().flush().unwrap();
151
152        io::stdin()
153            .read_line(&mut input)
154            .expect("Failed to read line");
155
156        if input.trim().is_empty() {
157            self.commands_register.get_error_handler().input_void();
158            return;
159        }
160        let copy = input.clone();
161        let command = copy.split_ascii_whitespace().next().unwrap();
162
163        let handled = self.commands_register.check_input(input);
164
165        if !handled {
166            self.commands_register
167                .get_error_handler()
168                .wrong_command(command);
169        }
170    }
171}
172
173#[cfg(test)]
174mod tests {}