Skip to content

Commit 2473f4e

Browse files
committed
fix: Fragment support between Java / Template file (#896)
Fixes #896 Signed-off-by: azerr <azerr@redhat.com>
1 parent 0f37ca5 commit 2473f4e

File tree

21 files changed

+1224
-871
lines changed

21 files changed

+1224
-871
lines changed

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,8 @@ dependencies {
161161
lsp ('com.redhat.microprofile:com.redhat.quarkus.ls:0.13.0') {
162162
transitive = false
163163
}
164-
implementation 'com.redhat.microprofile:com.redhat.qute.ls:0.13.0'
165-
lsp ('com.redhat.microprofile:com.redhat.qute.ls:0.13.0:uber') {
164+
implementation 'com.redhat.microprofile:com.redhat.qute.ls:0.14.0'
165+
lsp ('com.redhat.microprofile:com.redhat.qute.ls:0.14.0:uber') {
166166
transitive = false
167167
}
168168
implementation files(new File(buildDir, 'server')) {
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package org.acme.qute;
2+
3+
import java.math.BigDecimal;
4+
import java.util.ArrayList;
5+
import java.util.List;
6+
import java.util.Map;
7+
8+
import javax.ws.rs.GET;
9+
import javax.ws.rs.Path;
10+
import javax.ws.rs.Produces;
11+
import javax.ws.rs.core.MediaType;
12+
13+
import io.quarkus.qute.CheckedTemplate;
14+
import io.quarkus.qute.TemplateExtension;
15+
import io.quarkus.qute.TemplateInstance;
16+
17+
@Path("items2")
18+
public class ItemResourceWithFragment {
19+
20+
@CheckedTemplate
21+
static class Templates {
22+
static native TemplateInstance items(List<Item> items);
23+
static native TemplateInstance items$id1(List<Item> items);
24+
static native TemplateInstance items3$id2(List<Item> items);
25+
static native TemplateInstance items3$(List<Item> items);
26+
}
27+
28+
@CheckedTemplate(ignoreFragments = true)
29+
static class Templates2 {
30+
static native TemplateInstance items2(List<Item> items);
31+
static native TemplateInstance items2$id1(List<Item> items);
32+
static native TemplateInstance items2$id2(List<Item> items);
33+
}
34+
35+
@GET
36+
@Produces(MediaType.TEXT_HTML)
37+
public TemplateInstance get() {
38+
List<Item> items = new ArrayList<>();
39+
items.add(new Item(new BigDecimal(10), "Apple"));
40+
items.add(new Item(new BigDecimal(16), "Pear"));
41+
items.add(new Item(new BigDecimal(30), "Orange"));
42+
return Templates.items(items);
43+
}
44+
45+
/**
46+
* This template extension method implements the "discountedPrice" computed
47+
* property.
48+
*/
49+
@TemplateExtension
50+
static BigDecimal discountedPrice(Item item) {
51+
return item.price.multiply(new BigDecimal("0.9"));
52+
}
53+
54+
}

projects/qute/projects/maven/qute-quickstart/src/main/resources/templates/ItemResourceWithFragment/items.html

Whitespace-only changes.

projects/qute/projects/maven/qute-quickstart/src/main/resources/templates/ItemResourceWithFragment/items2$id1.html

Whitespace-only changes.

projects/qute/projects/maven/qute-quickstart/src/main/resources/templates/ItemResourceWithFragment/items2.html

Whitespace-only changes.

src/main/java/com/redhat/devtools/intellij/qute/psi/internal/QuteJavaConstants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ public class QuteJavaConstants {
4141

4242
public static final String OLD_CHECKED_TEMPLATE_ANNOTATION = "io.quarkus.qute.api.CheckedTemplate";
4343

44+
public static final String CHECKED_TEMPLATE_ANNOTATION_IGNORE_FRAGMENTS = "ignoreFragments";
45+
4446
// @TemplateExtension
4547

4648
public static final String TEMPLATE_EXTENSION_ANNOTATION = "io.quarkus.qute.TemplateExtension";

src/main/java/com/redhat/devtools/intellij/qute/psi/internal/java/AbstractQuteTemplateLinkCollector.java

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,15 @@
1717
import com.intellij.openapi.util.TextRange;
1818
import com.intellij.openapi.vfs.VfsUtilCore;
1919
import com.intellij.openapi.vfs.VirtualFile;
20-
import com.intellij.psi.JavaRecursiveElementVisitor;
21-
import com.intellij.psi.PsiAnnotation;
22-
import com.intellij.psi.PsiClass;
23-
import com.intellij.psi.PsiClassType;
24-
import com.intellij.psi.PsiElement;
25-
import com.intellij.psi.PsiField;
26-
import com.intellij.psi.PsiFile;
27-
import com.intellij.psi.PsiIdentifier;
28-
import com.intellij.psi.PsiLiteralValue;
29-
import com.intellij.psi.PsiMethod;
30-
import com.intellij.psi.PsiType;
20+
import com.intellij.psi.*;
3121
import com.intellij.psi.util.PsiTreeUtil;
3222
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.utils.IPsiUtils;
3323
import com.redhat.devtools.intellij.lsp4ij.LSPIJUtils;
3424
import com.redhat.devtools.intellij.qute.psi.internal.AnnotationLocationSupport;
3525
import com.redhat.devtools.intellij.qute.psi.utils.AnnotationUtils;
3626
import com.redhat.devtools.intellij.qute.psi.utils.PsiQuteProjectUtils;
3727
import com.redhat.devtools.intellij.qute.psi.utils.PsiTypeUtils;
28+
import com.redhat.devtools.intellij.qute.psi.utils.TemplatePathInfo;
3829
import org.eclipse.lsp4j.Range;
3930
import org.jetbrains.annotations.Nullable;
4031

@@ -45,6 +36,7 @@
4536

4637
import static com.redhat.devtools.intellij.qute.psi.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION;
4738
import static com.redhat.devtools.intellij.qute.psi.internal.QuteJavaConstants.OLD_CHECKED_TEMPLATE_ANNOTATION;
39+
import static com.redhat.devtools.intellij.qute.psi.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION_IGNORE_FRAGMENTS;
4840
import static com.redhat.devtools.intellij.qute.psi.internal.QuteJavaConstants.TEMPLATE_CLASS;
4941

5042
/**
@@ -113,7 +105,7 @@ public void visitField(PsiField node) {
113105
.getLocationExpressionFromConstructorParameter(node.getName());
114106
}
115107
String fieldName = node.getName();
116-
collectTemplateLink(node, locationExpression, getTypeDeclaration(node), null, fieldName);
108+
collectTemplateLink(node, locationExpression, getTypeDeclaration(node), null, fieldName, false);
117109
}
118110
super.visitField(node);
119111
}
@@ -141,46 +133,78 @@ public void visitClass(PsiClass node) {
141133
// @CheckedTemplate
142134
// public static class Templates {
143135
// public static native TemplateInstance book(Book book);
136+
boolean ignoreFragments = isIgnoreFragments(annotation);
144137
for(PsiMethod method : node.getMethods()) {
145-
collectTemplateLink(method, node);
138+
collectTemplateLink(method, node, ignoreFragments );
146139
}
147140
}
148141
}
149142
super.visitClass(node);
150143
levelTypeDecl--;
151144
}
152145

146+
/**
147+
* Returns true if @CheckedTemplate annotation declares that fragment must be
148+
* ignored and false otherwise.
149+
*
150+
* <code>
151+
* @CheckedTemplate(ignoreFragments=true)
152+
* </code>
153+
*
154+
* @param checkedTemplateAnnotation the CheckedTemplate annotation.
155+
*
156+
* @return true if @CheckedTemplate annotation declares that fragment must be
157+
* ignored and false otherwise.
158+
*/
159+
private static boolean isIgnoreFragments(PsiAnnotation checkedTemplateAnnotation) {
160+
Boolean ignoreFragment = null;
161+
try {
162+
for(PsiNameValuePair pair : checkedTemplateAnnotation.getParameterList().getAttributes()) {
163+
if (CHECKED_TEMPLATE_ANNOTATION_IGNORE_FRAGMENTS.equalsIgnoreCase(pair.getAttributeName())) {
164+
ignoreFragment = AnnotationUtils.getValueAsBoolean(pair);
165+
}
166+
}
167+
} catch (Exception e) {
168+
// Do nothing
169+
}
170+
return ignoreFragment != null ? ignoreFragment.booleanValue() : false;
171+
}
172+
153173
private static PsiClass getTypeDeclaration(PsiElement node) {
154174
return PsiTreeUtil.getParentOfType(node, PsiClass.class);
155175
}
156176

157177

158-
private void collectTemplateLink(PsiMethod methodDeclaration, PsiClass type) {
178+
private void collectTemplateLink(PsiMethod methodDeclaration, PsiClass type, boolean ignoreFragments) {
159179
String className = null;
160180
boolean innerClass = levelTypeDecl > 1;
161181
if (innerClass) {
162182
className = PsiTypeUtils.getSimpleClassName(typeRoot.getName());
163183
}
164184
String methodName = methodDeclaration.getName();
165-
collectTemplateLink(methodDeclaration, null, type, className, methodName);
185+
collectTemplateLink(methodDeclaration, null, type, className, methodName, ignoreFragments );
166186
}
167187

168188
private void collectTemplateLink(PsiElement fieldOrMethod, PsiLiteralValue locationAnnotation, PsiClass type, String className,
169-
String fieldOrMethodName) {
189+
String fieldOrMethodName, boolean ignoreFragment ) {
170190
try {
171191
String location = locationAnnotation != null && locationAnnotation.getValue() instanceof String ? (String) locationAnnotation.getValue() : null;
172192
Module project = utils.getModule();
173-
String templateFilePath = location != null ? PsiQuteProjectUtils.getTemplatePath(null, location)
174-
: PsiQuteProjectUtils.getTemplatePath(className, fieldOrMethodName);
193+
TemplatePathInfo templatePathInfo = location != null
194+
? PsiQuteProjectUtils.getTemplatePath(null, location, ignoreFragment)
195+
: PsiQuteProjectUtils.getTemplatePath(className, fieldOrMethodName, ignoreFragment);
196+
175197
VirtualFile templateFile = null;
176198
if (location == null) {
177-
templateFile = getTemplateFile(project, templateFilePath);
178-
templateFilePath = getRelativePath(templateFilePath, templateFile, project);
199+
templateFile = getTemplateFile(project, templatePathInfo.getTemplateUri());
200+
templatePathInfo = new TemplatePathInfo(
201+
getRelativePath(templatePathInfo.getTemplateUri(), templateFile, project),
202+
templatePathInfo.getFragmentId());
179203
} else {
180-
templateFile = getVirtualFile(project, templateFilePath, "");
204+
templateFile = getVirtualFile(project, templatePathInfo.getTemplateUri(), "");
181205
}
182206
collectTemplateLink(fieldOrMethod, locationAnnotation, type, className, fieldOrMethodName, location,
183-
templateFile, templateFilePath);
207+
templateFile, templatePathInfo);
184208
} catch (RuntimeException e) {
185209
LOGGER.log(Level.WARNING, "Error while creating Qute CodeLens for Java file.", e);
186210
}
@@ -245,7 +269,7 @@ protected Range createRange(PsiElement fieldOrMethod) {
245269
}
246270

247271
protected abstract void collectTemplateLink(PsiElement node, PsiLiteralValue locationAnnotation, PsiClass type,
248-
String className, String fieldOrMethodName, String location, VirtualFile templateFile, String templateFilePath);
272+
String className, String fieldOrMethodName, String location, VirtualFile templateFile, TemplatePathInfo templatePathInfo);
249273

250274
private static boolean isTemplateType(PsiType type) {
251275
if (type instanceof PsiClassType) {

src/main/java/com/redhat/devtools/intellij/qute/psi/internal/java/QuteErrorCode.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313

1414
public enum QuteErrorCode implements IQuteErrorCode {
1515

16-
NoMatchingTemplate("No template matching the path {0} could be found for: {1}");
16+
NoMatchingTemplate("No template matching the path {0} could be found for: {1}"),
17+
FragmentNotDefined("Fragment [{0}] not defined in template {1}");
1718

1819
private final String rawMessage;
1920

0 commit comments

Comments
 (0)