From 98569f3490c4e179d8fd80259e6039f6875e5afd Mon Sep 17 00:00:00 2001 From: electria Date: Fri, 9 Oct 2026 16:07:05 -0700 Subject: [PATCH 1/6] feat: ignore underscores in input this isn't useful for typst usually, since underscores are subscript and don't appear in expressions much. however, when using tylc as a standalone calculator, this is useful eg to seperate sets of three digits. idea totally stolen from rust literals --- src/formatting.rs | 24 +++++++++++++----------- src/main.rs | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/formatting.rs b/src/formatting.rs index eb097c0..dad87e5 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -2,7 +2,9 @@ use rug::Float; use crate::nodes::{self, Error}; -pub fn pretty_eval(mut input: String, max_digits: usize) -> Result { +pub fn pretty_eval(input: &str, max_digits: usize) -> Result { + let mut input = input.replace('_', ""); + // no need to remove the characters here, // as we ignore the them in all other logic already let should_add_back_alignment = input.contains('&'); @@ -49,20 +51,20 @@ pub fn pretty_eval(mut input: String, max_digits: usize) -> Result usize { diff --git a/src/main.rs b/src/main.rs index c3349d2..c9634da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,7 @@ fn main() -> ExitCode { buf }); - match lib::formatting::pretty_eval(input, 10) { + match lib::formatting::pretty_eval(&input, 10) { Ok(s) => println!("{s}"), Err(e) => { From 046a3e5b206cb113887a28918c02aad1709e3aa7 Mon Sep 17 00:00:00 2001 From: electria Date: Fri, 9 Oct 2026 16:07:05 -0700 Subject: [PATCH 2/6] feat: ignore underscores in input this isn't useful for typst usually, since underscores are subscript and don't appear in expressions much. however, when using tylc as a standalone calculator, this is useful eg to seperate sets of three digits. idea totally stolen from rust literals note that this might cause problems when it comes to special variables, eg A_n for Avogadro's number (but just A is fine) --- src/formatting.rs | 24 +++++++++++++----------- src/main.rs | 2 +- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/formatting.rs b/src/formatting.rs index eb097c0..dad87e5 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -2,7 +2,9 @@ use rug::Float; use crate::nodes::{self, Error}; -pub fn pretty_eval(mut input: String, max_digits: usize) -> Result { +pub fn pretty_eval(input: &str, max_digits: usize) -> Result { + let mut input = input.replace('_', ""); + // no need to remove the characters here, // as we ignore the them in all other logic already let should_add_back_alignment = input.contains('&'); @@ -49,20 +51,20 @@ pub fn pretty_eval(mut input: String, max_digits: usize) -> Result usize { diff --git a/src/main.rs b/src/main.rs index c3349d2..c9634da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,7 @@ fn main() -> ExitCode { buf }); - match lib::formatting::pretty_eval(input, 10) { + match lib::formatting::pretty_eval(&input, 10) { Ok(s) => println!("{s}"), Err(e) => { From da825323614c2703d751cbf5e431b288f909c100 Mon Sep 17 00:00:00 2001 From: electria Date: Fri, 9 Oct 2026 16:20:04 -0700 Subject: [PATCH 3/6] refactor(formatting): move tests into module --- src/formatting.rs | 73 +++++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/src/formatting.rs b/src/formatting.rs index dad87e5..dcb740f 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -49,23 +49,6 @@ pub fn pretty_eval(input: &str, max_digits: usize) -> Result { ) .replace('e', " * 10^")) } -#[test] -fn test_character_readdition() { - assert_eq!(pretty_eval(" = 11", 10).unwrap(), " = 11"); - assert_eq!(pretty_eval(" &= 11", 10).unwrap(), " & = 11"); - assert_eq!(pretty_eval(" & 11", 10).unwrap(), " & 11"); - assert_eq!(pretty_eval(" & 11 \\", 10).unwrap(), " & 11 \\"); -} -#[test] -fn test_basic_up_to_999() { - assert_eq!(pretty_eval("1", 10).unwrap(), "1"); - assert_eq!(pretty_eval("10", 10).unwrap(), "10"); - assert_eq!(pretty_eval("100", 10).unwrap(), "100"); - assert_eq!(pretty_eval("999", 10).unwrap(), "999"); - assert_eq!(pretty_eval("1000", 10).unwrap(), "1 * 10^3"); - - assert_eq!(pretty_eval("11.111111", 10).unwrap(), "11.111111"); -} pub fn get_significant_digits(n: &Float) -> usize { let raw_string = n.to_string().replace('.', ""); @@ -101,23 +84,45 @@ pub fn get_significant_digits(n: &Float) -> usize { } #[cfg(test)] -fn eval(s: &str) -> Float { - crate::nodes::eval(s).unwrap() -} +mod tests { + use super::*; + fn eval(s: &str) -> Float { + crate::nodes::eval(s).unwrap() + } -#[test] -fn test_get_significant_digits() { - let many_zeros = eval("14.00643 + 1.00784 * 4 + 35.446 + 15.9994 * 4"); - assert_eq!(many_zeros.to_f64(), 117.48139); - let many_nines = eval("12.0096 + 15.9994 * 2"); - assert_eq!(many_nines.to_f64(), 44.0084); - let zero_nine_zero = eval("2+12321(5+123)"); - assert_eq!(zero_nine_zero.to_f64(), 1577090.0); - let test_4 = eval("12.0096 + 1.00784 * 3 + 12.0096 + 1.00784 * 2 + 15.9994 + 1.00784"); - assert_eq!(test_4.to_f64(), 46.06564); + #[test] + fn character_readdition() { + assert_eq!(pretty_eval(" = 11", 10).unwrap(), " = 11"); + assert_eq!(pretty_eval(" &= 11", 10).unwrap(), " & = 11"); + assert_eq!(pretty_eval(" & 11", 10).unwrap(), " & 11"); + assert_eq!(pretty_eval(" & 11 \\", 10).unwrap(), " & 11 \\"); + } - assert_eq!(get_significant_digits(&many_zeros), 8); - assert_eq!(get_significant_digits(&many_nines), 6); - assert_eq!(get_significant_digits(&zero_nine_zero), 6); - assert_eq!(get_significant_digits(&test_4), 7); + #[test] + fn basic_output_up_to_999() { + assert_eq!(pretty_eval("1", 10).unwrap(), "1"); + assert_eq!(pretty_eval("10", 10).unwrap(), "10"); + assert_eq!(pretty_eval("100", 10).unwrap(), "100"); + assert_eq!(pretty_eval("999", 10).unwrap(), "999"); + assert_eq!(pretty_eval("1000", 10).unwrap(), "1 * 10^3"); + + assert_eq!(pretty_eval("11.111111", 10).unwrap(), "11.111111"); + } + + #[test] + fn basic_get_significant_digits() { + let many_zeros = eval("14.00643 + 1.00784 * 4 + 35.446 + 15.9994 * 4"); + assert_eq!(many_zeros.to_f64(), 117.48139); + let many_nines = eval("12.0096 + 15.9994 * 2"); + assert_eq!(many_nines.to_f64(), 44.0084); + let zero_nine_zero = eval("2+12321(5+123)"); + assert_eq!(zero_nine_zero.to_f64(), 1577090.0); + let test_4 = eval("12.0096 + 1.00784 * 3 + 12.0096 + 1.00784 * 2 + 15.9994 + 1.00784"); + assert_eq!(test_4.to_f64(), 46.06564); + + assert_eq!(get_significant_digits(&many_zeros), 8); + assert_eq!(get_significant_digits(&many_nines), 6); + assert_eq!(get_significant_digits(&zero_nine_zero), 6); + assert_eq!(get_significant_digits(&test_4), 7); + } } From acc49edd3178b87db3acd36b39aca5dafd110d93 Mon Sep 17 00:00:00 2001 From: electria Date: Fri, 9 Oct 2026 18:50:19 -0700 Subject: [PATCH 4/6] feat: generalize removing and adding back prefix --- src/formatting.rs | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/src/formatting.rs b/src/formatting.rs index dcb740f..fff48dc 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -3,20 +3,19 @@ use rug::Float; use crate::nodes::{self, Error}; pub fn pretty_eval(input: &str, max_digits: usize) -> Result { - let mut input = input.replace('_', ""); + let (prefix, input) = input + .rsplit_once('=') + .map(|(p, i)| (p.to_owned() + "= ", i)) + .unwrap_or_else(|| { + input + .rsplit_once('&') + .map(|(p, i)| (p.to_owned() + "& ", i)) + .unwrap_or((String::new(), input)) + }); - // no need to remove the characters here, - // as we ignore the them in all other logic already - let should_add_back_alignment = input.contains('&'); + // no need to remove the character here, + // as we ignore it in all other logic already let should_add_back_backslash = input.contains('\\'); - let leading_spaces = input.chars().take_while(|c| *c == ' ').count(); - - let should_add_back_equals = input - .find('=') - .inspect(|i| { - input.remove(*i); - }) - .is_some(); let result = nodes::eval(&input)?; let display_digits = @@ -34,17 +33,7 @@ pub fn pretty_eval(input: &str, max_digits: usize) -> Result { }); Ok(format!( - "{}{}{result:.display_digits$}{}", - " ".repeat(leading_spaces), - if should_add_back_equals && should_add_back_alignment { - "& = " - } else if should_add_back_equals { - "= " - } else if should_add_back_alignment { - "& " - } else { - "" - }, + "{prefix}{result:.display_digits$}{}", if should_add_back_backslash { " \\" } else { "" } ) .replace('e', " * 10^")) @@ -93,7 +82,7 @@ mod tests { #[test] fn character_readdition() { assert_eq!(pretty_eval(" = 11", 10).unwrap(), " = 11"); - assert_eq!(pretty_eval(" &= 11", 10).unwrap(), " & = 11"); + assert_eq!(pretty_eval(" &= 11", 10).unwrap(), " &= 11"); assert_eq!(pretty_eval(" & 11", 10).unwrap(), " & 11"); assert_eq!(pretty_eval(" & 11 \\", 10).unwrap(), " & 11 \\"); } From 5cdfbfea5ece7ec3665bc2639f118d7eb93d09f0 Mon Sep 17 00:00:00 2001 From: electria Date: Fri, 9 Oct 2026 18:53:02 -0700 Subject: [PATCH 5/6] refactor: avoid extra owned string I think this is more readable, too --- src/formatting.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/formatting.rs b/src/formatting.rs index fff48dc..7c207f5 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -3,14 +3,14 @@ use rug::Float; use crate::nodes::{self, Error}; pub fn pretty_eval(input: &str, max_digits: usize) -> Result { - let (prefix, input) = input + let (prefix, deliminator, input) = input .rsplit_once('=') - .map(|(p, i)| (p.to_owned() + "= ", i)) + .map(|(p, i)| (p, "= ", i)) .unwrap_or_else(|| { input .rsplit_once('&') - .map(|(p, i)| (p.to_owned() + "& ", i)) - .unwrap_or((String::new(), input)) + .map(|(p, i)| (p, "& ", i)) + .unwrap_or(("", "", input)) }); // no need to remove the character here, @@ -33,7 +33,7 @@ pub fn pretty_eval(input: &str, max_digits: usize) -> Result { }); Ok(format!( - "{prefix}{result:.display_digits$}{}", + "{prefix}{deliminator}{result:.display_digits$}{}", if should_add_back_backslash { " \\" } else { "" } ) .replace('e', " * 10^")) From 2d6f03c28ca8719992f43fe69d744fd8012ff0ce Mon Sep 17 00:00:00 2001 From: electria Date: Fri, 9 Oct 2026 18:55:17 -0700 Subject: [PATCH 6/6] build: update flake (late commit) --- flake.lock | 17 +++++++---------- flake.nix | 2 +- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/flake.lock b/flake.lock index 8f6b10e..de0f8d5 100644 --- a/flake.lock +++ b/flake.lock @@ -20,18 +20,15 @@ }, "nixpkgs": { "locked": { - "lastModified": 1780749050, - "narHash": "sha256-3av0pIjlOWQ6rDbNOmpUSvbNnJkGORQKKjb4LtCZsIY=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "a799d3e3886da994fa307f817a6bc705ae538eeb", - "type": "github" + "lastModified": 1791260994, + "narHash": "sha256-MFBjw66d4h06MvpW6lIl7RwarLteD0sk859CncGwb1Q=", + "rev": "151fa4e8ddfdd8dd25d945ad94ed54a13de9f6e4", + "type": "tarball", + "url": "https://releases.nixos.org/nixos/unstable/nixos-26.11pre1086391.151fa4e8ddfd/nixexprs.tar.zst?lastModified=1791260994&rev=151fa4e8ddfdd8dd25d945ad94ed54a13de9f6e4" }, "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" + "type": "tarball", + "url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.zst" } }, "root": { diff --git a/flake.nix b/flake.nix index f7862ee..26109ec 100644 --- a/flake.nix +++ b/flake.nix @@ -1,6 +1,6 @@ { inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + nixpkgs.url = "https://channels.nixos.org/nixos-unstable/nixexprs.tar.zst"; flake-utils.url = "github:numtide/flake-utils"; };