Merge pull request #173 from ironcalc/bugfix/nicolas-format-issue

Bugfix/nicolas format issue
This commit is contained in:
Nicolás Hatcher Andrés
2024-12-10 00:39:30 +01:00
committed by GitHub
9 changed files with 73 additions and 11 deletions

View File

@@ -24,6 +24,25 @@ fn test_get_tokens() {
assert_eq!(l.end, 10); assert_eq!(l.end, 10);
} }
#[test]
fn get_tokens_unicode() {
let formula = "'🇵🇭 Philippines'!A1";
let t = get_tokens(formula);
assert_eq!(t.len(), 1);
let expected = TokenType::Reference {
sheet: Some("🇵🇭 Philippines".to_string()),
row: 1,
column: 1,
absolute_column: false,
absolute_row: false,
};
let l = t.first().expect("expected token");
assert_eq!(l.token, expected);
assert_eq!(l.start, 0);
assert_eq!(l.end, 19);
}
#[test] #[test]
fn test_simple_tokens() { fn test_simple_tokens() {
assert_eq!( assert_eq!(

View File

@@ -245,6 +245,9 @@ pub fn format_number(value_original: f64, format: &str, locale: &Locale) -> Form
} }
ParsePart::Number(p) => { ParsePart::Number(p) => {
let mut text = "".to_string(); let mut text = "".to_string();
if let Some(c) = p.currency {
text = format!("{}", c);
}
let tokens = &p.tokens; let tokens = &p.tokens;
value = value * 100.0_f64.powi(p.percent) / (1000.0_f64.powi(p.comma)); value = value * 100.0_f64.powi(p.percent) / (1000.0_f64.powi(p.comma));
// p.precision is the number of significant digits _after_ the decimal point // p.precision is the number of significant digits _after_ the decimal point

View File

@@ -10,6 +10,7 @@ pub struct Lexer {
pub enum Token { pub enum Token {
Color(i32), // [Red] or [Color 23] Color(i32), // [Red] or [Color 23]
Condition(Compare, f64), // [<=100] (Comparator, number) Condition(Compare, f64), // [<=100] (Comparator, number)
Currency(char), // [$€] ($ currency symbol)
Literal(char), // €, $, (, ), /, :, +, -, ^, ', {, }, <, =, !, ~, > and space or scaped \X Literal(char), // €, $, (, ), /, :, +, -, ^, ', {, }, <, =, !, ~, > and space or scaped \X
Spacer(char), // *X Spacer(char), // *X
Ghost(char), // _X Ghost(char), // _X
@@ -274,6 +275,15 @@ impl Lexer {
self.set_error("Failed to parse condition"); self.set_error("Failed to parse condition");
Token::ILLEGAL Token::ILLEGAL
} }
} else if c == '$' {
// currency
self.read_next_char();
if let Some(currency) = self.read_next_char() {
self.read_next_char();
return Token::Currency(currency);
}
self.set_error("Failed to parse currency");
Token::ILLEGAL
} else { } else {
// Color // Color
if let Some(index) = self.consume_color() { if let Some(index) = self.consume_color() {

View File

@@ -74,6 +74,7 @@ mod test;
// //
// * Color [Red] or [Color 23] or [Color23] // * Color [Red] or [Color 23] or [Color23]
// * Conditions [<100] // * Conditions [<100]
// * Currency [$€]
// * Space _X when X is any given char // * Space _X when X is any given char
// * A spacer of chars: *X where X is repeated as much as possible // * A spacer of chars: *X where X is repeated as much as possible
// * Literals: $, (, ), :, +, - and space // * Literals: $, (, ), :, +, - and space

View File

@@ -40,6 +40,7 @@ pub struct NumberPart {
pub is_scientific: bool, pub is_scientific: bool,
pub scientific_minus: bool, pub scientific_minus: bool,
pub exponent_digit_count: i32, pub exponent_digit_count: i32,
pub currency: Option<char>,
} }
pub struct DatePart { pub struct DatePart {
@@ -114,6 +115,7 @@ impl Parser {
let mut exponent_digit_count = 0; let mut exponent_digit_count = 0;
let mut number = 'i'; let mut number = 'i';
let mut index = 0; let mut index = 0;
let mut currency = None;
while token != Token::EOF && token != Token::Separator { while token != Token::EOF && token != Token::Separator {
let next_token = self.lexer.next_token(); let next_token = self.lexer.next_token();
@@ -170,6 +172,9 @@ impl Parser {
Token::Condition(cmp, value) => { Token::Condition(cmp, value) => {
condition = Some((cmp, value)); condition = Some((cmp, value));
} }
Token::Currency(c) => {
currency = Some(c);
}
Token::QuestionMark => { Token::QuestionMark => {
tokens.push(TextToken::Digit(Digit { tokens.push(TextToken::Digit(Digit {
kind: '?', kind: '?',
@@ -291,6 +296,7 @@ impl Parser {
is_scientific, is_scientific,
scientific_minus, scientific_minus,
exponent_digit_count, exponent_digit_count,
currency,
}) })
} }
} }

View File

@@ -76,6 +76,14 @@ fn test_color() {
assert_eq!(format_number(3.1, "[blue]0.00", locale).color, Some(4)); assert_eq!(format_number(3.1, "[blue]0.00", locale).color, Some(4));
} }
#[test]
fn dollar_euro() {
let locale = get_default_locale();
let format = "[$€]#,##0.00";
let t = format_number(3.1, format, locale);
assert_eq!(t.text, "€3.10");
}
#[test] #[test]
fn test_parts() { fn test_parts() {
let locale = get_default_locale(); let locale = get_default_locale();

View File

@@ -867,14 +867,18 @@ export default class WorksheetCanvas {
frozenRows, frozenRows,
frozenColumns, frozenColumns,
); );
if (frozenColumns > 0) {
xFrozenEnd += this.getColumnWidth( xFrozenEnd += this.getColumnWidth(
this.model.getSelectedSheet(), this.model.getSelectedSheet(),
frozenColumns, frozenColumns,
); );
}
if (frozenRows > 0) {
yFrozenEnd += this.getRowHeight( yFrozenEnd += this.getRowHeight(
this.model.getSelectedSheet(), this.model.getSelectedSheet(),
frozenRows, frozenRows,
); );
}
if (startRow <= frozenRows && endRow > frozenRows) { if (startRow <= frozenRows && endRow > frozenRows) {
yEnd = Math.max(yEnd, yFrozenEnd); yEnd = Math.max(yEnd, yFrozenEnd);
} }

View File

@@ -7,6 +7,16 @@ import {
} from "@ironcalc/wasm"; } from "@ironcalc/wasm";
import type { ActiveRange } from "../workbookState"; import type { ActiveRange } from "../workbookState";
function sliceString(
text: string,
startScalar: number,
endScalar: number,
): string {
const scalarValues = Array.from(text);
const sliced = scalarValues.slice(startScalar, endScalar);
return sliced.join("");
}
export function tokenIsReferenceType(token: TokenType): token is Reference { export function tokenIsReferenceType(token: TokenType): token is Reference {
return typeof token === "object" && "Reference" in token; return typeof token === "object" && "Reference" in token;
} }
@@ -127,7 +137,7 @@ function getFormulaHTML(
} }
html.push( html.push(
<span key={index} style={{ color }}> <span key={index} style={{ color }}>
{formula.slice(start, end)} {sliceString(formula, start, end)}
</span>, </span>,
); );
activeRanges.push({ activeRanges.push({
@@ -162,7 +172,7 @@ function getFormulaHTML(
} }
html.push( html.push(
<span key={index} style={{ color }}> <span key={index} style={{ color }}>
{formula.slice(start, end)} {sliceString(formula, start, end)}
</span>, </span>,
); );
colorCount += 1; colorCount += 1;
@@ -176,7 +186,7 @@ function getFormulaHTML(
color, color,
}); });
} else { } else {
html.push(<span key={index}>{formula.slice(start, end)}</span>); html.push(<span key={index}>{sliceString(formula, start, end)}</span>);
} }
} }
html = [<span key="equals">=</span>].concat(html); html = [<span key="equals">=</span>].concat(html);

View File

@@ -43,6 +43,7 @@ export const SheetRenameDialog = (properties: SheetRenameDialogProps) => {
setName(event.target.value); setName(event.target.value);
}} }}
spellCheck="false" spellCheck="false"
onPaste={(event) => event.stopPropagation()}
/> />
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>