diff --git a/buildscript/constants.rs b/buildscript/constants.rs index 38d9984..c7c72ef 100644 --- a/buildscript/constants.rs +++ b/buildscript/constants.rs @@ -91,6 +91,96 @@ pub fn write(target: &Path) { writeln!(file, "\t\t\t_ => None\n\t\t}}\n\t}}\n").unwrap(); + + + + writeln!(file, + concat!( + "\tpub fn all_consts() -> &'static [Constant] {{\n", + "\t\treturn &[" + ) + ).unwrap(); + + for c in constants { + writeln!(file, + "\t\t\tConstant::{e},", + e = c["enum_name"].as_str().unwrap(), + ).unwrap(); + } + + writeln!(file, "\t\t]\n\t}}\n").unwrap(); + + + + + + + writeln!(file, + concat!( + "\tpub fn source_strings(&self) -> &'static [&'static str] {{\n", + "\t\tmatch self {{" + ) + ).unwrap(); + + for c in constants { + write!(file, + "\t\t\tConstant::{e} => &[", + e = c["enum_name"].as_str().unwrap(), + ).unwrap(); + + if c["strings"].is_array() { + for s in c["strings"].as_array().unwrap() { + write!(file, + "\"{s}\",", + s = s.as_str().unwrap() + ).unwrap(); + } + write!(file, + "],", + ).unwrap(); + } else { + write!(file, + "\"{s}\"],", + s = c["strings"].as_str().unwrap() + ).unwrap(); + } + + write!(file, + "\n", + ).unwrap(); + } + + writeln!(file, "\t\t}}\n\t}}\n").unwrap(); + + + + + + + writeln!(file, + concat!( + "\tpub fn pretty_name(&self) -> Option<&'static str> {{\n", + "\t\tmatch self {{" + ) + ).unwrap(); + + for c in constants { + if c.as_table().unwrap().contains_key("pretty_name") { + writeln!(file, + "\t\t\tConstant::{e} => Some(&\"{s}\"),", + e = c["enum_name"].as_str().unwrap(), + s = c["pretty_name"].as_str().unwrap() + ).unwrap(); + } + } + + writeln!(file, "\t\t\t_ => None\n\t\t}}\n\t}}\n").unwrap(); + + + + + + writeln!(file, concat!( "\tpub fn value(&self) -> Expression {{\n", diff --git a/buildscript/constants.toml b/buildscript/constants.toml index 2fbed53..f5cf9d0 100644 --- a/buildscript/constants.toml +++ b/buildscript/constants.toml @@ -6,90 +6,108 @@ # strings: string or string array. What strings will be parsed as this constant. # The first entry in this array tells daisy how to print this constant. # value: value of this constant. Will be evaluated just like user input. -# unit: true if this constant represents a "fake unit" +# pretty_name: string, name of this constant in help texts. +# if this is missing, this constant will not be listed. [[constant]] enum_name = "Pi" +pretty_name = "π" strings = ["π", "pi"] value = "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067" [[constant]] enum_name = "Phi" -strings = ["φ", "phi", "goldenratio"] +pretty_name = "Golden ratio" +strings = ["φ", "phi"] value = "1.618033988749894848204586834365638117720309179805762862135448622705260462818902449707207204189391137" [[constant]] enum_name = "Euler" +pretty_name = "Euler's number" strings = "e" value = "2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427" [[constant]] enum_name = "LightSpeed" +pretty_name = "Speed of light" strings = "c" value = "299792458 meter/second" [[constant]] enum_name = "ElectricConstant" +pretty_name = "Electric constant" strings = ["ε₀", "epsilon_zero", "eps_zero", "electricconstant"] value = "8.8541878128e-12 F/m" [[constant]] enum_name = "ElectronCharge" +pretty_name = "Electron charge" strings = ["electroncharge", "elementarycharge"] value = "1.602176634e-19 C" [[constant]] enum_name = "ElectronMass" +pretty_name = "Electron mass" strings = ["me", "m_e", "electronmass"] value = "9.1093837015-31 kg" [[constant]] enum_name = "ProtonMass" +pretty_name = "Proton mass" strings = ["mp", "m_p", "protonmass"] value = "1.67262192369e-27 kg" [[constant]] enum_name = "GravityConstant" +pretty_name = "Graviational constant" strings = "G" value = "6.67430e-11 (m^3)/(s^2 * kg)" [[constant]] enum_name = "GravityEarth" +pretty_name = "Standard Earth gravity" strings = ["g₀", "g_zero", "gravity"] value = "9.80665 m/(s^2)" [[constant]] enum_name = "BoltzmannConstant" +pretty_name = "Boltzmann constant" strings = ["k_B", "boltzmannconstant"] value = "1.380649e-23 J/K" [[constant]] enum_name = "FaradayConstant" +pretty_name = "Faraday constant" strings = ["faradayconstant"] value = "9.64853321233100184e4 C/mol" [[constant]] enum_name = "MagneticConstant" +pretty_name = "Magnetic constant" strings = ["μ₀","mu_zero"] value = "1.25663706212 N/(A*A)" [[constant]] enum_name = "AvogadroConstant" +pretty_name = "Avogadro constant" strings = ["N_A", "avogadroconstant"] value = "6.02214076e23 mol^-1" [[constant]] enum_name = "PlanckConstant" +pretty_name = "Planck constant" strings = ["planckconstant"] value = "6.62607015e-34 J/Hz" [[constant]] enum_name = "Hbar" +pretty_name = "Reduced Planck constant" strings = ["ℏ", "h_bar"] value = "planckconstant / (2 pi)" [[constant]] enum_name = "GasConstant" +pretty_name = "Gas constant" strings = ["R", "gasconstant"] value = "avogadroconstant * boltzmannconstant" @@ -112,95 +130,79 @@ value = "avogadroconstant * boltzmannconstant" enum_name = "MPG" strings = "mpg" value = "mile/gallon" -unit = true [[constant]] enum_name = "MPH" strings = "mph" value = "mile/hour" -unit = true [[constant]] enum_name = "DPI" strings = "dpi" value = "dot/inch" -unit = true [[constant]] enum_name = "PPI" strings = "ppi" value = "pixel/inch" -unit = true [[constant]] enum_name = "FPS" strings = "fps" value = "frame/second" -unit = true [[constant]] enum_name = "PCT" strings = "pct" value = "0.01" -unit = true [[constant]] enum_name = "PPM" strings = "ppm" value = "1e-6" -unit = true [[constant]] enum_name = "PPB" strings = "ppb" value = "1e-9" -unit = true [[constant]] enum_name = "PPT" strings = "ppt" value = "1e-12" -unit = true [[constant]] enum_name = "PPQ" strings = "ppq" value = "1e-15" -unit = true [[constant]] enum_name = "WH" strings = "Wh" value = "W * hour" -unit = true [[constant]] enum_name = "KWH" strings = "kWh" value = "kW * hour" -unit = true [[constant]] enum_name = "MWH" strings = "WMh" value = "MW * hour" -unit = true [[constant]] enum_name = "GWH" strings = "GWh" value = "GW * hour" -unit = true [[constant]] enum_name = "TWH" strings = "TWh" value = "TW * hour" -unit = true [[constant]] enum_name = "PWH" strings = "PWh" -value = "PW * hour" -unit = true \ No newline at end of file +value = "PW * hour" \ No newline at end of file diff --git a/buildscript/main.rs b/buildscript/main.rs index 6c9e40f..0c3a3e9 100644 --- a/buildscript/main.rs +++ b/buildscript/main.rs @@ -16,6 +16,7 @@ fn main() -> Result<(), ()>{ units::write(&Path::new(&out_dir).join("units.rs")); constants::write(&Path::new(&out_dir).join("constants.rs")); + //constants::write(&Path::new("constants.rs")); return Ok(()); } \ No newline at end of file diff --git a/src/command/mod.rs b/src/command/mod.rs index 444f018..b376f71 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -1,4 +1,6 @@ use std::io::Write; +use crate::context::Context; +use crate::parser::Constant; use termion::{ raw::RawTerminal, @@ -15,12 +17,13 @@ pub fn is_command( "help" | "clear" | "ops" | "operators" | "fns" | "functions" + | "vars" + | "consts" | "constants" => true, _ => false } } - #[inline(always)] fn draw_greeter(stdout: &mut RawTerminal) -> Result<(), std::io::Error> { write!( @@ -51,7 +54,8 @@ fn draw_greeter(stdout: &mut RawTerminal) -> Result<(), std::io #[inline(always)] pub fn do_command( stdout: &mut RawTerminal, - s: &String + s: &String, + context: &mut Context ) -> Result<(), std::io::Error> { match &s[..] { @@ -73,16 +77,15 @@ pub fn do_command( " {c}clear{r} Clear the terminal\r\n", " {c}quit{r} Exit daisy\r\n", //" {c}units{r} List available units\r\n", - //" {c}const{r} List available constants\r\n", + " {c}consts{r} List built-in constants\r\n", " {c}ops{r} List built-in operators\r\n", " {c}fns{r} List built-in functions\r\n", - "\n", + " {c}vars{r} List user-defined variables\r\n", + "\n\n", ), r = format!("{}{}", color::Fg(color::Reset), style::Reset), - c = format!("{}{}", color::Fg(color::LightBlack), style::Italic), - t = format!("{}{}", color::Fg(color::Magenta), style::Bold) )?; }, @@ -115,7 +118,7 @@ pub fn do_command( " unit conversion {c}to{r}\r\n", " division (long) {c}per{r}\r\n", " modulo (long) {c}mod{r}\r\n", - "\n" + "\n\n" ), r = format!("{}{}", color::Fg(color::Reset), style::Reset), @@ -146,7 +149,7 @@ pub fn do_command( "\n", " convert to base unit {c}tobase{r}\r\n", " remove units {c}nounit{r}\r\n", - "\n" + "\n\n" ), r = format!("{}{}", color::Fg(color::Reset), style::Reset), @@ -154,6 +157,85 @@ pub fn do_command( t = format!("{}{}", color::Fg(color::Magenta), style::Bold) )?; }, + + "vars" => { + let v = context.get_variables(); + + if v.len() == 0 { + write!(stdout, + "You have not defined any variables.\r\n\n", + )?; + return Ok(()); + } + + write!(stdout, + "\r\n╞═══ {t}User-Defined Variables{r} ═══╡\r\n", + r = format!("{}{}", color::Fg(color::Reset), style::Reset), + t = format!("{}{}", color::Fg(color::Magenta), style::Bold) + )?; + + + + let mut longest = 0; + for (key, _) in v { + if key.len() > longest { + longest = key.len(); + } + } + + for (key, value) in v { + let padding = " ".repeat(longest - key.len()); + + write!(stdout, + concat!( + " {k}{p} = {c}{v}{r}\r\n", + ), + k = key, v = value.to_string(), + p = padding, + r = format!("{}{}", color::Fg(color::Reset), style::Reset), + c = format!("{}{}", color::Fg(color::LightBlack), style::Italic), + )?; + } + + write!(stdout, + "\r\n\n", + )?; + }, + + "consts" | "constants" => { + let a = Constant::all_consts(); + + write!(stdout, + "\r\n╞═══ {t}Built-in Constants{r} ═══╡\r\n", + r = format!("{}{}", color::Fg(color::Reset), style::Reset), + t = format!("{}{}", color::Fg(color::Magenta), style::Bold) + )?; + + for c in a { + let Some(p) = c.pretty_name() else { continue }; + + // If you subtract with overflow here, + // your padding length is too short. + let padding = " ".repeat(25 - p.chars().count()); + + write!(stdout, + " {n}{p}: {c}{s}{r}", + p = padding, + n = p, + s = c.source_strings().join(", "), + + r = format!("{}{}", color::Fg(color::Reset), style::Reset), + c = format!("{}{}", color::Fg(color::LightBlack), style::Italic), + )?; + + write!(stdout, "\r\n")?; + } + + write!(stdout, + "\r\n\n", + )?; + }, + _ => unreachable!("Bad command!") }; diff --git a/src/context.rs b/src/context.rs index f44d8be..70b9066 100644 --- a/src/context.rs +++ b/src/context.rs @@ -38,4 +38,8 @@ impl Context { } } + pub fn get_variables(&self) -> &HashMap { + return &self.variables + } + } diff --git a/src/entry/unix/unix.rs b/src/entry/unix/unix.rs index 727bd32..8d690a3 100644 --- a/src/entry/unix/unix.rs +++ b/src/entry/unix/unix.rs @@ -129,12 +129,14 @@ fn do_expression( #[inline(always)] pub fn main() -> Result<(), std::io::Error> { let mut stdout = stdout().into_raw_mode().unwrap(); + let mut pb: PromptBuffer = PromptBuffer::new(64); + let mut context: Context = Context::new(); - let args: Vec = env::args().collect(); // Handle command-line arguments + let args: Vec = env::args().collect(); if args.iter().any(|s| s == "--help") { - command::do_command(&mut stdout, &String::from("help"))?; + command::do_command(&mut stdout, &String::from("help"), &mut context)?; return Ok(()); } else if args.iter().any(|s| s == "--version") { write!(stdout, "Daisy v{}\r\n", env!("CARGO_PKG_VERSION"))?; @@ -145,8 +147,6 @@ pub fn main() -> Result<(), std::io::Error> { //let size = termion::terminal_size().unwrap(); //write!(stdout, "{:?}", size).unwrap(); - let mut pb: PromptBuffer = PromptBuffer::new(64); - let mut context: Context = Context::new(); 'outer: loop { @@ -165,7 +165,7 @@ pub fn main() -> Result<(), std::io::Error> { if in_str.trim() == "quit" { break 'outer; } else if command::is_command(&in_str) { - command::do_command(&mut stdout, &in_str)?; + command::do_command(&mut stdout, &in_str, &mut context)?; } else { let r = do_expression(&mut stdout, &in_str, &mut context); if let Ok(t) = r { context.push_hist(t); }