Merge pull request #173 from ironcalc/bugfix/nicolas-format-issue
Bugfix/nicolas format issue
This commit is contained in:
@@ -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!(
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user