diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc4a7e3..464ad83 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,3 +42,8 @@ jobs: crate: cargo-all-features version: latest - run: cargo test-all-features + + - name: Test Parsing + uses: actions-rs/cargo@v1 + with: + command: check --package parsing diff --git a/Cargo.lock b/Cargo.lock index be6255a..e984286 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -484,20 +484,28 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "eframe" -version = "0.17.0" -source = "git+https://github.com/Titaniumtown/egui.git#0e8e8b76a042115498449c9da8e0f2ccae87df82" +version = "0.18.0" +source = "git+https://github.com/Titaniumtown/egui.git#f2321e8a7cbfb11e0f076edbdd62e95528409ca1" dependencies = [ + "bytemuck", "egui", "egui-winit", "egui_glow", - "egui_web", - "epi", + "glow", + "glutin", + "js-sys", + "percent-encoding", + "tracing", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winit", ] [[package]] name = "egui" -version = "0.17.0" -source = "git+https://github.com/Titaniumtown/egui.git#0e8e8b76a042115498449c9da8e0f2ccae87df82" +version = "0.18.1" +source = "git+https://github.com/Titaniumtown/egui.git#f2321e8a7cbfb11e0f076edbdd62e95528409ca1" dependencies = [ "ahash", "epaint", @@ -507,13 +515,11 @@ dependencies = [ [[package]] name = "egui-winit" -version = "0.17.0" -source = "git+https://github.com/Titaniumtown/egui.git#0e8e8b76a042115498449c9da8e0f2ccae87df82" +version = "0.18.0" +source = "git+https://github.com/Titaniumtown/egui.git#f2321e8a7cbfb11e0f076edbdd62e95528409ca1" dependencies = [ "arboard", "egui", - "epi", - "glow", "instant", "tracing", "webbrowser", @@ -522,38 +528,18 @@ dependencies = [ [[package]] name = "egui_glow" -version = "0.17.0" -source = "git+https://github.com/Titaniumtown/egui.git#0e8e8b76a042115498449c9da8e0f2ccae87df82" +version = "0.18.0" +source = "git+https://github.com/Titaniumtown/egui.git#f2321e8a7cbfb11e0f076edbdd62e95528409ca1" dependencies = [ "bytemuck", "egui", - "egui-winit", - "epi", "glow", - "glutin", "memoffset", "tracing", "wasm-bindgen", "web-sys", ] -[[package]] -name = "egui_web" -version = "0.17.0" -source = "git+https://github.com/Titaniumtown/egui.git#0e8e8b76a042115498449c9da8e0f2ccae87df82" -dependencies = [ - "bytemuck", - "egui", - "egui_glow", - "epi", - "js-sys", - "percent-encoding", - "tracing", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "either" version = "1.6.1" @@ -562,16 +548,16 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "emath" -version = "0.17.0" -source = "git+https://github.com/Titaniumtown/egui.git#0e8e8b76a042115498449c9da8e0f2ccae87df82" +version = "0.18.0" +source = "git+https://github.com/Titaniumtown/egui.git#f2321e8a7cbfb11e0f076edbdd62e95528409ca1" dependencies = [ "bytemuck", ] [[package]] name = "epaint" -version = "0.17.0" -source = "git+https://github.com/Titaniumtown/egui.git#0e8e8b76a042115498449c9da8e0f2ccae87df82" +version = "0.18.1" +source = "git+https://github.com/Titaniumtown/egui.git#f2321e8a7cbfb11e0f076edbdd62e95528409ca1" dependencies = [ "ab_glyph", "ahash", @@ -582,16 +568,6 @@ dependencies = [ "parking_lot 0.12.0", ] -[[package]] -name = "epi" -version = "0.17.0" -source = "git+https://github.com/Titaniumtown/egui.git#0e8e8b76a042115498449c9da8e0f2ccae87df82" -dependencies = [ - "egui", - "glow", - "tracing", -] - [[package]] name = "error-code" version = "2.3.1" @@ -610,8 +586,8 @@ checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" [[package]] name = "exmex" -version = "0.15.0" -source = "git+https://github.com/bertiqwerty/exmex.git?branch=main#4f34fb927246009b6b716b5ba8e35f045d27c239" +version = "0.16.0" +source = "git+https://github.com/bertiqwerty/exmex.git?branch=main#a854d7af15d2bb65ec0c62b60f104640c70da5b3" dependencies = [ "lazy_static", "num", @@ -681,7 +657,7 @@ dependencies = [ "cfg-if 1.0.0", "js-sys", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi 0.10.0+wasi-snapshot-preview1", "wasm-bindgen", ] @@ -904,9 +880,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.124" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50" +checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" [[package]] name = "libgit2-sys" @@ -954,9 +930,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.16" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if 1.0.0", ] @@ -978,9 +954,9 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memmap2" @@ -1190,18 +1166,18 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26873667bbbb7c5182d4a37c1add32cdf09f841af72da53318fdb81543c15085" +checksum = "97fbc387afefefd5e9e39493299f3069e14a140dd34dc19b4c1c1a8fddb6a790" dependencies = [ "num-traits", ] [[package]] name = "num-integer" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg", "num-traits", @@ -1232,9 +1208,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", ] @@ -1351,7 +1327,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" dependencies = [ "lock_api", - "parking_lot_core 0.9.2", + "parking_lot_core 0.9.3", ] [[package]] @@ -1370,9 +1346,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "995f667a6c822200b0433ac218e05582f0e2efa1b922a3fd2fbaadc5f87bab37" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" dependencies = [ "cfg-if 1.0.0", "libc", @@ -1573,7 +1549,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "ruzstd" version = "0.2.4" -source = "git+https://github.com/KillingSpark/zstd-rs.git#66d02e41e8f88aac3f39e6f6a9ef4320073d9431" +source = "git+https://github.com/Titaniumtown/zstd-rs.git?branch=ringbuffer#d7f5caaf23146cd525a2a215241661ecf0aa073a" dependencies = [ "byteorder", "twox-hash", @@ -1608,15 +1584,15 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.136" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" [[package]] name = "serde_json" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +checksum = "f972498cf015f7c0746cac89ebe1d6ef10c293b94175a243a2d9442c163d9944" dependencies = [ "itoa", "ryu", @@ -1714,9 +1690,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.91" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d" +checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52" dependencies = [ "proc-macro2", "quote", @@ -1736,18 +1712,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", @@ -1765,11 +1741,12 @@ dependencies = [ [[package]] name = "time" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", + "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] @@ -1899,9 +1876,9 @@ dependencies = [ [[package]] name = "unicode-xid" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" [[package]] name = "url" @@ -1956,9 +1933,9 @@ dependencies = [ [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasi" @@ -2199,9 +2176,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5acdd78cb4ba54c0045ac14f62d8f94a03d10047904ae2a40afa1e99d8f70825" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ "windows_aarch64_msvc", "windows_i686_gnu", @@ -2212,33 +2189,33 @@ dependencies = [ [[package]] name = "windows_aarch64_msvc" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] name = "windows_i686_gnu" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] name = "windows_i686_msvc" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] name = "windows_x86_64_gnu" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] name = "windows_x86_64_msvc" -version = "0.34.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] name = "winit" @@ -2333,7 +2310,6 @@ dependencies = [ "egui", "emath", "epaint", - "epi", "instant", "itertools", "lazy_static", diff --git a/Cargo.toml b/Cargo.toml index b94d1b1..23a4dfa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ debug = false codegen-units = 1 opt-level = "z" #optimize for size #lto = "fat" #causes issues with wasm, disabling for the time being -strip = true +strip = false panic = "abort" [profile.dev] @@ -33,7 +33,6 @@ parsing = { path = "./parsing" } eframe = { git = "https://github.com/Titaniumtown/egui.git", default-features = false } egui = { git = "https://github.com/Titaniumtown/egui.git", default-features = false } epaint = { git = "https://github.com/Titaniumtown/egui.git", default-features = false } -epi = { git = "https://github.com/Titaniumtown/egui.git", default-features = false } emath = { git = "https://github.com/Titaniumtown/egui.git", default-features = false } shadow-rs = { version = "0.11", default-features = false } @@ -41,7 +40,7 @@ const_format = { version = "0.2", default-features = false, features = ["fmt"] } cfg-if = "1" lazy_static = "1" tar = "0.4" -ruzstd = { git = "https://github.com/KillingSpark/zstd-rs.git" } +ruzstd = { git = "https://github.com/Titaniumtown/zstd-rs.git", branch = "ringbuffer" } serde_json = "1.0" tracing = "0.1" itertools = "0.10" diff --git a/parsing/src/lib.rs b/parsing/src/lib.rs index 180c457..47a9fd0 100644 --- a/parsing/src/lib.rs +++ b/parsing/src/lib.rs @@ -1,2 +1,4 @@ +#![feature(const_trait_impl)] + pub mod parsing; pub mod suggestions; diff --git a/parsing/src/parsing.rs b/parsing/src/parsing.rs index 382cf4c..af5efd3 100644 --- a/parsing/src/parsing.rs +++ b/parsing/src/parsing.rs @@ -150,95 +150,11 @@ pub fn is_number(c: &char) -> bool { NUMBERS.contains(&c) } /// In the future I may want to completely rewrite this or implement this natively in exmex. // TODO: use `split_function` here instead of this janky code pub fn process_func_str(function_in: &str) -> String { - let function = function_in - .replace("log10(", "log(") // log10 -> log - .replace("pi", "π") // pi -> π - .replace("exp", "\u{1fc93}") // replace 'exp' with this random unicode character because it can't be parsed correctly - .replace("**", "^"); // alternate exponential representation - let function_chars: Vec = function.chars().collect(); - let mut output_string: String = String::new(); - for (i, c) in function_chars.iter().enumerate() { - let mut add_asterisk: bool = false; - - let prev_prev_prev_char = if i > 2 { - *function_chars.get(i - 3).unwrap() - } else { - ' ' - }; - - let prev_prev_char = if i > 1 { - *function_chars.get(i - 2).unwrap() - } else { - ' ' - }; - - let prev_char = if i > 0 { - *function_chars.get(i - 1).unwrap() - } else { - ' ' - }; - - let c_is_number = is_number(c); - let c_is_letter = is_letter(c); - let c_is_variable = is_variable(c); - let prev_char_is_variable = is_variable(&prev_char); - let prev_char_is_number = is_number(&prev_char); - - // makes special case for log with base of a 1-2 digit number - if ((prev_prev_prev_char == 'l') - && (prev_prev_char == 'o') - && (prev_char == 'g') - && c_is_number) - | ((prev_prev_char == 'c') && (prev_char == 'e') && (*c == 'i')) - { - output_string += &c.to_string(); - continue; - } - - let c_letters_var = c_is_letter | c_is_variable; - let prev_letters_var = prev_char_is_variable | is_letter(&prev_char); - - if prev_char == ')' { - // cases like `)x`, `)2`, and `)(` - if c_letters_var | c_is_number | (*c == '(') { - add_asterisk = true; - } - } else if *c == '(' { - // cases like `x(` and `2(` - if (prev_char_is_variable | prev_char_is_number) && !is_letter(&prev_prev_char) { - add_asterisk = true; - } - } else if prev_char_is_number { - // cases like `2x` and `2sin(x)` - if c_letters_var { - add_asterisk = true; - } - } else if c_is_letter { - // cases like `e2` and `xx` - if prev_char_is_number - | (prev_char_is_variable && c_is_variable) - | prev_char_is_variable - | (prev_char == 'π') - { - add_asterisk = true; - } - } else if (c_is_number | c_letters_var) && prev_letters_var { - // cases like `x2` and `xx` - add_asterisk = true; - } - - // if add_asterisk is true, add the asterisk - if add_asterisk { - output_string += "*"; - } - - // push current char to `output_string` (which is eventually returned) - output_string += &c.to_string(); + if function_in.is_empty() { + return String::new(); } - output_string - .replace("log(", "log10(") - .replace('\u{1fc93}', "exp") + crate::suggestions::split_function(&function_in).join("*") } #[cfg(test)] @@ -326,6 +242,7 @@ mod tests { ("pisin(x)", "π*sin(x)"), ("e^sin(x)", "e^sin(x)"), ("x**2", "x^2"), + ("(x+1)(x-3)", "(x+1)*(x-3)"), ]); for (key, value) in values { diff --git a/parsing/src/suggestions.rs b/parsing/src/suggestions.rs index e343af4..3209ee6 100644 --- a/parsing/src/suggestions.rs +++ b/parsing/src/suggestions.rs @@ -1,4 +1,4 @@ -use crate::parsing::is_number; +use crate::parsing::{is_letter, is_number, is_variable}; pub const HINT_EMPTY: Hint = Hint::Single("x^2"); const HINT_CLOSED_PARENS: Hint = Hint::Single(")"); @@ -13,7 +13,17 @@ macro_rules! test_print { } pub fn split_function(input: &str) -> Vec { - split_function_chars(&input.chars().collect::>()) + split_function_chars( + &input + .replace("pi", "π") + .replace("**", "^") + .replace("exp", "\u{1fc93}") + .chars() + .collect::>(), + ) + .iter() + .map(|x| x.replace("\u{1fc93}", "exp")) + .collect::>() } fn split_function_chars(chars: &[char]) -> Vec { @@ -22,19 +32,120 @@ fn split_function_chars(chars: &[char]) -> Vec { let mut split: Vec = Vec::new(); let mut buffer: Vec = Vec::new(); + + #[derive(Default)] + struct BoolSlice { + closing_parens: bool, + number: bool, + letter: bool, + variable: bool, + masked_num: bool, + masked_var: bool, + exists: bool, + } + + impl BoolSlice { + #[inline] + fn is_variable(&self) -> bool { self.variable && !self.masked_var } + + #[inline] + fn is_number(&self) -> bool { self.number && !self.masked_num } + } + let mut prev_char: BoolSlice = BoolSlice::default(); + for c in chars { - buffer.push(*c); - if *c == ')' { - split.push(buffer.iter().collect::()); - buffer.clear(); - continue; - } + let mut curr_c = BoolSlice { + closing_parens: c == &')', + number: is_number(c), + letter: is_letter(c), + variable: is_variable(c), + masked_num: if is_number(c) { + prev_char.masked_num + } else { + false + }, + masked_var: if is_variable(c) { + prev_char.masked_var + } else { + false + }, + exists: true, + }; let buffer_string = buffer.iter().collect::(); - if ((&buffer_string == "log") | (&buffer_string == "log1")) && is_number(&c) { - continue; + // Check if prev_char is valid + if prev_char.exists { + // if previous char was a masked number, and current char is a number, mask current char's variable status + if prev_char.masked_num && curr_c.number { + curr_c.masked_num = true; + } + + // if previous char was a masked variable, and current char is a variable, mask current char's variable status + if prev_char.masked_var && curr_c.variable { + curr_c.masked_var = true; + } + + // if letter and not a variable (or a masked variable) + if prev_char.letter && !(prev_char.variable && !prev_char.masked_var) { + // mask number status if current char is number + if curr_c.number { + curr_c.masked_num = true; + } + + // mask variable status if current char is a variable + if curr_c.variable { + curr_c.masked_var = true; + } + } } + + let mut do_split = false; + + if prev_char.closing_parens { + // cases like `)x`, `)2`, and `)(` + if (c == &'(') + | (curr_c.letter && !curr_c.is_variable()) + | curr_c.is_variable() + | curr_c.is_number() + { + do_split = true; + } + } else if c == &'(' { + // cases like `x(` and `2(` + if (prev_char.is_variable() | prev_char.is_number()) && !prev_char.letter { + do_split = true; + } + } else if prev_char.is_number() { + // cases like `2x` and `2sin(x)` + if curr_c.is_variable() | curr_c.letter { + do_split = true; + } + } else if curr_c.is_variable() | curr_c.letter { + // cases like `e2` and `xx` + if prev_char.is_number() + | (prev_char.is_variable() && curr_c.is_variable()) + | prev_char.is_variable() + { + do_split = true; + } + } else if (curr_c.is_number() | curr_c.letter | curr_c.is_variable()) + && (prev_char.is_number() | prev_char.letter) + { + // cases like `x2` and `xx` + do_split = true; + } else if curr_c.is_number() && prev_char.is_variable() { + do_split = true; + } + + // split and append buffer + if do_split { + split.push(buffer_string); + buffer.clear(); + } + + buffer.push(*c); + prev_char = curr_c; } if !buffer.is_empty() { @@ -75,10 +186,6 @@ pub enum Hint<'a> { None, } -impl<'a> std::fmt::Debug for Hint<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self) } -} - impl<'a> std::fmt::Display for Hint<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -95,6 +202,12 @@ impl<'a> std::fmt::Display for Hint<'a> { } } +impl<'a> std::fmt::Debug for Hint<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + std::fmt::Display::fmt(self, f) + } +} + impl<'a> Hint<'a> { pub fn is_none(&self) -> bool { matches!(self, Hint::None) } @@ -163,11 +276,17 @@ mod tests { .flatten() .filter(|func| !SUPPORTED_FUNCTIONS.contains(&func.as_str())) .for_each(|key| { - println!("{}", key); - if super::generate_hint(&key).is_none() { + let split = super::split_function(&key); + + if split.len() != 1 { + panic!("failed: {} (len: {}, split: {:?})", key, split.len(), split); + } + + let generated_hint = super::generate_hint(&key); + if generated_hint.is_none() { println!("success: {}", key); } else { - panic!("failed: {}", key); + panic!("failed: {} (Hint: '{}')", key, generated_hint.to_string()); } }); } @@ -179,6 +298,7 @@ mod tests { ("cos(", vec!["cos("]), ("cos(x)sin(x)", vec!["cos(x)", "sin(x)"]), ("aaaaaaaaaaa", vec!["aaaaaaaaaaa"]), + ("emax(x)", vec!["e", "max(x)"]), ]); for (key, value) in values { diff --git a/src/function_manager.rs b/src/function_manager.rs index 191860a..073bedd 100644 --- a/src/function_manager.rs +++ b/src/function_manager.rs @@ -1,7 +1,7 @@ use crate::consts::is_mobile; use crate::function_entry::{FunctionEntry, DEFAULT_FUNCTION_ENTRY}; use crate::widgets::{move_cursor_to_end, widgets_ontop, Movement}; -use egui::{Button, Key, Modifiers}; +use egui::{Button, Key, Modifiers, RichText, WidgetText}; use emath::vec2; use parsing::suggestions::Hint; use std::ops::BitXorAssign; @@ -128,8 +128,8 @@ impl FunctionManager { } /// Function that creates button that's used with the `button_area` - fn button_area_button(text: impl Into) -> Button { - Button::new(text.into()).frame(false) + const fn button_area_button(text: String) -> Button { + Button::new_const(WidgetText::RichText(RichText::new_const(text))).frame(false) } /// the y offset multiplier of the `buttons_area` area @@ -144,7 +144,7 @@ impl FunctionManager { ui.horizontal(|ui| { // There's more than 1 function! Functions can now be deleted if ui - .add_enabled(can_remove, button_area_button("✖")) + .add_enabled(can_remove, button_area_button("✖".to_owned())) .on_hover_text("Delete Function") .clicked() { @@ -153,7 +153,7 @@ impl FunctionManager { // Toggle integral being enabled or not function.integral.bitxor_assign( - ui.add(button_area_button("∫")) + ui.add(button_area_button("∫".to_owned())) .on_hover_text(match function.integral { true => "Don't integrate", false => "Integrate", @@ -163,7 +163,7 @@ impl FunctionManager { // Toggle showing the derivative (even though it's already calculated this option just toggles if it's displayed or not) function.derivative.bitxor_assign( - ui.add(button_area_button("d/dx")) + ui.add(button_area_button("d/dx".to_owned())) .on_hover_text(match function.derivative { true => "Don't Differentiate", false => "Differentiate", @@ -172,7 +172,7 @@ impl FunctionManager { ); function.settings_opened.bitxor_assign( - ui.add(button_area_button("⚙")) + ui.add(button_area_button("⚙".to_owned())) .on_hover_text(match function.settings_opened { true => "Close Settings", false => "Open Settings", diff --git a/src/lib.rs b/src/lib.rs index 40f5c81..f46ce7f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ #![feature(const_mut_refs)] #![feature(let_chains)] #![feature(stmt_expr_attributes)] +#![feature(const_trait_impl)] #[macro_use] extern crate static_assertions; diff --git a/src/main.rs b/src/main.rs index 3f74f81..d33928e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ #![feature(const_mut_refs)] #![feature(let_chains)] #![feature(stmt_expr_attributes)] +#![feature(const_trait_impl)] #[macro_use] extern crate static_assertions; diff --git a/src/math_app.rs b/src/math_app.rs index 6e84c01..594a976 100644 --- a/src/math_app.rs +++ b/src/math_app.rs @@ -2,6 +2,7 @@ use crate::consts::*; use crate::function_entry::Riemann; use crate::function_manager::FunctionManager; use crate::misc::{dyn_mut_iter, option_vec_printer, TextData}; +use eframe::App; use egui::{ plot::Plot, style::Margin, vec2, Button, CentralPanel, Color32, ComboBox, Context, FontData, FontDefinitions, FontFamily, Frame, Key, RichText, SidePanel, Slider, TopBottomPanel, Vec2, @@ -136,8 +137,6 @@ impl MathApp { #[cfg(not(threading))] tracing::info!("Threading: Disabled"); - tracing::info!("Integration name: {}", cc.integration_info.name); - if let Some(web_info) = &cc.integration_info.web_info { tracing::info!("Web Info: {:?}", web_info); } @@ -382,9 +381,9 @@ impl MathApp { } } -impl epi::App for MathApp { +impl App for MathApp { /// Called each time the UI needs repainting. - fn update(&mut self, ctx: &Context, _frame: &mut epi::Frame) { + fn update(&mut self, ctx: &Context, _frame: &mut eframe::Frame) { // start timer let start = if self.opened.info { Some(instant::Instant::now()) diff --git a/src/misc.rs b/src/misc.rs index 6d0fc78..f81cd1e 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -298,7 +298,7 @@ where .map(|x| { x.as_ref() .map(|x_1| x_1.to_string()) - .unwrap_or_else(|| "None".to_string()) + .unwrap_or_else(|| "None".to_owned()) }) .enumerate() .map(|(i, x)| { diff --git a/src/widgets.rs b/src/widgets.rs index ca9d415..664d993 100644 --- a/src/widgets.rs +++ b/src/widgets.rs @@ -10,7 +10,7 @@ pub enum Movement { None, } -impl Default for Movement { +impl const Default for Movement { fn default() -> Self { Self::None } } @@ -21,7 +21,7 @@ pub struct AutoComplete<'a> { pub string: String, } -impl<'a> Default for AutoComplete<'a> { +impl<'a> const Default for AutoComplete<'a> { fn default() -> AutoComplete<'a> { AutoComplete { i: 0, @@ -34,9 +34,14 @@ impl<'a> Default for AutoComplete<'a> { impl<'a> AutoComplete<'a> { pub fn update_string(&mut self, string: &str) { if self.string != string { - self.i = 0; - self.string = string.to_string(); - self.hint = generate_hint(string); + // catch empty strings here to avoid call to `generate_hint` and unnecessary logic + if string.is_empty() { + *self = Self::default(); + } else { + self.i = 0; + self.string = string.to_string(); + self.hint = generate_hint(string); + } } }