mirror of https://github.com/rm-dr/daisy
Compare commits
No commits in common. "09996801d818eed2b81565d1861e31529058bcd7" and "36540f37b89c79fa691b4837cb75a50a26f77ef8" have entirely different histories.
09996801d8
...
36540f37b8
|
@ -28,7 +28,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "daisycalc"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"rug",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "daisycalc"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
build = "buildscript/main.rs"
|
||||
license = "GPL-3.0-only"
|
||||
|
|
|
@ -5,7 +5,6 @@ A high-precision scientific calculator with support for units, derivatives, and
|
|||
Many features are missing, this is still under development.
|
||||
|
||||
# 📦 Installation
|
||||
- **Cargo:** `cargo install daisycalc`
|
||||
- **Arch:** `yay -S daisy`
|
||||
- **Debian:** coming soon
|
||||
|
||||
|
|
11
TODO.md
11
TODO.md
|
@ -2,9 +2,9 @@
|
|||
- update Cargo.toml
|
||||
- run cargo test
|
||||
- commit
|
||||
- push
|
||||
- merge
|
||||
- git tag -a v1.0.0 -m "Version 1.0.0" on merge commit
|
||||
- git tag -a v1.0.0 -m "Version 1.0.0"
|
||||
- git push
|
||||
- git push origin v1.0.0
|
||||
- cargo publish
|
||||
- Update packages
|
||||
|
||||
|
@ -27,6 +27,11 @@
|
|||
- Optional history file
|
||||
- daisyrc file
|
||||
- Compile to WASM, publish a webapp
|
||||
- Options:
|
||||
- disable replacement
|
||||
- disable special characters
|
||||
- 1/ as -1 power toggle
|
||||
- powers as superscripts toggle
|
||||
- evaluate straight from command line
|
||||
- Auto-push to crates.io
|
||||
- Package for debian
|
||||
|
|
|
@ -170,7 +170,7 @@ pub fn do_command(
|
|||
|
||||
t.push(&format!(
|
||||
" {key}{padding} = [c]{v}[n]\n",
|
||||
v = value.display(context),
|
||||
v = value.to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ pub fn do_command(
|
|||
|
||||
t.push(&format!(
|
||||
" {s}{padding} = [c]{v}[n]\n",
|
||||
v = exp.display(context),
|
||||
v = exp.to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,68 +3,7 @@ use crate::quantity::freeunit_from_string;
|
|||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone)]
|
||||
pub struct Config {
|
||||
|
||||
// How to color terminal text.
|
||||
// 0: No colors
|
||||
// 1: ANSI-compatible, 8 colors
|
||||
// 2: Full 256 color and special styles
|
||||
pub term_color_type: u8,
|
||||
|
||||
// Should we accept input and print in unicode?
|
||||
//pub enable_unicode: bool,
|
||||
|
||||
// Should we replace certain strings (like "pi")
|
||||
// with prettier unicode alternatives?
|
||||
//
|
||||
// Automatically disabled if enable_unicode is off.
|
||||
//pub enable_substituion: bool,
|
||||
|
||||
// Should we print simple powers
|
||||
// as unicode superscript chars?
|
||||
//
|
||||
// Automatically disables if enable_unicode is off.
|
||||
pub enable_super_powers: bool,
|
||||
|
||||
// Should we write "one-over" fractions
|
||||
// as -1 powers?
|
||||
//
|
||||
// Automatically disabled if enable_super_powers is off.
|
||||
pub enable_one_over_power: bool,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new() -> Config {
|
||||
Config{
|
||||
term_color_type: 2,
|
||||
//enable_substituion: true,
|
||||
//enable_unicode: true,
|
||||
enable_super_powers: true,
|
||||
enable_one_over_power: true
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check(&mut self) {
|
||||
//if !self.enable_unicode {
|
||||
// self.enable_substituion = false;
|
||||
// self.enable_super_powers = false;
|
||||
//}
|
||||
|
||||
if !self.enable_super_powers {
|
||||
self.enable_one_over_power = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone)]
|
||||
pub struct Context {
|
||||
pub config: Config,
|
||||
|
||||
history: Vec<Expression>,
|
||||
variables: HashMap<String, Expression>,
|
||||
functions: HashMap<String, (Vec<String>, Expression)>,
|
||||
|
@ -77,7 +16,6 @@ pub struct Context {
|
|||
impl Context {
|
||||
pub fn new() -> Context {
|
||||
Context{
|
||||
config: Config::new(),
|
||||
history: Vec::new(),
|
||||
variables: HashMap::new(),
|
||||
functions: HashMap::new(),
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use std::io::Write;
|
||||
use std::io::stdout;
|
||||
use std::io::stdin;
|
||||
use std::env;
|
||||
|
@ -5,33 +6,19 @@ use std::env;
|
|||
use termion::{
|
||||
event::Key,
|
||||
input::TermRead,
|
||||
raw::IntoRawMode,
|
||||
color::DetectColors
|
||||
raw::IntoRawMode
|
||||
};
|
||||
|
||||
use super::promptbuffer::PromptBuffer;
|
||||
use crate::command;
|
||||
use crate::context::Context;
|
||||
use crate::FormattedText;
|
||||
|
||||
|
||||
#[inline(always)]
|
||||
pub fn main() -> Result<(), std::io::Error> {
|
||||
let mut stdout = stdout().into_raw_mode().unwrap();
|
||||
let mut pb: PromptBuffer = PromptBuffer::new(64);
|
||||
let mut context = Context::new();
|
||||
|
||||
// Set color compatibilty
|
||||
let term_colors = stdout.available_colors().unwrap_or(0);
|
||||
if term_colors >= 256 {
|
||||
context.config.term_color_type = 2
|
||||
} else if term_colors >= 8 {
|
||||
context.config.term_color_type = 1
|
||||
} else {
|
||||
context.config.term_color_type = 0
|
||||
}
|
||||
|
||||
context.config.check();
|
||||
|
||||
let mut context: Context = Context::new();
|
||||
|
||||
|
||||
// Handle command-line arguments
|
||||
|
@ -41,21 +28,7 @@ pub fn main() -> Result<(), std::io::Error> {
|
|||
t.write(&context, &mut stdout)?;
|
||||
return Ok(());
|
||||
} else if args.iter().any(|s| s == "--version") {
|
||||
let t = FormattedText::new(format!(
|
||||
"Daisy v{}\n", env!("CARGO_PKG_VERSION")
|
||||
));
|
||||
t.write(&context, &mut stdout)?;
|
||||
return Ok(());
|
||||
} else if args.iter().any(|s| s == "--debug") {
|
||||
let t = FormattedText::new(format!(
|
||||
concat!(
|
||||
"Daisy v{}\n",
|
||||
"Your terminal supports {} colors.\n"
|
||||
),
|
||||
env!("CARGO_PKG_VERSION"),
|
||||
term_colors
|
||||
));
|
||||
t.write(&context, &mut stdout)?;
|
||||
write!(stdout, "Daisy v{}\r\n", env!("CARGO_PKG_VERSION"))?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -72,7 +45,7 @@ pub fn main() -> Result<(), std::io::Error> {
|
|||
// while inside a substitution
|
||||
pb.write_prompt_nocursor(&mut context, &mut stdout)?;
|
||||
let in_str = pb.enter();
|
||||
FormattedText::newline(&mut stdout)?;
|
||||
write!(stdout, "\r\n")?;
|
||||
if in_str == "" { break; }
|
||||
|
||||
if in_str.trim() == "quit" {
|
||||
|
@ -110,6 +83,6 @@ pub fn main() -> Result<(), std::io::Error> {
|
|||
}
|
||||
}
|
||||
|
||||
FormattedText::newline(&mut stdout)?;
|
||||
write!(stdout, "\r\n")?;
|
||||
return Ok(());
|
||||
}
|
|
@ -78,8 +78,8 @@ pub fn eval_operator(context: &mut Context, g: &Expression) -> Result<Option<Exp
|
|||
return Err((
|
||||
*la + *lb + *op_loc,
|
||||
DaisyError::IncompatibleUnits(
|
||||
a.convert_to_base().unit.display(context),
|
||||
b.convert_to_base().unit.display(context)
|
||||
a.convert_to_base().unit.to_string(),
|
||||
b.convert_to_base().unit.to_string()
|
||||
)
|
||||
));
|
||||
}
|
||||
|
@ -101,8 +101,8 @@ pub fn eval_operator(context: &mut Context, g: &Expression) -> Result<Option<Exp
|
|||
return Err((
|
||||
*la + *lb + *op_loc,
|
||||
DaisyError::IncompatibleUnits(
|
||||
a.convert_to_base().unit.display(context),
|
||||
b.convert_to_base().unit.display(context)
|
||||
a.convert_to_base().unit.to_string(),
|
||||
b.convert_to_base().unit.to_string()
|
||||
)
|
||||
));
|
||||
}
|
||||
|
@ -179,8 +179,8 @@ pub fn eval_operator(context: &mut Context, g: &Expression) -> Result<Option<Exp
|
|||
return Err((
|
||||
*la + *lb + *op_loc,
|
||||
DaisyError::IncompatibleUnits(
|
||||
va.convert_to_base().unit.display(context),
|
||||
vb.convert_to_base().unit.display(context)
|
||||
va.convert_to_base().unit.to_string(),
|
||||
vb.convert_to_base().unit.to_string()
|
||||
)
|
||||
));
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ use termion::style;
|
|||
use termion::clear;
|
||||
use termion::cursor;
|
||||
use std::ops::Add;
|
||||
use crate::context::Context;
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -19,92 +18,8 @@ impl ToString for FormattedText {
|
|||
}
|
||||
|
||||
|
||||
fn format_map_none(c: char) -> Option<String> {
|
||||
Some(match c {
|
||||
'n'|'i'|'t'|'a'|
|
||||
'e'|'c'|'s'|'r'
|
||||
=> { "".to_string() },
|
||||
_ => { return None }
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
fn format_map_ansi(c: char) -> Option<String> {
|
||||
Some(match c {
|
||||
'n' => { // Normal text
|
||||
format!("{}{}", color::Fg(color::Reset), color::Bg(color::Reset))
|
||||
},
|
||||
'i' => { // Normal italic text
|
||||
format!("{}{}", color::Fg(color::Reset), color::Bg(color::Reset))
|
||||
},
|
||||
't' => { // Title text
|
||||
format!("{}{}", color::Fg(color::AnsiValue(6)), color::Bg(color::Reset))
|
||||
},
|
||||
'a' => { // Colored text
|
||||
format!("{}{}", color::Fg(color::AnsiValue(5)), color::Bg(color::Reset))
|
||||
},
|
||||
'e' => { // Error titles
|
||||
format!("{}{}", color::Fg(color::AnsiValue(1)), color::Bg(color::Reset))
|
||||
},
|
||||
'c' => { // Console text
|
||||
format!("{}{}", color::Fg(color::AnsiValue(0)), color::Bg(color::AnsiValue(7)))
|
||||
},
|
||||
's' => { // Repeat prompt (how => is styled)
|
||||
format!("{}{}", color::Fg(color::AnsiValue(2)), color::Bg(color::Reset))
|
||||
},
|
||||
'r' => { // Result prompt (how = is styled)
|
||||
format!("{}{}", color::Fg(color::AnsiValue(4)), color::Bg(color::Reset))
|
||||
},
|
||||
|
||||
_ => { return None }
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
fn format_map_full(c: char) -> Option<String> {
|
||||
Some(match c {
|
||||
'n' => { // Normal text
|
||||
format!("{}{}", color::Fg(color::Reset), style::Reset)
|
||||
},
|
||||
'i' => { // Normal italic text
|
||||
format!("{}{}", color::Fg(color::Reset), style::Italic)
|
||||
},
|
||||
't' => { // Title text
|
||||
format!("{}{}", color::Fg(color::Magenta), style::Bold)
|
||||
},
|
||||
'a' => { // Colored text
|
||||
format!("{}{}", color::Fg(color::Magenta), style::Reset)
|
||||
},
|
||||
'e' => { // Error titles
|
||||
format!("{}{}", color::Fg(color::Red), style::Bold)
|
||||
},
|
||||
'c' => { // Console text
|
||||
format!("{}{}", color::Fg(color::LightBlack), style::Italic)
|
||||
},
|
||||
's' => { // Repeat prompt (how => is styled)
|
||||
format!("{}{}", color::Fg(color::Magenta), style::Bold)
|
||||
},
|
||||
'r' => { // Result prompt (how = is styled)
|
||||
format!("{}{}", color::Fg(color::Green), style::Bold)
|
||||
},
|
||||
|
||||
_ => { return None }
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
impl FormattedText {
|
||||
pub fn newline(stdout: &mut RawTerminal<std::io::Stdout>) -> Result<(), std::io::Error> {
|
||||
write!(
|
||||
stdout,
|
||||
"\r\n",
|
||||
)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl FormattedText {
|
||||
pub fn new(s: String) -> FormattedText {
|
||||
return FormattedText {
|
||||
text: s
|
||||
|
@ -143,22 +58,30 @@ impl FormattedText {
|
|||
let b = chars.next().unwrap();
|
||||
|
||||
match (a, b) {
|
||||
(c, ']') => { // Normal text
|
||||
('n', ']') => { // Normal text
|
||||
s.push_str(&format!("{}{}", color::Fg(color::Reset), style::Reset));
|
||||
},
|
||||
('i', ']') => { // Normal italic text
|
||||
s.push_str(&format!("{}{}", color::Fg(color::Reset), style::Italic));
|
||||
},
|
||||
('t', ']') => { // Title text
|
||||
s.push_str(&format!("{}{}", color::Fg(color::Magenta), style::Bold));
|
||||
},
|
||||
('a', ']') => { // Colored text
|
||||
s.push_str(&format!("{}{}", color::Fg(color::Magenta), style::Reset));
|
||||
},
|
||||
('e', ']') => { // Error titles
|
||||
s.push_str(&format!("{}{}", color::Fg(color::Red), style::Bold));
|
||||
},
|
||||
('c', ']') => { // Console text
|
||||
s.push_str(&format!("{}{}", color::Fg(color::LightBlack), style::Italic));
|
||||
},
|
||||
|
||||
let q = match context.config.term_color_type {
|
||||
0 => format_map_none(c),
|
||||
1 => format_map_ansi(c),
|
||||
2 => format_map_full(c),
|
||||
_ => unreachable!("Invalid term_color_type")
|
||||
};
|
||||
|
||||
if q.is_some() {
|
||||
s.push_str(&q.unwrap());
|
||||
} else {
|
||||
s.push('[');
|
||||
s.push(a);
|
||||
s.push(b);
|
||||
}
|
||||
('s', ']') => { // Repeat prompt (how => is styled)
|
||||
s.push_str(&format!("{}{}", color::Fg(color::Magenta), style::Bold));
|
||||
},
|
||||
('r', ']') => { // Result prompt (how = is styled)
|
||||
s.push_str(&format!("{}{}", color::Fg(color::Green), style::Bold));
|
||||
},
|
||||
|
||||
_ => {
|
||||
|
|
|
@ -85,13 +85,13 @@ fn do_expression(
|
|||
// Display parsed string
|
||||
output.push(&format!(
|
||||
" [s]=>[n] {}\n\n",
|
||||
g.display(context)
|
||||
g.to_string()
|
||||
));
|
||||
|
||||
// Display result
|
||||
output.push(&format!(
|
||||
" [r]=[n] {}\n\n",
|
||||
g_evaluated.display_outer(context),
|
||||
g_evaluated.to_string_outer(),
|
||||
));
|
||||
|
||||
return Ok((output, g_evaluated));
|
||||
|
@ -224,7 +224,7 @@ fn do_assignment(
|
|||
// Display parsed string
|
||||
output.push(&format!(
|
||||
" [s]=>[n] {left} = {}\n\n",
|
||||
g.display(context)
|
||||
g.to_string()
|
||||
));
|
||||
|
||||
// Evaluate expression with shadow variables
|
||||
|
@ -266,7 +266,7 @@ fn do_assignment(
|
|||
// Display parsed string
|
||||
output.push(&format!(
|
||||
" [t]=>[n] {left} = {}\n\n",
|
||||
g.display(context)
|
||||
g.to_string()
|
||||
));
|
||||
|
||||
// Evaluate expression
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use std::collections::VecDeque;
|
||||
use crate::quantity::Quantity;
|
||||
use crate::context::Context;
|
||||
|
||||
use super::Operator;
|
||||
use super::Constant;
|
||||
|
@ -18,17 +17,17 @@ pub enum Expression {
|
|||
Tuple(LineLocation, VecDeque<Expression>),
|
||||
}
|
||||
|
||||
impl Expression {
|
||||
pub fn display(&self, context: &Context) -> String {
|
||||
impl ToString for Expression {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
Expression::Quantity(_, v) => v.display(context),
|
||||
Expression::Quantity(_, v) => v.to_string(),
|
||||
Expression::Constant(_, c) => c.to_string(),
|
||||
Expression::Variable(_, s) => s.clone(),
|
||||
Expression::Operator(_, o,a) => o.display(context, a),
|
||||
Expression::Operator(_, o,a) => o.print(a),
|
||||
Expression::Tuple(_, v) => {
|
||||
format!("({})",
|
||||
v.iter()
|
||||
.map(|x| x.display(context))
|
||||
.map(|x| x.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
)
|
||||
|
@ -40,16 +39,16 @@ impl Expression {
|
|||
impl Expression {
|
||||
// This is called only when this is the outermost Expression.
|
||||
// This sometimes leads to different--usually more verbose--behavior.
|
||||
pub fn display_outer(&self, context: &Context) -> String {
|
||||
pub fn to_string_outer(&self) -> String {
|
||||
match self {
|
||||
Expression::Quantity(_, v) => v.display_outer(context),
|
||||
Expression::Quantity(_, v) => v.to_string_outer(),
|
||||
Expression::Constant(_, c) => c.to_string(),
|
||||
Expression::Variable(_, s) => s.clone(),
|
||||
Expression::Operator(_, o,a) => o.display(context, a),
|
||||
Expression::Operator(_, o,a) => o.print(a),
|
||||
Expression::Tuple(_, v) => {
|
||||
format!("({})",
|
||||
v.iter()
|
||||
.map(|x| x.display(context))
|
||||
.map(|x| x.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
)
|
||||
|
|
|
@ -128,8 +128,8 @@ impl Operator {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn add_parens_to_arg(&self, context: &Context, arg: &Expression) -> String {
|
||||
let mut astr: String = arg.display(context);
|
||||
fn add_parens_to_arg(&self, arg: &Expression) -> String {
|
||||
let mut astr: String = arg.to_string();
|
||||
if let Expression::Operator(_, o,_) = arg {
|
||||
if o.print_map() < self.print_map() {
|
||||
astr = format!("({})", astr);
|
||||
|
@ -139,8 +139,8 @@ impl Operator {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn add_parens_to_arg_strict(&self, context: &Context, arg: &Expression) -> String {
|
||||
let mut astr: String = arg.display(context);
|
||||
fn add_parens_to_arg_strict(&self, arg: &Expression) -> String {
|
||||
let mut astr: String = arg.to_string();
|
||||
if let Expression::Operator(_, o,_) = arg {
|
||||
if o.print_map() <= self.print_map() {
|
||||
astr = format!("({})", astr);
|
||||
|
@ -150,56 +150,56 @@ impl Operator {
|
|||
}
|
||||
|
||||
|
||||
pub fn display(&self, context: &Context, args: &VecDeque<Expression>) -> String {
|
||||
pub fn print(&self, args: &VecDeque<Expression>) -> String {
|
||||
match self {
|
||||
Operator::Negative => {
|
||||
return format!("-{}", self.add_parens_to_arg(context, &args[0]));
|
||||
return format!("-{}", self.add_parens_to_arg(&args[0]));
|
||||
},
|
||||
|
||||
Operator::Sqrt => {
|
||||
return format!(
|
||||
"√{}",
|
||||
self.add_parens_to_arg(context, &args[0]),
|
||||
self.add_parens_to_arg(&args[0]),
|
||||
);
|
||||
},
|
||||
|
||||
Operator::ModuloLong => {
|
||||
return format!(
|
||||
"{} mod {}",
|
||||
self.add_parens_to_arg(context, &args[0]),
|
||||
self.add_parens_to_arg(context, &args[1])
|
||||
self.add_parens_to_arg(&args[0]),
|
||||
self.add_parens_to_arg(&args[1])
|
||||
);
|
||||
},
|
||||
|
||||
Operator::DivideLong => {
|
||||
return format!(
|
||||
"{} per {}",
|
||||
self.add_parens_to_arg(context, &args[0]),
|
||||
self.add_parens_to_arg(context, &args[1])
|
||||
self.add_parens_to_arg(&args[0]),
|
||||
self.add_parens_to_arg(&args[1])
|
||||
);
|
||||
},
|
||||
|
||||
Operator::UnitConvert => {
|
||||
return format!(
|
||||
"{} to {}",
|
||||
self.add_parens_to_arg(context, &args[0]),
|
||||
self.add_parens_to_arg(context, &args[1])
|
||||
self.add_parens_to_arg(&args[0]),
|
||||
self.add_parens_to_arg(&args[1])
|
||||
);
|
||||
},
|
||||
|
||||
Operator::Modulo => {
|
||||
return format!(
|
||||
"{} % {}",
|
||||
self.add_parens_to_arg(context, &args[0]),
|
||||
self.add_parens_to_arg(context, &args[1])
|
||||
self.add_parens_to_arg(&args[0]),
|
||||
self.add_parens_to_arg(&args[1])
|
||||
);
|
||||
},
|
||||
|
||||
Operator::Subtract => {
|
||||
return format!(
|
||||
"{} - {}",
|
||||
self.add_parens_to_arg(context, &args[0]),
|
||||
self.add_parens_to_arg(context, &args[1])
|
||||
self.add_parens_to_arg(&args[0]),
|
||||
self.add_parens_to_arg(&args[1])
|
||||
);
|
||||
},
|
||||
|
||||
|
@ -208,13 +208,13 @@ impl Operator {
|
|||
let q = &args[1];
|
||||
|
||||
if {
|
||||
context.config.enable_super_powers &&
|
||||
//context.config.enable_super_powers &&
|
||||
q.is_unitless_integer() &&
|
||||
!q.display(context).contains("e")
|
||||
!q.to_string().contains("e")
|
||||
} {
|
||||
// Write integer powers as a superscript
|
||||
let mut b = String::new();
|
||||
for c in q.display(context).chars() {
|
||||
for c in q.to_string().chars() {
|
||||
b.push(match c {
|
||||
'-' => '⁻',
|
||||
'0' => '⁰',
|
||||
|
@ -233,27 +233,27 @@ impl Operator {
|
|||
|
||||
return format!(
|
||||
"{}{}",
|
||||
self.add_parens_to_arg_strict(context, &args[0]),
|
||||
self.add_parens_to_arg_strict(&args[0]),
|
||||
b
|
||||
);
|
||||
} else {
|
||||
return format!(
|
||||
"{}^{}",
|
||||
self.add_parens_to_arg_strict(context, &args[0]),
|
||||
self.add_parens_to_arg_strict(context, &args[1])
|
||||
self.add_parens_to_arg_strict(&args[0]),
|
||||
self.add_parens_to_arg_strict(&args[1])
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
Operator::Factorial => {
|
||||
return format!("{}!", self.add_parens_to_arg(context, &args[0]));
|
||||
return format!("{}!", self.add_parens_to_arg(&args[0]));
|
||||
},
|
||||
|
||||
Operator::Add => {
|
||||
return format!(
|
||||
"{} + {}",
|
||||
self.add_parens_to_arg(context, &args[0]),
|
||||
self.add_parens_to_arg(context, &args[1])
|
||||
self.add_parens_to_arg(&args[0]),
|
||||
self.add_parens_to_arg(&args[1])
|
||||
);
|
||||
},
|
||||
|
||||
|
@ -283,26 +283,26 @@ impl Operator {
|
|||
if let Expression::Quantity(_, u) = b {
|
||||
if u.unit.no_space() {
|
||||
return format!("{}{}",
|
||||
self.add_parens_to_arg_strict(context, a),
|
||||
self.add_parens_to_arg_strict(context, b)
|
||||
self.add_parens_to_arg_strict(a),
|
||||
self.add_parens_to_arg_strict(b)
|
||||
);
|
||||
} else {
|
||||
return format!("{} {}",
|
||||
self.add_parens_to_arg_strict(context, a),
|
||||
self.add_parens_to_arg_strict(context, b)
|
||||
self.add_parens_to_arg_strict(a),
|
||||
self.add_parens_to_arg_strict(b)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return format!("{}{}",
|
||||
self.add_parens_to_arg_strict(context, a),
|
||||
self.add_parens_to_arg_strict(context, b)
|
||||
self.add_parens_to_arg_strict(a),
|
||||
self.add_parens_to_arg_strict(b)
|
||||
);
|
||||
};
|
||||
|
||||
} else {
|
||||
return format!("{} × {}",
|
||||
self.add_parens_to_arg_strict(context, a),
|
||||
self.add_parens_to_arg_strict(context, b)
|
||||
self.add_parens_to_arg_strict(a),
|
||||
self.add_parens_to_arg_strict(b)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
@ -313,25 +313,25 @@ impl Operator {
|
|||
|
||||
|
||||
if let Expression::Quantity(_, q) = a {
|
||||
if q.is_one() && context.config.enable_one_over_power {
|
||||
if q.is_one() {
|
||||
return format!("{}⁻¹",
|
||||
self.add_parens_to_arg_strict(context, b)
|
||||
self.add_parens_to_arg_strict(b)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return format!("{} ÷ {}",
|
||||
self.add_parens_to_arg_strict(context, a),
|
||||
self.add_parens_to_arg_strict(context, b)
|
||||
self.add_parens_to_arg_strict(a),
|
||||
self.add_parens_to_arg_strict(b)
|
||||
);
|
||||
},
|
||||
|
||||
Operator::Function(s) => {
|
||||
return format!("{}({})", s.to_string(), args[0].display(context));
|
||||
return format!("{}({})", s.to_string(), args[0].to_string());
|
||||
},
|
||||
|
||||
Operator::UserFunction(s) => {
|
||||
return format!("{}({})", s, args[0].display(context));
|
||||
return format!("{}({})", s.to_string(), args[0].to_string());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ use std::ops::{
|
|||
};
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::quantity::Unit;
|
||||
use crate::quantity::FreeUnit;
|
||||
|
||||
|
@ -22,12 +21,12 @@ pub struct Quantity {
|
|||
|
||||
|
||||
|
||||
impl Quantity {
|
||||
pub fn display(&self, context: &Context) -> String {
|
||||
impl ToString for Quantity {
|
||||
fn to_string(&self) -> String {
|
||||
let n = self.scalar.to_string();
|
||||
if self.unitless() { return n; }
|
||||
|
||||
let u = self.unit.display(context);
|
||||
let u = self.unit.to_string();
|
||||
if self.is_one() { return u; };
|
||||
|
||||
if self.unit.no_space() {
|
||||
|
@ -39,11 +38,11 @@ impl Quantity {
|
|||
}
|
||||
|
||||
impl Quantity {
|
||||
pub fn display_outer(&self, context: &Context) -> String {
|
||||
pub fn to_string_outer(&self) -> String {
|
||||
let n = self.scalar.to_string();
|
||||
if self.unitless() { return n; }
|
||||
|
||||
let u = self.unit.display(context);
|
||||
let u = self.unit.to_string();
|
||||
if self.unit.no_space() {
|
||||
return format!("{n}{u}");
|
||||
} else {
|
||||
|
|
|
@ -4,7 +4,6 @@ use std::ops::{
|
|||
MulAssign, DivAssign
|
||||
};
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::quantity::Scalar;
|
||||
use crate::quantity::Quantity;
|
||||
use super::FreeUnit;
|
||||
|
@ -17,8 +16,8 @@ pub struct Unit {
|
|||
pub val: HashMap<FreeUnit, Scalar>
|
||||
}
|
||||
|
||||
impl Unit {
|
||||
pub fn display(&self, context: &Context) -> String {
|
||||
impl ToString for Unit {
|
||||
fn to_string(&self) -> String {
|
||||
|
||||
if self.unitless() { return String::new(); };
|
||||
|
||||
|
@ -38,11 +37,7 @@ impl Unit {
|
|||
|
||||
if *p == Scalar::new_rational(1f64).unwrap() {
|
||||
t.push_str(&format!("{c}·"));
|
||||
} else if {
|
||||
context.config.enable_super_powers &&
|
||||
p.is_int() &&
|
||||
!p.to_string().contains("e")
|
||||
} {
|
||||
} else if p.is_int() && !p.to_string().contains("e"){
|
||||
t.push_str(&c);
|
||||
for c in p.to_string().chars() {
|
||||
t.push( match c {
|
||||
|
@ -79,11 +74,7 @@ impl Unit {
|
|||
bottom_count += 1;
|
||||
if t.len() != 0 && *p == Scalar::new_rational(-1f64).unwrap() {
|
||||
b.push_str(&format!("{c}·"));
|
||||
} else if {
|
||||
context.config.enable_super_powers &&
|
||||
p.is_int() &&
|
||||
!p.to_string().contains("e")
|
||||
} {
|
||||
} else if p.is_int() && !p.to_string().contains("e") {
|
||||
b.push_str(&c);
|
||||
for c in p.to_string().chars() {
|
||||
if c == '-' && t.len() != 0 { continue; }
|
||||
|
|
|
@ -10,10 +10,8 @@ fn eval_to_str(s: &str) -> Result<String, ()> {
|
|||
};
|
||||
//let out_str = g.print();
|
||||
|
||||
let mut c = Context::new();
|
||||
|
||||
return match evaluate(&mut c, &g) {
|
||||
Ok(x) => Ok(x.display_outer(&c)),
|
||||
return match evaluate(&mut Context::new(), &g) {
|
||||
Ok(x) => Ok(x.to_string_outer()),
|
||||
Err(_) => Err(())
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue