diff --git a/quarkus.ls.ext/com.redhat.quarkus.ls/pom.xml b/quarkus.ls.ext/com.redhat.quarkus.ls/pom.xml
index 14ac91e8c..45d09df45 100644
--- a/quarkus.ls.ext/com.redhat.quarkus.ls/pom.xml
+++ b/quarkus.ls.ext/com.redhat.quarkus.ls/pom.xml
@@ -39,7 +39,7 @@
yyyyMMdd-HHmm
${maven.build.timestamp}
0.14.0
- 0.13.0-SNAPSHOT
+ 0.13.0
jboss-releases-repository
https://repository.jboss.org/nexus/content/repositories/releases/
jboss-snapshots-repository
diff --git a/qute.jdt/com.redhat.qute.jdt.test/src/main/java/com/redhat/qute/jdt/template/TemplateGenerateMissingJavaMemberTest.java b/qute.jdt/com.redhat.qute.jdt.test/src/main/java/com/redhat/qute/jdt/template/TemplateGenerateMissingJavaMemberTest.java
index 5ee7ecc89..fd34f7a9d 100644
--- a/qute.jdt/com.redhat.qute.jdt.test/src/main/java/com/redhat/qute/jdt/template/TemplateGenerateMissingJavaMemberTest.java
+++ b/qute.jdt/com.redhat.qute.jdt.test/src/main/java/com/redhat/qute/jdt/template/TemplateGenerateMissingJavaMemberTest.java
@@ -188,7 +188,7 @@ public void generateTemplateExtensionInNewClass() throws Exception {
sep //
+ "/**" + sep //
+ " * " + sep //
- + " */" + sep //
+ + " java*/" + sep //
+ sep //
+ "@io.quarkus.qute.TemplateExtension" + sep //
+ "public class TemplateExtensions {" + sep //
@@ -236,7 +236,7 @@ public void generateTemplateExtensionInNewClassWithExisting() throws Exception {
sep //
+ "/**" + sep //
+ " * " + sep //
- + " */" + sep //
+ + " java*/" + sep //
+ sep //
+ "@io.quarkus.qute.TemplateExtension" + sep //
+ "public class TemplateExtensions1 {" + sep //
@@ -259,7 +259,7 @@ public void generateTemplateExtensionInNewClassWithExisting() throws Exception {
sep //
+ "/**" + sep //
+ " * " + sep //
- + " */" + sep //
+ + " java*/" + sep //
+ sep //
+ "@io.quarkus.qute.TemplateExtension" + sep //
+ "public class TemplateExtensions2 {" + sep //
diff --git a/qute.jdt/com.redhat.qute.jdt/plugin.properties b/qute.jdt/com.redhat.qute.jdt/plugin.properties
index a90540695..c7e664c3e 100644
--- a/qute.jdt/com.redhat.qute.jdt/plugin.properties
+++ b/qute.jdt/com.redhat.qute.jdt/plugin.properties
@@ -13,5 +13,6 @@
pluginName=JDT Qute Extension
providerName=Red Hat
+templateRootPathProviders.name=Template Root Path Providers
dataModelProviders.name=Data model providers
resolvedJavaTypeFactoriesName=Resolved Java Type Factories
\ No newline at end of file
diff --git a/qute.jdt/com.redhat.qute.jdt/plugin.xml b/qute.jdt/com.redhat.qute.jdt/plugin.xml
index 542f3ef69..ab915112c 100644
--- a/qute.jdt/com.redhat.qute.jdt/plugin.xml
+++ b/qute.jdt/com.redhat.qute.jdt/plugin.xml
@@ -2,6 +2,9 @@
+
@@ -21,6 +24,7 @@
+
@@ -35,6 +39,11 @@
+
+
+
+
+
@@ -71,9 +80,21 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/qute.jdt/com.redhat.qute.jdt/schema/templateRootPathProviders.exsd b/qute.jdt/com.redhat.qute.jdt/schema/templateRootPathProviders.exsd
new file mode 100644
index 000000000..f480d4fb9
--- /dev/null
+++ b/qute.jdt/com.redhat.qute.jdt/schema/templateRootPathProviders.exsd
@@ -0,0 +1,89 @@
+
+
+
+
+
+
+
+
+ This extension point allows adding a template root path providers to add new templates folder to scan.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Template root path provider
+
+
+
+
+
+
+ Name of a class that implements ITemplateRootPathProvider
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ The following is an example of a template root path providers extension:
+
+<pre>
+ <extension point="com.redhat.qute.jdt.templateRootPathProviders">
+ <provider class="com.redhat.qute.jdt.internal.extensions.webbundler.WebBundlerTemplateRootPathProvider" />
+ </extension>
+</pre>
+
+
+
+
+
+
+
diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/FileUtils.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/FileUtils.java
new file mode 100644
index 000000000..264948902
--- /dev/null
+++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/FileUtils.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+* Copyright (c) 2021 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;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+
+/**
+ * File utilities.
+ *
+ * @author Angelo ZERR
+ *
+ */
+public class FileUtils {
+
+ private static final String FILE_SCHEME = "file";
+
+ /**
+ * Returns true if the given uri is a file uri and false otherwise.
+ *
+ * @param uri the uri
+ *
+ * @return true if the given uri is a file uri and false otherwise.
+ */
+ public static boolean isFileURI(URI uri) {
+ return isEmpty(uri.getScheme()) || FILE_SCHEME.equals(uri.getScheme());
+ }
+
+ public static URI createUri(String uriString) {
+ if (isEmpty(uriString)) {
+ return null;
+ }
+
+ try {
+ if (uriString.startsWith("file:/")) {
+ String convertedUri = uriString.replace("file:///", "file:/"); //$NON-NLS-1$//$NON-NLS-2$
+ convertedUri = convertedUri.replace("file://", "file:/"); //$NON-NLS-1$//$NON-NLS-2$
+ }
+ if (uriString.indexOf('%') != -1) {
+ uriString = uriDecode(uriString, StandardCharsets.UTF_8);
+ }
+ URI uri = URI.create(uriString);
+ if (!isFileURI(uri)) {
+ // The uri is not a file URI, ignore it.
+ return null;
+ }
+ return uri;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the path for the given file uri and null otherwise.
+ *
+ * @param uriString the Uri as string.
+ *
+ * @return the path for the given file uri and null otherwise.
+ */
+ public static Path createPath(String uriString) {
+ URI fileURi = createUri(uriString);
+ if (fileURi == null) {
+ return null;
+ }
+ if (fileURi.isAbsolute()) {
+ return new File(fileURi).toPath();
+ }
+ return new File(uriString).toPath();
+ }
+
+ public static String toUri(Path path) {
+ return path.toUri().toASCIIString();
+ }
+
+ /**
+ * Decode the given encoded URI component value. Based on the following rules:
+ *
+ * - Alphanumeric characters {@code "a"} through {@code "z"}, {@code "A"}
+ * through {@code "Z"}, and {@code "0"} through {@code "9"} stay the same.
+ * - Special characters {@code "-"}, {@code "_"}, {@code "."}, and {@code "*"}
+ * stay the same.
+ * - A sequence "{@code %xy}" is interpreted as a hexadecimal
+ * representation of the character.
+ * - For all other characters (including those already decoded), the output is
+ * undefined.
+ *
+ *
+ * @param source the encoded String
+ * @param charset the character set
+ * @return the decoded value
+ * @throws IllegalArgumentException when the given source contains invalid
+ * encoded sequences
+ * @since 5.0
+ * @see java.net.URLDecoder#decode(String, String)
+ *
+ * This method is a copy / paste from
+ * https://github.com/spring-projects/spring-framework/blob/67c7b80c2bed0f4f91b27d735541e9dfad8ce5b3/spring-core/src/main/java/org/springframework/util/StringUtils.java#L821
+ */
+ private static String uriDecode(String source, Charset charset) {
+ int length = source.length();
+ if (length == 0) {
+ return source;
+ }
+ // Assert.notNull(charset, "Charset must not be null");
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(length);
+ boolean changed = false;
+ for (int i = 0; i < length; i++) {
+ int ch = source.charAt(i);
+ if (ch == '%') {
+ if (i + 2 < length) {
+ char hex1 = source.charAt(i + 1);
+ char hex2 = source.charAt(i + 2);
+ int u = Character.digit(hex1, 16);
+ int l = Character.digit(hex2, 16);
+ if (u == -1 || l == -1) {
+ throw new IllegalArgumentException("Invalid encoded sequence \"" + source.substring(i) + "\"");
+ }
+ baos.write((char) ((u << 4) + l));
+ i += 2;
+ changed = true;
+ } else {
+ throw new IllegalArgumentException("Invalid encoded sequence \"" + source.substring(i) + "\"");
+ }
+ } else {
+ baos.write(ch);
+ }
+ }
+ return (changed ? copyToString(baos, charset) : source);
+ }
+
+ private static String copyToString(ByteArrayOutputStream baos, Charset charset) {
+ try {
+ return baos.toString(charset.name());
+ } catch (UnsupportedEncodingException e) {
+ return baos.toString();
+ }
+ }
+
+ private static boolean isEmpty(String value) {
+ return value == null || value.isEmpty();
+ }
+
+}
diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/ProjectInfo.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/ProjectInfo.java
index e048ca38f..597492417 100644
--- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/ProjectInfo.java
+++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/ProjectInfo.java
@@ -23,17 +23,17 @@ public class ProjectInfo {
private String uri;
- private String templateBaseDir;
+ private List templateRootPaths;
private List projectDependencyUris;
public ProjectInfo() {
}
- public ProjectInfo(String projectUri, List projectDependencies, String templateBaseDir) {
+ public ProjectInfo(String projectUri, List projectDependencies, List templateRootPaths) {
setUri(projectUri);
setProjectDependencyUris(projectDependencies);
- setTemplateBaseDir(templateBaseDir);
+ setTemplateRootPaths(templateRootPaths);
}
/**
@@ -73,20 +73,20 @@ public void setProjectDependencyUris(List projectDependencyUris) {
}
/**
- * Returns the Qute templates base directory and null otherwise.
+ * Returns the list of the template root path supported by the Qute project.
*
- * @return the Qute templates base directory and null otherwise.
+ * @return the list of the template root path supported by the Qute project.
*/
- public String getTemplateBaseDir() {
- return templateBaseDir;
+ public List getTemplateRootPaths() {
+ return templateRootPaths;
}
/**
- * Set the Qute templates base directory.
+ * Set the list of the template root path supported by the Qute project.
*
- * @param templateBaseDir the Qute templates base directory.
+ * @param templateRootPaths the list of the template root path.
*/
- public void setTemplateBaseDir(String templateBaseDir) {
- this.templateBaseDir = templateBaseDir;
+ public void setTemplateRootPaths(List templateRootPaths) {
+ this.templateRootPaths = templateRootPaths;
}
}
diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/TemplateRootPath.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/TemplateRootPath.java
new file mode 100644
index 000000000..628d81466
--- /dev/null
+++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/TemplateRootPath.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+* Copyright (c) 2024 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;
+
+import java.nio.file.Path;
+import java.util.List;
+
+/**
+ * Template root path which hosts Qute templates (ex :
+ * src/main/resources/templates).
+ */
+public class TemplateRootPath {
+
+ public static final String TAGS_DIR = "tags";
+
+ public static class FilePath {
+
+ private boolean folder;
+ private String path;
+
+ public boolean isFolder() {
+ return folder;
+ }
+
+ public void setFolder(boolean folder) {
+ this.folder = folder;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ }
+
+ private String baseDir;
+
+ private String origin;
+
+ private transient Path basePath;
+
+ private transient Path tagsDir;
+
+ private List includes;
+
+ private List excludes;
+
+ public TemplateRootPath() {
+
+ }
+
+ public TemplateRootPath(String baseDir) {
+ this(baseDir, null);
+ }
+
+ public TemplateRootPath(String baseDir, String origin) {
+ setBaseDir(baseDir);
+ setOrigin(origin);
+ }
+
+ public String getBaseDir() {
+ return baseDir;
+ }
+
+ /**
+ * Returns the origin Quarkus extension (ex : core, roq, etc) which generates
+ * this template root path.
+ *
+ * @return the origin Quarkus extension (ex : core, roq, etc) which generates
+ * this template root path.
+ */
+ public String getOrigin() {
+ return origin;
+ }
+
+ public void setOrigin(String origin) {
+ this.origin = origin;
+ }
+
+ /**
+ * Returns the base path of the template root path (ex
+ * :src/main/resources/templates) and null otherwise.
+ *
+ * @return the base path of the template root path (ex
+ * :src/main/resources/templates) and null otherwise.
+ */
+ public Path getBasePath() {
+ if (basePath == null && baseDir != null) {
+ basePath = FileUtils.createPath(baseDir);
+ }
+ return basePath;
+ }
+
+ /**
+ * Returns the 'tags' dir path of the template root path (ex
+ * :src/main/resources/templates/tags) and null otherwise.
+ *
+ * @return the 'tags' dir path of the template root path (ex
+ * :src/main/resources/templates/tags) and null otherwise.
+ */
+ public Path getTagsDir() {
+ if (tagsDir != null) {
+ return tagsDir;
+ }
+ Path basePath = getBasePath();
+ if (basePath != null) {
+ this.tagsDir = basePath.resolve(TAGS_DIR);
+ }
+ return tagsDir;
+ }
+
+ public void setBaseDir(String baseDir) {
+ this.baseDir = baseDir;
+ }
+
+ public List getIncludes() {
+ return includes;
+ }
+
+ public void setIncludes(List includes) {
+ this.includes = includes;
+ }
+
+ public List getExcludes() {
+ return excludes;
+ }
+
+ public void setExcludes(List excludes) {
+ this.excludes = excludes;
+ }
+
+ /**
+ * Returns true if the given uri is included in the template root path and
+ * false otherwise.
+ *
+ * @param path the file path.
+ * @return true if the given uri is included in the template root path and
+ * false otherwise.
+ */
+ public boolean isIncluded(String uri) {
+ Path path = FileUtils.createPath(uri);
+ return isIncluded(path);
+ }
+
+ /**
+ * Returns true if the given path is included in the template root path and
+ * false otherwise.
+ *
+ * @param path the file path.
+ * @return true if the given path is included in the template root path and
+ * false otherwise.
+ */
+ public boolean isIncluded(Path path) {
+ if (path == null) {
+ return false;
+ }
+ Path basePath = getBasePath();
+ if (basePath == null) {
+ return false;
+ }
+ return path.startsWith(basePath);
+ }
+}
diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/extensions/roq/RoqJavaConstants.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/extensions/roq/RoqJavaConstants.java
index 02e430707..d48206623 100644
--- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/extensions/roq/RoqJavaConstants.java
+++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/extensions/roq/RoqJavaConstants.java
@@ -23,7 +23,7 @@ private RoqJavaConstants() {
}
public static final String DATA_MAPPING_ANNOTATION = "io.quarkiverse.roq.data.runtime.annotations.DataMapping";
-
+
public static final String SITE_CLASS = "io.quarkiverse.roq.frontmatter.runtime.model.Site";
}
\ No newline at end of file
diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/extensions/roq/RoqTemplateRootPathProvider.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/extensions/roq/RoqTemplateRootPathProvider.java
new file mode 100644
index 000000000..1227215d6
--- /dev/null
+++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/extensions/roq/RoqTemplateRootPathProvider.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+* Copyright (c) 2024 Red Hat Inc. and others.
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License v. 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+* which is available at https://www.apache.org/licenses/LICENSE-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+*
+* Contributors:
+* Red Hat Inc. - initial API and implementation
+*******************************************************************************/
+package com.redhat.qute.jdt.internal.extensions.roq;
+
+import java.util.List;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.jdt.core.IJavaProject;
+
+import com.redhat.qute.commons.TemplateRootPath;
+import com.redhat.qute.jdt.template.rootpath.ITemplateRootPathProvider;
+import com.redhat.qute.jdt.utils.JDTTypeUtils;
+
+/**
+ * Roq template root path provider for Roq project.
+ */
+public class RoqTemplateRootPathProvider implements ITemplateRootPathProvider {
+
+ private static final String ORIGIN = "roq";
+
+ private static final String[] TEMPLATES_BASE_DIRS = { "templates/", "content/", "src/main/resources/content/" };
+
+ @Override
+ public boolean isApplicable(IJavaProject javaProject) {
+ return JDTTypeUtils.findType(javaProject, RoqJavaConstants.SITE_CLASS) != null;
+ }
+
+ @Override
+ public void collectTemplateRootPaths(IJavaProject javaProject, List rootPaths) {
+ IProject project = javaProject.getProject();
+ for (String baseDir : TEMPLATES_BASE_DIRS) {
+ String templateBaseDir = project.getFile(baseDir).getLocationURI().toString();
+ rootPaths.add(new TemplateRootPath(templateBaseDir, ORIGIN));
+ }
+ }
+
+}
diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/extensions/webbundler/WebBundlerJavaConstants.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/extensions/webbundler/WebBundlerJavaConstants.java
new file mode 100644
index 000000000..d2baa6b04
--- /dev/null
+++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/extensions/webbundler/WebBundlerJavaConstants.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+* Copyright (c) 2024 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.jdt.internal.extensions.webbundler;
+
+/**
+ * Web Bundler Java constants.
+ *
+ * @author Angelo ZERR
+ *
+ */
+public class WebBundlerJavaConstants {
+
+ private WebBundlerJavaConstants() {
+ }
+
+ public static final String BUNDLE_CLASS = "io.quarkiverse.web.bundler.runtime.Bundle";
+
+}
diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/extensions/webbundler/WebBundlerTemplateRootPathProvider.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/extensions/webbundler/WebBundlerTemplateRootPathProvider.java
new file mode 100644
index 000000000..41417c264
--- /dev/null
+++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/extensions/webbundler/WebBundlerTemplateRootPathProvider.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+* Copyright (c) 2024 Red Hat Inc. and others.
+*
+* This program and the accompanying materials are made available under the
+* terms of the Eclipse Public License v. 2.0 which is available at
+* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+* which is available at https://www.apache.org/licenses/LICENSE-2.0.
+*
+* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+*
+* Contributors:
+* Red Hat Inc. - initial API and implementation
+*******************************************************************************/
+package com.redhat.qute.jdt.internal.extensions.webbundler;
+
+import java.util.List;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.jdt.core.IJavaProject;
+
+import com.redhat.qute.commons.TemplateRootPath;
+import com.redhat.qute.jdt.template.rootpath.ITemplateRootPathProvider;
+import com.redhat.qute.jdt.utils.JDTTypeUtils;
+
+/**
+ * Web Bundler template root path provider for Web Bundler project.
+ */
+public class WebBundlerTemplateRootPathProvider implements ITemplateRootPathProvider {
+
+ private static final String ORIGIN = "web-bundler";
+
+ private static final String[] TEMPLATES_BASE_DIRS = { "src/main/resources/web/templates/" };
+
+ @Override
+ public boolean isApplicable(IJavaProject javaProject) {
+ return JDTTypeUtils.findType(javaProject, WebBundlerJavaConstants.BUNDLE_CLASS) != null;
+ }
+
+ @Override
+ public void collectTemplateRootPaths(IJavaProject javaProject, List rootPaths) {
+ IProject project = javaProject.getProject();
+ for (String baseDir : TEMPLATES_BASE_DIRS) {
+ String templateBaseDir = project.getFile(baseDir).getLocationURI().toString();
+ rootPaths.add(new TemplateRootPath(templateBaseDir, ORIGIN));
+ }
+ }
+
+}
diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/ls/QuteSupportForTemplateDelegateCommandHandler.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/ls/QuteSupportForTemplateDelegateCommandHandler.java
index d73c38999..96a73803d 100644
--- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/ls/QuteSupportForTemplateDelegateCommandHandler.java
+++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/ls/QuteSupportForTemplateDelegateCommandHandler.java
@@ -15,6 +15,7 @@
import static com.redhat.qute.jdt.internal.ls.ArgumentUtils.getFirst;
import static com.redhat.qute.jdt.internal.ls.ArgumentUtils.getString;
+import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
@@ -29,6 +30,7 @@
import org.eclipse.lsp4j.WorkspaceEdit;
import com.redhat.qute.commons.DocumentFormat;
+import com.redhat.qute.commons.FileUtils;
import com.redhat.qute.commons.GenerateMissingJavaMemberParams;
import com.redhat.qute.commons.GenerateMissingJavaMemberParams.MemberType;
import com.redhat.qute.commons.JavaTypeInfo;
@@ -39,6 +41,7 @@
import com.redhat.qute.commons.QuteProjectParams;
import com.redhat.qute.commons.QuteResolvedJavaTypeParams;
import com.redhat.qute.commons.ResolvedJavaTypeInfo;
+import com.redhat.qute.commons.TemplateRootPath;
import com.redhat.qute.commons.datamodel.DataModelParameter;
import com.redhat.qute.commons.datamodel.DataModelProject;
import com.redhat.qute.commons.datamodel.DataModelTemplate;
@@ -86,32 +89,36 @@ public class QuteSupportForTemplateDelegateCommandHandler extends AbstractQuteDe
private static final String QUTE_TEMPLATE_JAVA_DEFINITION_COMMAND_ID = "qute/template/javaDefinition";
private static final String QUTE_TEMPLATE_RESOLVED_JAVA_TYPE_COMMAND_ID = "qute/template/resolvedJavaType";
-
+
private static final String QUTE_JAVADOC_RESOLVE_COMMAND_ID = "qute/template/javadoc";
private static final String QUTE_TEMPLATE_GENERATE_MISSING_JAVA_MEMBER = "qute/template/generateMissingJavaMember";
+ private static final String QUTE_TEMPLATE_IS_IN_TEMPLATE = "qute/template/isInTemplate";
+
@Override
public Object executeCommand(String commandId, List