diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelFragment.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelFragment.java new file mode 100644 index 000000000..1f28a28bf --- /dev/null +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelFragment.java @@ -0,0 +1,35 @@ +/******************************************************************************* +* 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.commons.datamodel; + +import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; + +public class DataModelFragment extends DataModelParameters { + + private String id; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + public String toString() { + ToStringBuilder b = new ToStringBuilder(this); + b.add("id", this.id); + b.add("parameters", this.getParameters()); + return b.toString(); + } +} diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelParameters.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelParameters.java new file mode 100644 index 000000000..ff1cdb248 --- /dev/null +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelParameters.java @@ -0,0 +1,119 @@ +/******************************************************************************* +* 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.commons.datamodel; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class DataModelParameters { + + private String sourceType; + + private String sourceMethod; + + private List parameters; + + private transient Map parametersMap; + + /** + * Returns the Java source type where this data model template is defined. + * + * @return the Java source type where this data model template is defined. + */ + public String getSourceType() { + return sourceType; + } + + /** + * Set the Java source type where this data model template is defined. + * + * @param sourceType the Java source type where this data model template is + * defined. + */ + public void setSourceType(String sourceType) { + this.sourceType = sourceType; + } + + /** + * Returns the Java source method where this data model template is defined and + * null otherwise. + * + * @return the Java source method where this data model template is defined and + * null otherwise. + */ + public String getSourceMethod() { + return sourceMethod; + } + + /** + * Set the Java source method where this data model template is defined and null + * otherwise. + * + * @param sourceMethod the Java source method where this data model template is + * defined and null otherwise. + */ + public void setSourceMethod(String sourceMethod) { + this.sourceMethod = sourceMethod; + } + + /** + * Returns the list of data model parameters. + * + * @return the list of data model parameters. + */ + public List getParameters() { + return parameters; + } + + /** + * Set the list of data model parameters. + * + * @param parameters the list of data model parameters. + */ + public void setParameters(List parameters) { + this.parameters = parameters; + } + + /** + * Returns the parameter from the given key and null otherwise. + * + * @param key the parameter key. + * + * @return the parameter from the given key and null otherwise. + */ + public T getParameter(String key) { + List parameters = getParameters(); + if (parameters == null) { + return null; + } + return getParametersMap().get(key); + } + + public void addParameter(T parameter) { + if (parameters == null) { + parameters = new ArrayList<>(); + } + parameters.add(parameter); + getParametersMap().put(parameter.getKey(), parameter); + } + + private Map getParametersMap() { + if (parametersMap == null) { + parametersMap = parameters.stream() + .collect(Collectors.toMap(DataModelParameter::getKey, Function.identity())); + } + return parametersMap; + } +} diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelTemplate.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelTemplate.java index 34e68d04e..e87ab0e9d 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelTemplate.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/datamodel/DataModelTemplate.java @@ -13,9 +13,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; @@ -27,19 +24,13 @@ * * @param data model parameter. */ -public class DataModelTemplate { +public class DataModelTemplate extends DataModelParameters { private String templateUri; - private String sourceType; - - private String sourceMethod; - private String sourceField; - - private List parameters; - private transient Map parametersMap; + private List> fragments; /** * Returns the template Uri. @@ -59,47 +50,6 @@ public void setTemplateUri(String templateUri) { this.templateUri = templateUri; } - /** - * Returns the Java source type where this data model template is defined. - * - * @return the Java source type where this data model template is defined. - */ - public String getSourceType() { - return sourceType; - } - - /** - * Set the Java source type where this data model template is defined. - * - * @param sourceType the Java source type where this data model template is - * defined. - */ - public void setSourceType(String sourceType) { - this.sourceType = sourceType; - } - - /** - * Returns the Java source method where this data model template is defined and - * null otherwise. - * - * @return the Java source method where this data model template is defined and - * null otherwise. - */ - public String getSourceMethod() { - return sourceMethod; - } - - /** - * Set the Java source method where this data model template is defined and null - * otherwise. - * - * @param sourceMethod the Java source method where this data model template is - * defined and null otherwise. - */ - public void setSourceMethod(String sourceMethod) { - this.sourceMethod = sourceMethod; - } - /** * Returns the Java source field where this data model template is defined and * null otherwise. @@ -122,63 +72,46 @@ public void setSourceField(String sourceField) { this.sourceField = sourceField; } - /** - * Returns the list of data model parameters. - * - * @return the list of data model parameters. - */ - public List getParameters() { - return parameters; + public void addFragment(DataModelFragment fragment) { + if (fragments == null) { + fragments = new ArrayList<>(); + } + fragments.add(fragment); } - /** - * Set the list of data model parameters. - * - * @param parameters the list of data model parameters. - */ - public void setParameters(List parameters) { - this.parameters = parameters; + public List> getFragments() { + return fragments; } - /** - * Returns the parameter from the given key and null otherwise. - * - * @param key the parameter key. - * - * @return the parameter from the given key and null otherwise. - */ - public T getParameter(String key) { - List parameters = getParameters(); - if (parameters == null) { - return null; - } - return getParametersMap().get(key); + public void setFragments(List> fragments) { + this.fragments = fragments; } - public void addParameter(T parameter) { - if (parameters == null) { - parameters = new ArrayList<>(); + public DataModelFragment getFragment(String fragmentId) { + if (fragmentId == null) { + return null; } - parameters.add(parameter); - getParametersMap().put(parameter.getKey(), parameter); - } - - private Map getParametersMap() { - if (parametersMap == null) { - parametersMap = parameters.stream() - .collect(Collectors.toMap(DataModelParameter::getKey, Function.identity())); + List> fragments = getFragments(); + if (fragments == null || fragments.isEmpty()) { + return null; + } + for (DataModelFragment fragment : fragments) { + if (fragmentId.equals(fragment.getId())) { + return fragment; + } } - return parametersMap; + return null; } @Override public String toString() { ToStringBuilder b = new ToStringBuilder(this); b.add("templateUri", this.templateUri); - b.add("sourceType", this.sourceType); - b.add("sourceMethod", this.sourceMethod); + b.add("sourceType", this.getSourceType()); + b.add("sourceMethod", this.getSourceMethod()); b.add("sourceField", this.sourceField); - b.add("parameters", this.parameters); + b.add("parameters", this.getParameters()); + b.add("fragments", this.getFragments()); return b.toString(); } } diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/QuteJavaConstants.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/QuteJavaConstants.java index 253fd03c8..6396c2136 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/QuteJavaConstants.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/QuteJavaConstants.java @@ -41,6 +41,8 @@ public class QuteJavaConstants { public static final String OLD_CHECKED_TEMPLATE_ANNOTATION = "io.quarkus.qute.api.CheckedTemplate"; + public static final String CHECKED_TEMPLATE_ANNOTATION_IGNORE_FRAGMENTS = "ignoreFragments"; + // @TemplateExtension public static final String TEMPLATE_EXTENSION_ANNOTATION = "io.quarkus.qute.TemplateExtension"; diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/AbstractQuteTemplateLinkCollector.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/AbstractQuteTemplateLinkCollector.java index dbc89205c..22488cc87 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/AbstractQuteTemplateLinkCollector.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/AbstractQuteTemplateLinkCollector.java @@ -12,6 +12,7 @@ package com.redhat.qute.jdt.internal.java; import static com.redhat.qute.jdt.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION; +import static com.redhat.qute.jdt.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION_IGNORE_FRAGMENTS; import static com.redhat.qute.jdt.internal.QuteJavaConstants.OLD_CHECKED_TEMPLATE_ANNOTATION; import static com.redhat.qute.jdt.internal.QuteJavaConstants.TEMPLATE_CLASS; @@ -28,6 +29,7 @@ import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.Annotation; import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.SimpleName; @@ -44,6 +46,7 @@ import com.redhat.qute.jdt.utils.IJDTUtils; import com.redhat.qute.jdt.utils.JDTQuteProjectUtils; import com.redhat.qute.jdt.utils.JDTTypeUtils; +import com.redhat.qute.jdt.utils.TemplatePathInfo; /** * Abstract class which collects {@link MethodDeclaration} or @@ -66,6 +69,8 @@ public abstract class AbstractQuteTemplateLinkCollector extends ASTVisitor { private static final String PREFERRED_SUFFIX = ".html"; // TODO make it configurable + private static final boolean FRAGMENT_SUPPORT = true; // TODO make it configurable + protected final ITypeRoot typeRoot; protected final IJDTUtils utils; protected final IProgressMonitor monitor; @@ -118,7 +123,7 @@ public boolean visit(FieldDeclaration node) { .getLocationExpressionFromConstructorParameter(variable.getName().getIdentifier()); } String fieldName = variable.getName().getIdentifier(); - collectTemplateLink(node, locationExpression, getTypeDeclaration(node), null, fieldName); + collectTemplateLink(node, locationExpression, getTypeDeclaration(node), null, fieldName, false); } } return super.visit(node); @@ -151,10 +156,11 @@ public boolean visit(TypeDeclaration node) { // @CheckedTemplate // public static class Templates { // public static native TemplateInstance book(Book book); + boolean ignoreFragments = isIgnoreFragments(annotation); List body = node.bodyDeclarations(); for (Object declaration : body) { if (declaration instanceof MethodDeclaration) { - collectTemplateLink((MethodDeclaration) declaration, node); + collectTemplateLink((MethodDeclaration) declaration, node, ignoreFragments); } } } @@ -163,6 +169,18 @@ public boolean visit(TypeDeclaration node) { return super.visit(node); } + private static boolean isIgnoreFragments(Annotation checkedTemplateAnnotation) { + Boolean ignoreFragment = null; + try { + Expression ignoreFragmentExpr = AnnotationUtils.getAnnotationMemberValueExpression( + checkedTemplateAnnotation, CHECKED_TEMPLATE_ANNOTATION_IGNORE_FRAGMENTS); + ignoreFragment = AnnotationUtils.getBoolean(ignoreFragmentExpr); + } catch (Exception e) { + // Do nothing + } + return ignoreFragment != null ? ignoreFragment.booleanValue() : false; + } + @Override public void endVisit(TypeDeclaration node) { levelTypeDecl--; @@ -177,32 +195,36 @@ private static TypeDeclaration getTypeDeclaration(ASTNode node) { return parent != null && parent.getNodeType() == ASTNode.TYPE_DECLARATION ? (TypeDeclaration) parent : null; } - private void collectTemplateLink(MethodDeclaration methodDeclaration, TypeDeclaration type) { + private void collectTemplateLink(MethodDeclaration methodDeclaration, TypeDeclaration type, + boolean ignoreFragment) { String className = null; boolean innerClass = levelTypeDecl > 1; if (innerClass) { className = JDTTypeUtils.getSimpleClassName(typeRoot.getElementName()); } String methodName = methodDeclaration.getName().getIdentifier(); - collectTemplateLink(methodDeclaration, null, type, className, methodName); + collectTemplateLink(methodDeclaration, null, type, className, methodName, ignoreFragment); } private void collectTemplateLink(ASTNode fieldOrMethod, StringLiteral locationAnnotation, TypeDeclaration type, - String className, String fieldOrMethodName) { + String className, String fieldOrMethodName, boolean ignoreFragment) { try { String location = locationAnnotation != null ? locationAnnotation.getLiteralValue() : null; IProject project = typeRoot.getJavaProject().getProject(); - String templateFilePath = location != null ? JDTQuteProjectUtils.getTemplatePath(null, location) - : JDTQuteProjectUtils.getTemplatePath(className, fieldOrMethodName); + TemplatePathInfo templatePathInfo = location != null + ? JDTQuteProjectUtils.getTemplatePath(null, location, ignoreFragment) + : JDTQuteProjectUtils.getTemplatePath(className, fieldOrMethodName, ignoreFragment); IFile templateFile = null; if (location == null) { - templateFile = getTemplateFile(project, templateFilePath); - templateFilePath = templateFile.getLocation().makeRelativeTo(project.getLocation()).toString(); + templateFile = getTemplateFile(project, templatePathInfo.getTemplateUri()); + templatePathInfo = new TemplatePathInfo( + templateFile.getLocation().makeRelativeTo(project.getLocation()).toString(), + templatePathInfo.getFragmentId()); } else { - templateFile = project.getFile(templateFilePath); + templateFile = project.getFile(templatePathInfo.getTemplateUri()); } collectTemplateLink(fieldOrMethod, locationAnnotation, type, className, fieldOrMethodName, location, - templateFile, templateFilePath); + templateFile, templatePathInfo); } catch (JavaModelException e) { LOGGER.log(Level.SEVERE, "Error while creating Qute CodeLens for Java file.", e); } @@ -229,8 +251,8 @@ protected Range createRange(ASTNode fieldOrMethod) throws JavaModelException { } protected abstract void collectTemplateLink(ASTNode node, ASTNode locationAnnotation, TypeDeclaration type, - String className, String fieldOrMethodName, String location, IFile templateFile, String templateFilePath) - throws JavaModelException; + String className, String fieldOrMethodName, String location, IFile templateFile, + TemplatePathInfo templatePathInfo) throws JavaModelException; private static IFile getTemplateFile(IProject project, String templateFilePathWithoutExtension) { for (String suffix : suffixes) { diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaCodeLensCollector.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaCodeLensCollector.java index 15360eeb4..6cb881e60 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaCodeLensCollector.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaCodeLensCollector.java @@ -22,7 +22,6 @@ import org.eclipse.jdt.core.ITypeRoot; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.ASTNode; -import org.eclipse.jdt.core.dom.FieldDeclaration; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.MethodDeclaration; import org.eclipse.jdt.core.dom.SingleVariableDeclaration; @@ -37,6 +36,7 @@ import com.redhat.qute.jdt.QuteCommandConstants; import com.redhat.qute.jdt.utils.IJDTUtils; import com.redhat.qute.jdt.utils.JDTQuteProjectUtils; +import com.redhat.qute.jdt.utils.TemplatePathInfo; /** * Report codelens for opening/creating Qute template for: @@ -53,6 +53,8 @@ public class QuteJavaCodeLensCollector extends AbstractQuteTemplateLinkCollector private static final String QUTE_COMMAND_OPEN_URI_MESSAGE = "Open `{0}`"; + private static final String QUTE_COMMAND_OPEN_URI_WITH_FRAGMENT_MESSAGE = "Open `{0}` fragment of `{1}`"; + private static final String QUTE_COMMAND_GENERATE_TEMPLATE_MESSAGE = "Create `{0}`"; private final List lenses; @@ -64,21 +66,27 @@ public QuteJavaCodeLensCollector(ITypeRoot typeRoot, List lenses, IJDT } @Override - protected void collectTemplateLink(ASTNode fieldOrMethod, ASTNode locationAnnotation, TypeDeclaration type, String className, String fieldOrMethodName, - String location, IFile templateFile, String templateFilePath) throws JavaModelException { + protected void collectTemplateLink(ASTNode fieldOrMethod, ASTNode locationAnnotation, TypeDeclaration type, + String className, String fieldOrMethodName, String location, IFile templateFile, + TemplatePathInfo templatePathInfo) throws JavaModelException { Command command = null; + String templateUri = templatePathInfo.getTemplateUri(); + String fragmentId = templatePathInfo.getFragmentId(); if (templateFile.exists()) { - command = new Command(MessageFormat.format(QUTE_COMMAND_OPEN_URI_MESSAGE, templateFilePath), // + String title = fragmentId != null + ? MessageFormat.format(QUTE_COMMAND_OPEN_URI_WITH_FRAGMENT_MESSAGE, fragmentId, templateUri) + : MessageFormat.format(QUTE_COMMAND_OPEN_URI_MESSAGE, templateUri); + command = new Command(title, // QuteCommandConstants.QUTE_COMMAND_OPEN_URI, - Arrays.asList(templateFile.getLocationURI().toString())); + Arrays.asList(templateFile.getLocationURI().toString(), fragmentId)); } else { List parameters = createParameters(fieldOrMethod); GenerateTemplateInfo info = new GenerateTemplateInfo(); info.setParameters(parameters); info.setProjectUri(JDTQuteProjectUtils.getProjectUri(typeRoot.getJavaProject())); info.setTemplateFileUri(templateFile.getLocationURI().toString()); - info.setTemplateFilePath(templateFilePath); - command = new Command(MessageFormat.format(QUTE_COMMAND_GENERATE_TEMPLATE_MESSAGE, templateFilePath), // + info.setTemplateFilePath(templateUri); + command = new Command(MessageFormat.format(QUTE_COMMAND_GENERATE_TEMPLATE_MESSAGE, templateUri), // QuteCommandConstants.QUTE_COMMAND_GENERATE_TEMPLATE_FILE, Arrays.asList(info)); } Range range = utils.toRange(typeRoot, fieldOrMethod.getStartPosition(), fieldOrMethod.getLength()); @@ -93,11 +101,6 @@ private static List createParameters(ASTNode node) { return Collections.emptyList(); } - private static List createParameter(FieldDeclaration node) { - List parameters = new ArrayList<>(); - return parameters; - } - private static List createParameter(MethodDeclaration method) { List parameters = new ArrayList<>(); @SuppressWarnings("rawtypes") diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaDiagnosticsCollector.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaDiagnosticsCollector.java index 21e2ff878..fdef516f8 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaDiagnosticsCollector.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaDiagnosticsCollector.java @@ -26,6 +26,7 @@ import org.eclipse.lsp4j.Range; import com.redhat.qute.jdt.utils.IJDTUtils; +import com.redhat.qute.jdt.utils.TemplatePathInfo; /** * Report diagnostics error for non existing Qute template for: @@ -52,8 +53,8 @@ public QuteJavaDiagnosticsCollector(ITypeRoot typeRoot, List diagnos @Override protected void collectTemplateLink(ASTNode fieldOrMethod, ASTNode locationAnnotation, TypeDeclaration type, - String className, String fieldOrMethodName, String location, IFile templateFile, String templateFilePath) - throws JavaModelException { + String className, String fieldOrMethodName, String location, IFile templateFile, + TemplatePathInfo templatePathInfo) throws JavaModelException { if (!templateFile.exists()) { // No template matching the path HelloResource/index could be found for: // org.acme.HelloResource$Templates.index diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaDocumentLinkCollector.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaDocumentLinkCollector.java index 7260d81c9..e553f8f2e 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaDocumentLinkCollector.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/java/QuteJavaDocumentLinkCollector.java @@ -24,6 +24,7 @@ import org.eclipse.lsp4j.Range; import com.redhat.qute.jdt.utils.IJDTUtils; +import com.redhat.qute.jdt.utils.TemplatePathInfo; /** * Report document link for opening/creating Qute template for: @@ -52,10 +53,10 @@ public QuteJavaDocumentLinkCollector(ITypeRoot typeRoot, List link @Override protected void collectTemplateLink(ASTNode fieldOrMethod, ASTNode locationAnnotation, TypeDeclaration type, - String className, String fieldOrMethodName, String location, IFile templateFile, String templateFilePath) - throws JavaModelException { + String className, String fieldOrMethodName, String location, IFile templateFile, + TemplatePathInfo templatePathInfo) throws JavaModelException { String templateUri = templateFile.getLocationURI().toString(); - String tooltip = getTooltip(templateFile, templateFilePath); + String tooltip = getTooltip(templateFile, templatePathInfo.getTemplateUri()); Range range = createRange(locationAnnotation != null ? locationAnnotation : fieldOrMethod); DocumentLink link = new DocumentLink(range, templateUri, null, tooltip); links.add(link); diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/TemplateDataCollector.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/TemplateDataCollector.java index 911966be8..8b971ccbd 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/TemplateDataCollector.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/TemplateDataCollector.java @@ -17,6 +17,7 @@ import org.eclipse.jdt.core.dom.StringLiteral; import com.redhat.qute.commons.datamodel.DataModelParameter; +import com.redhat.qute.commons.datamodel.DataModelParameters; import com.redhat.qute.commons.datamodel.DataModelTemplate; /** @@ -47,9 +48,9 @@ */ public class TemplateDataCollector extends TemplateDataVisitor { - private final DataModelTemplate template; + private final DataModelParameters template; - public TemplateDataCollector(DataModelTemplate template, IProgressMonitor monitor) { + public TemplateDataCollector(DataModelParameters template, IProgressMonitor monitor) { this.template = template; } diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/TemplateDataSupport.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/TemplateDataSupport.java index 4d466a56c..43cc5002f 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/TemplateDataSupport.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/TemplateDataSupport.java @@ -25,7 +25,7 @@ import org.eclipse.lsp4j.Location; import com.redhat.qute.commons.datamodel.DataModelParameter; -import com.redhat.qute.commons.datamodel.DataModelTemplate; +import com.redhat.qute.commons.datamodel.DataModelParameters; import com.redhat.qute.jdt.utils.IJDTUtils; /** @@ -49,7 +49,7 @@ public class TemplateDataSupport { * @param monitor the progress monitor. */ public static void collectParametersFromDataMethodInvocation(IMember fieldOrMethod, - DataModelTemplate template, IProgressMonitor monitor) { + DataModelParameters template, IProgressMonitor monitor) { try { search(fieldOrMethod, new TemplateDataCollector(template, monitor), monitor); } catch (CoreException e) { diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/datamodel/CheckedTemplateSupport.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/datamodel/CheckedTemplateSupport.java index 30c00c892..e1f02944b 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/datamodel/CheckedTemplateSupport.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/datamodel/CheckedTemplateSupport.java @@ -12,11 +12,13 @@ package com.redhat.qute.jdt.internal.template.datamodel; import static com.redhat.qute.jdt.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION; +import static com.redhat.qute.jdt.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION_IGNORE_FRAGMENTS; import static com.redhat.qute.jdt.internal.QuteJavaConstants.OLD_CHECKED_TEMPLATE_ANNOTATION; import static com.redhat.qute.jdt.utils.JDTQuteProjectUtils.getTemplatePath; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; @@ -29,13 +31,17 @@ import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; +import com.redhat.qute.commons.datamodel.DataModelFragment; import com.redhat.qute.commons.datamodel.DataModelParameter; +import com.redhat.qute.commons.datamodel.DataModelParameters; import com.redhat.qute.commons.datamodel.DataModelTemplate; import com.redhat.qute.jdt.internal.resolver.ITypeResolver; import com.redhat.qute.jdt.internal.template.TemplateDataSupport; import com.redhat.qute.jdt.template.datamodel.AbstractAnnotationTypeReferenceDataModelProvider; import com.redhat.qute.jdt.template.datamodel.SearchContext; +import com.redhat.qute.jdt.utils.AnnotationUtils; import com.redhat.qute.jdt.utils.JDTTypeUtils; +import com.redhat.qute.jdt.utils.TemplatePathInfo; /** * CheckedTemplate support for template files: @@ -75,27 +81,41 @@ protected String[] getAnnotationNames() { } @Override - protected void processAnnotation(IJavaElement javaElement, IAnnotation annotation, String annotationName, - SearchContext context, IProgressMonitor monitor) throws JavaModelException { + protected void processAnnotation(IJavaElement javaElement, IAnnotation checkedTemplateAnnotation, + String annotationName, SearchContext context, IProgressMonitor monitor) throws JavaModelException { if (javaElement instanceof IType) { IType type = (IType) javaElement; - collectDataModelTemplateForCheckedTemplate(type, context.getTypeResolver(type), + boolean ignoreFragments = isIgnoreFragments(checkedTemplateAnnotation); + collectDataModelTemplateForCheckedTemplate(type, ignoreFragments, context.getTypeResolver(type), context.getDataModelProject().getTemplates(), monitor); } } + private static boolean isIgnoreFragments(IAnnotation checkedTemplateAnnotation) { + try { + Boolean ignoreFragments = AnnotationUtils.getAnnotationMemberValueAsBoolean(checkedTemplateAnnotation, + CHECKED_TEMPLATE_ANNOTATION_IGNORE_FRAGMENTS); + return ignoreFragments != null ? ignoreFragments.booleanValue() : false; + } catch (Exception e) { + // Do nothing + return false; + } + } + /** * Collect data model template from @CheckedTemplate. * - * @param type the Java type. - * @param typeResolver the Java type resolver. - * @param templates the data model templates to update with collect of - * template. - * @param monitor the progress monitor. + * @param type the Java type. + * @param ignoreFragment true if fragment must be ignored and false otherwise. + * @param typeResolver the Java type resolver. + * @param templates the data model templates to update with collect of + * template. + * @param monitor the progress monitor. * @throws JavaModelException */ - private static void collectDataModelTemplateForCheckedTemplate(IType type, ITypeResolver typeResolver, - List> templates, IProgressMonitor monitor) throws JavaModelException { + private static void collectDataModelTemplateForCheckedTemplate(IType type, boolean ignoreFragment, + ITypeResolver typeResolver, List> templates, IProgressMonitor monitor) + throws JavaModelException { boolean innerClass = type.getParent() != null && type.getParent().getElementType() == IJavaElement.TYPE; String className = !innerClass ? null : JDTTypeUtils.getSimpleClassName( @@ -106,17 +126,43 @@ private static void collectDataModelTemplateForCheckedTemplate(IType type, IType // method. IMethod[] methods = type.getMethods(); for (IMethod method : methods) { - DataModelTemplate template = createTemplateDataModel(method, className, type, - typeResolver, monitor); - templates.add(template); + + // src/main/resources/templates/${className}/${methodName}.qute.html + TemplatePathInfo templatePathInfo = getTemplatePath(className, method.getElementName(), ignoreFragment); + + // Get or create template + String templateUri = templatePathInfo.getTemplateUri(); + String fragmentId = templatePathInfo.getFragmentId(); + + DataModelTemplate template = null; + Optional> existingTemplate = templates.stream() + .filter(t -> t.getTemplateUri().equals(templateUri)) // + .findFirst(); + if (existingTemplate.isEmpty()) { + template = createTemplateDataModel(templateUri, method, type); + templates.add(template); + } else { + template = existingTemplate.get(); + if (fragmentId == null) { + template.setSourceMethod(method.getElementName()); + } + } + + if (fragmentId != null && fragmentId.length() > 0) { + // Create fragment + DataModelFragment fragment = createFragmentDataModel(fragmentId, method, type); + template.addFragment(fragment); + // collect parameters for the fragment + collectParameters(method, typeResolver, fragment, monitor); + } else { + // collect parameters for the template + collectParameters(method, typeResolver, template, monitor); + } } } - private static DataModelTemplate createTemplateDataModel(IMethod method, String className, - IType type, ITypeResolver typeResolver, IProgressMonitor monitor) { - String methodName = method.getElementName(); - // src/main/resources/templates/${className}/${methodName}.qute.html - String templateUri = getTemplatePath(className, methodName); + private static DataModelTemplate createTemplateDataModel(String templateUri, IMethod method, + IType type) { // Create template data model with: // - template uri : Qute template file which must be bind with data model. @@ -126,8 +172,22 @@ private static DataModelTemplate createTemplateDataModel(IMe template.setParameters(new ArrayList<>()); template.setTemplateUri(templateUri); template.setSourceType(type.getFullyQualifiedName()); - template.setSourceMethod(methodName); + template.setSourceMethod(method.getElementName()); + return template; + } + private static DataModelFragment createFragmentDataModel(String fragmentId, IMethod method, + IType type) { + DataModelFragment template = new DataModelFragment(); + template.setParameters(new ArrayList<>()); + template.setId(fragmentId); + template.setSourceType(type.getFullyQualifiedName()); + template.setSourceMethod(method.getElementName()); + return template; + } + + public static void collectParameters(IMethod method, ITypeResolver typeResolver, + DataModelParameters templateOrFragment, IProgressMonitor monitor) { try { ILocalVariable[] parameters = method.getParameters(); if (parameters.length > 0) { @@ -135,7 +195,7 @@ private static DataModelTemplate createTemplateDataModel(IMe for (int i = 0; i < parameters.length; i++) { DataModelParameter parameter = createParameterDataModel(parameters[i], varargs && i == parameters.length - 1, typeResolver); - template.getParameters().add(parameter); + templateOrFragment.getParameters().add(parameter); } } } catch (Exception e) { @@ -143,8 +203,7 @@ private static DataModelTemplate createTemplateDataModel(IMe "Error while getting method template parameter of '" + method.getElementName() + "'.", e); } // Collect data parameters for the given template - TemplateDataSupport.collectParametersFromDataMethodInvocation(method, template, monitor); - return template; + TemplateDataSupport.collectParametersFromDataMethodInvocation(method, templateOrFragment, monitor); } private static DataModelParameter createParameterDataModel(ILocalVariable methodParameter, boolean varags, diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/datamodel/TemplateFieldSupport.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/datamodel/TemplateFieldSupport.java index 6ecc5ed30..f24da8b45 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/datamodel/TemplateFieldSupport.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/datamodel/TemplateFieldSupport.java @@ -113,13 +113,14 @@ private static void collectDataModelTemplateForTemplateField(IField field, templates.add(template); } - private static DataModelTemplate createTemplateDataModel(IField field, String locationFromConstructorParameter, - IProgressMonitor monitor) { + private static DataModelTemplate createTemplateDataModel(IField field, + String locationFromConstructorParameter, IProgressMonitor monitor) { - String location = locationFromConstructorParameter != null ? locationFromConstructorParameter : getLocation(field); + String location = locationFromConstructorParameter != null ? locationFromConstructorParameter + : getLocation(field); String fieldName = field.getElementName(); // src/main/resources/templates/${methodName}.qute.html - String templateUri = getTemplatePath(null, location != null ? location : fieldName); + String templateUri = getTemplatePath(null, location != null ? location : fieldName, true).getTemplateUri(); // Create template data model with: // - template uri : Qute template file which must be bind with data model. diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/AnnotationUtils.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/AnnotationUtils.java index 01343b1a7..7dadef470 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/AnnotationUtils.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/AnnotationUtils.java @@ -192,6 +192,24 @@ public static String getAnnotationMemberValue(IAnnotation annotation, String mem return null; } + /** + * Returns the value of the given member name of the given annotation. + * + * @param annotation the annotation. + * @param memberName the member name. + * @return the value of the given member name of the given annotation. + * @throws JavaModelException + */ + public static Boolean getAnnotationMemberValueAsBoolean(IAnnotation annotation, String memberName) + throws JavaModelException { + for (IMemberValuePair pair : annotation.getMemberValuePairs()) { + if (memberName.equals(pair.getMemberName())) { + return getValueAsBoolean(pair); + } + } + return null; + } + public static String getValueAsString(IMemberValuePair pair) { return pair.getValue() != null ? pair.getValue().toString() : null; } @@ -246,4 +264,14 @@ public static Expression getAnnotationMemberValueExpression(Annotation annotatio return null; } + public static Boolean getBoolean(Expression expression) { + if (expression == null) { + return null; + } + Object expressionValue = expression.resolveConstantExpressionValue(); + if (expressionValue instanceof Boolean) { + return (Boolean) expressionValue; + } + return null; + } } diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/JDTQuteProjectUtils.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/JDTQuteProjectUtils.java index 53059f141..139b62441 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/JDTQuteProjectUtils.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/JDTQuteProjectUtils.java @@ -84,13 +84,22 @@ public static boolean hasQuteSupport(IJavaProject javaProject) { return JDTTypeUtils.findType(javaProject, QuteJavaConstants.ENGINE_BUILDER_CLASS) != null; } - public static String getTemplatePath(String className, String methodOrFieldName) { - StringBuilder path = new StringBuilder(TEMPLATES_BASE_DIR); + public static TemplatePathInfo getTemplatePath(String className, String methodOrFieldName, boolean ignoreFragments) { + String fragmentId = null; + StringBuilder templateUri = new StringBuilder(TEMPLATES_BASE_DIR); if (className != null) { - path.append(className); - path.append('/'); + templateUri.append(className); + templateUri.append('/'); + if (!ignoreFragments) { + int fragmentIndex = methodOrFieldName != null ? methodOrFieldName.indexOf('$') : -1; + if (fragmentIndex != -1) { + fragmentId = methodOrFieldName.substring(fragmentIndex + 1, methodOrFieldName.length()); + methodOrFieldName = methodOrFieldName.substring(0, fragmentIndex); + } + } } - return path.append(methodOrFieldName).toString(); + templateUri.append(methodOrFieldName); + return new TemplatePathInfo(templateUri.toString(), fragmentId); } public static CompilationUnit getASTRoot(ITypeRoot typeRoot) { diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/TemplatePathInfo.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/TemplatePathInfo.java new file mode 100644 index 000000000..bc6e55b25 --- /dev/null +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/utils/TemplatePathInfo.java @@ -0,0 +1,22 @@ +package com.redhat.qute.jdt.utils; + +public class TemplatePathInfo { + + private final String templateUri; + + private final String fragmentId; + + public TemplatePathInfo(String templateUri, String fragmentId) { + this.templateUri = templateUri; + this.fragmentId = fragmentId; + } + + public String getTemplateUri() { + return templateUri; + } + + public String getFragmentId() { + return fragmentId; + } + +} diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelFragment.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelFragment.java new file mode 100644 index 000000000..1f28a28bf --- /dev/null +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelFragment.java @@ -0,0 +1,35 @@ +/******************************************************************************* +* 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.commons.datamodel; + +import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; + +public class DataModelFragment extends DataModelParameters { + + private String id; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + public String toString() { + ToStringBuilder b = new ToStringBuilder(this); + b.add("id", this.id); + b.add("parameters", this.getParameters()); + return b.toString(); + } +} diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelParameters.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelParameters.java new file mode 100644 index 000000000..ff1cdb248 --- /dev/null +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelParameters.java @@ -0,0 +1,119 @@ +/******************************************************************************* +* 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.commons.datamodel; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class DataModelParameters { + + private String sourceType; + + private String sourceMethod; + + private List parameters; + + private transient Map parametersMap; + + /** + * Returns the Java source type where this data model template is defined. + * + * @return the Java source type where this data model template is defined. + */ + public String getSourceType() { + return sourceType; + } + + /** + * Set the Java source type where this data model template is defined. + * + * @param sourceType the Java source type where this data model template is + * defined. + */ + public void setSourceType(String sourceType) { + this.sourceType = sourceType; + } + + /** + * Returns the Java source method where this data model template is defined and + * null otherwise. + * + * @return the Java source method where this data model template is defined and + * null otherwise. + */ + public String getSourceMethod() { + return sourceMethod; + } + + /** + * Set the Java source method where this data model template is defined and null + * otherwise. + * + * @param sourceMethod the Java source method where this data model template is + * defined and null otherwise. + */ + public void setSourceMethod(String sourceMethod) { + this.sourceMethod = sourceMethod; + } + + /** + * Returns the list of data model parameters. + * + * @return the list of data model parameters. + */ + public List getParameters() { + return parameters; + } + + /** + * Set the list of data model parameters. + * + * @param parameters the list of data model parameters. + */ + public void setParameters(List parameters) { + this.parameters = parameters; + } + + /** + * Returns the parameter from the given key and null otherwise. + * + * @param key the parameter key. + * + * @return the parameter from the given key and null otherwise. + */ + public T getParameter(String key) { + List parameters = getParameters(); + if (parameters == null) { + return null; + } + return getParametersMap().get(key); + } + + public void addParameter(T parameter) { + if (parameters == null) { + parameters = new ArrayList<>(); + } + parameters.add(parameter); + getParametersMap().put(parameter.getKey(), parameter); + } + + private Map getParametersMap() { + if (parametersMap == null) { + parametersMap = parameters.stream() + .collect(Collectors.toMap(DataModelParameter::getKey, Function.identity())); + } + return parametersMap; + } +} diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelTemplate.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelTemplate.java index 34e68d04e..e87ab0e9d 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelTemplate.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/datamodel/DataModelTemplate.java @@ -13,9 +13,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Collectors; import org.eclipse.xtext.xbase.lib.util.ToStringBuilder; @@ -27,19 +24,13 @@ * * @param data model parameter. */ -public class DataModelTemplate { +public class DataModelTemplate extends DataModelParameters { private String templateUri; - private String sourceType; - - private String sourceMethod; - private String sourceField; - - private List parameters; - private transient Map parametersMap; + private List> fragments; /** * Returns the template Uri. @@ -59,47 +50,6 @@ public void setTemplateUri(String templateUri) { this.templateUri = templateUri; } - /** - * Returns the Java source type where this data model template is defined. - * - * @return the Java source type where this data model template is defined. - */ - public String getSourceType() { - return sourceType; - } - - /** - * Set the Java source type where this data model template is defined. - * - * @param sourceType the Java source type where this data model template is - * defined. - */ - public void setSourceType(String sourceType) { - this.sourceType = sourceType; - } - - /** - * Returns the Java source method where this data model template is defined and - * null otherwise. - * - * @return the Java source method where this data model template is defined and - * null otherwise. - */ - public String getSourceMethod() { - return sourceMethod; - } - - /** - * Set the Java source method where this data model template is defined and null - * otherwise. - * - * @param sourceMethod the Java source method where this data model template is - * defined and null otherwise. - */ - public void setSourceMethod(String sourceMethod) { - this.sourceMethod = sourceMethod; - } - /** * Returns the Java source field where this data model template is defined and * null otherwise. @@ -122,63 +72,46 @@ public void setSourceField(String sourceField) { this.sourceField = sourceField; } - /** - * Returns the list of data model parameters. - * - * @return the list of data model parameters. - */ - public List getParameters() { - return parameters; + public void addFragment(DataModelFragment fragment) { + if (fragments == null) { + fragments = new ArrayList<>(); + } + fragments.add(fragment); } - /** - * Set the list of data model parameters. - * - * @param parameters the list of data model parameters. - */ - public void setParameters(List parameters) { - this.parameters = parameters; + public List> getFragments() { + return fragments; } - /** - * Returns the parameter from the given key and null otherwise. - * - * @param key the parameter key. - * - * @return the parameter from the given key and null otherwise. - */ - public T getParameter(String key) { - List parameters = getParameters(); - if (parameters == null) { - return null; - } - return getParametersMap().get(key); + public void setFragments(List> fragments) { + this.fragments = fragments; } - public void addParameter(T parameter) { - if (parameters == null) { - parameters = new ArrayList<>(); + public DataModelFragment getFragment(String fragmentId) { + if (fragmentId == null) { + return null; } - parameters.add(parameter); - getParametersMap().put(parameter.getKey(), parameter); - } - - private Map getParametersMap() { - if (parametersMap == null) { - parametersMap = parameters.stream() - .collect(Collectors.toMap(DataModelParameter::getKey, Function.identity())); + List> fragments = getFragments(); + if (fragments == null || fragments.isEmpty()) { + return null; + } + for (DataModelFragment fragment : fragments) { + if (fragmentId.equals(fragment.getId())) { + return fragment; + } } - return parametersMap; + return null; } @Override public String toString() { ToStringBuilder b = new ToStringBuilder(this); b.add("templateUri", this.templateUri); - b.add("sourceType", this.sourceType); - b.add("sourceMethod", this.sourceMethod); + b.add("sourceType", this.getSourceType()); + b.add("sourceMethod", this.getSourceMethod()); b.add("sourceField", this.sourceField); - b.add("parameters", this.parameters); + b.add("parameters", this.getParameters()); + b.add("fragments", this.getFragments()); return b.toString(); } } 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 index c2c0cd0e8..7fc9644f9 100644 --- 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 @@ -60,6 +60,23 @@ public SectionKind getSectionKind() { return SectionKind.FRAGMENT; } + public String getId() { + Parameter alias = getIdParameter(); + if (alias != null) { + return alias.getValue(); + } + return null; + } + + public Parameter getIdParameter() { + for (Parameter parameter : getParameters()) { + if (ID.equals(parameter.getName())) { + return parameter; + } + } + return null; + } + @Override public ParametersInfo getParametersInfo() { return PARAMETER_INFOS; diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/DataModelSourceProvider.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/DataModelSourceProvider.java new file mode 100644 index 000000000..5b739a2e2 --- /dev/null +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/DataModelSourceProvider.java @@ -0,0 +1,19 @@ +package com.redhat.qute.project.datamodel; + +import java.util.List; + +import com.redhat.qute.commons.QuteJavaDefinitionParams; + +public interface DataModelSourceProvider { + + String getSourceType(); + + String getSourceField(); + + String getSourceMethod(); + + QuteJavaDefinitionParams toJavaDefinitionParams(String projectUri); + + List getParameters(); + +} diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelFragment.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelFragment.java new file mode 100644 index 000000000..034e2bff7 --- /dev/null +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelFragment.java @@ -0,0 +1,44 @@ +/******************************************************************************* +* 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.project.datamodel; + +import com.redhat.qute.commons.QuteJavaDefinitionParams; +import com.redhat.qute.commons.datamodel.DataModelFragment; +import com.redhat.qute.commons.datamodel.DataModelParameter; + +public class ExtendedDataModelFragment extends DataModelFragment + implements DataModelSourceProvider { + + public ExtendedDataModelFragment(DataModelFragment fragment) { + super.setId(fragment.getId()); + super.setSourceType(fragment.getSourceType()); + super.setSourceMethod(fragment.getSourceMethod()); + super.setParameters(ExtendedDataModelTemplate.createParameters(fragment.getParameters(), this)); + } + + @Override + public QuteJavaDefinitionParams toJavaDefinitionParams(String projectUri) { + String sourceType = getSourceType(); + String sourceField = null; + String sourceMethod = getSourceMethod(); + + QuteJavaDefinitionParams params = new QuteJavaDefinitionParams(sourceType, projectUri); + params.setSourceField(sourceField); + params.setSourceMethod(sourceMethod); + return params; + } + + @Override + public String getSourceField() { + return null; + } +} diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelParameter.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelParameter.java index d48b78a8c..b8b2011e9 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelParameter.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelParameter.java @@ -18,9 +18,9 @@ public class ExtendedDataModelParameter extends DataModelParameter implements JavaTypeInfoProvider { - private final ExtendedDataModelTemplate template; + private final DataModelSourceProvider template; - public ExtendedDataModelParameter(DataModelParameter parameter, ExtendedDataModelTemplate template) { + public ExtendedDataModelParameter(DataModelParameter parameter, DataModelSourceProvider template) { super.setKey(parameter.getKey()); super.setSourceType(parameter.getSourceType()); super.setDataMethodInvocation(parameter.isDataMethodInvocation()); @@ -37,12 +37,12 @@ public Node getJavaTypeOwnerNode() { return null; } - public ExtendedDataModelTemplate getTemplate() { + private DataModelSourceProvider getTemplate() { return template; } public QuteJavaDefinitionParams toJavaDefinitionParams(String projectUri) { - ExtendedDataModelTemplate dataModelTemplate = getTemplate(); + DataModelSourceProvider dataModelTemplate = getTemplate(); String sourceType = dataModelTemplate.getSourceType(); String sourceField = dataModelTemplate.getSourceField(); String sourceMethod = dataModelTemplate.getSourceMethod(); diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelTemplate.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelTemplate.java index c3a004d2c..46bf8688b 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelTemplate.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/datamodel/ExtendedDataModelTemplate.java @@ -16,10 +16,12 @@ import java.util.stream.Collectors; import com.redhat.qute.commons.QuteJavaDefinitionParams; +import com.redhat.qute.commons.datamodel.DataModelFragment; import com.redhat.qute.commons.datamodel.DataModelParameter; import com.redhat.qute.commons.datamodel.DataModelTemplate; -public class ExtendedDataModelTemplate extends DataModelTemplate { +public class ExtendedDataModelTemplate extends DataModelTemplate + implements DataModelSourceProvider { public ExtendedDataModelTemplate(DataModelTemplate template) { super.setTemplateUri(template.getTemplateUri()); @@ -27,10 +29,22 @@ public ExtendedDataModelTemplate(DataModelTemplate template) super.setSourceMethod(template.getSourceMethod()); super.setSourceField(template.getSourceField()); super.setParameters(createParameters(template.getParameters(), this)); + super.setFragments(createFragments(template.getFragments(), this)); } - private List createParameters(List parameters, + private List> createFragments( + List> fragments, ExtendedDataModelTemplate template) { + if (fragments == null) { + return Collections.emptyList(); + } + return fragments.stream() // + .map(fragment -> new ExtendedDataModelFragment(fragment)) // + .collect(Collectors.toList()); + } + + static List createParameters(List parameters, + DataModelSourceProvider template) { if (parameters == null) { return Collections.emptyList(); } @@ -39,6 +53,7 @@ private List createParameters(List> getCodelens(Template template // #insert code lens references QuteProject project = template.getProject(); - collectInsertCodeLenses(template, template, project, lenses, cancelChecker); + collectInsertCodeLenses(templateDataModel, template, template, settings, project, lenses, + cancelChecker); // checked template code lenses - collectDataModelCodeLenses(templateDataModel, template, settings, lenses, cancelChecker); + collectDataModelFoTemplateCodeLenses(templateDataModel, template, settings, lenses, cancelChecker); if (UserTagUtils.isUserTag(template)) { // Template is an user tag @@ -77,7 +80,15 @@ public CompletableFuture> getCodelens(Template template }); } - private static void collectDataModelCodeLenses(ExtendedDataModelTemplate templateDataModel, Template template, + private static void collectDataModelFoTemplateCodeLenses(DataModelSourceProvider templateDataModel, + Template template, + SharedSettings settings, List lenses, CancelChecker cancelChecker) { + collectDataModelCodeLenses(LEFT_TOP_RANGE, templateDataModel, template.getProjectUri(), settings, lenses, + cancelChecker); + } + + private static void collectDataModelCodeLenses(Range range, DataModelSourceProvider templateDataModel, + String projectUri, SharedSettings settings, List lenses, CancelChecker cancelChecker) { if (templateDataModel == null || templateDataModel.getSourceType() == null) { return; @@ -85,14 +96,11 @@ private static void collectDataModelCodeLenses(ExtendedDataModelTemplate templat cancelChecker.checkCanceled(); - String projectUri = template.getProjectUri(); - boolean canSupportJavaDefinition = settings.getCommandCapabilities() .isCommandSupported(COMMAND_JAVA_DEFINITION); // Method/Field which is bound with the template String title = createCheckedTemplateTitle(templateDataModel); - Range range = LEFT_TOP_RANGE; Command command = !canSupportJavaDefinition ? new Command(title, "") : new Command(title, COMMAND_JAVA_DEFINITION, Arrays.asList(templateDataModel.toJavaDefinitionParams(projectUri))); @@ -121,7 +129,7 @@ private static String createParameterTitle(ExtendedDataModelParameter parameter) return title.toString(); } - private static String createCheckedTemplateTitle(DataModelTemplate dataModel) { + private static String createCheckedTemplateTitle(DataModelSourceProvider dataModel) { String className = dataModel.getSourceType(); int index = className.lastIndexOf('.'); className = className.substring(index + 1, className.length()); @@ -136,35 +144,63 @@ private static String createCheckedTemplateTitle(DataModelTemplate dataModel) return title.toString(); } - private static void collectInsertCodeLenses(Node parent, Template template, QuteProject project, + private static void collectInsertCodeLenses(ExtendedDataModelTemplate templateDataModel, Node parent, + Template template, SharedSettings settings, QuteProject project, List lenses, CancelChecker cancelChecker) { cancelChecker.checkCanceled(); if (parent.getKind() == NodeKind.Section) { Section section = (Section) parent; - if (section.getSectionKind() == SectionKind.INSERT) { - - if (project != null) { - Parameter parameter = section.getParameterAtIndex(0); - if (parameter != null) { - String tag = parameter.getValue(); - // TODO : implement findNbreferencesOfInsertTag correctly - int nbReferences = 0; // project.findNbreferencesOfInsertTag(template.getTemplateId(), tag); - if (nbReferences > 0) { - String title = nbReferences == 1 ? "1 reference" : nbReferences + " references"; - Range range = QutePositionUtility.createRange(parameter); - Command command = new Command(title, ""); - CodeLens codeLens = new CodeLens(range, command, null); - lenses.add(codeLens); - } - } - } - + switch (section.getSectionKind()) { + case INSERT: + collectInsertCodeLens(project, section, lenses); + break; + case FRAGMENT: + collectFragmentCodeLens(templateDataModel, section, settings, project, lenses, cancelChecker); + break; + default: } - } List children = parent.getChildren(); for (Node node : children) { - collectInsertCodeLenses(node, template, project, lenses, cancelChecker); + collectInsertCodeLenses(templateDataModel, node, template, settings, project, lenses, cancelChecker); + } + } + + private static void collectFragmentCodeLens(ExtendedDataModelTemplate templateDataModel, Section section, + SharedSettings settings, QuteProject project, List lenses, CancelChecker cancelChecker) { + if (templateDataModel == null) { + return; + } + FragmentSection fragment = (FragmentSection) section; + String fragmentId = fragment.getId(); + if (StringUtils.isEmpty(fragmentId)) { + return; + } + ExtendedDataModelFragment fragmentDataModel = (ExtendedDataModelFragment) templateDataModel + .getFragment(fragmentId); + if (fragmentDataModel == null) { + return; + } + Range range = QutePositionUtility.selectStartTagName(section); + collectDataModelCodeLenses(range, fragmentDataModel, project.getUri(), settings, lenses, + cancelChecker); + } + + public static void collectInsertCodeLens(QuteProject project, Section section, List lenses) { + if (project != null) { + Parameter parameter = section.getParameterAtIndex(0); + if (parameter != null) { + String tag = parameter.getValue(); + // TODO : implement findNbreferencesOfInsertTag correctly + int nbReferences = 0; // project.findNbreferencesOfInsertTag(template.getTemplateId(), tag); + if (nbReferences > 0) { + String title = nbReferences == 1 ? "1 reference" : nbReferences + " references"; + Range range = QutePositionUtility.createRange(parameter); + Command command = new Command(title, ""); + CodeLens codeLens = new CodeLens(range, command, null); + lenses.add(codeLens); + } + } } }