Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| lib:repl [2018/12/31 23:21] – [Adding Line Evaluation] reladm | lib:repl [2020/11/15 23:14] (current) – Stopped at printing; more needs to be done. sprowell | ||
|---|---|---|---|
| Line 9: | Line 9: | ||
| * Coloring of error and other message types. | * Coloring of error and other message types. | ||
| - | The REPL support | + | The REPL supports |
| ===== Simplest Use ===== | ===== Simplest Use ===== | ||
| The minimum that must be done is to make a new instance of the '' | The minimum that must be done is to make a new instance of the '' | ||
| + | |||
| + | The one wrinkle is that you must provide some data to the constructor. | ||
| <code Rust [enable_line_numbers=" | <code Rust [enable_line_numbers=" | ||
| use relision:: | use relision:: | ||
| + | use relision:: | ||
| fn main() { | fn main() { | ||
| - | let mut repl = repl:: | + | |
| + | | ||
| repl.run(); | repl.run(); | ||
| } | } | ||
| + | </ | ||
| + | |||
| + | Note the '' | ||
| + | |||
| + | We can try this. This example is '' | ||
| + | |||
| + | < | ||
| + | Commands start with a colon (:). Enter :help for help. | ||
| + | > :help | ||
| + | Commands can be abbreviated to the first few characters that uniquely identify them. | ||
| + | |||
| + | :help | ||
| + | : | ||
| + | :info | ||
| + | :quit Quit the REPL. | ||
| + | |||
| + | > :fred | ||
| + | Error: Command fred not found. | ||
| + | > fred | ||
| + | > :quit | ||
| </ | </ | ||
| ===== Adding Line Evaluation ===== | ===== Adding Line Evaluation ===== | ||
| - | Let's add custom | + | Let's add a custom |
| - | To do this we need to create a function that takes a ''& | + | To do this we need to create a function that takes a ''& |
| + | |||
| + | * If the returned '' | ||
| + | * If the Boolean is '' | ||
| The function we want looks like this. | The function we want looks like this. | ||
| <code Rust [enable_line_numbers=" | <code Rust [enable_line_numbers=" | ||
| - | fn echo(line: & | + | use relision:: |
| + | |||
| + | fn echo<U>(line: & | ||
| let answer = line.to_uppercase(); | let answer = line.to_uppercase(); | ||
| let cont = answer != " | let cont = answer != " | ||
| Line 39: | Line 68: | ||
| </ | </ | ||
| - | We install | + | The ''< |
| + | |||
| + | We install | ||
| <code Rust [enable_line_numbers=" | <code Rust [enable_line_numbers=" | ||
| + | use relision:: | ||
| + | use relision:: | ||
| + | |||
| + | fn echo< | ||
| + | let answer = line.to_uppercase(); | ||
| + | let cont = answer != " | ||
| + | (Some(answer), | ||
| + | } | ||
| + | |||
| fn main() { | fn main() { | ||
| - | let mut repl = repl:: | + | let mut repl = repl:: |
| repl.set_eval(echo); | repl.set_eval(echo); | ||
| repl.run(); | repl.run(); | ||
| } | } | ||
| </ | </ | ||
| + | |||
| + | Let's try this. You can run this from the source distribution with ''< | ||
| + | |||
| + | < | ||
| + | Commands start with a colon (:). Enter :help for help. | ||
| + | > :help | ||
| + | Commands can be abbreviated to the first few characters that uniquely identify them. | ||
| + | |||
| + | :help | ||
| + | : | ||
| + | :info | ||
| + | :quit Quit the REPL. | ||
| + | |||
| + | > :fred | ||
| + | Error: Command fred not found. | ||
| + | > fred | ||
| + | FRED | ||
| + | > quit | ||
| + | QUIT | ||
| + | </ | ||
| + | |||
| + | ===== Adding a New Command ===== | ||
| + | |||
| + | We can add a new command to the REPL using the '' | ||
| + | |||
| + | We will use our '' | ||
| + | |||
| + | We will also change the prompt, using '' | ||
| + | |||
| + | <code Rust [enable_line_numbers=" | ||
| + | use relision:: | ||
| + | use relision:: | ||
| + | |||
| + | fn noop< | ||
| + | (None, true) | ||
| + | } | ||
| + | |||
| + | fn echo< | ||
| + | let answer = line.to_uppercase(); | ||
| + | let cont = answer != " | ||
| + | (Some(answer), | ||
| + | } | ||
| + | |||
| + | fn main() { | ||
| + | let mut repl = repl:: | ||
| + | repl.set_eval(echo); | ||
| + | |||
| + | // Install a custom command (using a closure). | ||
| + | repl.add_command( | ||
| + | " | ||
| + | "Echo the rest of the line in uppercase." | ||
| + | " | ||
| + | Echo the provided line, after converting it to all upper case." | ||
| + | .to_string(), | ||
| + | |line, context| (echo(line, context).0, true), | ||
| + | ); | ||
| + | |||
| + | // Install a custom colon command (using a function pointer). | ||
| + | repl.add_command( | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | | ||
| + | .to_string(), | ||
| + | noop, | ||
| + | ); | ||
| + | |||
| + | // Set the prompt and start the REPL. | ||
| + | repl.set_prompt(" | ||
| + | repl.run(); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Again, let's try this. Note that this is '' | ||
| + | |||
| + | < | ||
| + | Commands start with a colon (:). Enter :help for help. | ||
| + | repl> :help | ||
| + | Commands can be abbreviated to the first few characters that uniquely identify them. | ||
| + | |||
| + | :echo Echo the rest of the line in uppercase. | ||
| + | :help | ||
| + | : | ||
| + | :info | ||
| + | :noop | ||
| + | :quit Quit the REPL. | ||
| + | |||
| + | repl> :echo I'm not shouting. | ||
| + | I'M NOT SHOUTING. | ||
| + | repl> :noop This is ignored. | ||
| + | repl> :echo quit | ||
| + | QUIT | ||
| + | repl> quit | ||
| + | QUIT | ||
| + | </ | ||
| + | |||
| + | ===== User Data ===== | ||
| + | |||
| + | Our functions will probably want to do something a little more sophisticated, | ||
| + | |||
| + | * The line editor (provided by the [[https:// | ||
| + | * The terminal (provided by the [[https:// | ||
| + | * The current value of the " | ||
| + | * Some user data, which can hold anything we want. | ||
| + | |||
| + | ==== Reading a Line ==== | ||
| + | |||
| + | You can read a line from the console using '' | ||
| + | |||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | * '' | ||
| + | |||
| + | Lines read in this way are not automatically added to the history; you can use '' | ||
| + | |||
| + | ==== Printing ==== | ||
| + | |||
| + | The context provides '' | ||
| + | |||
| + | Let's add a guessing game to the program. | ||
| + | |||
| + | <code Rust [enable_line_numbers=" | ||
| + | pub struct Counts { | ||
| + | pub win: u32, | ||
| + | pub lose: u32, | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Now we will specialize '' | ||
| + | |||
| + | <code Rust [enable_line_numbers=" | ||
| + | fn guess(_line: | ||
| + | let limit = 10; | ||
| + | let high = 100; | ||
| + | // Tell the user the rules. | ||
| + | sayln!(context, | ||
| + | sayln!(context, | ||
| + | context.get().win + context.get().lose, | ||
| + | sayln!(context, | ||
| + | // Pick a random number. | ||
| + | let secret = rand:: | ||
| + | // Collect guesses. | ||
| + | let mut attempt = 1; | ||
| + | while attempt < limit { | ||
| + | // Get the next guess. | ||
| + | let line = context.editor.readline( | ||
| + | format!(" | ||
| + | match line { | ||
| + | Ok(text) => { | ||
| + | sayln!(context, | ||
| + | match text.trim().parse::< | ||
| + | Ok(number) => { | ||
| + | if number < secret { | ||
| + | sayln!(context, | ||
| + | } else if number > secret { | ||
| + | sayln!(context, | ||
| + | } else { | ||
| + | sayln!(context, | ||
| + | context.get_mut().win += 1; | ||
| + | return (None, true); | ||
| + | } | ||
| + | }, | ||
| + | Err(_) => { | ||
| + | sayln!(context, | ||
| + | } | ||
| + | } | ||
| + | }, | ||
| + | Err(ReadlineError:: | ||
| + | // This is a CTRL+C. | ||
| + | sayln!(context, | ||
| + | return (None, true); | ||
| + | }, | ||
| + | Err(ReadlineError:: | ||
| + | // This is end of file (CTRL+D). | ||
| + | sayln!(context, | ||
| + | return (None, true); | ||
| + | }, | ||
| + | Err(err) => { | ||
| + | // This is just an error. | ||
| + | error!(" | ||
| + | } | ||
| + | } | ||
| + | attempt += 1; | ||
| + | } // Collect guesses. | ||
| + | context.get_mut().lose += 1; | ||
| + | sayln!(context, | ||
| + | (None, true) | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | There is a lot going on in this function. | ||
| + | |||
| + | If you wanted to add the line to the history, you would do the following. | ||
| + | |||
| + | <code Rust [enable_line_numbers=true]> | ||
| + | context.editor.add_history_entry(text.clone()); | ||
| + | </ | ||
| + | |||