libmathcat/
lib.rs

1//! A library for generating speech and braille from MathML
2//! 
3//! Typical usage is:
4//! 1. Set the rules directory [`set_rules_dir`]
5//! 2. Set whatever preferences are need with repeated calls to [`set_preference`].
6//! 3. Set MathML via [`set_mathml`]
7//!    A string representing the cleaned up MathML along with `id`s on each node is returned for highlighting if desired
8//! 4. Get the speech [`get_spoken_text`] or (Unicode) braille [`get_braille`].
9//!
10//! The expression can be navigated also.
11//! This is done in one of two ways:
12//! 1. Pass key strokes to allow a user to navigate the MathML by calling [`do_navigate_keypress`]; the speech is returned.
13//! 2. Pass the MathCAT navigation command directory by called [`do_navigate_command`]; the speech is return returned.
14//! 
15//! To get the MathML associated with the current navigation node, call [`get_navigation_mathml`].
16//! To just get the `id` and offset from the id of the current navigation node, call [`get_navigation_mathml_id`].
17#![recursion_limit = "1024"]
18
19#[macro_use]
20extern crate error_chain;
21
22// We'll put our errors in an `errors` module, and other modules in
23// this crate will `use errors::*;` to get access to everything
24// `error_chain!` creates.
25pub mod errors {
26    // Create the Error, ErrorKind, ResultExt, and Result types
27    error_chain! {
28        // foreign_links {
29        //     Io(std::io::Error);
30        //     HttpRequest(reqwest::Error);
31        // }
32    }
33}
34
35#[macro_use]
36extern crate lazy_static;
37
38#[macro_use]
39extern crate bitflags;
40
41#[macro_use]
42extern crate log;
43
44#[macro_use]
45extern crate cfg_if;
46
47
48pub mod interface;
49#[cfg(feature = "include-zip")]
50pub use shim_filesystem::ZIPPED_RULE_FILES;
51
52mod canonicalize;
53mod infer_intent;
54pub mod speech;
55mod braille;
56mod navigate;
57mod prefs;
58mod tts;
59mod xpath_functions;
60mod definitions;
61pub mod pretty_print;
62mod chemistry;
63
64pub mod shim_filesystem; // really just for override_file_for_debugging_rules, but the config seems to throw it off
65pub use interface::*;
66
67#[cfg(test)]
68pub fn init_logger() {
69    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug"))
70        .is_test(true)
71        .format_timestamp(None)
72        .format_module_path(false)
73        .format_indent(None)
74        .format_level(false)
75        .init();
76}
77
78#[cfg(test)]
79/// Build Absolute path to rules dir for testing
80pub fn abs_rules_dir_path() -> String {
81    return std::env::current_exe().unwrap().parent().unwrap()
82                .join("../../../Rules")
83                .to_str().unwrap().to_string();
84    // use std::path::PathBuf;
85    // let out_dir = std::env::var_os("OUT_DIR").unwrap();
86    // println!("abs_rules_dir_path: out_dir={:?}", out_dir);
87    // let out_dir = PathBuf::from(&out_dir);
88    // return PathBuf::from(&out_dir).join("Rules").to_string_lossy().to_string();
89}
90
91#[cfg(test)]
92pub fn are_strs_canonically_equal_with_locale(test: &str, target: &str, block_separators: &str, decimal_separators: &str) -> bool {
93    use crate::{interface::*, pretty_print::mml_to_string};
94    use sxd_document::parser;
95    use crate::canonicalize::canonicalize;
96    // this forces initialization
97    crate::interface::set_rules_dir(abs_rules_dir_path()).unwrap();
98    crate::speech::SPEECH_RULES.with(|rules|  rules.borrow_mut().read_files().unwrap());
99    set_preference("Language".to_string(), "en".to_string()).unwrap();
100    set_preference("BlockSeparators".to_string(), block_separators.to_string()).unwrap();
101    set_preference("DecimalSeparators".to_string(), decimal_separators.to_string()).unwrap();
102    
103    let package1 = &parser::parse(test).expect("Failed to parse test input");
104    let mathml = get_element(package1);
105    trim_element(mathml, false);
106    // debug!("test:\n{}", mml_to_string(mathml));
107    let mathml_test = canonicalize(mathml).unwrap();
108   
109    let package2 = &parser::parse(target).expect("Failed to parse target input");
110    let mathml_target = get_element(package2);
111    trim_element(mathml_target, false);
112    // debug!("target:\n{}", mml_to_string(mathml_target));
113
114    match is_same_element(mathml_test, mathml_target) {
115        Ok(_) => return true,
116        Err(e) => panic!("{}\nResult:\n{}\nTarget:\n{}", e, mml_to_string(mathml_test), mml_to_string(mathml_target)),
117    }
118}
119
120#[cfg(test)]
121// sets locale to be US standard
122pub fn are_strs_canonically_equal(test: &str, target: &str) -> bool {
123    return are_strs_canonically_equal_with_locale(test, target, ", \u{00A0}\u{202F}", ".");
124}
125