refactoring

This commit is contained in:
Simon Gardling 2022-04-21 23:25:33 -04:00
parent 06b062b5b4
commit 5d153f4842
14 changed files with 166 additions and 271 deletions

20
Cargo.lock generated
View File

@ -485,7 +485,7 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
[[package]]
name = "eframe"
version = "0.17.0"
source = "git+https://github.com/Titaniumtown/egui.git#b2fd225aa1e3177e8ec0b5c348f7240b0b7b0be0"
source = "git+https://github.com/Titaniumtown/egui.git#01e11a8e5b87aa1d7c35c637315b850b941b5e59"
dependencies = [
"egui",
"egui-winit",
@ -497,7 +497,7 @@ dependencies = [
[[package]]
name = "egui"
version = "0.17.0"
source = "git+https://github.com/Titaniumtown/egui.git#b2fd225aa1e3177e8ec0b5c348f7240b0b7b0be0"
source = "git+https://github.com/Titaniumtown/egui.git#01e11a8e5b87aa1d7c35c637315b850b941b5e59"
dependencies = [
"ahash",
"epaint",
@ -508,7 +508,7 @@ dependencies = [
[[package]]
name = "egui-winit"
version = "0.17.0"
source = "git+https://github.com/Titaniumtown/egui.git#b2fd225aa1e3177e8ec0b5c348f7240b0b7b0be0"
source = "git+https://github.com/Titaniumtown/egui.git#01e11a8e5b87aa1d7c35c637315b850b941b5e59"
dependencies = [
"arboard",
"egui",
@ -523,7 +523,7 @@ dependencies = [
[[package]]
name = "egui_glow"
version = "0.17.0"
source = "git+https://github.com/Titaniumtown/egui.git#b2fd225aa1e3177e8ec0b5c348f7240b0b7b0be0"
source = "git+https://github.com/Titaniumtown/egui.git#01e11a8e5b87aa1d7c35c637315b850b941b5e59"
dependencies = [
"bytemuck",
"egui",
@ -540,7 +540,7 @@ dependencies = [
[[package]]
name = "egui_web"
version = "0.17.0"
source = "git+https://github.com/Titaniumtown/egui.git#b2fd225aa1e3177e8ec0b5c348f7240b0b7b0be0"
source = "git+https://github.com/Titaniumtown/egui.git#01e11a8e5b87aa1d7c35c637315b850b941b5e59"
dependencies = [
"bytemuck",
"egui",
@ -563,7 +563,7 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "emath"
version = "0.17.0"
source = "git+https://github.com/Titaniumtown/egui.git#b2fd225aa1e3177e8ec0b5c348f7240b0b7b0be0"
source = "git+https://github.com/Titaniumtown/egui.git#01e11a8e5b87aa1d7c35c637315b850b941b5e59"
dependencies = [
"bytemuck",
]
@ -571,7 +571,7 @@ dependencies = [
[[package]]
name = "epaint"
version = "0.17.0"
source = "git+https://github.com/Titaniumtown/egui.git#b2fd225aa1e3177e8ec0b5c348f7240b0b7b0be0"
source = "git+https://github.com/Titaniumtown/egui.git#01e11a8e5b87aa1d7c35c637315b850b941b5e59"
dependencies = [
"ab_glyph",
"ahash",
@ -585,7 +585,7 @@ dependencies = [
[[package]]
name = "epi"
version = "0.17.0"
source = "git+https://github.com/Titaniumtown/egui.git#b2fd225aa1e3177e8ec0b5c348f7240b0b7b0be0"
source = "git+https://github.com/Titaniumtown/egui.git#01e11a8e5b87aa1d7c35c637315b850b941b5e59"
dependencies = [
"egui",
"glow",
@ -1820,9 +1820,9 @@ dependencies = [
[[package]]
name = "tracing-log"
version = "0.1.2"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3"
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
dependencies = [
"lazy_static",
"log",

View File

@ -23,8 +23,9 @@ strip = true
[profile.dev]
debug = true
opt-level = 2
lto = false
opt-level = 0
lto = true
strip = false
[dependencies]
eframe = { git = "https://github.com/Titaniumtown/egui.git", default-features = false }

View File

@ -18,8 +18,9 @@ if test "$1" == "" || test "$1" == "release"; then
wasm_opt #apply wasm optimizations
echo "Binary size (pre-strip): $(du -sb pkg/ytbn_graphing_software_bg.wasm)"
llvm-strip --strip-all pkg/ytbn_graphing_software_bg.wasm
elif test "$1" == "debug"; then
RUSTFLAGS=--cfg=web_sys_unstable_apis wasm-pack build --target web --debug --no-typescript
RUSTFLAGS=--cfg=web_sys_unstable_apis wasm-pack build --target web --dev --no-typescript
else
echo "ERROR: build.sh, argument invalid"
exit 1
@ -27,12 +28,13 @@ fi
mkdir tmp
cp -r pkg/ytbn_graphing_software_bg.wasm tmp/
sed -i 's/fatal: true/fatal: false/g' pkg/ytbn_graphing_software.js
sed -i "s/TextEncoder('utf-8')/TextEncoder('utf-8', { ignoreBOM: true, fatal: false })/g" pkg/ytbn_graphing_software.js
minify pkg/ytbn_graphing_software.js > tmp/ytbn_graphing_software.js
sed -i 's/fatal: true/fatal: false/g' tmp/ytbn_graphing_software.js
sed -i "s/TextEncoder('utf-8')/TextEncoder('utf-8', { ignoreBOM: true, fatal: false })/g" tmp/ytbn_graphing_software.js
cp www/* tmp/
minify www/index.html > tmp/index.html
minify www/sw.js > tmp/sw.js

View File

@ -1,7 +1,7 @@
#!/bin/bash
set -e #kill script if error occurs
cargo test
cargo test-all-features
bash build.sh

View File

@ -1,4 +1,4 @@
use crate::function::Riemann;
use crate::function_entry::Riemann;
use std::ops::RangeInclusive;
use const_format::formatc;

View File

@ -1,9 +1,9 @@
#![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::misc::*;
use crate::parsing::{process_func_str, BackingFunction};
use crate::suggestions::Hint;
use crate::widgets::{widgets_ontop, AutoComplete, Movement};
use eframe::{egui, emath, epaint};
use egui::{

View File

@ -0,0 +1,2 @@
pub mod parsing;
pub mod suggestions;

View File

@ -235,7 +235,7 @@ pub fn process_func_str(function_in: &str) -> String {
#[cfg(test)]
mod tests {
use super::*;
use crate::suggestions::SUPPORTED_FUNCTIONS;
use crate::function_handling::suggestions::SUPPORTED_FUNCTIONS;
use std::collections::HashMap;
/// returns if function with string `func_str` is valid after processing through [`process_func_str`]

View File

@ -6,11 +6,10 @@ extern crate static_assertions;
mod autocomplete_helper;
mod consts;
mod function;
mod function_entry;
mod function_handling;
mod math_app;
mod misc;
mod parsing;
mod suggestions;
mod widgets;
cfg_if::cfg_if! {

View File

@ -6,11 +6,10 @@ extern crate static_assertions;
mod autocomplete_helper;
mod consts;
mod function;
mod function_entry;
mod function_handling;
mod math_app;
mod misc;
mod parsing;
mod suggestions;
mod widgets;
// For running the program natively! (Because why not?)

View File

@ -1,5 +1,5 @@
use crate::consts::*;
use crate::function::{FunctionEntry, Riemann, DEFAULT_FUNCTION_ENTRY};
use crate::function_entry::{FunctionEntry, Riemann, DEFAULT_FUNCTION_ENTRY};
use crate::misc::{dyn_mut_iter, option_vec_printer, JsonFileOutput, SerdeValueHelper};
use eframe::{egui, emath, epi};
use egui::{
@ -14,221 +14,6 @@ use std::{io::Read, ops::BitXorAssign, str};
#[cfg(threading)]
use rayon::iter::{IndexedParallelIterator, ParallelIterator};
// Stores data loaded from files
struct Assets {
// Stores `FontDefinitions`
pub fonts: FontDefinitions,
// Help blurbs
pub text_help_expr: String,
pub text_help_vars: String,
pub text_help_panel: String,
pub text_help_function: String,
pub text_help_other: String,
pub text_welcome: String,
// Explanation of license
pub text_license_info: String,
}
impl Assets {
pub fn new(fonts: FontDefinitions, json: JsonFileOutput) -> Self {
Self {
fonts,
text_help_expr: json.help_expr,
text_help_vars: json.help_vars,
text_help_panel: json.help_panel,
text_help_function: json.help_function,
text_help_other: json.help_other,
text_license_info: json.license_info,
text_welcome: json.welcome_text,
}
}
#[cfg(test)] // Only used for testing
pub fn get_json_file_output(&self) -> JsonFileOutput {
JsonFileOutput {
help_expr: self.text_help_expr.clone(),
help_vars: self.text_help_vars.clone(),
help_panel: self.text_help_panel.clone(),
help_function: self.text_help_function.clone(),
help_other: self.text_help_other.clone(),
license_info: self.text_license_info.clone(),
welcome_text: self.text_welcome.clone(),
}
}
}
lazy_static::lazy_static! {
/// Load all of the data from the compressed tarball
static ref ASSETS: Assets = {
let start = instant::Instant::now();
tracing::info!("Loading assets...");
let mut tar_file_data = Vec::new();
let _ = ruzstd::StreamingDecoder::new(&mut include_bytes!("../assets.tar.zst").as_slice()).expect("failed to decompress assets").read_to_end(&mut tar_file_data).expect("failed to read assets");
let mut tar_archive = tar::Archive::new(&*tar_file_data);
// Stores fonts
let mut font_ubuntu_light: Option<FontData> = None;
let mut font_notoemoji: Option<FontData> = None;
let mut font_hack: Option<FontData> = None;
let mut font_emoji_icon: Option<FontData> = None;
// Stores text
let mut text_data: Option<JsonFileOutput> = None;
tracing::info!("Reading assets...");
// Iterate through all entries in the tarball
for file in tar_archive.entries().unwrap() {
let mut file = file.unwrap();
let mut data: Vec<u8> = Vec::new();
file.read_to_end(&mut data).unwrap();
let path = file.header().path().unwrap();
let path_string = path.to_string_lossy();
tracing::debug!("Loading file: {}", path_string);
// Match the file extention
if path_string.ends_with(".ttf") {
// Parse font files
let font_data = FontData::from_owned(data);
match path_string.as_ref() {
"Hack-Regular.ttf" => {
font_hack = Some(font_data);
},
"NotoEmoji-Regular.ttf" => {
font_notoemoji = Some(font_data);
},
"Ubuntu-Light.ttf" => {
font_ubuntu_light = Some(font_data);
},
"emoji-icon-font.ttf" => {
font_emoji_icon = Some(font_data.tweak(
egui::FontTweak {
scale: 0.8, // make it smaller
y_offset_factor: 0.07, // move it down slightly
y_offset: 0.0,
},
))
}
_ => {
panic!("Font File {} not expected!", path_string);
}
}
} else if path_string == "text.json" {
text_data = Some(SerdeValueHelper::new(str::from_utf8(&data).expect("unable to read text.json")).parse_values());
} else {
panic!("File {} not expected!", path_string);
}
}
tracing::info!("Done loading assets! Took: {:?}", start.elapsed());
let font_data: BTreeMap<String, FontData> = BTreeMap::from([
("Hack".to_owned(), font_hack.expect("Hack -Regular.ttf not found!")),
("Ubuntu-Light".to_owned(), font_ubuntu_light.expect("Ubuntu-Light.ttf not found!")),
("NotoEmoji-Regular".to_owned(), font_notoemoji.expect("NotoEmoji-Regular.ttf not found!")),
("emoji-icon-font".to_owned(), font_emoji_icon.expect("emoji-icon-font.ttf not found!"))
]);
let families = BTreeMap::from([
(FontFamily::Monospace,
vec![
"Hack".to_owned(),
"Ubuntu-Light".to_owned(),
"NotoEmoji-Regular".to_owned(),
"emoji-icon-font".to_owned(),
]),
(FontFamily::Proportional,
vec!["Ubuntu-Light".to_owned(), "NotoEmoji-Regular".to_owned(),
"emoji-icon-font".to_owned()])
]);
let fonts = FontDefinitions {
font_data,
families,
};
// Create and return Assets struct
Assets::new(
fonts, text_data.expect("text.json not found!"))
};
}
/// Tests to make sure archived (and compressed) assets match expected data
#[test]
fn test_file_data() {
let font_data: BTreeMap<String, FontData> = BTreeMap::from([
(
"Hack".to_owned(),
FontData::from_owned(include_bytes!("../assets/Hack-Regular.ttf").to_vec()),
),
(
"Ubuntu-Light".to_owned(),
FontData::from_owned(include_bytes!("../assets/Ubuntu-Light.ttf").to_vec()),
),
(
"NotoEmoji-Regular".to_owned(),
FontData::from_owned(include_bytes!("../assets/NotoEmoji-Regular.ttf").to_vec()),
),
(
"emoji-icon-font".to_owned(),
FontData::from_owned(include_bytes!("../assets/emoji-icon-font.ttf").to_vec()).tweak(
egui::FontTweak {
scale: 0.8,
y_offset_factor: 0.07,
y_offset: 0.0,
},
),
),
]);
let families = BTreeMap::from([
(
FontFamily::Monospace,
vec![
"Hack".to_owned(),
"Ubuntu-Light".to_owned(),
"NotoEmoji-Regular".to_owned(),
"emoji-icon-font".to_owned(),
],
),
(
FontFamily::Proportional,
vec![
"Ubuntu-Light".to_owned(),
"NotoEmoji-Regular".to_owned(),
"emoji-icon-font".to_owned(),
],
),
]);
let fonts = FontDefinitions {
font_data,
families,
};
assert_eq!(ASSETS.fonts, fonts);
let json_data: SerdeValueHelper = SerdeValueHelper::new(include_str!("../assets/text.json"));
let asset_json = ASSETS.get_json_file_output();
let json_data_parsed = json_data.parse_values();
assert_eq!(asset_json, json_data_parsed);
// NOTE: UPDATE THIS STRING IF `license_info` IN `text.json` IS MODIFIED
let target_license_info = "The AGPL license ensures that the end user, even if not hosting the program itself, is still guaranteed access to the source code of the project in question.";
assert_eq!(target_license_info, asset_json.license_info);
assert_eq!(target_license_info, json_data_parsed.license_info);
}
cfg_if::cfg_if! {
if #[cfg(target_arch = "wasm32")] {
use wasm_bindgen::JsCast;
@ -325,22 +110,12 @@ pub struct MathApp {
/// Stores opened windows/elements for later reference
opened: Opened,
text: JsonFileOutput,
/// Stores settings (pretty self-explanatory)
settings: AppSettings,
}
impl Default for MathApp {
fn default() -> Self {
Self {
functions: vec![DEFAULT_FUNCTION_ENTRY.clone()],
last_info: (vec![None], Duration::ZERO),
dark_mode: true,
opened: Opened::default(),
settings: AppSettings::default(),
}
}
}
impl MathApp {
#[allow(dead_code)] // This is used lol
/// Create new instance of [`MathApp`] and return it
@ -361,8 +136,128 @@ impl MathApp {
tracing::info!("Web Info: {:?}", web_info);
}
let start = instant::Instant::now();
tracing::info!("Loading assets...");
let mut tar_file_data = Vec::new();
let _ = ruzstd::StreamingDecoder::new(&mut include_bytes!("../assets.tar.zst").as_slice())
.expect("failed to decompress assets")
.read_to_end(&mut tar_file_data)
.expect("failed to read assets");
let mut tar_archive = tar::Archive::new(&*tar_file_data);
// Stores fonts
let mut font_ubuntu_light: Option<FontData> = None;
let mut font_notoemoji: Option<FontData> = None;
let mut font_hack: Option<FontData> = None;
let mut font_emoji_icon: Option<FontData> = None;
// Stores text
let mut text_data: Option<JsonFileOutput> = None;
tracing::info!("Reading assets...");
// Iterate through all entries in the tarball
for file in tar_archive.entries().unwrap() {
let mut file = file.unwrap();
let mut data: Vec<u8> = Vec::new();
file.read_to_end(&mut data).unwrap();
let path = file.header().path().unwrap();
let path_string = path.to_string_lossy();
tracing::debug!("Loading file: {}", path_string);
// Match the file extention
if path_string.ends_with(".ttf") {
// Parse font files
let font_data = FontData::from_owned(data);
match path_string.as_ref() {
"Hack-Regular.ttf" => {
font_hack = Some(font_data);
}
"NotoEmoji-Regular.ttf" => {
font_notoemoji = Some(font_data);
}
"Ubuntu-Light.ttf" => {
font_ubuntu_light = Some(font_data);
}
"emoji-icon-font.ttf" => {
font_emoji_icon = Some(font_data.tweak(egui::FontTweak {
scale: 0.8, // make it smaller
y_offset_factor: 0.07, // move it down slightly
y_offset: 0.0,
}))
}
_ => {
panic!("Font File {} not expected!", path_string);
}
}
} else if path_string == "text.json" {
text_data = Some(
SerdeValueHelper::new(str::from_utf8(&data).expect("unable to read text.json"))
.parse_values(),
);
} else {
panic!("File {} not expected!", path_string);
}
}
let fonts = FontDefinitions {
font_data: BTreeMap::from([
(
"Hack".to_owned(),
font_hack.expect("Hack -Regular.ttf not found!"),
),
(
"Ubuntu-Light".to_owned(),
font_ubuntu_light.expect("Ubuntu-Light.ttf not found!"),
),
(
"NotoEmoji-Regular".to_owned(),
font_notoemoji.expect("NotoEmoji-Regular.ttf not found!"),
),
(
"emoji-icon-font".to_owned(),
font_emoji_icon.expect("emoji-icon-font.ttf not found!"),
),
]),
families: BTreeMap::from([
(
FontFamily::Monospace,
vec![
"Hack".to_owned(),
"Ubuntu-Light".to_owned(),
"NotoEmoji-Regular".to_owned(),
"emoji-icon-font".to_owned(),
],
),
(
FontFamily::Proportional,
vec![
"Ubuntu-Light".to_owned(),
"NotoEmoji-Regular".to_owned(),
"emoji-icon-font".to_owned(),
],
),
]),
};
tracing::info!("Done loading assets! Took: {:?}", start.elapsed());
// Initialize fonts
// this used to be in the `update` method, but (after a ton of digging) this actually caused OOMs. that was a pain to debug
cc.egui_ctx.set_fonts(fonts);
tracing::info!("egui app initialized.");
Self::default() // initialize `MathApp`
Self {
functions: vec![DEFAULT_FUNCTION_ENTRY.clone()],
last_info: (vec![None], Duration::ZERO),
dark_mode: true,
text: text_data.expect("text.json failed to load"),
opened: Opened::default(),
settings: AppSettings::default(),
}
}
/// Creates SidePanel which contains configuration options
@ -477,7 +372,7 @@ impl MathApp {
ui.label(
RichText::new("(and licensed under AGPLv3)").color(Color32::LIGHT_GRAY),
)
.on_hover_text(&ASSETS.text_license_info);
.on_hover_text(&self.text.license_info);
// Hyperlink to project's github
ui.hyperlink_to(
@ -509,9 +404,6 @@ impl epi::App for MathApp {
.bitxor_assign(ctx.input_mut().consume_key(egui::Modifiers::NONE, Key::H));
}
// Initialize fonts
ctx.set_fonts(ASSETS.fonts.clone());
// Creates Top bar that contains some general options
TopBottomPanel::top("top_bar").show(ctx, |ui| {
ui.horizontal(|ui| {
@ -589,23 +481,23 @@ impl epi::App for MathApp {
ui.heading("Help With...");
ui.collapsing("Supported Expressions", |ui| {
ui.label(&ASSETS.text_help_expr);
ui.label(&self.text.help_expr);
});
ui.collapsing("Supported Constants", |ui| {
ui.label(&ASSETS.text_help_vars);
ui.label(&self.text.help_vars);
});
ui.collapsing("Panel", |ui| {
ui.label(&ASSETS.text_help_panel);
ui.label(&self.text.help_panel);
});
ui.collapsing("Functions", |ui| {
ui.label(&ASSETS.text_help_function);
ui.label(&self.text.help_function);
});
ui.collapsing("Other", |ui| {
ui.label(&ASSETS.text_help_other);
ui.label(&self.text.help_other);
});
});
@ -616,7 +508,7 @@ impl epi::App for MathApp {
.resizable(false)
.collapsible(false)
.show(ctx, |ui| {
ui.label(&*ASSETS.text_welcome);
ui.label(&self.text.welcome);
});
// Window with information about the build and current commit

View File

@ -189,7 +189,7 @@ pub struct JsonFileOutput {
pub help_function: String,
pub help_other: String,
pub license_info: String,
pub welcome_text: String,
pub welcome: String,
}
/// Helps parsing text data from `text.json`
@ -228,7 +228,7 @@ impl SerdeValueHelper {
help_function: self.parse_multiline("help_function"),
help_other: self.parse_multiline("help_other"),
license_info: self.parse_singleline("license_info"),
welcome_text: self.parse_multiline("welcome"),
welcome: self.parse_multiline("welcome"),
}
}
}

View File

@ -1,4 +1,4 @@
use crate::suggestions::{generate_hint, Hint};
use crate::function_handling::suggestions::{self, generate_hint, Hint};
use eframe::{egui, epaint};
use egui::{text::CCursor, text_edit::CursorRange, TextEdit};
@ -27,7 +27,7 @@ impl<'a> Default for AutoComplete<'a> {
fn default() -> AutoComplete<'a> {
AutoComplete {
i: 0,
hint: &crate::suggestions::HINT_EMPTY,
hint: &suggestions::HINT_EMPTY,
string: String::new(),
}
}