From d73ab43560b614a42da2ef11711e65baa7acd6cd Mon Sep 17 00:00:00 2001 From: Eivind Alexander Bergem Date: Thu, 29 Aug 2024 08:48:07 +0200 Subject: [PATCH] Working prompt --- examples/noline.rs | 3 +- examples/simple.rs | 4 +- src/lib.rs | 149 ++++++++++++++++++++++++--------------------- 3 files changed, 81 insertions(+), 75 deletions(-) diff --git a/examples/noline.rs b/examples/noline.rs index 3ea7b95..c43c5c2 100644 --- a/examples/noline.rs +++ b/examples/noline.rs @@ -152,8 +152,7 @@ fn main() { .unwrap(); let mut context = Context::default(); - let mut r = - Runner::new(&mut editor, ROOT_MENU, io, &mut context); + let mut r = Runner::new(&mut editor, ROOT_MENU, io, &mut context); while let Ok(_) = r.input_line(&mut context) {} } diff --git a/examples/simple.rs b/examples/simple.rs index 447b935..173b85e 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -111,7 +111,7 @@ fn main() { let mut context = Context::default(); let mut r = Runner::new(&mut buffer, ROOT_MENU, Output(window), &mut context); loop { - match r.interface().0.getch() { + match r.interface.0.getch() { Some(Input::Character('\n')) => { r.input_byte(b'\r', &mut context); } @@ -123,7 +123,7 @@ fn main() { } Some(Input::KeyDC) => break, Some(input) => { - r.interface().0.addstr(&format!("{:?}", input)); + r.interface.0.addstr(&format!("{:?}", input)); } None => (), } diff --git a/src/lib.rs b/src/lib.rs index 9622f20..8abdc04 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,12 +111,12 @@ where pub struct Runner<'a, I, T, B: ?Sized> { buffer: &'a mut B, used: usize, + pub interface: I, inner: InnerRunner<'a, I, T>, } struct InnerRunner<'a, I, T> { menu_mgr: menu_manager::MenuManager<'a, I, T>, - interface: I, } /// Describes the ways in which the API can fail @@ -262,12 +262,20 @@ enum PromptIterState { Done, } -#[derive(Clone)] struct PromptIter<'a, I, T> { menu_mgr: &'a MenuManager<'a, I, T>, state: PromptIterState, } +impl<'a, I, T> Clone for PromptIter<'a, I, T> { + fn clone(&self) -> Self { + Self { + menu_mgr: self.menu_mgr, + state: self.state.clone(), + } + } +} + impl<'a, I, T> PromptIter<'a, I, T> { fn new(menu_mgr: &'a MenuManager<'a, I, T>, newline: bool) -> Self { let state = if newline { @@ -323,18 +331,14 @@ where let mut r = Runner { buffer, used: 0, + interface, inner: InnerRunner { menu_mgr: menu_manager::MenuManager::new(menu), - interface, }, }; - r.inner.prompt(true); + r.inner.prompt(&mut r.interface, true); r } - - pub fn interface(&self) -> &I { - &self.inner.interface - } } #[cfg(feature = "noline")] @@ -350,10 +354,9 @@ where H: History, I: Read + Write, { - let prompt = "> "; - // let prompt = self.get_prompt(false); + let prompt = self.inner.get_prompt(false); - let line = self.buffer.readline(prompt, &mut self.inner.interface)?; + let line = self.buffer.readline(prompt, &mut self.interface)?; #[cfg(not(feature = "echo"))] { @@ -362,7 +365,8 @@ where write!(self.interface, "{}", line).unwrap(); } - self.inner.process_command(context, line); + self.inner + .process_command(&mut self.interface, context, line); Ok(()) } @@ -393,17 +397,18 @@ where write!(self.interface, "{}", line).unwrap(); } // Handle the command - self.inner.process_command(context, line); + self.inner + .process_command(&mut self.interface, context, line); } else { // Hmm .. we did not have a valid string - writeln!(self.inner.interface, "Input was not valid UTF-8").unwrap(); + writeln!(self.interface, "Input was not valid UTF-8").unwrap(); } Outcome::CommandProcessed } else if (input == 0x08) || (input == 0x7F) { // Handling backspace or delete if self.used > 0 { - write!(self.inner.interface, "\u{0008} \u{0008}").unwrap(); + write!(self.interface, "\u{0008} \u{0008}").unwrap(); self.used -= 1; } Outcome::NeedMore @@ -420,23 +425,23 @@ where let valid = core::str::from_utf8(&buffer[0..self.used]).is_ok(); // Now we've released the buffer, we can draw the prompt if valid { - write!(self.inner.interface, "\r").unwrap(); - self.inner.prompt(false); + write!(self.interface, "\r").unwrap(); + self.inner.prompt(&mut self.interface, false); } // Grab the buffer again to render it to the screen if let Ok(s) = core::str::from_utf8(&buffer[0..self.used]) { - write!(self.inner.interface, "{}", s).unwrap(); + write!(self.interface, "{}", s).unwrap(); } } Outcome::NeedMore } else { - writeln!(self.inner.interface, "Buffer overflow!").unwrap(); + writeln!(self.interface, "Buffer overflow!").unwrap(); Outcome::NeedMore }; match outcome { Outcome::CommandProcessed => { self.used = 0; - self.inner.prompt(true); + self.inner.prompt(&mut self.interface, true); } Outcome::NeedMore => {} } @@ -453,18 +458,18 @@ where /// Print out a new command prompt, including sub-menu names if /// applicable. - pub fn prompt(&mut self, newline: bool) { + pub fn prompt(&mut self, interface: &mut I, newline: bool) { let prompt = PromptIter::new(&self.menu_mgr, newline); for part in prompt { - write!(self.interface, "{}", part).unwrap(); + write!(interface, "{}", part).unwrap(); } } /// Scan the buffer and do the right thing based on its contents. - fn process_command(&mut self, context: &mut T, command_line: &str) { + fn process_command(&mut self, interface: &mut I, context: &mut T, command_line: &str) { // Go to the next line, below the prompt - writeln!(self.interface).unwrap(); + writeln!(interface).unwrap(); // We have a valid string let mut parts = command_line.split_whitespace(); if let Some(cmd) = parts.next() { @@ -473,34 +478,40 @@ where match parts.next() { Some(arg) => match menu.items.iter().find(|i| i.command == arg) { Some(item) => { - self.print_long_help(item); + self.print_long_help(interface, item); } None => { - writeln!(self.interface, "I can't help with {:?}", arg).unwrap(); + writeln!(interface, "I can't help with {:?}", arg).unwrap(); } }, _ => { - writeln!(self.interface, "AVAILABLE ITEMS:").unwrap(); + writeln!(interface, "AVAILABLE ITEMS:").unwrap(); for item in menu.items { - self.print_short_help(item); + self.print_short_help(interface, item); } if self.menu_mgr.depth() != 0 { - self.print_short_help(&Item { - command: "exit", - help: Some("Leave this menu."), - item_type: ItemType::_Dummy, - }); + self.print_short_help( + interface, + &Item { + command: "exit", + help: Some("Leave this menu."), + item_type: ItemType::_Dummy, + }, + ); } - self.print_short_help(&Item { - command: "help [ ]", - help: Some("Show this help, or get help on a specific command."), - item_type: ItemType::_Dummy, - }); + self.print_short_help( + interface, + &Item { + command: "help [ ]", + help: Some("Show this help, or get help on a specific command."), + item_type: ItemType::_Dummy, + }, + ); } } } else if cmd == "exit" && self.menu_mgr.depth() != 0 { if let Some(cb_fn) = menu.exit { - cb_fn(menu, &mut self.interface, context); + cb_fn(menu, interface, context); } self.menu_mgr.pop_menu(); } else { @@ -512,7 +523,7 @@ where function, parameters, } => Self::call_function( - &mut self.interface, + interface, context, function, parameters, @@ -522,7 +533,7 @@ where ), ItemType::Menu(incoming_menu) => { if let Some(cb_fn) = incoming_menu.entry { - cb_fn(incoming_menu, &mut self.interface, context); + cb_fn(incoming_menu, interface, context); } self.menu_mgr.push_menu(i); } @@ -535,27 +546,27 @@ where } } if !found { - writeln!(self.interface, "Command {:?} not found. Try 'help'.", cmd).unwrap(); + writeln!(interface, "Command {:?} not found. Try 'help'.", cmd).unwrap(); } } } else { - writeln!(self.interface, "Input was empty?").unwrap(); + writeln!(interface, "Input was empty?").unwrap(); } } - fn print_short_help(&mut self, item: &Item) { + fn print_short_help(&mut self, interface: &mut I, item: &Item) { let mut has_options = false; match item.item_type { ItemType::Callback { parameters, .. } => { - write!(self.interface, " {}", item.command).unwrap(); + write!(interface, " {}", item.command).unwrap(); if !parameters.is_empty() { for param in parameters.iter() { match param { Parameter::Mandatory { parameter_name, .. } => { - write!(self.interface, " <{}>", parameter_name).unwrap(); + write!(interface, " <{}>", parameter_name).unwrap(); } Parameter::Optional { parameter_name, .. } => { - write!(self.interface, " [ <{}> ]", parameter_name).unwrap(); + write!(interface, " [ <{}> ]", parameter_name).unwrap(); } Parameter::Named { .. } => { has_options = true; @@ -568,50 +579,46 @@ where } } ItemType::Menu(_menu) => { - write!(self.interface, " {}", item.command).unwrap(); + write!(interface, " {}", item.command).unwrap(); } ItemType::_Dummy => { - write!(self.interface, " {}", item.command).unwrap(); + write!(interface, " {}", item.command).unwrap(); } } if has_options { - write!(self.interface, " [OPTIONS...]").unwrap(); + write!(interface, " [OPTIONS...]").unwrap(); } - writeln!(self.interface).unwrap(); + writeln!(interface).unwrap(); } - fn print_long_help(&mut self, item: &Item) { - writeln!(self.interface, "SUMMARY:").unwrap(); + fn print_long_help(&mut self, interface: &mut I, item: &Item) { + writeln!(interface, "SUMMARY:").unwrap(); match item.item_type { ItemType::Callback { parameters, .. } => { - write!(self.interface, " {}", item.command).unwrap(); + write!(interface, " {}", item.command).unwrap(); if !parameters.is_empty() { for param in parameters.iter() { match param { Parameter::Mandatory { parameter_name, .. } => { - write!(self.interface, " <{}>", parameter_name).unwrap(); + write!(interface, " <{}>", parameter_name).unwrap(); } Parameter::Optional { parameter_name, .. } => { - write!(self.interface, " [ <{}> ]", parameter_name).unwrap(); + write!(interface, " [ <{}> ]", parameter_name).unwrap(); } Parameter::Named { parameter_name, .. } => { - write!(self.interface, " [ --{} ]", parameter_name).unwrap(); + write!(interface, " [ --{} ]", parameter_name).unwrap(); } Parameter::NamedValue { parameter_name, argument_name, .. } => { - write!( - self.interface, - " [ --{}={} ]", - parameter_name, argument_name - ) - .unwrap(); + write!(interface, " [ --{}={} ]", parameter_name, argument_name) + .unwrap(); } } } - writeln!(self.interface, "\n\nPARAMETERS:").unwrap(); + writeln!(interface, "\n\nPARAMETERS:").unwrap(); let default_help = "Undocumented option"; for param in parameters.iter() { match param { @@ -620,7 +627,7 @@ where help, } => { writeln!( - self.interface, + interface, " <{0}>\n {1}\n", parameter_name, help.unwrap_or(default_help), @@ -632,7 +639,7 @@ where help, } => { writeln!( - self.interface, + interface, " <{0}>\n {1}\n", parameter_name, help.unwrap_or(default_help), @@ -644,7 +651,7 @@ where help, } => { writeln!( - self.interface, + interface, " --{0}\n {1}\n", parameter_name, help.unwrap_or(default_help), @@ -657,7 +664,7 @@ where help, } => { writeln!( - self.interface, + interface, " --{0}={1}\n {2}\n", parameter_name, argument_name, @@ -670,14 +677,14 @@ where } } ItemType::Menu(_menu) => { - write!(self.interface, " {}", item.command).unwrap(); + write!(interface, " {}", item.command).unwrap(); } ItemType::_Dummy => { - write!(self.interface, " {}", item.command).unwrap(); + write!(interface, " {}", item.command).unwrap(); } } if let Some(help) = item.help { - writeln!(self.interface, "\n\nDESCRIPTION:\n{}", help).unwrap(); + writeln!(interface, "\n\nDESCRIPTION:\n{}", help).unwrap(); } }