use itertools::Itertools; use numbat::markup::plain_text_format; use numbat::module_importer::FileSystemImporter; use numbat::resolver::CodeSource; use numbat::Context; use percent_encoding; use std::path::Path; const AUTO_GENERATED_HINT: &str = ""; fn inspect_units(ctx: &Context) { println!("{AUTO_GENERATED_HINT} # List of supported units See also: [Unit notation](./unit-notation.md). All SI-accepted units support [metric prefixes](https://en.wikipedia.org/wiki/Metric_prefix) (`mm`, `cm`, `km`, ... or `millimeter`, `centimeter`, `kilometer`, ...) and — where sensible — units allow for [binary prefixes](https://en.wikipedia.org/wiki/Binary_prefix) (`MiB`, `GiB`, ... or `mebibyte`, `gibibyte`, ...). "); println!("| Dimension | Unit name | Identifier(s) |"); println!("| --- | --- | --- |"); for (ref unit_name, (_base_representation, unit_metadata)) in ctx .unit_representations() .sorted_by_key(|(u, (_, m))| (m.readable_type.to_string(), u.to_lowercase())) { let mut names = unit_metadata.aliases; names.sort_by_key(|(n, _)| n.to_lowercase()); let names = names.iter().map(|(n, _)| n).join("`, `"); let url = unit_metadata.url; let name = unit_metadata.name.unwrap_or(unit_name.clone()); let name_with_url = if let Some(url) = url { format!("[{name}]({url})") } else { name.clone() }; let readable_type = unit_metadata.readable_type; println!("| `{readable_type}` | {name_with_url} | `{names}` |"); } } fn inspect_functions_in_module(ctx: &Context, prelude_ctx: &Context, module: String) { for (fn_name, name, signature, description, url, examples, code_source) in ctx.functions() { let CodeSource::Module(module_path, _) = code_source else { unreachable!(); }; if module_path.to_string() != module { continue; } if let Some(name) = name { println!("### `{fn_name}` ({name})"); } else { println!("### `{fn_name}`"); } if let Some(ref description_raw) = description { let description = replace_equation_delimiters(description_raw.trim().to_string()); if description.ends_with('.') { println!("{description}"); } else { println!("{description}."); } } if let Some(url) = url { println!("More information [here]({url})."); } println!(); println!("```nbt"); println!("{signature}"); println!("```"); println!(); if !examples.is_empty() { println!("
"); println!("Examples"); println!(); for (example_code, example_description) in examples { let mut example_ctx = prelude_ctx.clone(); let extra_import = if !example_ctx .resolver() .imported_modules .contains(&module_path) { format!("use {}\n", module) } else { "".into() }; let _result = example_ctx .interpret(&extra_import, CodeSource::Internal) .unwrap(); if let Ok((statements, results)) = example_ctx.interpret(&example_code, CodeSource::Internal) { let code = extra_import + &example_code; //Format the example input let example_input = format!(">>> {}", code); //Encode the example url let example_url = format!( "https://numbat.dev/?q={}", percent_encoding::utf8_percent_encode( &code, percent_encoding::NON_ALPHANUMERIC ) ); //Assemble the example output let result_markup = results.to_markup( statements.last(), &example_ctx.dimension_registry(), true, true, ); let example_output = &plain_text_format(&result_markup, false); //Print the example if let Some(example_description) = example_description { println!("{}", replace_equation_delimiters(example_description)); } print!("
");
                    print!("
"); print!("", "Run this code", "Run this code", example_url); print!("
"); print!(""); for l in example_input.lines() { println!("{}", l); } println!(); for l in example_output.lines() { println!("{}", l); } println!("
"); println!(); } else { eprintln!( "Warning: Example \"{example_code}\" of function {fn_name} did not run successfully." ); } } println!("
"); println!(); } } } // Replace $..$ with \\( .. \\) for mdbook. fn replace_equation_delimiters(text_in: String) -> String { let mut text_out = String::new(); for (i, part) in text_in.split('$').enumerate() { if i % 2 == 0 { text_out.push_str(part); } else { text_out.push_str("\\\\( "); text_out.push_str(part); text_out.push_str(" \\\\)"); } } return text_out; } fn prepare_context() -> Context { let module_path = Path::new(&std::env::var_os("CARGO_MANIFEST_DIR").unwrap()).join("modules"); let mut importer = FileSystemImporter::default(); importer.add_path(module_path); return Context::new(importer); } fn main() { let mut ctx = prepare_context(); let _result = ctx.interpret("use all", CodeSource::Internal).unwrap(); let mut example_ctx = prepare_context(); let _result = example_ctx .interpret("use prelude", CodeSource::Internal) .unwrap(); let mut args = std::env::args(); args.next(); if let Some(arg) = args.next() { match arg.as_str() { "units" => inspect_units(&ctx), "functions" => { let module = args.next().unwrap(); inspect_functions_in_module(&ctx, &example_ctx, module) } _ => eprintln!("USAGE: inspect [units|functions ]"), } } }