11use javascript:: * ;
2+ use rustyline:: Editor ;
3+ use rustyline:: completion:: Completer ;
4+ use rustyline:: error:: ReadlineError ;
5+ use rustyline:: highlight:: Highlighter ;
6+ use rustyline:: hint:: Hinter ;
7+ use rustyline:: history:: FileHistory ;
8+ use rustyline:: validate:: Validator ;
9+ use std:: borrow:: Cow ;
10+ use std:: path:: PathBuf ;
211
312#[ derive( clap:: Parser ) ]
413#[ command( name = "js" , version, about = "JavaScript Rust Interpreter" ) ]
@@ -33,6 +42,33 @@ fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
3342 }
3443}
3544
45+ struct ReplPromptHelper ;
46+
47+ impl Completer for ReplPromptHelper {
48+ type Candidate = String ;
49+ }
50+
51+ impl Hinter for ReplPromptHelper {
52+ type Hint = String ;
53+ }
54+
55+ impl Validator for ReplPromptHelper { }
56+
57+ impl Highlighter for ReplPromptHelper {
58+ fn highlight_prompt < ' b , ' s : ' b , ' p : ' b > ( & ' s self , prompt : & ' p str , default : bool ) -> Cow < ' b , str > {
59+ let _ = default;
60+ if prompt == "js> " {
61+ Cow :: Borrowed ( "\x1b [1;32mjs> \x1b [0m" )
62+ } else if prompt == "... " {
63+ Cow :: Borrowed ( "\x1b [1;33m... \x1b [0m" )
64+ } else {
65+ Cow :: Borrowed ( prompt)
66+ }
67+ }
68+ }
69+
70+ impl rustyline:: Helper for ReplPromptHelper { }
71+
3672fn run_main ( ) -> Result < ( ) , Box < dyn std:: error:: Error + Send + Sync + ' static > > {
3773 let cli = <Cli as clap:: Parser >:: parse ( ) ;
3874
@@ -119,24 +155,23 @@ fn run_main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>>
119155// Persistent rustyline-powered REPL loop extracted into a helper to keep `main()` small.
120156#[ allow( clippy:: println_empty_string) ]
121157fn run_persistent_repl ( ) -> Result < ( ) , Box < dyn std:: error:: Error + Send + Sync + ' static > > {
122- use rustyline:: Editor ;
123- use rustyline:: error:: ReadlineError ;
124- use std:: path:: PathBuf ;
125-
126158 let ver = clap:: crate_version!( ) ;
127- println ! ( "JavaScript Interpreter REPL (VM mode) v{ver}. Type 'exit' or Ctrl-D to quit." ) ;
159+ println ! ( "JavaScript Interpreter REPL (VM mode) v{ver}. Type '. exit' or Ctrl-D to quit." ) ;
128160
129- let mut rl = match Editor :: < ( ) , rustyline :: history :: FileHistory > :: new ( ) {
161+ let mut rl = match Editor :: < ReplPromptHelper , FileHistory > :: new ( ) {
130162 Ok ( e) => e,
131163 Err ( err) => {
132164 eprintln ! ( "Failed to initialize line editor: {err}" ) ;
133165 std:: process:: exit ( 1 ) ;
134166 }
135167 } ;
168+ rl. set_helper ( Some ( ReplPromptHelper ) ) ;
136169
137170 // Simple history file in the user's home directory
138- let history_path: Option < PathBuf > = std:: env:: var ( "HOME" ) . ok ( ) . map ( |h| PathBuf :: from ( h) . join ( ".js_repl_history" ) ) ;
139- if let Some ( ref p) = history_path {
171+ let history_path: Option < PathBuf > = dirs:: home_dir ( ) . map ( |p| p. join ( ".js_repl_history" ) ) ;
172+ if let Some ( ref p) = history_path
173+ && p. exists ( )
174+ {
140175 rl. load_history ( p) ?;
141176 }
142177
@@ -145,18 +180,12 @@ fn run_persistent_repl() -> Result<(), Box<dyn std::error::Error + Send + Sync +
145180 let mut buffer = String :: new ( ) ;
146181
147182 loop {
148- // Use ANSI escape codes for color: \x1b[1;32m is bold green, \x1b[1;33m is bold yellow, \x1b[0m is reset
149- let prompt = if buffer. is_empty ( ) {
150- "\x1b [1;32mjs> \x1b [0m"
151- } else {
152- "\x1b [1;33m... \x1b [0m"
153- } ;
154-
183+ let prompt = if buffer. is_empty ( ) { "js> " } else { "... " } ;
155184 match rl. readline ( prompt) {
156185 Ok ( line) => {
157186 // support quick exit from the REPL
158187 let trimmed = line. trim ( ) ;
159- if trimmed == "exit" || trimmed == " .exit" {
188+ if trimmed == ".exit" {
160189 break ;
161190 }
162191
@@ -203,7 +232,6 @@ fn run_persistent_repl() -> Result<(), Box<dyn std::error::Error + Send + Sync +
203232 continue ;
204233 }
205234 Err ( ReadlineError :: Eof ) => {
206- println ! ( "Goodbye" ) ;
207235 break ;
208236 }
209237 Err ( err) => {
@@ -212,6 +240,7 @@ fn run_persistent_repl() -> Result<(), Box<dyn std::error::Error + Send + Sync +
212240 }
213241 }
214242 }
243+ println ! ( "Goodbye" ) ;
215244
216245 if let Some ( ref p) = history_path {
217246 rl. save_history ( p) ?;
0 commit comments