diff --git a/src/components/composer/composer/abstract_composer_store.ts b/src/components/composer/composer/abstract_composer_store.ts index 7d4a507d81..f04975fa5d 100644 --- a/src/components/composer/composer/abstract_composer_store.ts +++ b/src/components/composer/composer/abstract_composer_store.ts @@ -318,9 +318,20 @@ export abstract class AbstractComposerStore extends SpreadsheetStore { return; } - const missingParenthesis = this.getNumberOfMissingParenthesis(tokens); - if (missingParenthesis > 0) { - tokens.push(...Array(missingParenthesis).fill({ value: ")", type: "RIGHT_PAREN" })); + const missingSymbols = this.getMissingSymbols(this.currentTokens); + if (missingSymbols) { + for (const symb of missingSymbols) { + const typeOfSymb: "RIGHT_PAREN" | "RIGHT_BRACE" = + symb === ")" ? "RIGHT_PAREN" : "RIGHT_BRACE"; + const lastStart = tokens[tokens.length - 1].start; + tokens.push({ + value: symb, + type: typeOfSymb, + start: lastStart + 1, + end: lastStart + 2, + length: 1, + }); + } } let hoveredContextTokens = tokens; @@ -470,10 +481,8 @@ export abstract class AbstractComposerStore extends SpreadsheetStore { } if (content) { if (isFormula(content)) { - const missing = this.getNumberOfMissingParenthesis(this.currentTokens); - if (missing > 0) { - content += concat(new Array(missing).fill(")")); - } + const missingSymbols = this.getMissingSymbols(this.currentTokens); + content += concat(missingSymbols); } } this.confirmEdition(content); @@ -1011,9 +1020,25 @@ export abstract class AbstractComposerStore extends SpreadsheetStore { return false; } - private getNumberOfMissingParenthesis(tokens: EnrichedToken[]): number { - const left = tokens.filter((t) => t.type === "LEFT_PAREN").length; - const right = tokens.filter((t) => t.type === "RIGHT_PAREN").length; - return left - right; + private getMissingSymbols(tokens: EnrichedToken[]): (")" | "}")[] { + const stack: (")" | "}")[] = []; + for (const symb of tokens) { + switch (symb.value) { + case "(": + stack.push(")"); + break; + case "{": + stack.push("}"); + break; + case ")": + case "}": + if (stack.length > 0 && stack[stack.length - 1] === symb.value) { + stack.pop(); + } + break; + } + } + stack.reverse(); + return stack; } } diff --git a/tests/composer/composer_hover.test.ts b/tests/composer/composer_hover.test.ts index d24635df0f..81185c4c35 100644 --- a/tests/composer/composer_hover.test.ts +++ b/tests/composer/composer_hover.test.ts @@ -251,6 +251,28 @@ describe("Composer hover", () => { expect(".o-speech-bubble").toHaveText("1"); }); + test("Hovering an unfinished formula add the missing braces before evaluating", async () => { + await typeInComposer("={1,2,3"); + await hoverComposerContent("="); + expect(".o-speech-bubble").toHaveText("{1,2,3}"); + }); + + test("Hovering an unfinished formula add the missing parenthesis then braces before evaluating", async () => { + await typeInComposer("={1,2,SUM(3,4"); + await hoverComposerContent("="); + expect(".o-speech-bubble").toHaveText("{1,2,7}"); + await hoverComposerContent("SUM"); + expect(".o-speech-bubble").toHaveText("7"); + }); + + test("Hovering an unfinished formula add the missing braces then parenthesis before evaluating", async () => { + await typeInComposer("=SUM(1,2,{3,4"); + await hoverComposerContent("="); + expect(".o-speech-bubble").toHaveText("10"); + await hoverComposerContent("{"); + expect(".o-speech-bubble").toHaveText("{3,4}"); + }); + test("Hovering elements do nothing if the selection start and end are different", async () => { await typeInComposer("=12"); composerStore.changeComposerCursorSelection(0, 2);