diff --git a/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/QuteJavaConstants.java b/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/QuteJavaConstants.java index 93c3c1e6f..942982870 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/QuteJavaConstants.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/QuteJavaConstants.java @@ -49,6 +49,7 @@ 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"; + public static final String CHECKED_TEMPLATE_ANNOTATION_BASE_PATH = "basePath"; // @TemplateExtension diff --git a/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/java/AbstractQuteTemplateLinkCollector.java b/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/java/AbstractQuteTemplateLinkCollector.java index 0e612fbbe..43254ba20 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/java/AbstractQuteTemplateLinkCollector.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/java/AbstractQuteTemplateLinkCollector.java @@ -41,6 +41,8 @@ import static com.redhat.devtools.intellij.qute.psi.internal.QuteJavaConstants.OLD_CHECKED_TEMPLATE_ANNOTATION; import static com.redhat.devtools.intellij.qute.psi.internal.QuteJavaConstants.CHECKED_TEMPLATE_ANNOTATION_IGNORE_FRAGMENTS; import static com.redhat.devtools.intellij.qute.psi.internal.QuteJavaConstants.TEMPLATE_CLASS; +import static com.redhat.devtools.intellij.qute.psi.internal.template.datamodel.CheckedTemplateSupport.getBasePath; +import static com.redhat.devtools.intellij.qute.psi.internal.template.datamodel.CheckedTemplateSupport.isIgnoreFragments; /** * Abstract class which collects {@link PsiMethod} or @@ -108,7 +110,7 @@ public void visitField(PsiField node) { .getLocationExpressionFromConstructorParameter(node.getName()); } String fieldName = node.getName(); - collectTemplateLink(node, locationExpression, getTypeDeclaration(node), null, fieldName, false); + collectTemplateLink(null, node, locationExpression, getTypeDeclaration(node), null, fieldName, false); } super.visitField(node); } @@ -137,8 +139,9 @@ public void visitClass(PsiClass node) { // public static class Templates { // public static native TemplateInstance book(Book book); boolean ignoreFragments = isIgnoreFragments(annotation); + String basePath = getBasePath(annotation); for(PsiMethod method : node.getMethods()) { - collectTemplateLink(method, node, ignoreFragments ); + collectTemplateLink(basePath, method, node, ignoreFragments ); } } } @@ -146,58 +149,29 @@ public void visitClass(PsiClass node) { levelTypeDecl--; } - /** - * Returns true if @CheckedTemplate annotation declares that fragment must be - * ignored and false otherwise. - * - * - * @CheckedTemplate(ignoreFragments=true) - * - * - * @param checkedTemplateAnnotation the CheckedTemplate annotation. - * - * @return true if @CheckedTemplate annotation declares that fragment must be - * ignored and false otherwise. - */ - private static boolean isIgnoreFragments(PsiAnnotation checkedTemplateAnnotation) { - Boolean ignoreFragment = null; - try { - for(PsiNameValuePair pair : checkedTemplateAnnotation.getParameterList().getAttributes()) { - if (CHECKED_TEMPLATE_ANNOTATION_IGNORE_FRAGMENTS.equalsIgnoreCase(pair.getAttributeName())) { - ignoreFragment = AnnotationUtils.getValueAsBoolean(pair); - } - } - } catch (IndexNotReadyException | ProcessCanceledException | CancellationException e) { - throw e; - } catch (Exception e) { - // Do nothing - } - return ignoreFragment != null ? ignoreFragment.booleanValue() : false; - } - private static PsiClass getTypeDeclaration(PsiElement node) { return PsiTreeUtil.getParentOfType(node, PsiClass.class); } - private void collectTemplateLink(PsiMethod methodDeclaration, PsiClass type, boolean ignoreFragments) { + private void collectTemplateLink(String basePath, PsiMethod methodDeclaration, PsiClass type, boolean ignoreFragments) { String className = null; boolean innerClass = levelTypeDecl > 1; if (innerClass) { className = PsiTypeUtils.getSimpleClassName(typeRoot.getName()); } String methodName = methodDeclaration.getName(); - collectTemplateLink(methodDeclaration, null, type, className, methodName, ignoreFragments ); + collectTemplateLink(basePath, methodDeclaration, null, type, className, methodName, ignoreFragments ); } - private void collectTemplateLink(PsiElement fieldOrMethod, PsiLiteralValue locationAnnotation, PsiClass type, String className, + private void collectTemplateLink(String basePath, PsiElement fieldOrMethod, PsiLiteralValue locationAnnotation, PsiClass type, String className, String fieldOrMethodName, boolean ignoreFragment ) { try { String location = locationAnnotation != null && locationAnnotation.getValue() instanceof String ? (String) locationAnnotation.getValue() : null; Module project = utils.getModule(); TemplatePathInfo templatePathInfo = location != null - ? PsiQuteProjectUtils.getTemplatePath(null, location, ignoreFragment) - : PsiQuteProjectUtils.getTemplatePath(className, fieldOrMethodName, ignoreFragment); + ? PsiQuteProjectUtils.getTemplatePath(basePath, null, location, ignoreFragment) + : PsiQuteProjectUtils.getTemplatePath(basePath, className, fieldOrMethodName, ignoreFragment); VirtualFile templateFile = null; if (location == null) { diff --git a/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/CheckedTemplateSupport.java b/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/CheckedTemplateSupport.java index 091bb7f62..f8cd5097e 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/CheckedTemplateSupport.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/CheckedTemplateSupport.java @@ -80,7 +80,8 @@ protected void processAnnotation(PsiElement javaElement, PsiAnnotation checkedTe if (javaElement instanceof PsiClass) { PsiClass type = (PsiClass) javaElement; boolean ignoreFragments = isIgnoreFragments(checkedTemplateAnnotation); - collectDataModelTemplateForCheckedTemplate(type, ignoreFragments, context.getTypeResolver(type), + String basePath = getBasePath(checkedTemplateAnnotation); + collectDataModelTemplateForCheckedTemplate(type, basePath, ignoreFragments, context.getTypeResolver(type), context.getDataModelProject().getTemplates(), monitor); } } @@ -96,7 +97,7 @@ protected void processAnnotation(PsiElement javaElement, PsiAnnotation checkedTe * ignored and false otherwise. * @CheckedTemplate(ignoreFragments=true) */ - private static boolean isIgnoreFragments(PsiAnnotation checkedTemplateAnnotation) { + public static boolean isIgnoreFragments(PsiAnnotation checkedTemplateAnnotation) { Boolean ignoreFragment = null; try { for (PsiNameValuePair pair : checkedTemplateAnnotation.getParameterList().getAttributes()) { @@ -112,15 +113,32 @@ private static boolean isIgnoreFragments(PsiAnnotation checkedTemplateAnnotation return ignoreFragment != null ? ignoreFragment.booleanValue() : false; } + public static String getBasePath(PsiAnnotation checkedTemplateAnnotation) { + String basePath = ""; + try { + for (PsiNameValuePair pair : checkedTemplateAnnotation.getParameterList().getAttributes()) { + if (CHECKED_TEMPLATE_ANNOTATION_BASE_PATH.equalsIgnoreCase(pair.getAttributeName())) { + basePath = pair.getLiteralValue(); + } + } + } catch (IndexNotReadyException | ProcessCanceledException | CancellationException e) { + throw e; + } catch (Exception e) { + // Do nothing + } + return basePath; + } + /** * Collect data model template from @CheckedTemplate. * * @param type the Java type. + * @param basePath the base path relative to the templates root * @param ignoreFragments true if fragments must be ignored and false otherwise. * @param templates the data model templates to update with collect of template. * @param monitor the progress monitor. */ - private static void collectDataModelTemplateForCheckedTemplate(PsiClass type, boolean ignoreFragments, ITypeResolver typeResolver, + private static void collectDataModelTemplateForCheckedTemplate(PsiClass type, String basePath, boolean ignoreFragments, ITypeResolver typeResolver, List> templates, ProgressIndicator monitor) { boolean innerClass = type.getContainingClass() != null; String className = !innerClass ? null @@ -131,7 +149,7 @@ private static void collectDataModelTemplateForCheckedTemplate(PsiClass type, bo PsiMethod[] methods = type.getMethods(); for (PsiMethod method : methods) { // src/main/resources/templates/${className}/${methodName}.qute.html - TemplatePathInfo templatePathInfo = getTemplatePath(className, method.getName(), ignoreFragments); + TemplatePathInfo templatePathInfo = getTemplatePath(basePath, className, method.getName(), ignoreFragments); // Get or create template String templateUri = templatePathInfo.getTemplateUri(); diff --git a/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/TemplateFieldSupport.java b/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/TemplateFieldSupport.java index a07d6b5c2..b9834887f 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/TemplateFieldSupport.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/psi/internal/template/datamodel/TemplateFieldSupport.java @@ -117,7 +117,7 @@ private static DataModelTemplate createTemplateDataModel(Psi String location = locationFromConstructorParameter != null ? locationFromConstructorParameter : getLocation(field); String fieldName = field.getName(); // src/main/resources/templates/${methodName}.qute.html - String templateUri = getTemplatePath(null, location != null ? location : fieldName, true).getTemplateUri(); + String templateUri = getTemplatePath(null,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/src/main/java/com/redhat/devtools/intellij/qute/psi/utils/PsiQuteProjectUtils.java b/src/main/java/com/redhat/devtools/intellij/qute/psi/utils/PsiQuteProjectUtils.java index 1876ab861..8d24bb3ef 100644 --- a/src/main/java/com/redhat/devtools/intellij/qute/psi/utils/PsiQuteProjectUtils.java +++ b/src/main/java/com/redhat/devtools/intellij/qute/psi/utils/PsiQuteProjectUtils.java @@ -61,8 +61,14 @@ public static boolean hasQuteSupport(Module javaProject) { return PsiTypeUtils.findType(javaProject, QuteJavaConstants.ENGINE_BUILDER_CLASS) != null; } - public static String getTemplatePath(String className, String methodOrFieldName) { + public static String getTemplatePath(String basePath, String className, String methodOrFieldName) { StringBuilder path = new StringBuilder(TEMPLATES_BASE_DIR); + if (basePath != null && !basePath.isBlank()){ + path.append(basePath.startsWith("/")? basePath.substring(1): basePath); + if (!basePath.endsWith("/")) { + path.append('/'); + } + } if (className != null) { path.append(className); path.append('/'); @@ -70,9 +76,15 @@ public static String getTemplatePath(String className, String methodOrFieldName) return path.append(methodOrFieldName).toString(); } - public static TemplatePathInfo getTemplatePath(String className, String methodOrFieldName, boolean ignoreFragments) { + public static TemplatePathInfo getTemplatePath(String basePath, String className, String methodOrFieldName, boolean ignoreFragments) { String fragmentId = null; StringBuilder templateUri = new StringBuilder(TEMPLATES_BASE_DIR); + if (basePath != null && !basePath.isBlank()){ + templateUri.append(basePath.startsWith("/")? basePath.substring(1): basePath); + if (!basePath.endsWith("/")) { + templateUri.append('/'); + } + } if (className != null) { templateUri.append(className); templateUri.append('/');