forked from dylan-sutton-chavez/edge-python
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrepl.rs
More file actions
82 lines (73 loc) · 2.65 KB
/
repl.rs
File metadata and controls
82 lines (73 loc) · 2.65 KB
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
/*
Interactive REPL: a persistent engine session driven by rustyline; multi-line blocks via the `:` heuristic.
*/
use anyhow::Result;
use rustyline::{error::ReadlineError, DefaultEditor};
use std::path::Path;
use crate::engine::Session;
use crate::pkg::Manifest;
const PROMPT: &str = ">>> ";
const CONT: &str = "... ";
pub fn run(manifest_path: &Path) -> Result<()> {
let manifest = Manifest::load(manifest_path)?;
let mut session = Session::open(&manifest)?;
println!("Edge Python {} · .exit, Ctrl+C or Ctrl+D to quit", env!("CARGO_PKG_VERSION"));
let mut rl = DefaultEditor::new()?;
loop {
let first = match rl.readline(PROMPT) {
Ok(s) => s,
Err(ReadlineError::Interrupted) => break, // Ctrl+C exits
Err(ReadlineError::Eof) => break, // Ctrl+D exits
Err(e) => { eprintln!("repl error: {e}"); break; }
};
let _ = rl.add_history_entry(first.as_str());
let block = match read_block(&mut rl, first)? {
BlockResult::Done(b) => b,
BlockResult::Exit => break,
};
let trimmed = block.trim();
if trimmed.is_empty() { continue; }
match trimmed {
".exit" => break,
".reset" => {
// Wipe runtime modules in place; the browser keeps running.
session.reset()?;
continue;
}
_ => {}
}
let outcome = session.eval(&block, |line| println!("{line}"))?;
// `raise SystemExit` quits the session with its code, matching the one-shot runner.
if let Some(code) = outcome.exit_code {
std::process::exit(code);
}
if let Some(err) = outcome.err {
crate::ui::traceback(&err);
}
}
Ok(())
}
enum BlockResult {
Done(String),
Exit
}
/// Collect a multi-line block when the first line ends with `:`; an empty line closes it.
fn read_block(rl: &mut DefaultEditor, first: String) -> Result<BlockResult> {
if !first.trim_end().ends_with(':') {
return Ok(BlockResult::Done(first));
}
let mut block = first;
loop {
match rl.readline(CONT) {
Ok(line) if line.is_empty() => return Ok(BlockResult::Done(block)),
Ok(line) => {
let _ = rl.add_history_entry(line.as_str());
block.push('\n');
block.push_str(&line);
}
Err(ReadlineError::Interrupted) => return Ok(BlockResult::Exit), // Ctrl+C exits
Err(ReadlineError::Eof) => return Ok(BlockResult::Done(block)), // Ctrl+D submits the partial block
Err(e) => return Err(e.into()),
}
}
}