cl-repl: Terminal pipe support + fun stylistic fixups

This commit is contained in:
John 2024-03-01 05:33:35 -06:00
parent 9cae7e4eb8
commit 2eade74d3a
2 changed files with 34 additions and 16 deletions

View File

@ -1,6 +1,13 @@
use cl_repl::cli::run; use cl_repl::{cli::run, tools::is_terminal};
use std::error::Error; use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
if is_terminal() {
println!(
"--- {} v{} 💪🦈 ---",
env!("CARGO_BIN_NAME"),
env!("CARGO_PKG_VERSION"),
);
}
run(argh::from_env()) run(argh::from_env())
} }

View File

@ -8,9 +8,9 @@
pub mod ansi { pub mod ansi {
// ANSI color escape sequences // ANSI color escape sequences
pub const ANSI_RED: &str = "\x1b[31m"; pub const ANSI_RED: &str = "\x1b[31m";
// const ANSI_GREEN: &str = "\x1b[32m"; // the color of type checker mode pub const ANSI_GREEN: &str = "\x1b[32m"; // the color of type checker mode
pub const ANSI_CYAN: &str = "\x1b[36m"; pub const ANSI_CYAN: &str = "\x1b[36m";
pub const ANSI_BRIGHT_GREEN: &str = "\x1b[92m"; // pub const ANSI_BRIGHT_GREEN: &str = "\x1b[92m";
pub const ANSI_BRIGHT_BLUE: &str = "\x1b[94m"; pub const ANSI_BRIGHT_BLUE: &str = "\x1b[94m";
pub const ANSI_BRIGHT_MAGENTA: &str = "\x1b[95m"; pub const ANSI_BRIGHT_MAGENTA: &str = "\x1b[95m";
// const ANSI_BRIGHT_CYAN: &str = "\x1b[96m"; // const ANSI_BRIGHT_CYAN: &str = "\x1b[96m";
@ -21,6 +21,7 @@ pub mod ansi {
} }
pub mod args { pub mod args {
use crate::tools::is_terminal;
use argh::FromArgs; use argh::FromArgs;
use std::{path::PathBuf, str::FromStr}; use std::{path::PathBuf, str::FromStr};
@ -39,9 +40,9 @@ pub mod args {
#[argh(option, short = 'm', default = "Default::default()")] #[argh(option, short = 'm', default = "Default::default()")]
pub mode: Mode, pub mode: Mode,
/// whether to start the repl /// whether to start the repl (`true` or `false`)
#[argh(switch, short = 'r')] #[argh(option, short = 'r', default = "is_terminal()")]
pub no_repl: bool, pub repl: bool,
} }
/// The CLI's operating mode /// The CLI's operating mode
@ -187,14 +188,19 @@ pub mod cli {
/// Run the command line interface /// Run the command line interface
pub fn run(args: Args) -> Result<(), Box<dyn Error>> { pub fn run(args: Args) -> Result<(), Box<dyn Error>> {
let Args { file, include, mode, no_repl } = args; let Args { file, include, mode, repl } = args;
let mut env = Environment::new(); let mut env = Environment::new();
for path in include { for path in include {
load_file(&mut env, path)?; load_file(&mut env, path)?;
} }
if no_repl { if repl {
if let Some(file) = file {
load_file(&mut env, file)?;
}
Repl::with_env(mode, env).repl()
} else {
let code = match &file { let code = match &file {
Some(file) => std::fs::read_to_string(file)?, Some(file) => std::fs::read_to_string(file)?,
None => std::io::read_to_string(std::io::stdin())?, None => std::io::read_to_string(std::io::stdin())?,
@ -206,11 +212,6 @@ pub mod cli {
Mode::Beautify => beautify(code), Mode::Beautify => beautify(code),
Mode::Interpret => interpret(code, &mut env), Mode::Interpret => interpret(code, &mut env),
}?; }?;
} else {
if let Some(file) = file {
load_file(&mut env, file)?;
}
Repl::with_env(mode, env).repl()
} }
Ok(()) Ok(())
} }
@ -251,7 +252,10 @@ pub mod cli {
ret => println!("{ret}"), ret => println!("{ret}"),
} }
if env.get("main").is_ok() { if env.get("main").is_ok() {
println!("-> {}", env.call("main", &[])?); match env.call("main", &[])? {
ConValue::Empty => {}
ret => println!("{ret}"),
}
} }
Ok(()) Ok(())
} }
@ -304,8 +308,8 @@ pub mod repl {
println!("{ANSI_CLEAR_LINES}{ANSI_RED}{prompt} {err}{ANSI_RESET}") println!("{ANSI_CLEAR_LINES}{ANSI_RED}{prompt} {err}{ANSI_RESET}")
} }
pub fn prompt_succs(&self, value: &impl Display) { pub fn prompt_succs(&self, value: &impl Display) {
let Self { prompt_succs: prompt, .. } = self; let Self { prompt_succs: _prompt, .. } = self;
println!("{ANSI_BRIGHT_GREEN}{prompt}{ANSI_RESET} {value}") println!("{ANSI_GREEN}{value}{ANSI_RESET}")
} }
/// Resets the cursor to the start of the line, clears the terminal, /// Resets the cursor to the start of the line, clears the terminal,
/// and sets the output color /// and sets the output color
@ -327,6 +331,7 @@ pub mod repl {
/// Runs the main REPL loop /// Runs the main REPL loop
pub fn repl(&mut self) { pub fn repl(&mut self) {
use crate::repline::{error::Error, Repline}; use crate::repline::{error::Error, Repline};
let mut rl = Repline::new(self.mode.ansi_color(), self.prompt_begin, self.prompt_again); let mut rl = Repline::new(self.mode.ansi_color(), self.prompt_begin, self.prompt_again);
fn clear_line() { fn clear_line() {
print!("\x1b[G\x1b[J"); print!("\x1b[G\x1b[J");
@ -437,6 +442,8 @@ pub mod repl {
pub mod tools { pub mod tools {
use cl_token::Token; use cl_token::Token;
use std::io::IsTerminal;
/// Prints a token in the particular way cl-repl does
pub fn print_token(t: &Token) { pub fn print_token(t: &Token) {
println!( println!(
"{:02}:{:02}: {:#19} │{}│", "{:02}:{:02}: {:#19} │{}│",
@ -446,6 +453,10 @@ pub mod tools {
t.data(), t.data(),
) )
} }
/// gets whether stdin AND stdout are a terminal, for pipelining
pub fn is_terminal() -> bool {
std::io::stdin().is_terminal() && std::io::stdout().is_terminal()
}
} }
pub mod repline; pub mod repline;