cli/commands/
repl.rs

1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 */
6
7use 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}