formula: don't take the blank before an operator into the wrapper

The operand of an @ or of a union list ends where an operator further
out ends it, and the whitespace in front of that operator was still
inside it. So the blank was written inside the call parentheses, and
since a range ending in whitespace is no longer one parenthesised
group, the operand got a second pair of parentheses on top of the
ones it had - @(A1) + 1 came out as _xlfn.SINGLE((A1) )+ 1.

The wrapper now ends in front of those tokens. A blank before the #
stays with the operand, that one is the operator being rewritten.

Signed-off-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>
Change-Id: Ie6fe2df4e3e05b0ef845ebdb8a1aedb54b3f2a66
Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/10851
Tested-by: Tomaž Vajngerl <tomaz.vajngerl@collabora.com>
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit fd39c3a52d1cab7c0429bb98c4749bbfed088e6a)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/210478
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
Tomaž Vajngerl
2026-09-15 11:16:16 +02:00
committed by Xisco Fauli
parent 95e804b637
commit a074008d58
2 changed files with 20 additions and 3 deletions
+15 -3
View File
@@ -120,6 +120,7 @@ private:
};
OpCode opCodeAt(sal_uInt16 nPosition) const;
sal_uInt16 endWithoutTrailingWhitespace(sal_uInt16 nBegin, sal_uInt16 nEnd) const;
sal_uInt16 literalOffsetArgument(sal_uInt16 nPosition) const;
bool isCallBeforeArguments(OpCode eOp, sal_uInt16 nPosition) const;
bool isOneParenthesizedGroup(sal_uInt16 nBegin, sal_uInt16 nEnd) const;
@@ -143,6 +144,14 @@ OpCode RewriteCollector::opCodeAt(sal_uInt16 nPosition) const
return mrTokens.TokenAt(nPosition)->GetOpCode();
}
// An operand stops before the whitespace in front of the operator that ends it.
sal_uInt16 RewriteCollector::endWithoutTrailingWhitespace(sal_uInt16 nBegin, sal_uInt16 nEnd) const
{
while (nEnd > nBegin && isWhitespaceOpCode(opCodeAt(sal_uInt16(nEnd - 1))))
--nEnd;
return nEnd;
}
// Position of the first argument if the token at nPosition opens an OFFSET() call with a
// literal string or number there, NO_POSITION otherwise. OFFSET() needs a reference, so a
// literal cannot be written out in a way any reader accepts.
@@ -260,8 +269,9 @@ void RewriteCollector::closeSingleValues(size_t nScope, sal_uInt16 nEnd)
// An empty operand gets no wrapper.
if (rSingle.mbHasOperand)
{
mrWrappers.push_back({ rSingle.mnBegin, nEnd, ocSingleValue,
!isOneParenthesizedGroup(rSingle.mnBegin, nEnd) });
const sal_uInt16 nOperandEnd = endWithoutTrailingWhitespace(rSingle.mnBegin, nEnd);
mrWrappers.push_back({ rSingle.mnBegin, nOperandEnd, ocSingleValue,
!isOneParenthesizedGroup(rSingle.mnBegin, nOperandEnd) });
// The wrapper now encloses the expression, so the expression starts at the
// wrapper. Whitespace the scope start had skipped is inside the wrapper too,
// so pull that start back as well.
@@ -291,7 +301,9 @@ void RewriteCollector::closeUnionList(sal_uInt16 nEnd, bool bMayTakeScopeParenth
if (!(bMayTakeScopeParenthesis && rScope.mbGroupParenthesis
&& rScope.mnListStart == rScope.mnContentStart))
{
mrWrappers.push_back({ rScope.mnListStart, nEnd, ocNone, true });
mrWrappers.push_back({ rScope.mnListStart,
endWithoutTrailingWhitespace(rScope.mnListStart, nEnd), ocNone,
true });
}
rScope.mnListStart = NO_POSITION;
}