model, boolean replace,
String lineDelimiter, String whitespacesIndent) {
StringBuilder text = new StringBuilder();
diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/ASTVisitor.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/ASTVisitor.java
index 31612bbc5..14a53cbaf 100644
--- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/ASTVisitor.java
+++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/ASTVisitor.java
@@ -21,6 +21,7 @@
import com.redhat.qute.parser.template.sections.EachSection;
import com.redhat.qute.parser.template.sections.ElseSection;
import com.redhat.qute.parser.template.sections.ForSection;
+import com.redhat.qute.parser.template.sections.FragmentSection;
import com.redhat.qute.parser.template.sections.IfSection;
import com.redhat.qute.parser.template.sections.IncludeSection;
import com.redhat.qute.parser.template.sections.InsertSection;
@@ -236,6 +237,21 @@ public boolean visit(ForSection node) {
return true;
}
+ /**
+ * Visits the given type-specific AST node.
+ *
+ * The default implementation does nothing and return true. Subclasses may
+ * reimplement.
+ *
+ *
+ * @param node the node to visit
+ * @return true
if the children of this node should be visited, and
+ * false
if the children of this node should be skipped
+ */
+ public boolean visit(FragmentSection node) {
+ return true;
+ }
+
/**
* Visits the given type-specific AST node.
*
@@ -596,6 +612,18 @@ public void endVisit(ForSection node) {
// default implementation: do nothing
}
+ /**
+ * End of visit the given type-specific AST node.
+ *
+ * The default implementation does nothing. Subclasses may reimplement.
+ *
+ *
+ * @param node the node to visit
+ */
+ public void endVisit(FragmentSection node) {
+ // default implementation: do nothing
+ }
+
/**
* End of visit the given type-specific AST node.
*
diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/SectionKind.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/SectionKind.java
index f74eb2c95..b887c4641 100644
--- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/SectionKind.java
+++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/SectionKind.java
@@ -16,6 +16,7 @@ public enum SectionKind {
EACH, //
EVAL, //
FOR, //
+ FRAGMENT, //
IF, //
ELSE, //
INCLUDE, //
diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/sections/DefaultSectionFactory.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/sections/DefaultSectionFactory.java
index 89edfa99e..1a37acad9 100644
--- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/sections/DefaultSectionFactory.java
+++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/sections/DefaultSectionFactory.java
@@ -24,6 +24,7 @@ public class DefaultSectionFactory implements SectionFactory {
factoryByTag = new HashMap<>();
factoryByTag.put(EachSection.TAG, (tag, start, end) -> new EachSection(start, end));
factoryByTag.put(ForSection.TAG, (tag, start, end) -> new ForSection(start, end));
+ factoryByTag.put(FragmentSection.TAG, (tag, start, end) -> new FragmentSection(start, end));
factoryByTag.put(IfSection.TAG, (tag, start, end) -> new IfSection(start, end));
factoryByTag.put(ElseSection.TAG, (tag, start, end) -> new ElseSection(start, end));
factoryByTag.put(IncludeSection.TAG, (tag, start, end) -> new IncludeSection(start, end));
diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/sections/FragmentSection.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/sections/FragmentSection.java
new file mode 100644
index 000000000..c2c0cd0e8
--- /dev/null
+++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/sections/FragmentSection.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+* Copyright (c) 2023 Red Hat Inc. and others.
+* All rights reserved. This program and the accompanying materials
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v20.html
+*
+* SPDX-License-Identifier: EPL-2.0
+*
+* Contributors:
+* Red Hat Inc. - initial API and implementation
+*******************************************************************************/
+package com.redhat.qute.parser.template.sections;
+
+import java.util.List;
+
+import com.redhat.qute.parser.template.ASTVisitor;
+import com.redhat.qute.parser.template.Parameter;
+import com.redhat.qute.parser.template.ParameterInfo;
+import com.redhat.qute.parser.template.ParametersInfo;
+import com.redhat.qute.parser.template.Section;
+import com.redhat.qute.parser.template.SectionKind;
+
+/**
+ * Fragment section AST node.
+ *
+ *
+ {#fragment id=item_aliases}
+ Aliases
+
+ {#for alias in aliases}
+ - {alias}
+ {/for}
+
+ {/fragment}
+ *
+ *
+ * @author Angelo ZERR
+ *
+ * @see https://quarkus.io/guides/qute-reference#fragments
+ */
+public class FragmentSection extends Section {
+
+ public static final String TAG = "fragment";
+
+ private static final String ID = "id";
+
+ private static final String RENDERED = "rendered";
+
+ private static final ParametersInfo PARAMETER_INFOS = ParametersInfo.builder() //
+ .addParameter(ID) //
+ .addParameter(new ParameterInfo(RENDERED, null, true)) //
+ .build();
+
+ public FragmentSection(int start, int end) {
+ super(TAG, start, end);
+ }
+
+ @Override
+ public SectionKind getSectionKind() {
+ return SectionKind.FRAGMENT;
+ }
+
+ @Override
+ public ParametersInfo getParametersInfo() {
+ return PARAMETER_INFOS;
+ }
+
+ @Override
+ protected void initializeParameters(List parameters) {
+ parameters.forEach(parameter -> {
+ parameter.setCanHaveExpression(false);
+ });
+ }
+
+ @Override
+ protected void accept0(ASTVisitor visitor) {
+ boolean visitChildren = visitor.visit(this);
+ if (visitChildren) {
+ List parameters = getParameters();
+ for (Parameter parameter : parameters) {
+ acceptChild(visitor, parameter);
+ }
+ acceptChildren(visitor, getChildren());
+ }
+ visitor.endVisit(this);
+ }
+}
diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/utils/DocumentationUtils.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/utils/DocumentationUtils.java
index 5350ca49e..14b07c8f1 100644
--- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/utils/DocumentationUtils.java
+++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/utils/DocumentationUtils.java
@@ -12,6 +12,8 @@
package com.redhat.qute.utils;
import static com.redhat.qute.commons.JavaElementInfo.getSimpleType;
+import static com.redhat.qute.ls.commons.snippets.SnippetRegistry.addLink;
+import static com.redhat.qute.ls.commons.snippets.SnippetRegistry.addLinks;
import java.net.URI;
import java.util.List;
@@ -282,6 +284,8 @@ public static MarkupContent getDocumentation(Snippet snippet, boolean markdown)
documentation.append(snippet.getDescription());
}
+ addLinks(snippet.getLinks(), documentation, markdown);
+
return createMarkupContent(documentation, markdown);
}
@@ -340,14 +344,9 @@ private static void addUrl(String url, StringBuilder documentation, boolean mark
if (!StringUtils.isEmpty(url)) {
documentation.append(System.lineSeparator());
documentation.append("See ");
- if (markdown) {
- documentation.append("[here](");
- documentation.append(url);
- documentation.append(")");
- } else {
- documentation.append(url);
- }
+ addLink(url, "here", documentation, markdown);
documentation.append(" for more informations.");
}
}
+
}
\ No newline at end of file
diff --git a/qute.ls/com.redhat.qute.ls/src/main/resources/com/redhat/qute/services/snippets/qute-snippets.json b/qute.ls/com.redhat.qute.ls/src/main/resources/com/redhat/qute/services/snippets/qute-snippets.json
index fadc31238..816a6616b 100644
--- a/qute.ls/com.redhat.qute.ls/src/main/resources/com/redhat/qute/services/snippets/qute-snippets.json
+++ b/qute.ls/com.redhat.qute.ls/src/main/resources/com/redhat/qute/services/snippets/qute-snippets.json
@@ -1,18 +1,49 @@
-{ "#each": {
- "prefix": ["each", "{#"],
+{
+ "#each": {
+ "prefix": [
+ "each",
+ "{#"
+ ],
"body": [
"{#each ${1:items}}",
"\t{it.${2:name}}$0",
"{/each}"
],
- "description": "Loop section with implicit alias"
+ "description": "Loop section with implicit alias",
+ "link": {
+ "url": "https://quarkus.io/guides/qute-reference#loop_section",
+ "label": "Loop section"
+ }
},
"#eval": {
"prefix": "eval",
"body": [
"{#eval ${1:content} /}$0"
],
- "description": "Parse and evaluate a template dynamically"
+ "description": "Parse and evaluate a template dynamically",
+ "link": {
+ "url": "https://quarkus.io/guides/qute-reference#eval_section",
+ "label": "Eval section"
+ }
+ },
+ "#fragment": {
+ "prefix": "fragment",
+ "body": [
+ "{#fragment id=\"${1:item}\"}",
+ "\t$0",
+ "{/fragment}"
+ ],
+ "description": "A fragment represents a part of the template that can be treated as a separate template, i.e. rendered separately.",
+ "link": [
+ {
+ "url": "https://quarkus.io/guides/qute-reference#fragments",
+ "label": "Fragments"
+ },
+ {
+ "url": "https://quarkus.io/guides/qute-reference#type_safe_fragments",
+ "label": "Type-safe Fragments"
+ }
+ ]
},
"#for": {
"prefix": "for",
@@ -21,7 +52,11 @@
"\t{${1:item}.${3:name}}$0",
"{/for}"
],
- "description": "Loop section with alias"
+ "description": "Loop section with alias",
+ "link": {
+ "url": "https://quarkus.io/guides/qute-reference#loop_section",
+ "label": "Loop section"
+ }
},
"#if": {
"prefix": "if",
@@ -30,7 +65,11 @@
"\t$0",
"{/if}"
],
- "description": "If section"
+ "description": "If section",
+ "link": {
+ "url": "https://quarkus.io/guides/qute-reference#if_section",
+ "label": "If section"
+ }
},
"#else": {
"prefix": "if-else",
@@ -41,7 +80,11 @@
"\t$0",
"{/if}"
],
- "description": "Else section"
+ "description": "Else section",
+ "link": {
+ "url": "https://quarkus.io/guides/qute-reference#if_section",
+ "label": "If section"
+ }
},
"#elseif": {
"prefix": "if-elseif",
@@ -54,7 +97,11 @@
"\t$0",
"{/if}"
],
- "description": "Else If section"
+ "description": "Else If section",
+ "link": {
+ "url": "https://quarkus.io/guides/qute-reference#if_section",
+ "label": "If section"
+ }
},
"#include": {
"prefix": "include",
@@ -63,7 +110,11 @@
"\t$0",
"{/include}"
],
- "description": "Include section"
+ "description": "Include section",
+ "link": {
+ "url": "https://quarkus.io/guides/qute-reference#include_helper",
+ "label": "Include section"
+ }
},
"#insert": {
"prefix": "insert",
@@ -72,7 +123,11 @@
"\t$0",
"{/insert}"
],
- "description": "Insert section"
+ "description": "Insert section",
+ "link": {
+ "url": "https://quarkus.io/guides/qute-reference#include_helper",
+ "label": "Include section"
+ }
},
"#let": {
"prefix": "let",
@@ -81,14 +136,22 @@
"\t$0",
"{/let}"
],
- "description": "Let section"
+ "description": "Let section",
+ "link": {
+ "url": "https://quarkus.io/guides/qute-reference#let_section",
+ "label": "Let section"
+ }
},
"#parameter": {
"prefix": "parameter",
"body": [
"{@${1:class} ${2:alias}}$0"
],
- "description": "Insert parameter declaration"
+ "description": "Insert parameter declaration",
+ "link": {
+ "url": "https://quarkus.io/guides/qute-reference#typesafe_expressions",
+ "label": "Typesafe expressions"
+ }
},
"#set": {
"prefix": "set",
@@ -97,7 +160,11 @@
"\t$0",
"{/set}"
],
- "description": "Let section"
+ "description": "Set section",
+ "link": {
+ "url": "https://quarkus.io/guides/qute-reference#let_section",
+ "label": "Let section"
+ }
},
"#switch": {
"prefix": "switch",
@@ -106,7 +173,11 @@
"\t{#case ${2:case}}$0",
"{/switch}"
],
- "description": "Switch section"
+ "description": "Switch section",
+ "link": {
+ "url": "https://quarkus.io/guides/qute-reference#when_section",
+ "label": "When section"
+ }
},
"#with": {
"prefix": "with",
@@ -115,7 +186,11 @@
"\t{${2:name}}$0",
"{/with}"
],
- "description": "With section"
+ "description": "With section",
+ "link": {
+ "url": "https://quarkus.io/guides/qute-reference#with_section",
+ "label": "With section"
+ }
},
"#when": {
"prefix": "when",
@@ -124,6 +199,10 @@
"\t{#is ${2:case}}$0",
"{/when}"
],
- "description": "When section"
+ "description": "When section",
+ "link": {
+ "url": "https://quarkus.io/guides/qute-reference#when_section",
+ "label": "When section"
+ }
}
}
diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/QuteAssert.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/QuteAssert.java
index 664f022c5..592fbbce1 100644
--- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/QuteAssert.java
+++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/QuteAssert.java
@@ -106,7 +106,7 @@ public class QuteAssert {
private static final String FILE_URI = "test.qute";
- public static final int SECTION_SNIPPET_SIZE = 14 /* #each, #for */ + 3 /* #user, #formElement */;
+ public static final int SECTION_SNIPPET_SIZE = 15 /* #each, #for, ... #fragment ... */ + 3 /* #user, #formElement */;
public static String getFileUri(String templateFile) {
return Paths.get(TEMPLATE_BASE_DIR + templateFile).toUri().toString();
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 0b3cfb6cf..a0605908d 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
@@ -511,7 +511,7 @@ public void quoteNoteClosed() throws Exception {
"{foo.getBytes('abcd)}";
testDiagnosticsFor(template, //
d(1, 22, 1, 22, QuteErrorCode.SyntaxError,
- "Parser error on line 2: unexpected non-text buffer at the end of the template - unterminated string literal: foo.getBytes('abcd)}",
+ "Parser error: unexpected non-text buffer at the end of the template - unterminated string literal: foo.getBytes('abcd)}",
DiagnosticSeverity.Error));
}
diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionWithLetSectionTest.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionWithLetSectionTest.java
index 9386df394..4563fa8f6 100644
--- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionWithLetSectionTest.java
+++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionWithLetSectionTest.java
@@ -94,7 +94,7 @@ public void autoClose() throws Exception {
testDiagnosticsFor(template, //
d(2, 6, 2, 6, QuteErrorCode.SyntaxError,
- "Parser error on line 3: no section start tag found for {/let}", DiagnosticSeverity.Error), //
+ "Parser error: no section start tag found for {/let}", DiagnosticSeverity.Error), //
d);
testCodeActionsFor(template, d, //
ca(d, te(0, 0, 0, 0, "{@java.lang.String name}\r\n")),
diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionWithNamespaceTest.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionWithNamespaceTest.java
index 5938ef20c..40840124d 100644
--- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionWithNamespaceTest.java
+++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsInExpressionWithNamespaceTest.java
@@ -130,7 +130,7 @@ public void badNamespace() throws Exception {
Diagnostic d = d(0, 1, 0, 2, QuteErrorCode.UndefinedNamespace, "No namespace resolver found for: `X`.",
DiagnosticSeverity.Warning);
testDiagnosticsFor(template,
- d(0, 0, 0, 3, QuteErrorCode.SyntaxError, "Parser error on line 1: empty expression found {X:}",
+ d(0, 0, 0, 3, QuteErrorCode.SyntaxError, "Parser error on: empty expression found {X:}",
DiagnosticSeverity.Error), //
d);
diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsSyntaxErrorTest.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsSyntaxErrorTest.java
index d14840779..4152f064d 100644
--- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsSyntaxErrorTest.java
+++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsSyntaxErrorTest.java
@@ -29,7 +29,7 @@ public class QuteDiagnosticsSyntaxErrorTest {
public void emptyParameterDeclaration() {
String template = "{@}";
testDiagnosticsFor(template, //
- d(0, 2, 0, 2, QuteErrorCode.SyntaxError, "Parser error on line 1: invalid parameter declaration {@}",
+ d(0, 2, 0, 2, QuteErrorCode.SyntaxError, "Parser error: invalid parameter declaration {@}",
DiagnosticSeverity.Error));
}
}
diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsWithIncludeSectionTest.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsWithIncludeSectionTest.java
index 2ecf6c753..27014e39a 100644
--- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsWithIncludeSectionTest.java
+++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/QuteDiagnosticsWithIncludeSectionTest.java
@@ -31,7 +31,7 @@ public void templateNotDefined() throws Exception {
testDiagnosticsFor(template, //
// error coming from the real Qute parser
d(0, 11, 0, 11, QuteErrorCode.SyntaxError,
- "Parser error on line 1: mandatory section parameters not declared for {#include /}: [template]",
+ "Parser error: mandatory section parameters not declared for {#include /}: [template]",
DiagnosticSeverity.Error), //
// error coming from Qute LS parser
d(0, 1, 0, 9, QuteErrorCode.TemplateNotDefined, "Template id must be defined as parameter.",
diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/hover/QuteHoverInTag.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/hover/QuteHoverInTag.java
index 392a97dce..233b33e22 100644
--- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/hover/QuteHoverInTag.java
+++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/hover/QuteHoverInTag.java
@@ -38,7 +38,10 @@ public void coreTag() throws Exception {
assertHover(template, "**#for** section tag " + //
System.lineSeparator() + //
System.lineSeparator() + //
- "Loop section with alias", //
+ "Loop section with alias" + //
+ System.lineSeparator() + //
+ System.lineSeparator() + //
+ "See [Loop section](https://quarkus.io/guides/qute-reference#loop_section) for more informations.", //
r(0, 1, 0, 5));
}
diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/hover/QuteHoverInUserTag.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/hover/QuteHoverInUserTag.java
index 2691a1448..c510915c8 100644
--- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/hover/QuteHoverInUserTag.java
+++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/hover/QuteHoverInUserTag.java
@@ -44,7 +44,11 @@ public void parameterPropertyPart() throws Exception {
System.lineSeparator() + //
"String org.acme.Item.name" + //
System.lineSeparator() + //
- "```", //
+ "```" + //
+ System.lineSeparator() + //
+ "---" + //
+ System.lineSeparator() + //
+ "The name of the item", //
r(1, 17, 1, 21));
}
@@ -68,7 +72,11 @@ public void itParameterPropertyPart() throws Exception {
System.lineSeparator() + //
"String org.acme.Item.name" + //
System.lineSeparator() + //
- "```", //
+ "```" + //
+ System.lineSeparator() + //
+ "---" + //
+ System.lineSeparator() + //
+ "The name of the item", //
r(1, 12, 1, 16));
}