From 21ef00e91d6b8b0913c0a84bd3a11dc883110223 Mon Sep 17 00:00:00 2001 From: azerr Date: Thu, 7 Nov 2024 13:43:23 +0100 Subject: [PATCH] Qute expression escape support. Signed-off-by: azerr --- .../template/scanner/TemplateScanner.java | 91 ++++++++++--------- .../QuteDiagnosticsInExpressionTest.java | 6 ++ 2 files changed, 53 insertions(+), 44 deletions(-) diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/scanner/TemplateScanner.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/scanner/TemplateScanner.java index a695af59e..594e15bf5 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/scanner/TemplateScanner.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/scanner/TemplateScanner.java @@ -66,51 +66,54 @@ protected TokenType internalScan() { case WithinContent: { if (stream.advanceIfChar('{')) { - // A valid identifier must start with a digit, alphabet, underscore, comment - // delimiter, cdata start delimiter or a tag command (e.g. # for sections) - // see - // https://github.com/quarkusio/quarkus/blob/7164bfa115d9096a3ba0b2929c98f89ac01c2dce/independent-projects/qute/core/src/main/java/io/quarkus/qute/Parser.java#L332 - if (stream.advanceIfChar('!')) { - // Comment -> {! This is a comment !} - state = ScannerState.WithinComment; - return finishToken(offset, TokenType.StartComment); - } else if (stream.advanceIfChar('|')) { - // Unparsed Character Data -> {| |} - state = ScannerState.WithinCDATA; - return finishToken(offset, TokenType.CDATATagOpen); - } else if (stream.advanceIfChar('[')) { - // Unparsed Character Data (old syntax) -> {[ ]} - state = ScannerState.WithinCDATAOld; - return finishToken(offset, TokenType.CDATAOldTagOpen); - } else if (stream.advanceIfChar('#')) { - // Section (start) tag -> {#if - state = ScannerState.AfterOpeningStartTag; - return finishToken(offset, TokenType.StartTagOpen); - } else if (stream.advanceIfChar('/')) { - if (stream.advanceIfChar('}')) { - // Section (end) tag with name optional syntax -> {/} - state = ScannerState.WithinContent; - return finishToken(offset, TokenType.EndTagSelfClose); - } - // Section (end) tag -> {/if} - state = ScannerState.AfterOpeningEndTag; - return finishToken(offset, TokenType.EndTagOpen); - } else if (stream.advanceIfChar('@')) { - // Parameter declaration -> {@org.acme.Foo foo} - state = ScannerState.WithinParameterDeclaration; - return finishToken(offset, TokenType.StartParameterDeclaration); - } else { - int ch = stream.peekChar(); - if (isValidIdentifierStart(ch)) { - // Expression - state = ScannerState.WithinExpression; - return finishToken(offset, TokenType.StartExpression); + // check if the bracket is not escaped + if (!(stream.peekCharAtOffset(stream.pos() - 2) == '\\')) { + // A valid identifier must start with a digit, alphabet, underscore, comment + // delimiter, cdata start delimiter or a tag command (e.g. # for sections) + // see + // https://github.com/quarkusio/quarkus/blob/7164bfa115d9096a3ba0b2929c98f89ac01c2dce/independent-projects/qute/core/src/main/java/io/quarkus/qute/Parser.java#L332 + if (stream.advanceIfChar('!')) { + // Comment -> {! This is a comment !} + state = ScannerState.WithinComment; + return finishToken(offset, TokenType.StartComment); + } else if (stream.advanceIfChar('|')) { + // Unparsed Character Data -> {| |} + state = ScannerState.WithinCDATA; + return finishToken(offset, TokenType.CDATATagOpen); + } else if (stream.advanceIfChar('[')) { + // Unparsed Character Data (old syntax) -> {[ ]} + state = ScannerState.WithinCDATAOld; + return finishToken(offset, TokenType.CDATAOldTagOpen); + } else if (stream.advanceIfChar('#')) { + // Section (start) tag -> {#if + state = ScannerState.AfterOpeningStartTag; + return finishToken(offset, TokenType.StartTagOpen); + } else if (stream.advanceIfChar('/')) { + if (stream.advanceIfChar('}')) { + // Section (end) tag with name optional syntax -> {/} + state = ScannerState.WithinContent; + return finishToken(offset, TokenType.EndTagSelfClose); + } + // Section (end) tag -> {/if} + state = ScannerState.AfterOpeningEndTag; + return finishToken(offset, TokenType.EndTagOpen); + } else if (stream.advanceIfChar('@')) { + // Parameter declaration -> {@org.acme.Foo foo} + state = ScannerState.WithinParameterDeclaration; + return finishToken(offset, TokenType.StartParameterDeclaration); } else { - // Text node, increment position if needed - if (!stream.eos()) { - stream.advance(1); + int ch = stream.peekChar(); + if (isValidIdentifierStart(ch)) { + // Expression + state = ScannerState.WithinExpression; + return finishToken(offset, TokenType.StartExpression); + } else { + // Text node, increment position if needed + if (!stream.eos()) { + stream.advance(1); + } } } } diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionTest.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionTest.java index e92962656..dfb2eda1e 100644 --- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionTest.java +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionTest.java @@ -684,4 +684,10 @@ public void undefinedObjectPartWithKwownMethodResolver() throws Exception { d(0, 1, 0, 6, QuteErrorCode.UndefinedObject, "`items` cannot be resolved to an object.", DiagnosticSeverity.Warning)); } + + @Test + public void escape() throws Exception { + String template = "function gtag()\\{dataLayer.push(arguments);\\}"; + testDiagnosticsFor(template); + } }