Browse Source

info <dimension>

David Peter 4 months ago
parent
commit
43a75b7483
5 changed files with 89 additions and 2 deletions
  1. 1 1
      book/src/cli-usage.md
  2. 1 1
      book/src/web-usage.md
  3. 4 0
      numbat/src/dimension.rs
  4. 77 0
      numbat/src/lib.rs
  5. 6 0
      numbat/src/registry.rs

+ 1 - 1
book/src/cli-usage.md

@@ -37,7 +37,7 @@ There is a set of special commands that only work in interactive mode:
 |---------|--------|
 | `list` | List all functions, dimensions, variables and units |
 | `list <what>` | Where `<what>` can be `functions`, `dimensions`, `variables`, `units` |
-| `info <identifier>` | Get more information about units, variables, and functions |
+| `info <identifier>` | Get more information about units, dimensions, variables, and functions |
 | `clear` | Clear screen |
 | `help`, `?` | View short help text |
 | `save` | Save the current session history to file `history.nbt` in the current directory |

+ 1 - 1
book/src/web-usage.md

@@ -26,7 +26,7 @@ There is a set of special commands that only work in the web version:
 |---------|--------|
 | `list` | List all functions, dimensions, variables and units |
 | `list <what>` | Where `<what>` can be `functions`, `dimensions`, `variables`, `units` |
-| `info <identifier>` | Get more information about units, variables, and functions |
+| `info <identifier>` | Get more information about units, dimensions, variables, and functions |
 | `clear` | Clear screen |
 | `help`, `?` | View short help text |
 | `reset` | Reset state (clear constants, functions, units, …) |

+ 4 - 0
numbat/src/dimension.rs

@@ -94,6 +94,10 @@ impl DimensionRegistry {
     pub fn contains(&self, dimension_name: &str) -> bool {
         self.registry.contains(dimension_name)
     }
+
+    pub fn is_base_dimension(&self, dimension_name: &str) -> bool {
+        self.registry.is_base_dimension(dimension_name)
+    }
 }
 
 #[test]

+ 77 - 0
numbat/src/lib.rs

@@ -64,6 +64,7 @@ use markup::FormatType;
 use markup::Markup;
 use module_importer::{ModuleImporter, NullImporter};
 use prefix_transformer::Transformer;
+use pretty_print::PrettyPrint;
 
 use resolver::CodeSource;
 use resolver::Resolver;
@@ -352,6 +353,7 @@ impl Context {
         }
         let reg = self.interpreter.get_unit_registry();
 
+        // Check if it's a unit
         if let PrefixParserResult::UnitIdentifier(_span, prefix, _, full_name) =
             self.prefix_transformer.prefix_parser.parse(keyword)
         {
@@ -453,6 +455,80 @@ impl Context {
             }
         };
 
+        // Check if it's a dimension
+        if self.dimension_registry().contains(keyword) {
+            let mut help =
+                m::text("Dimension:   ") + m::type_identifier(keyword.to_compact_string());
+
+            if let Ok(base_representation) = self
+                .dimension_registry()
+                .get_base_representation_for_name(keyword)
+            {
+                if self.dimension_registry().is_base_dimension(keyword) {
+                    help += m::text(" (Base dimension)") + m::nl();
+                } else {
+                    help += m::space()
+                        + m::operator("=")
+                        + m::space()
+                        + base_representation.pretty_print()
+                        + m::nl();
+                }
+
+                let equivalent_dimensions = self
+                    .dimension_registry()
+                    .get_derived_entry_names_for(&base_representation);
+                if equivalent_dimensions.len() > 1 {
+                    let other_names: Vec<CompactString> = equivalent_dimensions
+                        .iter()
+                        .filter(|&name| name.as_str() != keyword)
+                        .cloned()
+                        .collect();
+                    if !other_names.is_empty() {
+                        help += m::text("Equivalent:  ");
+                        for (i, name) in other_names.iter().enumerate() {
+                            if i > 0 {
+                                help += m::text(", ");
+                            }
+                            help += m::type_identifier(name.clone());
+                        }
+                        help += m::nl();
+                    }
+                }
+
+                // List units that belong to this dimension
+                let matching_units: Vec<CompactString> = self
+                    .unit_representations()
+                    .filter_map(|(_unit_name, (_unit_base_rep, unit_metadata))| {
+                        if let Type::Dimension(unit_dim) = &unit_metadata.type_ {
+                            if unit_dim.to_base_representation() == base_representation {
+                                if let Some((primary_alias, _)) = unit_metadata.aliases.first() {
+                                    return Some(primary_alias.clone());
+                                }
+                            }
+                        }
+                        None
+                    })
+                    .collect();
+
+                if !matching_units.is_empty() {
+                    let mut sorted_units = matching_units;
+                    sorted_units.sort_by_key(|unit| unit.to_lowercase());
+
+                    help += m::text("Units:       ");
+                    for (i, unit) in sorted_units.iter().enumerate() {
+                        if i > 0 {
+                            help += m::text(", ");
+                        }
+                        help += m::unit(unit.clone());
+                    }
+                    help += m::nl();
+                }
+            }
+
+            return help;
+        }
+
+        // Check if it's a valid identifier
         if let Some(l) = self.interpreter.lookup_global(keyword) {
             let mut help = m::text("Variable: ");
             if let Some(name) = &l.metadata.name {
@@ -506,6 +582,7 @@ impl Context {
             return help;
         }
 
+        // Check if it's a function
         if let Some((fn_signature, fn_metadata)) = self.typechecker.lookup_function(keyword) {
             let metadata = fn_metadata.clone();
 

+ 6 - 0
numbat/src/registry.rs

@@ -178,4 +178,10 @@ impl<Metadata: Clone> Registry<Metadata> {
     pub fn iter_derived_entries(&self) -> impl Iterator<Item = CompactString> + '_ {
         self.derived_entries.keys().cloned()
     }
+
+    pub fn is_base_dimension(&self, dimension_name: &str) -> bool {
+        self.base_entries
+            .iter()
+            .any(|(name, _)| name == dimension_name)
+    }
 }