mirror of
				https://github.com/rm-dr/daisy
				synced 2025-10-30 22:14:55 -07:00 
			
		
		
		
	Compare commits
	
		
			14 Commits
		
	
	
		
			27ea64e172
			...
			1fae11a380
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 1fae11a380 | |||
| bc1716eefd | |||
| 42555e0df7 | |||
| cd1074d30f | |||
| 937b45e3b0 | |||
| 7726eea34d | |||
| 6fd315a9fe | |||
| 0d81d58370 | |||
| 2ff42bf62a | |||
| b5a23f814f | |||
| e3e23a686d | |||
| 93c34ca4a4 | |||
| 80f17ac210 | |||
| 3c8ed9f4f3 | 
| @ -28,4 +28,5 @@ What to do | ||||
|  - Tag merge commit on `master` (`git tag -a v1.0.0 -m "Version 1.0.0"`) | ||||
|  - `cargo publish` | ||||
|  - Update web demo & pull server (`make docker`) | ||||
|  - Update aur package | ||||
|  - Update aur package | ||||
|  - Update `default.nix` (test with `make nix`) | ||||
							
								
								
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -28,7 +28,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" | ||||
|  | ||||
| [[package]] | ||||
| name = "daisycalc" | ||||
| version = "1.1.5" | ||||
| version = "1.1.7" | ||||
| dependencies = [ | ||||
|  "cfg-if", | ||||
|  "num", | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| [package] | ||||
| name = "daisycalc" | ||||
| version = "1.1.5" | ||||
| version = "1.1.7" | ||||
| edition = "2021" | ||||
| build = "buildscript/main.rs" | ||||
| license = "GPL-3.0-only" | ||||
|  | ||||
							
								
								
									
										3
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Makefile
									
									
									
									
									
								
							| @ -1,6 +1,9 @@ | ||||
| release: | ||||
| 	cargo build --release | ||||
|  | ||||
| nix: | ||||
| 	nix-build -E 'let pkgs = import <nixpkgs> { }; in pkgs.callPackage ./default.nix {}' | ||||
|  | ||||
| test: | ||||
| 	cargo test | ||||
|  | ||||
|  | ||||
							
								
								
									
										20
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								README.md
									
									
									
									
									
								
							| @ -7,13 +7,25 @@ Many features are missing, this is still under development. | ||||
| **Web demo: [here](https://daisy.betalupi.com) (won't work on mobile)** | ||||
|  | ||||
| # 📦 Installation | ||||
|  - **From source:** `cargo build --release`, binary will be at `./target/release/daisy` | ||||
|  - **Cargo:** `cargo install daisycalc` | ||||
|  - **Arch:** `yay -S daisy` | ||||
|  - **Debian:** coming soon | ||||
|  - **Nix:** Use `default.nix`. Daisy isn't in nixpkgs yet, you'll need to add something like the following to `configuration.nix`: | ||||
|  | ||||
| From source: `cargo build --release` \ | ||||
| Binary will be in `target/release/daisy` | ||||
|  | ||||
| ```nix | ||||
| let | ||||
|   daisy = builtins.fetchGit { | ||||
|     url = "https://github.com/rm-dr/daisy.git"; | ||||
|     ref = "master"; | ||||
|   } + /default.nix; | ||||
| in | ||||
| { | ||||
|   environment.systemPackages = with pkgs; [ | ||||
|     (callPackage daisy { }) | ||||
|   ]; | ||||
| } | ||||
| ``` | ||||
|  | ||||
| # 📹 Screenshot | ||||
|  | ||||
| @ -22,7 +34,7 @@ Binary will be in `target/release/daisy` | ||||
| # 🛠️ Features | ||||
|  - Open-source | ||||
|  - Extremely high precision | ||||
|    - Uses a rational datatype when possible, and a high-precision float when not. | ||||
| 	 - Uses a rational datatype when possible, and a high-precision float when not. | ||||
|  - Pretty printing in prompt (with special substitutions) | ||||
|  - Supports many physical units, with metric and binary prefixes | ||||
|  - Supports exponential notation | ||||
|  | ||||
							
								
								
									
										2
									
								
								TODO.md
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								TODO.md
									
									
									
									
									
								
							| @ -20,6 +20,8 @@ | ||||
|  - Sums and products with functional arguments | ||||
|  - Add functions: gcd, inverse mod, dice | ||||
|  - Tuple operations | ||||
|  - Number theory: select a group, inverses, etc | ||||
|  - Negative mod | ||||
|  | ||||
| ## Prompt | ||||
|  - Fix terminal color detection | ||||
|  | ||||
							
								
								
									
										10
									
								
								default.nix
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								default.nix
									
									
									
									
									
								
							| @ -1,17 +1,17 @@ | ||||
| { lib, fetchgit, rustPlatform }: | ||||
| rustPlatform.buildRustPackage rec { | ||||
| 	pname = "daisy"; | ||||
| 	version = "1.1.4"; | ||||
| 	version = "1.1.7"; | ||||
| 	cargoLock.lockFile = src + /Cargo.lock; | ||||
|  | ||||
| 	src = fetchgit { | ||||
| 	src = builtins.fetchGit { | ||||
| 		url = "https://github.com/rm-dr/daisy.git"; | ||||
| 		rev = "v${version}"; | ||||
| 		sha256 = "sha256-aENuKtE1+tBRN0HZzRr8Gk+dVEYTiP6FNRz817Sk88o="; | ||||
| 		ref = "refs/tags/v${version}"; | ||||
| 		#rev = ""; Ideally, we'd have a hash here, but that would make git history messy. | ||||
| 	}; | ||||
|  | ||||
| 	meta = with lib; { | ||||
| 		description = "A pretty command-line scientific calculator"; | ||||
| 		description = "A general-purpose scientific calculator"; | ||||
| 		homepage = "https://github.com/rm-dr/daisy"; | ||||
| 		#license = licenses.GPL; | ||||
| 		maintainers = [ maintainers.tailhook ]; | ||||
|  | ||||
| @ -247,7 +247,7 @@ pub fn do_command( | ||||
| 			if args.len() != 2 { | ||||
| 				return FormattedText::new( | ||||
| 					format!( | ||||
| 						"[c]{first}[n] [t]takes exactly one argument.[n]\n\n", | ||||
| 						"[c]{first}[n] [e]takes exactly one argument.[n]\n\n", | ||||
| 					) | ||||
| 				); | ||||
| 			} | ||||
| @ -261,7 +261,7 @@ pub fn do_command( | ||||
| 				Err(()) => { | ||||
| 					FormattedText::new( | ||||
| 						format!( | ||||
| 							"[c]{v}[n] [t]isn't a variable.[n]\n\n", | ||||
| 							"[c]{v}[n] [e]isn't a variable.[n]\n\n", | ||||
| 						) | ||||
| 					) | ||||
| 				} | ||||
|  | ||||
| @ -90,6 +90,7 @@ impl Context { | ||||
|  | ||||
| 	pub fn delete(&mut self, s: &String) -> Result<(), ()> { | ||||
| 		if !(self.is_varible(s) || self.is_function(s)) { return Err(()) }; | ||||
| 		if s == "ans" { return Err(()) }; | ||||
| 		if self.is_varible(s) { self.variables.remove(s); } | ||||
| 		if self.is_function(s) { self.functions.remove(s); } | ||||
| 		return Ok(()); | ||||
|  | ||||
| @ -63,7 +63,7 @@ pub fn evaluate( | ||||
|  | ||||
| 					context.get_variable(&s) | ||||
| 				}, | ||||
| 				Expression::Operator(_, Operator::Function(_), _) => { eval_function(g)? }, | ||||
| 				Expression::Operator(_, Operator::Function(_), _) => { eval_function(context, g)? }, | ||||
| 				Expression::Operator(_, _, _) => { eval_operator(context, g)? }, | ||||
| 			}; | ||||
|  | ||||
|  | ||||
| @ -3,11 +3,12 @@ use crate::parser::Function; | ||||
| use crate::parser::Operator; | ||||
| use crate::parser::LineLocation; | ||||
| use crate::quantity::FreeUnit; | ||||
| use crate::quantity::Unit; | ||||
| use crate::quantity::WholeUnit; | ||||
| use crate::quantity::Quantity; | ||||
| use crate::quantity::Scalar; | ||||
| use crate::errors::DaisyError; | ||||
|  | ||||
| use crate::context::Context; | ||||
|  | ||||
| // If unitless, do nothing | ||||
| // If compatible with radians, convert to radians and return unitless | ||||
| @ -26,7 +27,7 @@ fn to_radians(q: Quantity) -> Result<Quantity, ()> { | ||||
|  | ||||
|  | ||||
|  | ||||
| pub fn eval_function(g: &Expression) -> Result<Option<Expression>, (LineLocation, DaisyError)> { | ||||
| pub fn eval_function(context: &mut Context, g: &Expression) -> Result<Option<Expression>, (LineLocation, DaisyError)> { | ||||
|  | ||||
| 	let Expression::Operator(loc, Operator::Function(f), args) = g else {unreachable!()}; | ||||
|  | ||||
| @ -154,17 +155,51 @@ pub fn eval_function(g: &Expression) -> Result<Option<Expression>, (LineLocation | ||||
| 		Function::ToCelsius => { | ||||
| 			let mut k = Quantity::new_rational(1f64).unwrap(); | ||||
| 			k.insert_unit(FreeUnit::from_whole(WholeUnit::Kelvin), Scalar::new_rational(1f64).unwrap()); | ||||
| 			let Some(q) = q.convert_to(k) else { return Err((*loc + *l, DaisyError::IncompatibleUnit)) }; | ||||
|  | ||||
| 			let q_s: String; | ||||
| 			if q.unitless() { | ||||
| 				q_s = String::from("scalar"); | ||||
| 			} else { | ||||
| 				q_s = q.convert_to_base().unit().display(context); | ||||
| 			} | ||||
|  | ||||
| 			let Some(q) = q.convert_to(k) else { | ||||
| 				return Err(( | ||||
| 					*loc + *l, | ||||
| 					DaisyError::IncompatibleUnits( | ||||
| 						q_s, | ||||
| 						Unit::from_free(FreeUnit::from_whole(WholeUnit::Kelvin)).display(context) | ||||
| 					) | ||||
| 				)) | ||||
| 			}; | ||||
|  | ||||
| 			let mut r = q.without_unit(); | ||||
| 			r += Quantity::new_rational(-273.15f64).unwrap(); | ||||
|  | ||||
| 			return Ok(Some(Expression::Quantity(*loc + *l, r))); | ||||
| 		}, | ||||
|  | ||||
|  | ||||
| 		Function::ToFahrenheit => { | ||||
| 			let mut k = Quantity::new_rational(1f64).unwrap(); | ||||
| 			k.insert_unit(FreeUnit::from_whole(WholeUnit::Kelvin), Scalar::new_rational(1f64).unwrap()); | ||||
| 			let Some(q) = q.convert_to(k) else { return Err((*loc + *l, DaisyError::IncompatibleUnit)) }; | ||||
|  | ||||
| 			let q_s: String; | ||||
| 			if q.unitless() { | ||||
| 				q_s = String::from("scalar"); | ||||
| 			} else { | ||||
| 				q_s = q.convert_to_base().unit().display(context); | ||||
| 			} | ||||
|  | ||||
| 			let Some(q) = q.convert_to(k) else { | ||||
| 				return Err(( | ||||
| 					*loc + *l, | ||||
| 					DaisyError::IncompatibleUnits( | ||||
| 						q_s, | ||||
| 						Unit::from_free(FreeUnit::from_whole(WholeUnit::Kelvin)).display(context) | ||||
| 					) | ||||
| 				)) | ||||
| 			}; | ||||
|  | ||||
| 			let mut r = q.without_unit(); | ||||
| 			r *= Quantity::new_rational_from_frac(9i64, 5i64).unwrap(); | ||||
| @ -173,8 +208,18 @@ pub fn eval_function(g: &Expression) -> Result<Option<Expression>, (LineLocation | ||||
|  | ||||
| 			return Ok(Some(Expression::Quantity(*loc + *l, r))); | ||||
| 		}, | ||||
|  | ||||
|  | ||||
| 		Function::FromCelsius => { | ||||
| 			if !q.unitless() { return Err((*loc + *l, DaisyError::IncompatibleUnit));} | ||||
| 			if !q.unitless() { | ||||
| 				return Err(( | ||||
| 					*loc + *l, | ||||
| 					DaisyError::IncompatibleUnits( | ||||
| 						q.convert_to_base().unit().display(context), | ||||
| 						"scalar".to_string() | ||||
| 					) | ||||
| 				)); | ||||
| 			} | ||||
|  | ||||
| 			let mut r = Quantity::new_rational(273.15f64).unwrap(); | ||||
| 			r += q.clone(); | ||||
| @ -182,8 +227,18 @@ pub fn eval_function(g: &Expression) -> Result<Option<Expression>, (LineLocation | ||||
|  | ||||
| 			return Ok(Some(Expression::Quantity(*loc + *l, r))); | ||||
| 		}, | ||||
|  | ||||
|  | ||||
| 		Function::FromFahrenheit => { | ||||
| 			if !q.unitless() { return Err((*loc + *l, DaisyError::IncompatibleUnit));} | ||||
| 			if !q.unitless() { | ||||
| 				return Err(( | ||||
| 					*loc + *l, | ||||
| 					DaisyError::IncompatibleUnits( | ||||
| 						q.convert_to_base().unit().display(context), | ||||
| 						"scalar".to_string() | ||||
| 					) | ||||
| 				)); | ||||
| 			} | ||||
|  | ||||
| 			let mut r = q.clone(); | ||||
| 			r += Quantity::new_rational(459.67).unwrap(); | ||||
|  | ||||
| @ -124,6 +124,8 @@ pub fn eval_operator(context: &mut Context, g: &Expression) -> Result<Option<Exp | ||||
| 			if let Expression::Quantity(la, a) = a { | ||||
| 				if let Expression::Quantity(lb, b) = b { | ||||
| 					if !a.unit.compatible_with(&b.unit) { | ||||
| 						let a = a.convert_to_base().unit; | ||||
| 						let b = b.convert_to_base().unit; | ||||
|  | ||||
| 						let a_s: String; | ||||
| 						let b_s: String; | ||||
|  | ||||
		Reference in New Issue
	
	Block a user