From f38496852a2ddfaad3b89b1042f5ff56c639da0d Mon Sep 17 00:00:00 2001 From: Andrew Chin Date: Wed, 22 Nov 2023 18:14:17 -0500 Subject: [PATCH] Enhance the help command to print info about a given unit CC #238 --- numbat-cli/src/main.rs | 9 ++++ numbat/src/bytecode_interpreter.rs | 10 +++++ numbat/src/lib.rs | 71 ++++++++++++++++++++++++++++++ numbat/src/prefix_transformer.rs | 2 +- numbat/src/unit.rs | 14 +++++- 5 files changed, 104 insertions(+), 2 deletions(-) diff --git a/numbat-cli/src/main.rs b/numbat-cli/src/main.rs index 151aae32..4ac3e2b4 100644 --- a/numbat-cli/src/main.rs +++ b/numbat-cli/src/main.rs @@ -370,6 +370,15 @@ impl Cli { println!(); } _ => { + if let Some(keyword) = line.strip_prefix("help") { + let help = self + .context + .lock() + .unwrap() + .print_help_for_keyword(keyword.trim()); + println!("{}", ansi_format(&help, true)); + continue; + } let result = self.parse_and_evaluate( &line, CodeSource::Text, diff --git a/numbat/src/bytecode_interpreter.rs b/numbat/src/bytecode_interpreter.rs index c022d861..1e5d39d4 100644 --- a/numbat/src/bytecode_interpreter.rs +++ b/numbat/src/bytecode_interpreter.rs @@ -359,6 +359,16 @@ impl BytecodeInterpreter { fn current_depth(&self) -> usize { self.locals.len() - 1 } + + pub fn get_defining_unit(&self, unit_name: &str) -> Option<&Unit> { + self.unit_name_to_constant_index + .get(unit_name) + .and_then(|idx| self.vm.constants.get(*idx as usize)) + .and_then(|constant| match constant { + Constant::Unit(u) => Some(u), + _ => None, + }) + } } impl Interpreter for BytecodeInterpreter { diff --git a/numbat/src/lib.rs b/numbat/src/lib.rs index 19e8fb42..09b06f4d 100644 --- a/numbat/src/lib.rs +++ b/numbat/src/lib.rs @@ -64,8 +64,11 @@ pub use registry::BaseRepresentation; pub use registry::BaseRepresentationFactor; pub use typed_ast::Statement; pub use typed_ast::Type; +use unit::BaseUnitAndFactor; use unit_registry::UnitMetadata; +use crate::prefix_parser::PrefixParserResult; + #[derive(Debug, Error)] pub enum NumbatError { #[error("{0}")] @@ -253,6 +256,74 @@ impl Context { words.into_iter().filter(move |w| w.starts_with(word_part)) } + pub fn print_help_for_keyword(&mut self, keyword: &str) -> Markup { + let reg = self.interpreter.get_unit_registry(); + + if let PrefixParserResult::UnitIdentifier(_span, prefix, _, full_name) = + self.prefix_transformer.prefix_parser.parse(keyword) + { + if let Some(md) = reg + .inner + .get_base_representation_for_name(&full_name) + .ok() + .map(|(_, md)| md) + { + let mut help = m::unit(md.name.as_deref().unwrap_or(keyword)) + m::nl(); + if let Some(url) = &md.url { + help += m::string(url) + m::nl(); + } + if md.aliases.len() > 1 { + help += m::text("Aliases: ") + + m::text( + md.aliases + .iter() + .map(|(x, _)| x.as_str()) + .collect::>() + .join(", "), + ) + + m::nl(); + } + + help += m::text("A unit of [") + md.readable_type + m::text("]") + m::nl(); + + if let Some(defining_info) = self.interpreter.get_defining_unit(&full_name) { + let x = defining_info + .iter() + .filter(|u| !u.unit_id.is_base()) + .map(|unit_factor| unit_factor.unit_id.unit_and_factor()) + .next(); + + if !prefix.is_none() { + help += m::nl() + + m::value("1 ") + + m::type_identifier(keyword) + + m::text(" = ") + + m::value(prefix.factor().pretty_print()) + + m::space() + + m::type_identifier(&full_name); + } + + if let Some(BaseUnitAndFactor(prod, num)) = x { + help += m::nl() + + m::value("1 ") + + m::type_identifier(&full_name) + + m::text(" = ") + + m::value(num.pretty_print()) + + m::space() + + prod.pretty_print_with(|f| f.exponent, 'x', '/', true); + } else { + help += + m::nl() + m::type_identifier(&full_name) + m::text(" is a base unit"); + } + }; + + return help; + } + }; + + m::text("Not found") + } + pub fn list_modules(&self) -> impl Iterator { let modules = self.resolver.get_importer().list_modules(); modules.into_iter().map(|m| m.0.join("::")) diff --git a/numbat/src/prefix_transformer.rs b/numbat/src/prefix_transformer.rs index c88513ea..46a020b3 100644 --- a/numbat/src/prefix_transformer.rs +++ b/numbat/src/prefix_transformer.rs @@ -10,7 +10,7 @@ type Result = std::result::Result; #[derive(Debug, Clone)] pub(crate) struct Transformer { - prefix_parser: PrefixParser, + pub prefix_parser: PrefixParser, pub variable_names: Vec, pub function_names: Vec, diff --git a/numbat/src/unit.rs b/numbat/src/unit.rs index 3e35f5c5..7b0eb623 100644 --- a/numbat/src/unit.rs +++ b/numbat/src/unit.rs @@ -27,7 +27,7 @@ pub struct UnitIdentifier { kind: UnitKind, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct BaseUnitAndFactor(pub Unit, pub Number); impl std::iter::Product for BaseUnitAndFactor { @@ -42,6 +42,18 @@ impl UnitIdentifier { matches!(self.kind, UnitKind::Base) } + pub fn unit_and_factor(&self) -> BaseUnitAndFactor { + match &self.kind { + UnitKind::Base => BaseUnitAndFactor( + Unit::new_base(&self.name, &self.canonical_name), + Number::from_f64(1.0), + ), + UnitKind::Derived(factor, defining_unit) => { + BaseUnitAndFactor(defining_unit.clone(), *factor) + } + } + } + pub fn base_unit_and_factor(&self) -> BaseUnitAndFactor { match &self.kind { UnitKind::Base => BaseUnitAndFactor(