1use ion::Context;
8use modules::Modules;
9use mozjs::rust::{JSEngine, Runtime};
10use runtime::RuntimeBuilder;
11use rustyline::Editor;
12use rustyline::error::ReadlineError;
13
14use crate::evaluate::eval_inline;
15use crate::repl::{ReplHelper, rustyline_config};
16
17pub(crate) async fn start_repl() {
18 let engine = JSEngine::init().unwrap();
19 let rt = Runtime::new(engine.handle());
20
21 let cx = &mut Context::from_runtime(&rt);
22 let rt = RuntimeBuilder::<(), _>::new()
23 .microtask_queue()
24 .macrotask_queue()
25 .standard_modules(Modules)
26 .build(cx);
27
28 let mut repl = match Editor::with_config(rustyline_config()) {
29 Ok(repl) => repl,
30 Err(err) => {
31 eprintln!("{err}");
32 return;
33 }
34 };
35 repl.set_helper(Some(ReplHelper));
36 let mut terminate: u8 = 0;
37
38 loop {
39 let mut input = String::new();
40
41 match repl.readline("> ") {
42 Ok(i) => input = String::from(i.trim()),
43 Err(error) => terminate += handle_error(error),
44 }
45
46 repl.add_history_entry(&input).unwrap();
47
48 if terminate == 1 && input.is_empty() {
49 println!("Press Ctrl+C again or Ctrl+D to exit.");
50 continue;
51 } else if terminate > 1 {
52 break;
53 }
54
55 if !input.is_empty() && input != "exit" {
56 terminate = 0;
57 eval_inline(&rt, &input).await;
58 }
59
60 if terminate > 1 || input == "exit" {
61 break;
62 }
63 }
64}
65
66fn handle_error(error: ReadlineError) -> u8 {
67 match error {
68 ReadlineError::Interrupted => 1,
69 ReadlineError::Eof => 2,
70 _ => 0,
71 }
72}