[−][src]Crate repl_rs
repl-rs - REPL library for Rust
Example
use std::collections::HashMap; use repl_rs::{Command, Error, Parameter, Result, Value}; use repl_rs::{Convert, Repl}; // Write "Hello" fn hello<T>(args: HashMap<String, Value>, _context: &mut T) -> Result<Option<String>> { Ok(Some(format!("Hello, {}", args["who"]))) } fn main() -> Result<()> { let mut repl = Repl::new(()) .with_name("MyApp") .with_version("v0.1.0") .with_description("My very cool app") .add_command( Command::new("hello", hello) .with_parameter(Parameter::new("who").set_required(true)?)? .with_help("Greetings!"), ); repl.run() }
repl-rs uses the builder pattern extensively. What these lines are doing is:
- creating a repl with an empty Context (see below)
 - with a name of "MyApp", the given version, and the given description
 - and adding a "hello" command which calls out to the 
hellocallback function defined above - the 
hellocommand has a single parameter, "who", which is required, and has the given help message 
The hello function takes a HashMap of named arguments, contained in a
Value struct, and an (unused) Context, which is used to hold state if you
need to - the initial context is passed in to the call to
Repl::new, in our case, ().
Because we're not using a Context, we need to include a generic type in our hello function,
because there's no way to pass an argument of type () otherwise.
All command function callbacks return a Result<Option<String>>. This has the following
effect:
- If the return is 
Ok(Some(String)), it prints the string to stdout - If the return is 
Ok(None), it prints nothing - If the return is an error, it prints the error message to stderr
 
Conversions
The Value type has conversions defined for all the primitive types. Here's how that works in practice:
use repl_rs::{Command, Parameter, Result, Value}; use repl_rs::{Convert, Repl}; use std::collections::HashMap; // Add two numbers. fn add<T>(args: HashMap<String, Value>, _context: &mut T) -> Result<Option<String>> { let first: i32 = args["first"].convert()?; let second: i32 = args["second"].convert()?; Ok(Some((first + second).to_string())) } fn main() -> Result<()> { let mut repl = Repl::new(()) .with_name("MyApp") .with_version("v0.1.0") .with_description("My very cool app") .add_command( Command::new("add", add) .with_parameter(Parameter::new("first").set_required(true)?)? .with_parameter(Parameter::new("second").set_required(true)?)? .with_help("Add two numbers together"), ); repl.run() }
This example adds two numbers. The convert() function manages the conversion for you.
Context
The Context type is used to keep state between REPL calls. Here's an example:
use repl_rs::{Command, Parameter, Result, Value}; use repl_rs::{Convert, Repl}; use std::collections::{HashMap, VecDeque}; #[derive(Default)] struct Context { list: VecDeque<String>, } // Append name to list fn append(args: HashMap<String, Value>, context: &mut Context) -> Result<Option<String>> { let name: String = args["name"].convert()?; context.list.push_back(name); let list: Vec<String> = context.list.clone().into(); Ok(Some(list.join(", "))) } // Prepend name to list fn prepend(args: HashMap<String, Value>, context: &mut Context) -> Result<Option<String>> { let name: String = args["name"].convert()?; context.list.push_front(name); let list: Vec<String> = context.list.clone().into(); Ok(Some(list.join(", "))) } fn main() -> Result<()> { let mut repl = Repl::new(Context::default()) .add_command( Command::new("append", append) .with_parameter(Parameter::new("name").set_required(true)?)? .with_help("Append name to end of list"), ) .add_command( Command::new("prepend", prepend) .with_parameter(Parameter::new("name").set_required(true)?)? .with_help("Prepend name to front of list"), ); repl.run() }
A few things to note:
- you pass in the initial value for your Context struct to the call to Repl::new()
 - the context is passed to your command callback functions as a mutable reference
 
Help
repl-rs has support for supplying help commands for your REPL. This is accomplished through the HelpViewer, which is a trait that has a default implementation which should give you pretty much what you expect.
% myapp
Welcome to MyApp v0.1.0
MyApp> help
MyApp v0.1.0: My very cool app
------------------------------
append - Append name to end of list
prepend - Prepend name to front of list
MyApp> help append
append: Append name to end of list
Usage:
        append name
MyApp>
If you want to roll your own help, just implement HelpViewer and add it to your REPL using the .with_help_viewer() method.
Structs
| Command | Struct to define a command in the REPL  | 
| HelpContext | Struct which gets sent to HelpViewer when   | 
| HelpEntry | Help entry which gets sent to HelpViewer when help for a particular command is requested  | 
| Parameter | Command parameter  | 
| Repl | Main REPL struct  | 
| Value | Value type. Has conversions to every primitive type.  | 
Enums
| Error | Error type  | 
Traits
| Convert | Trait to convert from a Value to some other type.  | 
| HelpViewer | Trait to be used if you want your own custom Help output  | 
Type Definitions
| Callback | Command callback function signature  | 
| Result | Result type  |