use anyhow::Result; use rustyline::Editor; use rustyline::error::ReadlineError; use crate::process::Process; use crate::scanner::{MemoryScanner, ScanValueType}; pub fn run_interactive_mode(process_name: &str) -> Result<()> { println!( "# Scanning for process \"{}\" like how pgrep -f works", process_name ); let process = Process::find_by_name(process_name)?; let mut scanner = MemoryScanner::new(process)?; println!("Please enter current value, or \"help\" for other commands."); let mut rl = Editor::<(), rustyline::history::DefaultHistory>::new()?; let mut first_scan = true; loop { let prompt = if first_scan { "> ".to_string() } else { format!("{}> ", scanner.get_matches_count()) }; let readline = rl.readline(&prompt); match readline { Ok(line) => { let _ = rl.add_history_entry(&line); let line = line.trim(); if line.is_empty() { continue; } if line == "help" { print_help(); continue; } if line == "exit" || line == "quit" { break; } if line.starts_with("set ") { handle_set_command(&mut scanner, line)?; continue; } match parse_value(line) { Ok(value) => { if first_scan { match scanner.scan_for_value(value) { Ok(_) => first_scan = false, Err(e) => println!("Error scanning: {}", e), } } else { match scanner.filter_matches(value) { Ok(_) => {} Err(e) => println!("Error filtering: {}", e), } } } Err(e) => println!("Invalid value: {}", e), } } Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => { println!("Exiting..."); break; } Err(err) => { println!("Error: {}", err); break; } } } Ok(()) } fn print_help() { println!("Available commands:"); println!(" - Search for value or narrow down existing results"); println!(" set - Set value at the memory address at index "); println!(" help - Show this help message"); println!(" exit/quit - Exit the program"); } fn handle_set_command(scanner: &mut MemoryScanner, command: &str) -> Result<()> { let parts: Vec<&str> = command.split_whitespace().collect(); if parts.len() != 3 { anyhow::bail!("Invalid set command format. Use: set "); } let idx = match parts[1].parse::() { Ok(idx) => idx, Err(_) => anyhow::bail!("Invalid index: {}", parts[1]), }; let value = match parse_value(parts[2])? { ScanValueType::I32(val) => val, _ => anyhow::bail!("Only i32 values are currently supported for setting"), }; scanner.set_value(idx, value) } fn parse_value(value_str: &str) -> Result { if let Ok(val) = value_str.parse::() { return Ok(ScanValueType::I32(val)); } // TODO missing implementation for all the other types anyhow::bail!("Could not parse '{}' as a valid number", value_str) }