cl-repl: Terminal pipe support + fun stylistic fixups
This commit is contained in:
parent
9cae7e4eb8
commit
2eade74d3a
@ -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())
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user