Added terminal color detection

Added configuration
Cleaned up context args
pull/2/head
Mark 2023-08-17 10:10:38 -07:00
parent fc4c28543f
commit e0ca8be79f
Signed by: Mark
GPG Key ID: AD62BB059C2AAEE4
11 changed files with 282 additions and 103 deletions

View File

@ -170,7 +170,7 @@ pub fn do_command(
t.push(&format!( t.push(&format!(
" {key}{padding} = [c]{v}[n]\n", " {key}{padding} = [c]{v}[n]\n",
v = value.to_string(), v = value.display(context),
)); ));
} }
} }
@ -184,7 +184,7 @@ pub fn do_command(
t.push(&format!( t.push(&format!(
" {s}{padding} = [c]{v}[n]\n", " {s}{padding} = [c]{v}[n]\n",
v = exp.to_string(), v = exp.display(context),
)); ));
} }
} }

View File

@ -3,7 +3,68 @@ use crate::quantity::freeunit_from_string;
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Debug)] #[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 struct Context {
pub config: Config,
history: Vec<Expression>, history: Vec<Expression>,
variables: HashMap<String, Expression>, variables: HashMap<String, Expression>,
functions: HashMap<String, (Vec<String>, Expression)>, functions: HashMap<String, (Vec<String>, Expression)>,
@ -16,6 +77,7 @@ pub struct Context {
impl Context { impl Context {
pub fn new() -> Context { pub fn new() -> Context {
Context{ Context{
config: Config::new(),
history: Vec::new(), history: Vec::new(),
variables: HashMap::new(), variables: HashMap::new(),
functions: HashMap::new(), functions: HashMap::new(),

View File

@ -1,4 +1,3 @@
use std::io::Write;
use std::io::stdout; use std::io::stdout;
use std::io::stdin; use std::io::stdin;
use std::env; use std::env;
@ -6,19 +5,33 @@ use std::env;
use termion::{ use termion::{
event::Key, event::Key,
input::TermRead, input::TermRead,
raw::IntoRawMode raw::IntoRawMode,
color::DetectColors
}; };
use super::promptbuffer::PromptBuffer; use super::promptbuffer::PromptBuffer;
use crate::command; use crate::command;
use crate::context::Context; use crate::context::Context;
use crate::FormattedText;
#[inline(always)] #[inline(always)]
pub fn main() -> Result<(), std::io::Error> { pub fn main() -> Result<(), std::io::Error> {
let mut stdout = stdout().into_raw_mode().unwrap(); let mut stdout = stdout().into_raw_mode().unwrap();
let mut pb: PromptBuffer = PromptBuffer::new(64); let mut pb: PromptBuffer = PromptBuffer::new(64);
let mut context: Context = Context::new(); 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();
// Handle command-line arguments // Handle command-line arguments
@ -28,7 +41,21 @@ pub fn main() -> Result<(), std::io::Error> {
t.write(&context, &mut stdout)?; t.write(&context, &mut stdout)?;
return Ok(()); return Ok(());
} else if args.iter().any(|s| s == "--version") { } else if args.iter().any(|s| s == "--version") {
write!(stdout, "Daisy v{}\r\n", env!("CARGO_PKG_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)?;
return Ok(()); return Ok(());
} }
@ -45,7 +72,7 @@ pub fn main() -> Result<(), std::io::Error> {
// while inside a substitution // while inside a substitution
pb.write_prompt_nocursor(&mut context, &mut stdout)?; pb.write_prompt_nocursor(&mut context, &mut stdout)?;
let in_str = pb.enter(); let in_str = pb.enter();
write!(stdout, "\r\n")?; FormattedText::newline(&mut stdout)?;
if in_str == "" { break; } if in_str == "" { break; }
if in_str.trim() == "quit" { if in_str.trim() == "quit" {
@ -83,6 +110,6 @@ pub fn main() -> Result<(), std::io::Error> {
} }
} }
write!(stdout, "\r\n")?; FormattedText::newline(&mut stdout)?;
return Ok(()); return Ok(());
} }

View File

@ -78,8 +78,8 @@ pub fn eval_operator(context: &mut Context, g: &Expression) -> Result<Option<Exp
return Err(( return Err((
*la + *lb + *op_loc, *la + *lb + *op_loc,
DaisyError::IncompatibleUnits( DaisyError::IncompatibleUnits(
a.convert_to_base().unit.to_string(), a.convert_to_base().unit.display(context),
b.convert_to_base().unit.to_string() b.convert_to_base().unit.display(context)
) )
)); ));
} }
@ -101,8 +101,8 @@ pub fn eval_operator(context: &mut Context, g: &Expression) -> Result<Option<Exp
return Err(( return Err((
*la + *lb + *op_loc, *la + *lb + *op_loc,
DaisyError::IncompatibleUnits( DaisyError::IncompatibleUnits(
a.convert_to_base().unit.to_string(), a.convert_to_base().unit.display(context),
b.convert_to_base().unit.to_string() b.convert_to_base().unit.display(context)
) )
)); ));
} }
@ -179,8 +179,8 @@ pub fn eval_operator(context: &mut Context, g: &Expression) -> Result<Option<Exp
return Err(( return Err((
*la + *lb + *op_loc, *la + *lb + *op_loc,
DaisyError::IncompatibleUnits( DaisyError::IncompatibleUnits(
va.convert_to_base().unit.to_string(), va.convert_to_base().unit.display(context),
vb.convert_to_base().unit.to_string() vb.convert_to_base().unit.display(context)
) )
)); ));
} }

View File

@ -5,6 +5,7 @@ use termion::style;
use termion::clear; use termion::clear;
use termion::cursor; use termion::cursor;
use std::ops::Add; use std::ops::Add;
use crate::context::Context;
#[derive(Debug)] #[derive(Debug)]
@ -18,8 +19,92 @@ impl ToString for FormattedText {
} }
impl 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 { pub fn new(s: String) -> FormattedText {
return FormattedText { return FormattedText {
text: s text: s
@ -58,30 +143,22 @@ impl FormattedText {
let b = chars.next().unwrap(); let b = chars.next().unwrap();
match (a, b) { match (a, b) {
('n', ']') => { // Normal text (c, ']') => { // 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));
},
('s', ']') => { // Repeat prompt (how => is styled) let q = match context.config.term_color_type {
s.push_str(&format!("{}{}", color::Fg(color::Magenta), style::Bold)); 0 => format_map_none(c),
}, 1 => format_map_ansi(c),
('r', ']') => { // Result prompt (how = is styled) 2 => format_map_full(c),
s.push_str(&format!("{}{}", color::Fg(color::Green), style::Bold)); _ => unreachable!("Invalid term_color_type")
};
if q.is_some() {
s.push_str(&q.unwrap());
} else {
s.push('[');
s.push(a);
s.push(b);
}
}, },
_ => { _ => {

View File

@ -85,13 +85,13 @@ fn do_expression(
// Display parsed string // Display parsed string
output.push(&format!( output.push(&format!(
" [s]=>[n] {}\n\n", " [s]=>[n] {}\n\n",
g.to_string() g.display(context)
)); ));
// Display result // Display result
output.push(&format!( output.push(&format!(
" [r]=[n] {}\n\n", " [r]=[n] {}\n\n",
g_evaluated.to_string_outer(), g_evaluated.display_outer(context),
)); ));
return Ok((output, g_evaluated)); return Ok((output, g_evaluated));
@ -224,7 +224,7 @@ fn do_assignment(
// Display parsed string // Display parsed string
output.push(&format!( output.push(&format!(
" [s]=>[n] {left} = {}\n\n", " [s]=>[n] {left} = {}\n\n",
g.to_string() g.display(context)
)); ));
// Evaluate expression with shadow variables // Evaluate expression with shadow variables
@ -266,7 +266,7 @@ fn do_assignment(
// Display parsed string // Display parsed string
output.push(&format!( output.push(&format!(
" [t]=>[n] {left} = {}\n\n", " [t]=>[n] {left} = {}\n\n",
g.to_string() g.display(context)
)); ));
// Evaluate expression // Evaluate expression

View File

@ -1,5 +1,6 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use crate::quantity::Quantity; use crate::quantity::Quantity;
use crate::context::Context;
use super::Operator; use super::Operator;
use super::Constant; use super::Constant;
@ -17,17 +18,17 @@ pub enum Expression {
Tuple(LineLocation, VecDeque<Expression>), Tuple(LineLocation, VecDeque<Expression>),
} }
impl ToString for Expression { impl Expression {
fn to_string(&self) -> String { pub fn display(&self, context: &Context) -> String {
match self { match self {
Expression::Quantity(_, v) => v.to_string(), Expression::Quantity(_, v) => v.display(context),
Expression::Constant(_, c) => c.to_string(), Expression::Constant(_, c) => c.to_string(),
Expression::Variable(_, s) => s.clone(), Expression::Variable(_, s) => s.clone(),
Expression::Operator(_, o,a) => o.print(a), Expression::Operator(_, o,a) => o.display(context, a),
Expression::Tuple(_, v) => { Expression::Tuple(_, v) => {
format!("({})", format!("({})",
v.iter() v.iter()
.map(|x| x.to_string()) .map(|x| x.display(context))
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join(", ") .join(", ")
) )
@ -39,16 +40,16 @@ impl ToString for Expression {
impl Expression { impl Expression {
// This is called only when this is the outermost Expression. // This is called only when this is the outermost Expression.
// This sometimes leads to different--usually more verbose--behavior. // This sometimes leads to different--usually more verbose--behavior.
pub fn to_string_outer(&self) -> String { pub fn display_outer(&self, context: &Context) -> String {
match self { match self {
Expression::Quantity(_, v) => v.to_string_outer(), Expression::Quantity(_, v) => v.display_outer(context),
Expression::Constant(_, c) => c.to_string(), Expression::Constant(_, c) => c.to_string(),
Expression::Variable(_, s) => s.clone(), Expression::Variable(_, s) => s.clone(),
Expression::Operator(_, o,a) => o.print(a), Expression::Operator(_, o,a) => o.display(context, a),
Expression::Tuple(_, v) => { Expression::Tuple(_, v) => {
format!("({})", format!("({})",
v.iter() v.iter()
.map(|x| x.to_string()) .map(|x| x.display(context))
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join(", ") .join(", ")
) )

View File

@ -128,8 +128,8 @@ impl Operator {
} }
#[inline(always)] #[inline(always)]
fn add_parens_to_arg(&self, arg: &Expression) -> String { fn add_parens_to_arg(&self, context: &Context, arg: &Expression) -> String {
let mut astr: String = arg.to_string(); let mut astr: String = arg.display(context);
if let Expression::Operator(_, o,_) = arg { if let Expression::Operator(_, o,_) = arg {
if o.print_map() < self.print_map() { if o.print_map() < self.print_map() {
astr = format!("({})", astr); astr = format!("({})", astr);
@ -139,8 +139,8 @@ impl Operator {
} }
#[inline(always)] #[inline(always)]
fn add_parens_to_arg_strict(&self, arg: &Expression) -> String { fn add_parens_to_arg_strict(&self, context: &Context, arg: &Expression) -> String {
let mut astr: String = arg.to_string(); let mut astr: String = arg.display(context);
if let Expression::Operator(_, o,_) = arg { if let Expression::Operator(_, o,_) = arg {
if o.print_map() <= self.print_map() { if o.print_map() <= self.print_map() {
astr = format!("({})", astr); astr = format!("({})", astr);
@ -150,56 +150,56 @@ impl Operator {
} }
pub fn print(&self, args: &VecDeque<Expression>) -> String { pub fn display(&self, context: &Context, args: &VecDeque<Expression>) -> String {
match self { match self {
Operator::Negative => { Operator::Negative => {
return format!("-{}", self.add_parens_to_arg(&args[0])); return format!("-{}", self.add_parens_to_arg(context, &args[0]));
}, },
Operator::Sqrt => { Operator::Sqrt => {
return format!( return format!(
"√{}", "√{}",
self.add_parens_to_arg(&args[0]), self.add_parens_to_arg(context, &args[0]),
); );
}, },
Operator::ModuloLong => { Operator::ModuloLong => {
return format!( return format!(
"{} mod {}", "{} mod {}",
self.add_parens_to_arg(&args[0]), self.add_parens_to_arg(context, &args[0]),
self.add_parens_to_arg(&args[1]) self.add_parens_to_arg(context, &args[1])
); );
}, },
Operator::DivideLong => { Operator::DivideLong => {
return format!( return format!(
"{} per {}", "{} per {}",
self.add_parens_to_arg(&args[0]), self.add_parens_to_arg(context, &args[0]),
self.add_parens_to_arg(&args[1]) self.add_parens_to_arg(context, &args[1])
); );
}, },
Operator::UnitConvert => { Operator::UnitConvert => {
return format!( return format!(
"{} to {}", "{} to {}",
self.add_parens_to_arg(&args[0]), self.add_parens_to_arg(context, &args[0]),
self.add_parens_to_arg(&args[1]) self.add_parens_to_arg(context, &args[1])
); );
}, },
Operator::Modulo => { Operator::Modulo => {
return format!( return format!(
"{} % {}", "{} % {}",
self.add_parens_to_arg(&args[0]), self.add_parens_to_arg(context, &args[0]),
self.add_parens_to_arg(&args[1]) self.add_parens_to_arg(context, &args[1])
); );
}, },
Operator::Subtract => { Operator::Subtract => {
return format!( return format!(
"{} - {}", "{} - {}",
self.add_parens_to_arg(&args[0]), self.add_parens_to_arg(context, &args[0]),
self.add_parens_to_arg(&args[1]) self.add_parens_to_arg(context, &args[1])
); );
}, },
@ -208,13 +208,13 @@ impl Operator {
let q = &args[1]; let q = &args[1];
if { if {
//context.config.enable_super_powers && context.config.enable_super_powers &&
q.is_unitless_integer() && q.is_unitless_integer() &&
!q.to_string().contains("e") !q.display(context).contains("e")
} { } {
// Write integer powers as a superscript // Write integer powers as a superscript
let mut b = String::new(); let mut b = String::new();
for c in q.to_string().chars() { for c in q.display(context).chars() {
b.push(match c { b.push(match c {
'-' => '⁻', '-' => '⁻',
'0' => '⁰', '0' => '⁰',
@ -233,27 +233,27 @@ impl Operator {
return format!( return format!(
"{}{}", "{}{}",
self.add_parens_to_arg_strict(&args[0]), self.add_parens_to_arg_strict(context, &args[0]),
b b
); );
} else { } else {
return format!( return format!(
"{}^{}", "{}^{}",
self.add_parens_to_arg_strict(&args[0]), self.add_parens_to_arg_strict(context, &args[0]),
self.add_parens_to_arg_strict(&args[1]) self.add_parens_to_arg_strict(context, &args[1])
); );
} }
}, },
Operator::Factorial => { Operator::Factorial => {
return format!("{}!", self.add_parens_to_arg(&args[0])); return format!("{}!", self.add_parens_to_arg(context, &args[0]));
}, },
Operator::Add => { Operator::Add => {
return format!( return format!(
"{} + {}", "{} + {}",
self.add_parens_to_arg(&args[0]), self.add_parens_to_arg(context, &args[0]),
self.add_parens_to_arg(&args[1]) self.add_parens_to_arg(context, &args[1])
); );
}, },
@ -283,26 +283,26 @@ impl Operator {
if let Expression::Quantity(_, u) = b { if let Expression::Quantity(_, u) = b {
if u.unit.no_space() { if u.unit.no_space() {
return format!("{}{}", return format!("{}{}",
self.add_parens_to_arg_strict(a), self.add_parens_to_arg_strict(context, a),
self.add_parens_to_arg_strict(b) self.add_parens_to_arg_strict(context, b)
); );
} else { } else {
return format!("{} {}", return format!("{} {}",
self.add_parens_to_arg_strict(a), self.add_parens_to_arg_strict(context, a),
self.add_parens_to_arg_strict(b) self.add_parens_to_arg_strict(context, b)
); );
} }
} else { } else {
return format!("{}{}", return format!("{}{}",
self.add_parens_to_arg_strict(a), self.add_parens_to_arg_strict(context, a),
self.add_parens_to_arg_strict(b) self.add_parens_to_arg_strict(context, b)
); );
}; };
} else { } else {
return format!("{} × {}", return format!("{} × {}",
self.add_parens_to_arg_strict(a), self.add_parens_to_arg_strict(context, a),
self.add_parens_to_arg_strict(b) self.add_parens_to_arg_strict(context, b)
); );
} }
}, },
@ -313,25 +313,25 @@ impl Operator {
if let Expression::Quantity(_, q) = a { if let Expression::Quantity(_, q) = a {
if q.is_one() { if q.is_one() && context.config.enable_one_over_power {
return format!("{}⁻¹", return format!("{}⁻¹",
self.add_parens_to_arg_strict(b) self.add_parens_to_arg_strict(context, b)
); );
} }
} }
return format!("{} ÷ {}", return format!("{} ÷ {}",
self.add_parens_to_arg_strict(a), self.add_parens_to_arg_strict(context, a),
self.add_parens_to_arg_strict(b) self.add_parens_to_arg_strict(context, b)
); );
}, },
Operator::Function(s) => { Operator::Function(s) => {
return format!("{}({})", s.to_string(), args[0].to_string()); return format!("{}({})", s.to_string(), args[0].display(context));
}, },
Operator::UserFunction(s) => { Operator::UserFunction(s) => {
return format!("{}({})", s.to_string(), args[0].to_string()); return format!("{}({})", s, args[0].display(context));
} }
}; };
} }

View File

@ -7,6 +7,7 @@ use std::ops::{
}; };
use std::cmp::Ordering; use std::cmp::Ordering;
use crate::context::Context;
use crate::quantity::Unit; use crate::quantity::Unit;
use crate::quantity::FreeUnit; use crate::quantity::FreeUnit;
@ -21,12 +22,12 @@ pub struct Quantity {
impl ToString for Quantity { impl Quantity {
fn to_string(&self) -> String { pub fn display(&self, context: &Context) -> String {
let n = self.scalar.to_string(); let n = self.scalar.to_string();
if self.unitless() { return n; } if self.unitless() { return n; }
let u = self.unit.to_string(); let u = self.unit.display(context);
if self.is_one() { return u; }; if self.is_one() { return u; };
if self.unit.no_space() { if self.unit.no_space() {
@ -38,11 +39,11 @@ impl ToString for Quantity {
} }
impl Quantity { impl Quantity {
pub fn to_string_outer(&self) -> String { pub fn display_outer(&self, context: &Context) -> String {
let n = self.scalar.to_string(); let n = self.scalar.to_string();
if self.unitless() { return n; } if self.unitless() { return n; }
let u = self.unit.to_string(); let u = self.unit.display(context);
if self.unit.no_space() { if self.unit.no_space() {
return format!("{n}{u}"); return format!("{n}{u}");
} else { } else {

View File

@ -4,6 +4,7 @@ use std::ops::{
MulAssign, DivAssign MulAssign, DivAssign
}; };
use crate::context::Context;
use crate::quantity::Scalar; use crate::quantity::Scalar;
use crate::quantity::Quantity; use crate::quantity::Quantity;
use super::FreeUnit; use super::FreeUnit;
@ -16,8 +17,8 @@ pub struct Unit {
pub val: HashMap<FreeUnit, Scalar> pub val: HashMap<FreeUnit, Scalar>
} }
impl ToString for Unit { impl Unit {
fn to_string(&self) -> String { pub fn display(&self, context: &Context) -> String {
if self.unitless() { return String::new(); }; if self.unitless() { return String::new(); };
@ -37,7 +38,11 @@ impl ToString for Unit {
if *p == Scalar::new_rational(1f64).unwrap() { if *p == Scalar::new_rational(1f64).unwrap() {
t.push_str(&format!("{c}·")); t.push_str(&format!("{c}·"));
} else if p.is_int() && !p.to_string().contains("e"){ } else if {
context.config.enable_super_powers &&
p.is_int() &&
!p.to_string().contains("e")
} {
t.push_str(&c); t.push_str(&c);
for c in p.to_string().chars() { for c in p.to_string().chars() {
t.push( match c { t.push( match c {
@ -74,7 +79,11 @@ impl ToString for Unit {
bottom_count += 1; bottom_count += 1;
if t.len() != 0 && *p == Scalar::new_rational(-1f64).unwrap() { if t.len() != 0 && *p == Scalar::new_rational(-1f64).unwrap() {
b.push_str(&format!("{c}·")); b.push_str(&format!("{c}·"));
} else if p.is_int() && !p.to_string().contains("e") { } else if {
context.config.enable_super_powers &&
p.is_int() &&
!p.to_string().contains("e")
} {
b.push_str(&c); b.push_str(&c);
for c in p.to_string().chars() { for c in p.to_string().chars() {
if c == '-' && t.len() != 0 { continue; } if c == '-' && t.len() != 0 { continue; }

View File

@ -10,8 +10,10 @@ fn eval_to_str(s: &str) -> Result<String, ()> {
}; };
//let out_str = g.print(); //let out_str = g.print();
return match evaluate(&mut Context::new(), &g) { let mut c = Context::new();
Ok(x) => Ok(x.to_string_outer()),
return match evaluate(&mut c, &g) {
Ok(x) => Ok(x.display_outer(&c)),
Err(_) => Err(()) Err(_) => Err(())
}; };
} }