1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/*[toml]
[dependencies]
clap-repl = "0.1.1" # Old `rustyline`-compatible version
*/
/// Older version of published clap_repl crate example, modified to prototype a
/// (dummy) Rust REPL.
//# Purpose: Yet another REPL demo, this time using `rustyline`.
//# Categories: REPL, technique
use clap::Parser;
use clap_repl::ClapEditor;
use console::style;
use quote::quote;
use rustyline::config::Configurer;
use rustyline::DefaultEditor;
use syn::{self, Expr};
#[derive(Debug, Parser)]
// This change didn't do the trick. I want an explanatory prompt up front,
// not expect the user to guess and type "help"".
#[command(name = "", arg_required_else_help(true))] // This name will show up in clap's error messages, so it is important to set it to "".
enum SampleCommand {
Download {
path: String,
/// Some explanation about what this flag do.
#[arg(long)]
check_sha: bool,
},
/// A command to evaluate a Rust expression.
Eval,
/// A command to upload things.
Upload,
Login {
/// Optional. You will be prompted if you don't provide it.
#[arg(short, long)]
username: Option<String>,
},
Exit,
Quit,
}
fn main() {
// Use `ClapEditor` instead of the `rustyline::DefaultEditor`.
let mut editor = ClapEditor::<SampleCommand>::new();
loop {
// Use `read_command` instead of `readline`.
let Some(command) = editor.read_command() else {
continue;
};
match command {
SampleCommand::Download { path, check_sha } => {
println!("Downloaded {path} with checking = {check_sha}");
}
SampleCommand::Upload => {
println!("Uploaded");
}
SampleCommand::Login { username } => {
// You can use another `rustyline::Editor` inside the loop.
let mut rl = DefaultEditor::new().unwrap();
let username = username.unwrap_or_else(|| {
rl.readline(&style("What is your username? ").bold().to_string())
.unwrap()
});
let password = rl
.readline(&style("What is your password? ").bold().to_string())
.unwrap();
println!("Logged in with {username} and {password}");
}
SampleCommand::Exit | SampleCommand::Quit => return,
SampleCommand::Eval => {
let mut rl = DefaultEditor::new().unwrap();
rl.set_auto_add_history(true);
loop {
println!("Enter an expression (e.g., 2 + 3), or q to quit:");
let input = rl.readline(">> ").expect("Failed to read input");
// Process user input (line)
// rl.add_history_entry(&line); // Add current line to history
// Parse the expression string into a syntax tree
let str = &input.trim();
if str.to_lowercase() == "q" {
break;
}
let expr: Result<Expr, syn::Error> = syn::parse_str::<Expr>(str);
match expr {
Ok(expr) => {
// Generate Rust code for the expression
let rust_code = quote!(println!("result={}", #expr););
eprintln!("rust_code={rust_code}");
}
Err(err) => println!("Error parsing expression: {}", err),
}
}
}
}
}
}