Control logging using key events

This commit is contained in:
eatmynerds 2024-12-05 01:33:44 -06:00 committed by BitSyndicate
parent 1be431cf6f
commit f982c78c5b
6 changed files with 94 additions and 52 deletions

View file

@ -1,10 +1,68 @@
use super::{commands, Callable, COMMAND_LIST};
use crate::{
core::repl::{commands, Callable, COMMAND_LIST},
utils::logger::LOGGER,
};
use anyhow::Result;
use chrono::Local;
use colored::Colorize;
use log::debug;
use regex::Regex;
use rustyline::DefaultEditor;
use rustyline::{
error::ReadlineError, highlight::Highlighter, hint::HistoryHinter, history::DefaultHistory,
Cmd, Completer, ConditionalEventHandler, Editor, Event, EventContext, EventHandler, Helper,
Hinter, KeyEvent, RepeatCount, Validator,
};
use std::{
borrow::Cow::{self, Borrowed, Owned},
sync::{Arc, Mutex},
};
#[derive(Completer, Helper, Hinter, Validator)]
struct MyHelper(#[rustyline(Hinter)] HistoryHinter);
impl Highlighter for MyHelper {
fn highlight_prompt<'b, 's: 'b, 'p: 'b>(
&'s self,
prompt: &'p str,
default: bool,
) -> Cow<'b, str> {
if default {
Owned(prompt.bright_black().bold().to_string())
} else {
Borrowed(prompt)
}
}
fn highlight_hint<'h>(&self, hint: &'h str) -> Cow<'h, str> {
Owned(hint.bold().to_string())
}
}
#[derive(Clone)]
struct BacktickEventHandler {
toggle_state: Arc<Mutex<bool>>, // Tracks whether logging is enabled or disabled
}
impl ConditionalEventHandler for BacktickEventHandler {
fn handle(&self, evt: &Event, _: RepeatCount, _: bool, _: &EventContext) -> Option<Cmd> {
if let Some(k) = evt.get(0) {
if *k == KeyEvent::from('`') {
let mut state = self.toggle_state.lock().unwrap();
if *state {
LOGGER.write_to_stdout();
} else {
LOGGER.write_to_file("z.log");
}
*state = !*state;
Some(Cmd::Noop)
} else {
None
}
} else {
unreachable!()
}
}
}
fn register_commands() {
COMMAND_LIST.add_command(
@ -42,13 +100,10 @@ fn register_commands() {
None,
);
// EXAMPLE
// Adding aliases for commands
// Example of adding aliases for commands
COMMAND_LIST.add_alias("clear".to_string(), "cls".to_string());
}
fn evaluate_command(input: &str) {
if input.trim().is_empty() {
return;
@ -79,35 +134,43 @@ fn evaluate_command(input: &str) {
}
}
pub async fn handle_repl() -> rustyline::Result<()> {
let mut line_editor = DefaultEditor::new()?;
if line_editor.load_history("history.txt").is_err() {
pub async fn handle_repl() -> Result<()> {
let mut rl = Editor::<MyHelper, DefaultHistory>::new()?;
rl.set_helper(Some(MyHelper(HistoryHinter::new())));
rl.bind_sequence(
KeyEvent::from('`'),
EventHandler::Conditional(Box::new(BacktickEventHandler {
toggle_state: Arc::new(Mutex::new(false)),
})),
);
if rl.load_history("history.txt").is_err() {
debug!("No previous history.");
}
let time = Local::now().format("%H:%M:%S.%3f").to_string();
let prompt = format!("[{}/{}] {}", time,"SHELL", ">>\t");
register_commands();
loop {
let sig = line_editor.readline(
&prompt.bright_white()
);
let time = Local::now().format("%H:%M:%S.%3f").to_string();
let prompt = format!("[{}/{}] {}", time, "SHELL", ">>\t");
let sig = rl.readline(&prompt.bright_white());
match sig {
Ok(line) => {
line_editor.add_history_entry(line.as_str())?;
rl.add_history_entry(line.as_str())?;
evaluate_command(line.as_str());
}
Err(rustyline::error::ReadlineError::Interrupted) => {
Err(ReadlineError::Interrupted) => {
println!("CTRL+C received, exiting...");
std::process::exit(0);
}
Err(rustyline::error::ReadlineError::Eof) => {
Err(ReadlineError::Eof) => {
println!("Error: CTRL+D pressed. Exiting...");
std::process::exit(0);
}
Err(err) => {
println!("Error: {}", err);
}
}
}