Skip to content

Commit 4e72c52

Browse files
committed
Basic repl based on rustyline
1 parent 2f424eb commit 4e72c52

File tree

4 files changed

+36
-19
lines changed

4 files changed

+36
-19
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
__pycache__
55
**/*.pytest_cache
66
.*sw*
7+
.repl_history.txt

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ env_logger="0.5.10"
1111
clap = "2.31.2"
1212
rustpython_parser = {path = "parser"}
1313
rustpython_vm = {path = "vm"}
14+
rustyline = "2.1.0"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Or use the interactive shell:
1717

1818
$ cargo run
1919
Welcome to rustpython
20-
>>>>> 2+2
20+
>>> 2+2
2121
4
2222

2323
<!-- Or use pip to install extra modules:

src/main.rs

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ extern crate env_logger;
66
extern crate log;
77
extern crate rustpython_parser;
88
extern crate rustpython_vm;
9+
extern crate rustyline;
910

1011
use clap::{App, Arg};
1112
use rustpython_parser::parser;
@@ -14,8 +15,8 @@ use rustpython_vm::print_exception;
1415
use rustpython_vm::pyobject::{PyObjectRef, PyResult};
1516
use rustpython_vm::VirtualMachine;
1617
use rustpython_vm::{compile, import};
17-
use std::io;
18-
use std::io::prelude::*;
18+
use rustyline::error::ReadlineError;
19+
use rustyline::Editor;
1920
use std::path::Path;
2021

2122
fn main() {
@@ -146,23 +147,30 @@ fn run_shell(vm: &mut VirtualMachine) -> PyResult {
146147

147148
// Read a single line:
148149
let mut input = String::new();
150+
let mut rl = Editor::<()>::new();
151+
152+
// TODO: Store the history in a proper XDG directory
153+
let repl_history_path = ".repl_history.txt";
154+
if rl.load_history(repl_history_path).is_err() {
155+
println!("No previous history.");
156+
}
157+
149158
loop {
150159
// TODO: modules dont support getattr / setattr yet
151160
//let prompt = match vm.get_attribute(vm.sys_module.clone(), "ps1") {
152161
// Ok(value) => objstr::get_value(&value),
153162
// Err(_) => ">>>>> ".to_string(),
154163
//};
155-
print!(">>>>> ");
156164

157-
io::stdout().flush().expect("Could not flush stdout");
158-
match io::stdin().read_line(&mut input) {
159-
Ok(0) => {
160-
break;
161-
}
162-
Ok(_) => {
165+
match rl.readline(">>> ") {
166+
Ok(line) => {
167+
input.push_str(&line);
168+
input.push_str("\n");
169+
163170
debug!("You entered {:?}", input);
164171
if shell_exec(vm, &input, vars.clone()) {
165172
// Line was complete.
173+
rl.add_history_entry(input.as_ref());
166174
input = String::new();
167175
} else {
168176
loop {
@@ -171,16 +179,11 @@ fn run_shell(vm: &mut VirtualMachine) -> PyResult {
171179
// Ok(value) => objstr::get_value(&value),
172180
// Err(_) => "..... ".to_string(),
173181
//};
174-
print!("..... ");
175-
io::stdout().flush().expect("Could not flush stdout");
176-
let mut line = String::new();
177-
match io::stdin().read_line(&mut line) {
178-
Ok(_) => {
179-
line = line
180-
.trim_right_matches(|c| c == '\r' || c == '\n')
181-
.to_string();
182+
match rl.readline("... ") {
183+
Ok(line) => {
182184
if line.len() == 0 {
183185
if shell_exec(vm, &input, vars.clone()) {
186+
rl.add_history_entry(input.as_ref());
184187
input = String::new();
185188
break;
186189
}
@@ -194,9 +197,21 @@ fn run_shell(vm: &mut VirtualMachine) -> PyResult {
194197
}
195198
}
196199
}
197-
Err(msg) => panic!("Error: {:?}", msg),
200+
Err(ReadlineError::Interrupted) => {
201+
// TODO: Raise a real KeyboardInterrupt exception
202+
println!("^C");
203+
break;
204+
}
205+
Err(ReadlineError::Eof) => {
206+
break;
207+
}
208+
Err(err) => {
209+
println!("Error: {:?}", err);
210+
break;
211+
}
198212
};
199213
}
214+
rl.save_history(repl_history_path).unwrap();
200215

201216
Ok(vm.get_none())
202217
}

0 commit comments

Comments
 (0)