refactoring
This commit is contained in:
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -22,8 +22,8 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
command: check
|
command: check
|
||||||
|
|
||||||
test:
|
parsing_test:
|
||||||
name: Tests
|
name: Parsing Crate Tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout sources
|
- name: Checkout sources
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,3 +2,4 @@
|
|||||||
/pkg
|
/pkg
|
||||||
/tmp
|
/tmp
|
||||||
/assets.tar.zst
|
/assets.tar.zst
|
||||||
|
/Cargo.lock
|
||||||
|
|||||||
12
Cargo.lock
generated
12
Cargo.lock
generated
@@ -1379,6 +1379,16 @@ dependencies = [
|
|||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parsing"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"exmex",
|
||||||
|
"lazy_static",
|
||||||
|
"phf",
|
||||||
|
"phf_codegen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
@@ -2312,10 +2322,10 @@ dependencies = [
|
|||||||
"emath",
|
"emath",
|
||||||
"epaint",
|
"epaint",
|
||||||
"epi",
|
"epi",
|
||||||
"exmex",
|
|
||||||
"instant",
|
"instant",
|
||||||
"itertools",
|
"itertools",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"parsing",
|
||||||
"phf",
|
"phf",
|
||||||
"phf_codegen",
|
"phf_codegen",
|
||||||
"rayon",
|
"rayon",
|
||||||
|
|||||||
20
Cargo.toml
20
Cargo.toml
@@ -2,7 +2,6 @@
|
|||||||
name = "ytbn_graphing_software"
|
name = "ytbn_graphing_software"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
build = "build.rs"
|
|
||||||
license = "AGPL-3.0"
|
license = "AGPL-3.0"
|
||||||
repository = "https://github.com/Titaniumtown/YTBN-Graphing-Software"
|
repository = "https://github.com/Titaniumtown/YTBN-Graphing-Software"
|
||||||
description = "Crossplatform (and web-compatible) graphing calculator"
|
description = "Crossplatform (and web-compatible) graphing calculator"
|
||||||
@@ -14,20 +13,9 @@ crate-type = ["cdylib"]
|
|||||||
threading = ["async-lock", "rayon"]
|
threading = ["async-lock", "rayon"]
|
||||||
|
|
||||||
|
|
||||||
[profile.release]
|
|
||||||
debug = false
|
|
||||||
codegen-units = 1
|
|
||||||
opt-level = "z" #optimize for size
|
|
||||||
lto = true
|
|
||||||
strip = true
|
|
||||||
|
|
||||||
[profile.dev]
|
|
||||||
debug = true
|
|
||||||
opt-level = 0
|
|
||||||
lto = true
|
|
||||||
strip = false
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
parsing = { path = "./parsing" }
|
||||||
|
|
||||||
eframe = { git = "https://github.com/Titaniumtown/egui.git", default-features = false }
|
eframe = { git = "https://github.com/Titaniumtown/egui.git", default-features = false }
|
||||||
egui = { 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 }
|
epaint = { git = "https://github.com/Titaniumtown/egui.git", default-features = false }
|
||||||
@@ -39,9 +27,6 @@ const_format = { version = "0.2.22", default-features = false, features = [
|
|||||||
"fmt",
|
"fmt",
|
||||||
] }
|
] }
|
||||||
cfg-if = "1.0.0"
|
cfg-if = "1.0.0"
|
||||||
exmex = { git = "https://github.com/bertiqwerty/exmex.git", branch = "main", features = [
|
|
||||||
"partial",
|
|
||||||
] }
|
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
tar = "0.4.38"
|
tar = "0.4.38"
|
||||||
ruzstd = { git = "https://github.com/KillingSpark/zstd-rs.git", branch = "ringbuffer" }
|
ruzstd = { git = "https://github.com/KillingSpark/zstd-rs.git", branch = "ringbuffer" }
|
||||||
@@ -74,6 +59,5 @@ wasm-bindgen = { version = "0.2.80", default-features = false, features = [
|
|||||||
web-sys = "0.3.57"
|
web-sys = "0.3.57"
|
||||||
tracing-wasm = "0.2.1"
|
tracing-wasm = "0.2.1"
|
||||||
|
|
||||||
|
|
||||||
[package.metadata.cargo-all-features]
|
[package.metadata.cargo-all-features]
|
||||||
skip_optional_dependencies = true #don't test optional dependencies, only features
|
skip_optional_dependencies = true #don't test optional dependencies, only features
|
||||||
|
|||||||
62
build.rs
62
build.rs
@@ -1,71 +1,11 @@
|
|||||||
use std::env;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::{BufWriter, Write};
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
const SUPPORTED_FUNCTIONS: [&str; 22] = [
|
|
||||||
"abs", "signum", "sin", "cos", "tan", "asin", "acos", "atan", "sinh", "cosh", "tanh", "floor",
|
|
||||||
"round", "ceil", "trunc", "fract", "exp", "sqrt", "cbrt", "ln", "log2", "log10",
|
|
||||||
];
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// rebuild if new commit or contents of `assets` folder changed
|
// rebuild if new commit or contents of `assets` folder changed
|
||||||
println!("cargo:rerun-if-changed=.git/logs/HEAD");
|
println!("cargo:rerun-if-changed=.git/logs/HEAD");
|
||||||
println!("cargo:rerun-if-changed=assets/*");
|
println!("cargo:rerun-if-changed=assets/*");
|
||||||
|
|
||||||
let _ = command_run::Command::with_args("./pack_assets.sh", &[""])
|
let _ = command_run::Command::with_args("../pack_assets.sh", &[""])
|
||||||
.enable_capture()
|
.enable_capture()
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
shadow_rs::new().expect("Could not initialize shadow_rs");
|
shadow_rs::new().expect("Could not initialize shadow_rs");
|
||||||
|
|
||||||
generate_hashmap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_hashmap() {
|
|
||||||
let path = Path::new(&env::var("OUT_DIR").unwrap()).join("codegen.rs");
|
|
||||||
let mut file = BufWriter::new(File::create(&path).expect("Could not create file"));
|
|
||||||
let max_len: usize = SUPPORTED_FUNCTIONS
|
|
||||||
.to_vec()
|
|
||||||
.iter()
|
|
||||||
.map(|func| func.len())
|
|
||||||
.max()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let string_hashmap = compile_hashmap(
|
|
||||||
SUPPORTED_FUNCTIONS
|
|
||||||
.to_vec()
|
|
||||||
.iter()
|
|
||||||
.map(|a| a.to_string())
|
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut hashmap = phf_codegen::Map::new();
|
|
||||||
|
|
||||||
for (key, value) in string_hashmap.iter() {
|
|
||||||
hashmap.entry(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
write!(
|
|
||||||
&mut file,
|
|
||||||
"static COMPLETION_HASHMAP: phf::Map<&'static str, Hint> = {};",
|
|
||||||
hashmap.build()
|
|
||||||
)
|
|
||||||
.expect("Could not write to file");
|
|
||||||
|
|
||||||
writeln!(&mut file, "const MAX_COMPLETION_LEN: usize = {};", max_len)
|
|
||||||
.expect("Could not write to file");
|
|
||||||
|
|
||||||
write!(
|
|
||||||
&mut file,
|
|
||||||
"#[allow(dead_code)] pub const SUPPORTED_FUNCTIONS: [&str; {}] = {:?};",
|
|
||||||
SUPPORTED_FUNCTIONS.len(),
|
|
||||||
SUPPORTED_FUNCTIONS.to_vec()
|
|
||||||
)
|
|
||||||
.expect("Could not write to file");
|
|
||||||
}
|
|
||||||
|
|
||||||
include!(concat!(
|
|
||||||
env!("CARGO_MANIFEST_DIR"),
|
|
||||||
"/src/autocomplete_helper.rs"
|
|
||||||
));
|
|
||||||
|
|||||||
2
parsing/.gitignore
vendored
Normal file
2
parsing/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/target
|
||||||
|
/Cargo.lock
|
||||||
20
parsing/Cargo.toml
Normal file
20
parsing/Cargo.toml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
[package]
|
||||||
|
name = "parsing"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
build = "build.rs"
|
||||||
|
license = "AGPL-3.0"
|
||||||
|
repository = "https://github.com/Titaniumtown/YTBN-Graphing-Software/tree/main/parsing"
|
||||||
|
description = "Parsing library for YTBN-Graphing-Software"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
phf = "0.10.1"
|
||||||
|
exmex = { git = "https://github.com/bertiqwerty/exmex.git", branch = "main", features = [
|
||||||
|
"partial",
|
||||||
|
] }
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
phf_codegen = "0.10.0"
|
||||||
55
parsing/build.rs
Normal file
55
parsing/build.rs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
use std::env;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufWriter, Write};
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
const SUPPORTED_FUNCTIONS: [&str; 22] = [
|
||||||
|
"abs", "signum", "sin", "cos", "tan", "asin", "acos", "atan", "sinh", "cosh", "tanh", "floor",
|
||||||
|
"round", "ceil", "trunc", "fract", "exp", "sqrt", "cbrt", "ln", "log2", "log10",
|
||||||
|
];
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("cargo:rerun-if-changed=.git/logs/HEAD");
|
||||||
|
println!("cargo:rerun-if-changed=src/*");
|
||||||
|
|
||||||
|
generate_hashmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_hashmap() {
|
||||||
|
let path = Path::new(&env::var("OUT_DIR").unwrap()).join("codegen.rs");
|
||||||
|
let mut file = BufWriter::new(File::create(&path).expect("Could not create file"));
|
||||||
|
|
||||||
|
let string_hashmap = compile_hashmap(
|
||||||
|
SUPPORTED_FUNCTIONS
|
||||||
|
.to_vec()
|
||||||
|
.iter()
|
||||||
|
.map(|a| a.to_string())
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut hashmap = phf_codegen::Map::new();
|
||||||
|
|
||||||
|
for (key, value) in string_hashmap.iter() {
|
||||||
|
hashmap.entry(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(
|
||||||
|
&mut file,
|
||||||
|
"static COMPLETION_HASHMAP: phf::Map<&'static str, Hint> = {};",
|
||||||
|
hashmap.build()
|
||||||
|
)
|
||||||
|
.expect("Could not write to file");
|
||||||
|
|
||||||
|
write!(
|
||||||
|
&mut file,
|
||||||
|
"#[allow(dead_code)] pub const SUPPORTED_FUNCTIONS: [&str; {}] = {:?};",
|
||||||
|
SUPPORTED_FUNCTIONS.len(),
|
||||||
|
SUPPORTED_FUNCTIONS.to_vec()
|
||||||
|
)
|
||||||
|
.expect("Could not write to file");
|
||||||
|
}
|
||||||
|
|
||||||
|
include!(concat!(
|
||||||
|
env!("CARGO_MANIFEST_DIR"),
|
||||||
|
"/src/autocomplete_helper.rs"
|
||||||
|
));
|
||||||
@@ -128,7 +128,7 @@ fn prettyify_function_str(func: &str) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const VALID_VARIABLES: [char; 5] = ['x', 'X', 'e', 'E', 'π'];
|
pub const VALID_VARIABLES: [char; 5] = ['x', 'X', 'e', 'E', 'π'];
|
||||||
const LETTERS: [char; 52] = [
|
const LETTERS: [char; 52] = [
|
||||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
|
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
|
||||||
't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
|
't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
|
||||||
@@ -136,6 +136,15 @@ const LETTERS: [char; 52] = [
|
|||||||
];
|
];
|
||||||
const NUMBERS: [char; 10] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
const NUMBERS: [char; 10] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_variable(c: &char) -> bool { VALID_VARIABLES.contains(&c) }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_letter(c: &char) -> bool { LETTERS.contains(&c) }
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_number(c: &char) -> bool { NUMBERS.contains(&c) }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
EXTREMELY Janky function that tries to put asterisks in the proper places to be parsed. This is so cursed. But it works, and I hopefully won't ever have to touch it again.
|
EXTREMELY Janky function that tries to put asterisks in the proper places to be parsed. This is so cursed. But it works, and I hopefully won't ever have to touch it again.
|
||||||
One limitation though, variables with multiple characters like `pi` cannot be multiplied (like `pipipipi` won't result in `pi*pi*pi*pi`). But that's such a niche use case (and that same thing could be done by using exponents) that it doesn't really matter.
|
One limitation though, variables with multiple characters like `pi` cannot be multiplied (like `pipipipi` won't result in `pi*pi*pi*pi`). But that's such a niche use case (and that same thing could be done by using exponents) that it doesn't really matter.
|
||||||
@@ -169,11 +178,11 @@ pub fn process_func_str(function_in: &str) -> String {
|
|||||||
' '
|
' '
|
||||||
};
|
};
|
||||||
|
|
||||||
let c_is_number = NUMBERS.contains(c);
|
let c_is_number = is_number(c);
|
||||||
let c_is_letter = LETTERS.contains(c);
|
let c_is_letter = is_letter(c);
|
||||||
let c_is_variable = VALID_VARIABLES.contains(c);
|
let c_is_variable = is_variable(c);
|
||||||
let prev_char_is_variable = VALID_VARIABLES.contains(&prev_char);
|
let prev_char_is_variable = is_variable(&prev_char);
|
||||||
let prev_char_is_number = NUMBERS.contains(&prev_char);
|
let prev_char_is_number = is_number(&prev_char);
|
||||||
|
|
||||||
// makes special case for log with base of a 1-2 digit number
|
// makes special case for log with base of a 1-2 digit number
|
||||||
if ((prev_prev_prev_char == 'l')
|
if ((prev_prev_prev_char == 'l')
|
||||||
@@ -187,7 +196,7 @@ pub fn process_func_str(function_in: &str) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let c_letters_var = c_is_letter | c_is_variable;
|
let c_letters_var = c_is_letter | c_is_variable;
|
||||||
let prev_letters_var = prev_char_is_variable | LETTERS.contains(&prev_char);
|
let prev_letters_var = prev_char_is_variable | is_letter(&prev_char);
|
||||||
|
|
||||||
if prev_char == ')' {
|
if prev_char == ')' {
|
||||||
// cases like `)x`, `)2`, and `)(`
|
// cases like `)x`, `)2`, and `)(`
|
||||||
@@ -196,7 +205,7 @@ pub fn process_func_str(function_in: &str) -> String {
|
|||||||
}
|
}
|
||||||
} else if *c == '(' {
|
} else if *c == '(' {
|
||||||
// cases like `x(` and `2(`
|
// cases like `x(` and `2(`
|
||||||
if (prev_char_is_variable | prev_char_is_number) && !LETTERS.contains(&prev_prev_char) {
|
if (prev_char_is_variable | prev_char_is_number) && !is_letter(&prev_prev_char) {
|
||||||
add_asterisk = true;
|
add_asterisk = true;
|
||||||
}
|
}
|
||||||
} else if prev_char_is_number {
|
} else if prev_char_is_number {
|
||||||
@@ -235,7 +244,7 @@ pub fn process_func_str(function_in: &str) -> String {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::function_handling::suggestions::SUPPORTED_FUNCTIONS;
|
use crate::suggestions::SUPPORTED_FUNCTIONS;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
/// returns if function with string `func_str` is valid after processing through [`process_func_str`]
|
/// returns if function with string `func_str` is valid after processing through [`process_func_str`]
|
||||||
@@ -1,8 +1,17 @@
|
|||||||
use crate::misc::chars_take;
|
use crate::parsing::is_number;
|
||||||
|
|
||||||
pub const HINT_EMPTY: Hint = Hint::Single("x^2");
|
pub const HINT_EMPTY: Hint = Hint::Single("x^2");
|
||||||
const HINT_CLOSED_PARENS: Hint = Hint::Single(")");
|
const HINT_CLOSED_PARENS: Hint = Hint::Single(")");
|
||||||
|
|
||||||
|
/// Only enacts println if cfg(test) is enabled
|
||||||
|
macro_rules! test_print {
|
||||||
|
($($arg:tt)*) => {
|
||||||
|
#[cfg(test)]
|
||||||
|
println!($($arg)*)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Generate a hint based on the input `input`, returns an `Option<String>`
|
/// Generate a hint based on the input `input`, returns an `Option<String>`
|
||||||
pub fn generate_hint<'a>(input: &str) -> &'a Hint<'a> {
|
pub fn generate_hint<'a>(input: &str) -> &'a Hint<'a> {
|
||||||
if input.is_empty() {
|
if input.is_empty() {
|
||||||
@@ -23,20 +32,38 @@ pub fn generate_hint<'a>(input: &str) -> &'a Hint<'a> {
|
|||||||
return &HINT_CLOSED_PARENS;
|
return &HINT_CLOSED_PARENS;
|
||||||
}
|
}
|
||||||
|
|
||||||
let len = chars.len();
|
// let len = chars.len();
|
||||||
|
|
||||||
for key in (1..=MAX_COMPLETION_LEN)
|
|
||||||
.rev()
|
let mut split: Vec<String> = Vec::new();
|
||||||
.filter(|i| len >= *i)
|
|
||||||
.map(|i| chars_take(&chars, i))
|
let mut buffer: Vec<char> = Vec::new();
|
||||||
.filter(|cut_string| !cut_string.is_empty())
|
for c in chars {
|
||||||
{
|
buffer.push(c);
|
||||||
if let Some(output) = COMPLETION_HASHMAP.get(&key) {
|
if c == ')' {
|
||||||
return output;
|
split.push(buffer.iter().collect::<String>());
|
||||||
|
buffer.clear();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let buffer_string = buffer.iter().collect::<String>();
|
||||||
|
|
||||||
|
if ((&buffer_string == "log") | (&buffer_string == "log1")) && is_number(&c) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&Hint::None
|
if !buffer.is_empty() {
|
||||||
|
split.push(buffer.iter().collect::<String>());
|
||||||
|
}
|
||||||
|
|
||||||
|
test_print!("split: {:?}", split);
|
||||||
|
|
||||||
|
if split.is_empty() {
|
||||||
|
return COMPLETION_HASHMAP.get(input).unwrap_or(&Hint::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
COMPLETION_HASHMAP.get(& unsafe {split.last().unwrap_unchecked()}.as_str()).unwrap_or(&Hint::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
@@ -95,6 +122,7 @@ mod tests {
|
|||||||
("sin(", Hint::Single(")")),
|
("sin(", Hint::Single(")")),
|
||||||
("sqrt", Hint::Single("(")),
|
("sqrt", Hint::Single("(")),
|
||||||
("ln(x)", Hint::None),
|
("ln(x)", Hint::None),
|
||||||
|
("ln(x)cos", Hint::Many(&["(", "h("])),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
for (key, value) in values {
|
for (key, value) in values {
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
#![allow(clippy::too_many_arguments)] // Clippy, shut
|
#![allow(clippy::too_many_arguments)] // Clippy, shut
|
||||||
|
|
||||||
use crate::function_handling::parsing::{process_func_str, BackingFunction};
|
|
||||||
use crate::function_handling::suggestions::Hint;
|
|
||||||
use crate::math_app::AppSettings;
|
use crate::math_app::AppSettings;
|
||||||
use crate::misc::*;
|
use crate::misc::*;
|
||||||
use crate::widgets::{widgets_ontop, AutoComplete, Movement};
|
use crate::widgets::{widgets_ontop, AutoComplete, Movement};
|
||||||
@@ -12,6 +10,10 @@ use egui::{
|
|||||||
};
|
};
|
||||||
use emath::vec2;
|
use emath::vec2;
|
||||||
use epaint::Color32;
|
use epaint::Color32;
|
||||||
|
use parsing::{
|
||||||
|
parsing::{process_func_str, BackingFunction},
|
||||||
|
suggestions::Hint,
|
||||||
|
};
|
||||||
use std::fmt::{self, Debug};
|
use std::fmt::{self, Debug};
|
||||||
use std::ops::BitXorAssign;
|
use std::ops::BitXorAssign;
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,8 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate static_assertions;
|
extern crate static_assertions;
|
||||||
|
|
||||||
mod autocomplete_helper;
|
|
||||||
mod consts;
|
mod consts;
|
||||||
mod function_entry;
|
mod function_entry;
|
||||||
mod function_handling;
|
|
||||||
mod math_app;
|
mod math_app;
|
||||||
mod misc;
|
mod misc;
|
||||||
mod widgets;
|
mod widgets;
|
||||||
|
|||||||
@@ -4,10 +4,8 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate static_assertions;
|
extern crate static_assertions;
|
||||||
|
|
||||||
mod autocomplete_helper;
|
|
||||||
mod consts;
|
mod consts;
|
||||||
mod function_entry;
|
mod function_entry;
|
||||||
mod function_handling;
|
|
||||||
mod math_app;
|
mod math_app;
|
||||||
mod misc;
|
mod misc;
|
||||||
mod widgets;
|
mod widgets;
|
||||||
|
|||||||
42
src/misc.rs
42
src/misc.rs
@@ -333,31 +333,6 @@ pub fn step_helper(max_i: usize, min_x: &f64, step: &f64) -> Vec<f64> {
|
|||||||
(0..max_i).map(|x| (x as f64 * step) + min_x).collect()
|
(0..max_i).map(|x| (x as f64 * step) + min_x).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes `take` number of chars from the end of `chars` and returns a string
|
|
||||||
pub fn chars_take(chars: &[char], take: usize) -> String {
|
|
||||||
let len = chars.len();
|
|
||||||
assert!(len >= take);
|
|
||||||
|
|
||||||
match take {
|
|
||||||
0 => {
|
|
||||||
// return empty string if `take == 0`
|
|
||||||
String::new()
|
|
||||||
}
|
|
||||||
1 => {
|
|
||||||
// return last character as a string if take == 1
|
|
||||||
chars[len - 1].to_string()
|
|
||||||
}
|
|
||||||
_ if take == len => {
|
|
||||||
// return `chars` turned into a string if `take == len`
|
|
||||||
return chars.iter().collect::<String>();
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// actually do the thing
|
|
||||||
return chars.iter().rev().take(take).rev().collect::<String>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -450,21 +425,4 @@ mod tests {
|
|||||||
assert_eq!(option_vec_printer(&key), value);
|
assert_eq!(option_vec_printer(&key), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn chars_take_test() {
|
|
||||||
let values = HashMap::from([
|
|
||||||
(("test", 2), "st"),
|
|
||||||
(("cool text", 4), "text"),
|
|
||||||
(("aaa", 0), ""),
|
|
||||||
(("aaab", 1), "b"),
|
|
||||||
]);
|
|
||||||
|
|
||||||
for ((in_str, i), value) in values {
|
|
||||||
assert_eq!(
|
|
||||||
chars_take(&in_str.chars().collect::<Vec<char>>(), i),
|
|
||||||
value.to_owned()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::function_handling::suggestions::{self, generate_hint, Hint};
|
|
||||||
use egui::{text::CCursor, text_edit::CursorRange, TextEdit};
|
use egui::{text::CCursor, text_edit::CursorRange, TextEdit};
|
||||||
use epaint::text::cursor::{Cursor, PCursor, RCursor};
|
use epaint::text::cursor::{Cursor, PCursor, RCursor};
|
||||||
|
use parsing::suggestions::{self, generate_hint, Hint};
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub enum Movement {
|
pub enum Movement {
|
||||||
|
|||||||
Reference in New Issue
Block a user