From 17f8d246cb84e2d4e956e95fd202eb8b90554457 Mon Sep 17 00:00:00 2001 From: azerr Date: Wed, 16 Oct 2024 18:24:24 +0200 Subject: [PATCH] feat: support multiple template root paths. Signed-off-by: azerr --- .../com.redhat.qute.jdt/plugin.properties | 1 + qute.jdt/com.redhat.qute.jdt/plugin.xml | 25 +++ .../schema/templateRootPathProviders.exsd | 89 ++++++++++ .../com/redhat/qute/commons/FileUtils.java | 155 ++++++++++++++++++ .../com/redhat/qute/commons/ProjectInfo.java | 24 +-- .../redhat/qute/commons/TemplateRootPath.java | 123 ++++++++++++++ .../extensions/roq/RoqJavaConstants.java | 27 +++ .../roq/RoqTemplateRootPathProvider.java | 48 ++++++ .../webbundler/WebBundlerJavaConstants.java | 27 +++ .../WebBundlerTemplateRootPathProvider.java | 48 ++++++ ...portForTemplateDelegateCommandHandler.java | 73 ++++++--- .../TemplateRootPathProviderRegistry.java | 79 +++++++++ .../DefaultTemplateRootPathProvider.java | 44 +++++ .../rootpath/ITemplateRootPathProvider.java | 46 ++++++ .../qute/jdt/utils/JDTQuteProjectUtils.java | 13 +- .../com/redhat/qute/commons/FileUtils.java | 155 ++++++++++++++++++ .../com/redhat/qute/commons/ProjectInfo.java | 24 +-- .../redhat/qute/commons/TemplateRootPath.java | 123 ++++++++++++++ .../redhat/qute/parser/template/Template.java | 10 +- .../template/sections/IncludeSection.java | 21 ++- .../com/redhat/qute/project/QuteProject.java | 34 ++-- .../qute/project/QuteProjectFilesWatcher.java | 4 +- .../qute/project/QuteProjectRegistry.java | 11 +- .../documents/QuteClosedTextDocument.java | 2 +- .../documents/QuteClosedTextDocuments.java | 23 ++- .../documents/QuteOpenedTextDocument.java | 2 +- .../qute/project/tags/UserTagRegistry.java | 22 ++- .../qute/settings/QuteValidationSettings.java | 2 +- .../java/com/redhat/qute/utils/FileUtils.java | 71 -------- .../com/redhat/qute/utils/UserTagUtils.java | 3 +- .../test/java/com/redhat/qute/QuteAssert.java | 37 +++-- .../qute/project/multiple/QuteProjectA.java | 5 +- .../qute/project/multiple/QuteProjectB.java | 8 +- .../redhat/qute/project/roq/RoqProject.java | 2 +- ...rateTemplateContentCommandHandlerTest.java | 4 +- .../AbstractQuteDiagnosticsInProjectTest.java | 5 +- ...ojectWithLSPDidChangeWatchedFilesTest.java | 2 +- .../QuteReferenceWithInsertSectionTest.java | 2 +- 38 files changed, 1183 insertions(+), 211 deletions(-) create mode 100644 qute.jdt/com.redhat.qute.jdt/schema/templateRootPathProviders.exsd create mode 100644 qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/FileUtils.java create mode 100644 qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/TemplateRootPath.java create mode 100644 qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/extensions/roq/RoqJavaConstants.java create mode 100644 qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/extensions/roq/RoqTemplateRootPathProvider.java create mode 100644 qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/extensions/webbundler/WebBundlerJavaConstants.java create mode 100644 qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/extensions/webbundler/WebBundlerTemplateRootPathProvider.java create mode 100644 qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/rootpath/TemplateRootPathProviderRegistry.java create mode 100644 qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/template/rootpath/DefaultTemplateRootPathProvider.java create mode 100644 qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/template/rootpath/ITemplateRootPathProvider.java create mode 100644 qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/FileUtils.java create mode 100644 qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/TemplateRootPath.java delete mode 100644 qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/utils/FileUtils.java 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 6a3e6e2f0..abb9c4056 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 @@ + @@ -33,6 +37,11 @@ + + + + + @@ -53,6 +62,8 @@ class="com.redhat.qute.jdt.internal.extensions.quarkus.InjectNamespaceResolverSupport" /> + + + + + + + + + + + + + + + + \ 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..aadc6534f --- /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 resolved Java Type factory extension: + +<pre> + <extension point="com.redhat.qute.jdt.resolvedJavaTypeFactories"> + <factory class="com.redhat.qute.jdt.internal.extensions.renarde.RenardeResolvedJavaTypeFactory" /> + </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..fd0f0b2a5 --- /dev/null +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/FileUtils.java @@ -0,0 +1,155 @@ +/******************************************************************************* +* 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; + } + return new File(fileURi).toPath(); + } + + public static String toUri(Path path) { + return path.toUri().toASCIIString(); + } + + /** + * Decode the given encoded URI component value. Based on the following rules: + * + * + * @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..385ea820f 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); } /** @@ -72,21 +72,11 @@ public void setProjectDependencyUris(List projectDependencyUris) { this.projectDependencyUris = projectDependencyUris; } - /** - * Returns the Qute templates base directory and null otherwise. - * - * @return the Qute templates base directory and null otherwise. - */ - public String getTemplateBaseDir() { - return templateBaseDir; + public List getTemplateRootPaths() { + return templateRootPaths; } - /** - * Set the Qute templates base directory. - * - * @param templateBaseDir the Qute templates base directory. - */ - 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..60368592c --- /dev/null +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/commons/TemplateRootPath.java @@ -0,0 +1,123 @@ +package com.redhat.qute.commons; + +import java.nio.file.Path; +import java.util.List; + +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; + } + + public String getOrigin() { + return origin; + } + + public void setOrigin(String origin) { + this.origin = origin; + } + + public Path getBasePath() { + if (basePath == null && baseDir != null) { + basePath = FileUtils.createPath(baseDir); + } + return basePath; + } + + 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; + } + + public boolean isIncluded(String uri) { + Path path = FileUtils.createPath(uri); + return isIncluded(path); + } + + 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 new file mode 100644 index 000000000..2422be6bc --- /dev/null +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/extensions/roq/RoqJavaConstants.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.roq; + +/** + * Roq Java constants. + * + * @author Angelo ZERR + * + */ +public class RoqJavaConstants { + + private RoqJavaConstants() { + } + + public static final String SITE_CLASS = "io.quarkiverse.roq.frontmatter.runtime.model.Site"; + +} 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 arguments, IProgressMonitor monitor) throws Exception { switch (commandId) { case QUTE_TEMPLATE_PROJECTS_COMMAND_ID: return getProjects(commandId, monitor); - case QUTE_TEMPLATE_PROJECT_COMMAND_ID: - return getProjectInfo(arguments, commandId, monitor); - case QUTE_TEMPLATE_PROJECT_DATA_MODEL_COMMAND_ID: - return getProjectDataModel(arguments, commandId, monitor); - case QUTE_TEMPLATE_USER_TAGS_COMMAND_ID: - return getUserTags(arguments, commandId, monitor); - case QUTE_TEMPLATE_JAVA_TYPES_COMMAND_ID: - return getJavaTypes(arguments, commandId, monitor); - case QUTE_TEMPLATE_RESOLVED_JAVA_TYPE_COMMAND_ID: - return getResolvedJavaType(arguments, commandId, monitor); - case QUTE_TEMPLATE_JAVA_DEFINITION_COMMAND_ID: - return getJavaDefinition(arguments, commandId, monitor); - case QUTE_JAVADOC_RESOLVE_COMMAND_ID: - return getJavadoc(arguments, commandId, monitor); - case QUTE_TEMPLATE_GENERATE_MISSING_JAVA_MEMBER: - return generateMissingJavaMember(arguments, commandId, monitor); + case QUTE_TEMPLATE_PROJECT_COMMAND_ID: + return getProjectInfo(arguments, commandId, monitor); + case QUTE_TEMPLATE_PROJECT_DATA_MODEL_COMMAND_ID: + return getProjectDataModel(arguments, commandId, monitor); + case QUTE_TEMPLATE_USER_TAGS_COMMAND_ID: + return getUserTags(arguments, commandId, monitor); + case QUTE_TEMPLATE_JAVA_TYPES_COMMAND_ID: + return getJavaTypes(arguments, commandId, monitor); + case QUTE_TEMPLATE_RESOLVED_JAVA_TYPE_COMMAND_ID: + return getResolvedJavaType(arguments, commandId, monitor); + case QUTE_TEMPLATE_JAVA_DEFINITION_COMMAND_ID: + return getJavaDefinition(arguments, commandId, monitor); + case QUTE_JAVADOC_RESOLVE_COMMAND_ID: + return getJavadoc(arguments, commandId, monitor); + case QUTE_TEMPLATE_GENERATE_MISSING_JAVA_MEMBER: + return generateMissingJavaMember(arguments, commandId, monitor); + case QUTE_TEMPLATE_IS_IN_TEMPLATE: + return isInTemplate(arguments, commandId, monitor); } return null; } @@ -119,7 +126,7 @@ public Object executeCommand(String commandId, List arguments, IProgress private static List getProjects(String commandId, IProgressMonitor monitor) { return QuteSupportForTemplate.getInstance().getProjects(JDTUtilsLSImpl.getInstance(), monitor); } - + private static ProjectInfo getProjectInfo(List arguments, String commandId, IProgressMonitor monitor) { QuteProjectParams params = createQuteProjectParams(arguments, commandId); return QuteSupportForTemplate.getInstance().getProjectInfo(params, JDTUtilsLSImpl.getInstance(), monitor); @@ -259,7 +266,7 @@ private static QuteResolvedJavaTypeParams createQuteResolvedJavaTypeParams(List< kind = ValueResolverKind.forValue(ArgumentUtils.getInt(obj, "kind")); } catch (IllegalArgumentException e) { // ignored - } + } return new QuteResolvedJavaTypeParams(className, kind, projectUri); } @@ -339,8 +346,7 @@ private static QuteJavaDefinitionParams createQuteJavaDefinitionParams(List arguments, String commandId, - IProgressMonitor monitor) - throws JavaModelException, CoreException { + IProgressMonitor monitor) throws JavaModelException, CoreException { // Create java definition parameter GenerateMissingJavaMemberParams params = createGenerateMissingJavaMemberParams(arguments, commandId); @@ -354,8 +360,8 @@ private static GenerateMissingJavaMemberParams createGenerateMissingJavaMemberPa Map obj = getFirst(arguments); if (obj == null) { - throw new UnsupportedOperationException(String - .format("Command '%s' must be called with one GenerateMissingJavaMemberParams argument!", commandId)); + throw new UnsupportedOperationException(String.format( + "Command '%s' must be called with one GenerateMissingJavaMemberParams argument!", commandId)); } MemberType memberType = null; @@ -397,17 +403,16 @@ private static GenerateMissingJavaMemberParams createGenerateMissingJavaMemberPa commandId)); } - return new GenerateMissingJavaMemberParams(memberType, missingProperty, javaType, projectUri, templateClass); } - + private static String getJavadoc(List arguments, String commandId, IProgressMonitor monitor) { QuteJavadocParams quteJavadocParams = createQuteJavadocParams(arguments, commandId); return QuteSupportForTemplate.getInstance().getJavadoc(quteJavadocParams, JDTUtilsLSImpl.getInstance(), monitor); } - + private static QuteJavadocParams createQuteJavadocParams(List arguments, String commandId) { Map obj = getFirst(arguments); if (obj == null) { @@ -453,4 +458,20 @@ private static QuteJavadocParams createQuteJavadocParams(List arguments, return new QuteJavadocParams(sourceType, projectUri, memberName, signature, documentFormat); } + private static boolean isInTemplate(List arguments, String commandId, IProgressMonitor monitor) { + QuteProjectParams params = createQuteProjectParams(arguments, commandId); + ProjectInfo projectInfo = QuteSupportForTemplate.getInstance().getProjectInfo(params, + JDTUtilsLSImpl.getInstance(), monitor); + if (projectInfo == null) { + return false; + } + Path templatePath = FileUtils.createPath(params.getTemplateFileUri()); + for (TemplateRootPath rootPath : projectInfo.getTemplateRootPaths()) { + if (rootPath.isIncluded(templatePath)) { + return true; + } + } + return false; + } + } diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/rootpath/TemplateRootPathProviderRegistry.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/rootpath/TemplateRootPathProviderRegistry.java new file mode 100644 index 000000000..1fc472c6b --- /dev/null +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/internal/template/rootpath/TemplateRootPathProviderRegistry.java @@ -0,0 +1,79 @@ +/******************************************************************************* +* 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.template.rootpath; + +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.core.IJavaProject; + +import com.redhat.qute.commons.TemplateRootPath; +import com.redhat.qute.jdt.internal.AbstractQuteExtensionPointRegistry; +import com.redhat.qute.jdt.template.datamodel.IDataModelProvider; +import com.redhat.qute.jdt.template.rootpath.ITemplateRootPathProvider; + +/** + * Registry to handle instances of {@link IDataModelProvider} + * + * @author Angelo ZERR + */ +public class TemplateRootPathProviderRegistry extends AbstractQuteExtensionPointRegistry { + + private static final Logger LOGGER = Logger.getLogger(TemplateRootPathProviderRegistry.class.getName()); + + private static final String TEMPLATE_ROOT_PATH_PROVIDERS_EXTENSION_POINT_ID = "templateRootPathProviders"; + private static final TemplateRootPathProviderRegistry INSTANCE = new TemplateRootPathProviderRegistry(); + + private TemplateRootPathProviderRegistry() { + super(); + } + + public static TemplateRootPathProviderRegistry getInstance() { + return INSTANCE; + } + + @Override + public String getProviderExtensionId() { + return TEMPLATE_ROOT_PATH_PROVIDERS_EXTENSION_POINT_ID; + } + + /** + * Returns the template root path list for the given java project. + * + * @param javaProject the java project. + * @param monitor the progress monitor. + * + * @return the template root path list for the given java project. + * + * @throws CoreException + */ + public List getTemplateRootPaths(IJavaProject javaProject, IProgressMonitor monitor) { + List rootPaths = new ArrayList<>(); + for (ITemplateRootPathProvider provider : super.getProviders()) { + if (provider.isApplicable(javaProject)) { + try { + provider.collectTemplateRootPaths(javaProject, rootPaths); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error while collecting template root path with the provider '" + + provider.getClass().getName() + "'.", e); + } + } + } + return rootPaths; + } +} diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/template/rootpath/DefaultTemplateRootPathProvider.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/template/rootpath/DefaultTemplateRootPathProvider.java new file mode 100644 index 000000000..13a8e95ea --- /dev/null +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/template/rootpath/DefaultTemplateRootPathProvider.java @@ -0,0 +1,44 @@ +/******************************************************************************* +* 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.template.rootpath; + +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.utils.JDTQuteProjectUtils; + +/** + * Default template root path provider for Qute project (src/main/resources/templates) + */ +public class DefaultTemplateRootPathProvider implements ITemplateRootPathProvider{ + + private static final String ORIGIN = "core"; + public static final String TEMPLATES_BASE_DIR = "src/main/resources/templates/"; + + @Override + public boolean isApplicable(IJavaProject project) { + return JDTQuteProjectUtils.hasQuteSupport(project); + } + + @Override + public void collectTemplateRootPaths(IJavaProject javaProject, List rootPaths) { + IProject project = javaProject.getProject(); + String templateBaseDir = project.getFile(TEMPLATES_BASE_DIR).getLocationURI().toString(); + rootPaths.add(new TemplateRootPath(templateBaseDir, ORIGIN)); + } + +} diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/template/rootpath/ITemplateRootPathProvider.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/template/rootpath/ITemplateRootPathProvider.java new file mode 100644 index 000000000..739245f1d --- /dev/null +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/template/rootpath/ITemplateRootPathProvider.java @@ -0,0 +1,46 @@ +/******************************************************************************* +* 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.template.rootpath; + +import java.util.List; + +import org.eclipse.jdt.core.IJavaProject; + +import com.redhat.qute.commons.TemplateRootPath; + +/** + * Template root path provider API. + * + * @author Angelo ZERR + * + */ +public interface ITemplateRootPathProvider { + + /** + * Returns true if the given Java project can provide template root path and + * false otherwise. + * + * @param project the Java project. + * @return true if the given Java project can provide template root path and + * false otherwise. + */ + boolean isApplicable(IJavaProject project); + + /** + * Collect template root path for the given Java project. + * + * @param javaProject the Java project. + */ + void collectTemplateRootPaths(IJavaProject javaProject, List rootPaths); +} 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 8fedc7a14..4f9aa85b4 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 @@ -28,7 +28,10 @@ import org.eclipse.jdt.internal.core.manipulation.dom.ASTResolving; import com.redhat.qute.commons.ProjectInfo; +import com.redhat.qute.commons.TemplateRootPath; import com.redhat.qute.jdt.internal.QuteJavaConstants; +import com.redhat.qute.jdt.internal.template.rootpath.TemplateRootPathProviderRegistry; +import com.redhat.qute.jdt.template.rootpath.DefaultTemplateRootPathProvider; import io.quarkus.runtime.util.StringUtil; @@ -42,8 +45,6 @@ public class JDTQuteProjectUtils { private static final Logger LOGGER = Logger.getLogger(JDTQuteProjectUtils.class.getName()); - private static final String TEMPLATES_BASE_DIR = "src/main/resources/templates/"; - /** * Value for Qute annotations indicating behaviour should be using the default */ @@ -56,7 +57,6 @@ private JDTQuteProjectUtils() { public static ProjectInfo getProjectInfo(IJavaProject javaProject) { IProject project = javaProject.getProject(); String projectUri = getProjectURI(project); - String templateBaseDir = project.getFile(TEMPLATES_BASE_DIR).getLocationURI().toString(); // Project dependencies List projectDependencies = Collections.emptyList(); try { @@ -70,7 +70,10 @@ public static ProjectInfo getProjectInfo(IJavaProject javaProject) { "Error while getting project dependencies for '" + javaProject.getElementName() + "' Java project.", e); } - return new ProjectInfo(projectUri, projectDependencies, templateBaseDir); + // Template root paths + List templateRootPaths = TemplateRootPathProviderRegistry.getInstance() + .getTemplateRootPaths(javaProject, null); + return new ProjectInfo(projectUri, projectDependencies, templateRootPaths); } /** @@ -117,7 +120,7 @@ public static boolean hasQuteSupport(IJavaProject javaProject) { public static TemplatePathInfo getTemplatePath(String basePath, String className, String methodOrFieldName, boolean ignoreFragments, TemplateNameStrategy templateNameStrategy) { String fragmentId = null; - StringBuilder templateUri = new StringBuilder(TEMPLATES_BASE_DIR); + StringBuilder templateUri = new StringBuilder(DefaultTemplateRootPathProvider.TEMPLATES_BASE_DIR); if (basePath != null && !DEFAULTED.equals(basePath)) { appendAndSlash(templateUri, basePath); } else if (className != null) { diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/FileUtils.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/FileUtils.java new file mode 100644 index 000000000..fd0f0b2a5 --- /dev/null +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/FileUtils.java @@ -0,0 +1,155 @@ +/******************************************************************************* +* 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; + } + return new File(fileURi).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.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/ProjectInfo.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/ProjectInfo.java index e048ca38f..385ea820f 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/ProjectInfo.java +++ b/qute.ls/com.redhat.qute.ls/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); } /** @@ -72,21 +72,11 @@ public void setProjectDependencyUris(List projectDependencyUris) { this.projectDependencyUris = projectDependencyUris; } - /** - * Returns the Qute templates base directory and null otherwise. - * - * @return the Qute templates base directory and null otherwise. - */ - public String getTemplateBaseDir() { - return templateBaseDir; + public List getTemplateRootPaths() { + return templateRootPaths; } - /** - * Set the Qute templates base directory. - * - * @param templateBaseDir the Qute templates base directory. - */ - public void setTemplateBaseDir(String templateBaseDir) { - this.templateBaseDir = templateBaseDir; + public void setTemplateRootPaths(List templateRootPaths) { + this.templateRootPaths = templateRootPaths; } } diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/TemplateRootPath.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/TemplateRootPath.java new file mode 100644 index 000000000..60368592c --- /dev/null +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/commons/TemplateRootPath.java @@ -0,0 +1,123 @@ +package com.redhat.qute.commons; + +import java.nio.file.Path; +import java.util.List; + +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; + } + + public String getOrigin() { + return origin; + } + + public void setOrigin(String origin) { + this.origin = origin; + } + + public Path getBasePath() { + if (basePath == null && baseDir != null) { + basePath = FileUtils.createPath(baseDir); + } + return basePath; + } + + 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; + } + + public boolean isIncluded(String uri) { + Path path = FileUtils.createPath(uri); + return isIncluded(path); + } + + 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.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/Template.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/Template.java index 57696efe7..7f1904ee0 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/Template.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/Template.java @@ -20,6 +20,7 @@ import org.eclipse.lsp4j.Position; +import com.redhat.qute.commons.FileUtils; import com.redhat.qute.commons.ProjectInfo; import com.redhat.qute.ls.commons.BadLocationException; import com.redhat.qute.ls.commons.LineIndentInfo; @@ -35,7 +36,6 @@ import com.redhat.qute.project.QuteTextDocument; import com.redhat.qute.project.datamodel.ExtendedDataModelParameter; import com.redhat.qute.project.datamodel.ExtendedDataModelTemplate; -import com.redhat.qute.utils.FileUtils; import com.redhat.qute.utils.UserTagUtils; public class Template extends Node { @@ -156,14 +156,6 @@ public String getProjectUri() { return projectUri; } - public Path getTemplateBaseDir() { - QuteProject project = getProject(); - if (project == null) { - return null; - } - return project.getTemplateBaseDir(); - } - public QuteProject getProject() { return projectRegistry != null ? projectRegistry.getProject(projectUri) : null; } diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/sections/IncludeSection.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/sections/IncludeSection.java index a23fde8d0..0966d786f 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/sections/IncludeSection.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/parser/template/sections/IncludeSection.java @@ -15,6 +15,7 @@ import java.nio.file.Path; import java.util.List; +import com.redhat.qute.commons.TemplateRootPath; import com.redhat.qute.parser.template.ASTVisitor; import com.redhat.qute.parser.template.Parameter; import com.redhat.qute.parser.template.Section; @@ -89,20 +90,26 @@ public Path getReferencedTemplateFile() { * section and null otherwise. */ private static Path getReferencedTemplateFile(String referencedTemplateId, QuteProject project) { - Path templateBaseDir = project.getTemplateBaseDir(); - if (templateBaseDir == null) { + List templateRootPaths = project.getTemplateRootPaths(); + if (templateRootPaths == null || templateRootPaths.isEmpty()) { return null; } - for (String suffix : project.getTemplateVariants()) { - Path referencedTemplateFile = templateBaseDir.resolve(referencedTemplateId + suffix); - if (Files.exists(referencedTemplateFile)) { - // The template file exists - return referencedTemplateFile; + for (TemplateRootPath rootPath : templateRootPaths) { + for (String suffix : project.getTemplateVariants()) { + Path templateBaseDir = rootPath.getBasePath(); + if (templateBaseDir != null) { + Path referencedTemplateFile = templateBaseDir.resolve(referencedTemplateId + suffix); + if (Files.exists(referencedTemplateFile)) { + // The template file exists + return referencedTemplateFile; + } + } } } // The template file doesn't exists, we return a file to create it if user wants // to do that (available when Ctrl+Click is processed). + Path templateBaseDir = templateRootPaths.get(0).getBasePath(); return templateBaseDir.resolve(referencedTemplateId + ".html"); } diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/QuteProject.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/QuteProject.java index e67dff444..a0835b24d 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/QuteProject.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/QuteProject.java @@ -12,7 +12,6 @@ package com.redhat.qute.project; import static com.redhat.qute.project.JavaDataModelCache.isSameType; -import static com.redhat.qute.utils.FileUtils.createPath; import java.io.IOException; import java.nio.file.Path; @@ -29,6 +28,7 @@ import org.eclipse.lsp4j.CompletionItem; import com.redhat.qute.commons.DocumentFormat; +import com.redhat.qute.commons.FileUtils; import com.redhat.qute.commons.InvalidMethodReason; import com.redhat.qute.commons.JavaElementInfo; import com.redhat.qute.commons.JavaFieldInfo; @@ -39,6 +39,7 @@ import com.redhat.qute.commons.ProjectInfo; import com.redhat.qute.commons.QuteJavadocParams; import com.redhat.qute.commons.ResolvedJavaTypeInfo; +import com.redhat.qute.commons.TemplateRootPath; import com.redhat.qute.commons.annotations.TemplateDataAnnotation; import com.redhat.qute.commons.datamodel.DataModelParameter; import com.redhat.qute.commons.datamodel.DataModelProject; @@ -71,7 +72,6 @@ import com.redhat.qute.services.nativemode.JavaTypeAccessibiltyRule; import com.redhat.qute.services.nativemode.JavaTypeFilter; import com.redhat.qute.services.nativemode.NativeModeJavaTypeFilter; -import com.redhat.qute.utils.FileUtils; import com.redhat.qute.utils.StringUtils; import com.redhat.qute.utils.UserTagUtils; @@ -91,7 +91,7 @@ public class QuteProject { private final String uri; - private final Path templateBaseDir; + private final List templateRootPaths; private final QuteClosedTextDocuments closedDocuments; @@ -121,12 +121,12 @@ public class QuteProject { public QuteProject(ProjectInfo projectInfo, QuteProjectRegistry projectRegistry, TemplateValidator validator) { this.uri = projectInfo.getUri(); - this.templateBaseDir = createPath(projectInfo.getTemplateBaseDir()); + this.templateRootPaths = projectInfo.getTemplateRootPaths(); this.documents = new HashMap<>(); this.closedDocuments = new QuteClosedTextDocuments(this, documents); this.projectRegistry = projectRegistry; this.resolvedJavaTypes = new HashMap<>(); - this.tagRegistry = new UserTagRegistry(this, templateBaseDir, projectRegistry); + this.tagRegistry = new UserTagRegistry(this, templateRootPaths, projectRegistry); this.filterInNativeMode = new NativeModeJavaTypeFilter(this); this.validator = validator; // Create a Java file watcher to track create/delete Qute file in @@ -169,8 +169,8 @@ public QuteProjectRegistry getProjectRegistry() { * @return the templates base dir folder of the project (ex : * src/main/resources/templates). */ - public Path getTemplateBaseDir() { - return templateBaseDir; + public List getTemplateRootPaths() { + return templateRootPaths; } /** @@ -181,14 +181,22 @@ public Path getTemplateBaseDir() { * @return the template id of the given template file path. */ public String getTemplateId(Path templateFilePath) { - if (templateFilePath == null || templateBaseDir == null) { + if (templateFilePath == null || templateRootPaths == null) { return null; } - try { - return templateBaseDir.relativize(templateFilePath).toString().replace('\\', '/'); - } catch (Exception e) { - return templateFilePath.getFileName().toString(); + for (TemplateRootPath rootPath : templateRootPaths) { + Path basePath = rootPath.getBasePath(); + if (basePath != null) { + if (templateFilePath.startsWith(basePath)) { + try { + return basePath.relativize(templateFilePath).toString().replace('\\', '/'); + } catch (Exception e) { + // Do nothing + } + } + } } + return templateFilePath.getFileName().toString(); } /** @@ -487,7 +495,7 @@ public void collectUserTagSuggestions(CompletionRequest completionRequest, Strin * @return the src/main/resources/templates/tags directory. */ public Path getTagsDir() { - return tagRegistry.getTagsDir(); + return tagRegistry.getPreferredTagsDir(); } public JavaTypeAccessibiltyRule getJavaTypeAccessibiltyInNativeMode(String javaTypeName) { diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/QuteProjectFilesWatcher.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/QuteProjectFilesWatcher.java index a4e73eb2e..049e70e4b 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/QuteProjectFilesWatcher.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/QuteProjectFilesWatcher.java @@ -25,7 +25,7 @@ import org.eclipse.lsp4j.FileChangeType; import org.eclipse.lsp4j.FileEvent; -import com.redhat.qute.utils.FileUtils; +import com.redhat.qute.commons.FileUtils; /** * This class provides the capability to track the deleted/created files from @@ -44,7 +44,7 @@ public class QuteProjectFilesWatcher extends WatchDir { private final Thread thread; public QuteProjectFilesWatcher(QuteProject project) throws IOException { - super(project.getTemplateBaseDir(), true); + super(project.getTemplateRootPaths().get(0).getBasePath(), true); this.project = project; thread = new Thread(this); thread.setName("Watch Qute templates for '" + project.getUri() + "'"); diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/QuteProjectRegistry.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/QuteProjectRegistry.java index 4780d2fae..561a4ab3b 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/QuteProjectRegistry.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/QuteProjectRegistry.java @@ -33,6 +33,7 @@ import org.eclipse.lsp4j.WorkDoneProgressReport; import org.eclipse.lsp4j.jsonrpc.messages.Either; +import com.redhat.qute.commons.FileUtils; import com.redhat.qute.commons.JavaTypeInfo; import com.redhat.qute.commons.ProjectInfo; import com.redhat.qute.commons.QuteJavaDefinitionParams; @@ -41,6 +42,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; @@ -64,7 +66,6 @@ import com.redhat.qute.services.nativemode.JavaTypeFilter; import com.redhat.qute.services.nativemode.ReflectionJavaTypeFilter; import com.redhat.qute.settings.QuteNativeSettings; -import com.redhat.qute.utils.FileUtils; /** * Registry which hosts Qute project {@link QuteProject}. @@ -333,7 +334,13 @@ private QuteProject findProjectFor(Path path) { } private static boolean isBelongToProject(Path path, QuteProject project) { - return path.startsWith(project.getTemplateBaseDir()); + for (TemplateRootPath rootPath : project.getTemplateRootPaths()) { + Path basePath = rootPath.getBasePath(); + if (basePath != null && path.startsWith(basePath)) { + return true; + } + } + return false; } public Collection getProjects() { diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/documents/QuteClosedTextDocument.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/documents/QuteClosedTextDocument.java index c60682655..99455d6ed 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/documents/QuteClosedTextDocument.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/documents/QuteClosedTextDocument.java @@ -19,6 +19,7 @@ import java.util.logging.Logger; import java.util.stream.Collectors; +import com.redhat.qute.commons.FileUtils; import com.redhat.qute.commons.ProjectInfo; import com.redhat.qute.ls.commons.TextDocument; import com.redhat.qute.parser.template.Parameter; @@ -27,7 +28,6 @@ import com.redhat.qute.parser.template.TemplateParser; import com.redhat.qute.project.QuteProject; import com.redhat.qute.project.QuteTextDocument; -import com.redhat.qute.utils.FileUtils; import com.redhat.qute.utils.IOUtils; /** diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/documents/QuteClosedTextDocuments.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/documents/QuteClosedTextDocuments.java index 2931c2d98..570b5e052 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/documents/QuteClosedTextDocuments.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/documents/QuteClosedTextDocuments.java @@ -13,13 +13,15 @@ import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; +import com.redhat.qute.commons.FileUtils; +import com.redhat.qute.commons.TemplateRootPath; import com.redhat.qute.project.QuteProject; import com.redhat.qute.project.QuteTextDocument; -import com.redhat.qute.utils.FileUtils; /** * Registry which stores Qute template document closed @@ -63,15 +65,25 @@ private synchronized void scan() { return; } - if (!Files.exists(project.getTemplateBaseDir())) { + List rootPaths = project.getTemplateRootPaths(); + for (TemplateRootPath templateRootPath : rootPaths) { + scan(templateRootPath.getBasePath()); + } + scanned = true; + } + + private void scan(Path basePath) { + if (basePath == null) { + return; + } + if (!Files.exists(basePath)) { // The Qute project doesn't contain the src/main/resources/templates directory return; } - // Scan all directories from src/main/resources/templates directory to collect // closed Templates try { - Files.walk(project.getTemplateBaseDir()).forEach(path -> { + Files.walk(basePath).forEach(path -> { try { tryToAddClosedTemplate(path, false); } catch (Exception e) { @@ -80,10 +92,7 @@ private synchronized void scan() { }); } catch (Exception e) { // Do nothing - } finally { - scanned = true; } - } /** diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/documents/QuteOpenedTextDocument.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/documents/QuteOpenedTextDocument.java index 98b2c759c..ebc8ef1a1 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/documents/QuteOpenedTextDocument.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/documents/QuteOpenedTextDocument.java @@ -11,7 +11,7 @@ *******************************************************************************/ package com.redhat.qute.project.documents; -import static com.redhat.qute.utils.FileUtils.createPath; +import static com.redhat.qute.commons.FileUtils.createPath; import java.nio.file.Path; import java.util.List; diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/tags/UserTagRegistry.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/tags/UserTagRegistry.java index 5ee8abd6d..eb5918d9d 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/tags/UserTagRegistry.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/tags/UserTagRegistry.java @@ -21,12 +21,12 @@ import org.eclipse.lsp4j.CompletionItem; +import com.redhat.qute.commons.TemplateRootPath; import com.redhat.qute.commons.usertags.QuteUserTagParams; import com.redhat.qute.commons.usertags.UserTagInfo; import com.redhat.qute.ls.api.QuteUserTagProvider; import com.redhat.qute.project.QuteProject; import com.redhat.qute.services.completions.CompletionRequest; -import com.redhat.qute.utils.UserTagUtils; /** * User tag (from source and binary) registry. @@ -39,8 +39,7 @@ public class UserTagRegistry { private final QuteProject project; - - private final Path tagsDir; + private final List templateRootPaths; private final QuteCompletionsForSourceUserTagSection completionsSourceUserTag; @@ -49,9 +48,10 @@ public class UserTagRegistry { private CompletableFuture> userTagFuture; - public UserTagRegistry(QuteProject project, Path templateBaseDir, QuteUserTagProvider userTagProvider) { + public UserTagRegistry(QuteProject project, List templateRootPaths, + QuteUserTagProvider userTagProvider) { this.project = project; - this.tagsDir = templateBaseDir.resolve(UserTagUtils.TAGS_DIR); + this.templateRootPaths = templateRootPaths; this.userTagProvider = userTagProvider; this.completionsSourceUserTag = new QuteCompletionsForSourceUserTagSection(); this.completionsBinaryUserTag = new QuteCompletionsForBinaryUserTagSection(); @@ -72,7 +72,12 @@ public Collection getSourceUserTags() { */ private void refresh() { // Loop for files from src/main/resources/tags to update list of user tags. - completionsSourceUserTag.refresh(getTagsDir(), project); + for (TemplateRootPath templateRootPath : templateRootPaths) { + Path tagsDir = templateRootPath.getTagsDir(); + if (tagsDir != null) { + completionsSourceUserTag.refresh(tagsDir, project); + } + } // Update from the 'templates.tags' entries of JARs of the classpath completionsBinaryUserTag.refresh(getBinaryUserTags()); } @@ -137,8 +142,9 @@ protected CompletableFuture> getBinaryUserTags(QuteUserTagPara * * @return the src/main/resources/templates/tags directory. */ - public Path getTagsDir() { - return tagsDir; + public Path getPreferredTagsDir() { + // TODO : select the non null tags dir + return templateRootPaths.get(0).getTagsDir(); } public void refreshDataModel() { diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/settings/QuteValidationSettings.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/settings/QuteValidationSettings.java index 11c547d8e..00b69d87f 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/settings/QuteValidationSettings.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/settings/QuteValidationSettings.java @@ -11,7 +11,7 @@ *******************************************************************************/ package com.redhat.qute.settings; -import static com.redhat.qute.utils.FileUtils.isFileURI; +import static com.redhat.qute.commons.FileUtils.isFileURI; import java.net.URI; import java.util.ArrayList; diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/utils/FileUtils.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/utils/FileUtils.java deleted file mode 100644 index d54c83bf1..000000000 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/utils/FileUtils.java +++ /dev/null @@ -1,71 +0,0 @@ -/******************************************************************************* -* 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.utils; - -import java.io.File; -import java.net.URI; -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 StringUtils.isEmpty(uri.getScheme()) || FILE_SCHEME.equals(uri.getScheme()); - } - - /** - * 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) { - if (StringUtils.isEmpty(uriString)) { - return null; - } - try { - URI uri = URI.create(uriString); - if (!isFileURI(uri)) { - // The uri is not a file URI, ignore it. - return null; - } - } catch (Exception e) { - return null; - } - String fileUri = uriString; - if (fileUri.startsWith("file:/")) { - String convertedUri = fileUri.replace("file:///", "file:/"); //$NON-NLS-1$//$NON-NLS-2$ - convertedUri = convertedUri.replace("file://", "file:/"); //$NON-NLS-1$//$NON-NLS-2$ - return new File(URI.create(convertedUri)).toPath(); - } - return new File(fileUri).toPath(); - } - - public static String toUri(Path path) { - return path.toUri().toASCIIString(); - } -} diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/utils/UserTagUtils.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/utils/UserTagUtils.java index 069cd76c2..6b396a31d 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/utils/UserTagUtils.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/utils/UserTagUtils.java @@ -21,6 +21,7 @@ import org.eclipse.lsp4j.jsonrpc.CancelChecker; +import com.redhat.qute.commons.TemplateRootPath; import com.redhat.qute.parser.expression.ObjectPart; import com.redhat.qute.parser.template.Expression; import com.redhat.qute.parser.template.Node; @@ -60,7 +61,7 @@ private static void register(SectionMetadata metadata) { SPECIAL_KEYS.put(metadata.getName(), metadata); } - public static final String TAGS_DIR = "tags"; + public static final String TAGS_DIR = TemplateRootPath.TAGS_DIR; public static boolean isUserTag(Template template) { String templateId = template.getTemplateId(); diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/QuteAssert.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/QuteAssert.java index f258eb9fd..a765cc010 100644 --- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/QuteAssert.java +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/QuteAssert.java @@ -73,6 +73,7 @@ import com.redhat.qute.commons.GenerateMissingJavaMemberParams; import com.redhat.qute.commons.ProjectInfo; +import com.redhat.qute.commons.TemplateRootPath; import com.redhat.qute.ls.api.QuteTemplateJavaTextEditProvider; import com.redhat.qute.ls.commons.BadLocationException; import com.redhat.qute.ls.commons.TextDocument; @@ -115,7 +116,8 @@ public class QuteAssert { public static final String FILE_URI = "test.qute"; public static final int USER_TAG_SIZE = 10 /* - * #input, #bundleStyle, #form, #title, #simpleTitle, #user, #formElement, + * #input, #bundleStyle, #form, #title, #simpleTitle, #user, + * #formElement, * #inputRequired, #myTag, #tagWithArgs */; @@ -210,7 +212,8 @@ public static void testCompletionFor(String value, boolean snippetSupport, boole public static void testCompletionFor(String value, String fileUri, String templateId, String projectUri, String templateBaseDir, Integer expectedCount, QuteNativeSettings nativeImagesSettings, - QuteCompletionSettings completionSettings, boolean itemDefaultsSupport, CompletionItem... expectedItems) throws Exception { + QuteCompletionSettings completionSettings, boolean itemDefaultsSupport, CompletionItem... expectedItems) + throws Exception { int offset = value.indexOf('|'); value = value.substring(0, offset) + value.substring(offset + 1); @@ -249,7 +252,8 @@ public static void testCompletionFor(String value, String fileUri, String templa } } - public static void assertCompletion(CompletionList completions, CompletionItem expected, boolean itemDefaultsSupport, Integer expectedCount) { + public static void assertCompletion(CompletionList completions, CompletionItem expected, + boolean itemDefaultsSupport, Integer expectedCount) { List matches = completions.getItems().stream().filter(completion -> { return expected.getLabel().equals(completion.getLabel()); }).collect(Collectors.toList()); @@ -277,7 +281,8 @@ public static void assertCompletion(CompletionList completions, CompletionItem e } } else if (itemDefaultsSupport) { assertEquals(expected.getTextEdit().getLeft().getNewText(), match.getTextEditText()); - assertEquals(expected.getTextEdit().getLeft().getRange(), completions.getItemDefaults().getEditRange().getLeft()); + assertEquals(expected.getTextEdit().getLeft().getRange(), + completions.getItemDefaults().getEditRange().getLeft()); assertNull(match.getTextEdit()); } @@ -292,11 +297,14 @@ public static void assertCompletion(CompletionList completions, CompletionItem e } - private static CompletionItem getCompletionMatch(List matches, boolean itemDefaultsSupport, CompletionItem expected) { + private static CompletionItem getCompletionMatch(List matches, boolean itemDefaultsSupport, + CompletionItem expected) { for (CompletionItem item : matches) { - if (!itemDefaultsSupport && expected.getTextEdit().getLeft().getNewText().equals(item.getTextEdit().getLeft().getNewText())) { + if (!itemDefaultsSupport && expected.getTextEdit().getLeft().getNewText() + .equals(item.getTextEdit().getLeft().getNewText())) { return item; - } else if (itemDefaultsSupport && expected.getTextEdit().getLeft().getNewText().equals(item.getTextEditText())) { + } else if (itemDefaultsSupport + && expected.getTextEdit().getLeft().getNewText().equals(item.getTextEditText())) { return item; } } @@ -710,7 +718,8 @@ public static void assertInlayHint(List actual, InlayHint.. // ------------------- CodeAction assert - public static void testCodeActionsWithConfigurationUpdateFor(String value, Diagnostic diagnostic, CodeAction... expected) + public static void testCodeActionsWithConfigurationUpdateFor(String value, Diagnostic diagnostic, + CodeAction... expected) throws Exception { testCodeActionsFor(value, diagnostic, createSharedSettings(true), expected); } @@ -1049,7 +1058,8 @@ private static Template createTemplate(String value, String fileUri, String proj QuteProjectRegistry projectRegistry) { Template template = TemplateParser.parse(value, fileUri != null ? fileUri : FILE_URI); template.setProjectUri(projectUri); - projectRegistry.getProject(new ProjectInfo(projectUri, Collections.emptyList(), templateBaseDir)); + projectRegistry.getProject(new ProjectInfo(projectUri, Collections.emptyList(), + Arrays.asList(new TemplateRootPath(templateBaseDir)))); template.setProjectRegistry(projectRegistry); return template; } @@ -1058,12 +1068,11 @@ public static SharedSettings createSharedSettings(boolean withConfigurationUpdat SharedSettings sharedSettings = new SharedSettings(); CommandCapabilities commandCapabilities = new CommandCapabilities(); CommandKindCapabilities kinds = new CommandKindCapabilities( - withConfigurationUpdate ? - Arrays.asList(QuteClientCommandConstants.COMMAND_JAVA_DEFINITION, + withConfigurationUpdate ? Arrays.asList(QuteClientCommandConstants.COMMAND_JAVA_DEFINITION, QuteClientCommandConstants.COMMAND_SHOW_REFERENCES, - QuteClientCommandConstants.COMMAND_CONFIGURATION_UPDATE) : - Arrays.asList(QuteClientCommandConstants.COMMAND_JAVA_DEFINITION, - QuteClientCommandConstants.COMMAND_SHOW_REFERENCES)); + QuteClientCommandConstants.COMMAND_CONFIGURATION_UPDATE) + : Arrays.asList(QuteClientCommandConstants.COMMAND_JAVA_DEFINITION, + QuteClientCommandConstants.COMMAND_SHOW_REFERENCES)); commandCapabilities.setCommandKind(kinds); sharedSettings.getCommandCapabilities().setCapabilities(commandCapabilities); return sharedSettings; diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/multiple/QuteProjectA.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/multiple/QuteProjectA.java index 443ca92ae..4f711af0c 100644 --- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/multiple/QuteProjectA.java +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/multiple/QuteProjectA.java @@ -11,6 +11,7 @@ *******************************************************************************/ package com.redhat.qute.project.multiple; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; @@ -18,6 +19,7 @@ import com.redhat.qute.commons.JavaTypeInfo; import com.redhat.qute.commons.ProjectInfo; 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.DataModelTemplate; import com.redhat.qute.commons.datamodel.resolvers.NamespaceResolverInfo; @@ -30,7 +32,8 @@ public class QuteProjectA extends MockQuteProject { public final static String PROJECT_URI = "project-a"; public QuteProjectA(QuteProjectRegistry projectRegistry) { - super(new ProjectInfo(PROJECT_URI, Collections.emptyList(), getProjectPath(PROJECT_URI) + "/src/main/resources/templates"), + super(new ProjectInfo(PROJECT_URI, Collections.emptyList(), + Arrays.asList(new TemplateRootPath(getProjectPath(PROJECT_URI) + "/src/main/resources/templates"))), projectRegistry); } diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/multiple/QuteProjectB.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/multiple/QuteProjectB.java index a31210a7e..1334cc9d6 100644 --- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/multiple/QuteProjectB.java +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/multiple/QuteProjectB.java @@ -11,6 +11,7 @@ *******************************************************************************/ package com.redhat.qute.project.multiple; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; @@ -18,6 +19,7 @@ import com.redhat.qute.commons.JavaTypeInfo; import com.redhat.qute.commons.ProjectInfo; 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.DataModelTemplate; import com.redhat.qute.commons.datamodel.resolvers.NamespaceResolverInfo; @@ -30,11 +32,13 @@ public class QuteProjectB extends MockQuteProject { public final static String PROJECT_URI = "project-b"; public QuteProjectB(QuteProjectRegistry projectRegistry) { - super(new ProjectInfo(PROJECT_URI, Collections.emptyList(), getProjectPath(PROJECT_URI) + "/src/main/resources/templates"), + super(new ProjectInfo(PROJECT_URI, Collections.emptyList(), + Arrays.asList(new TemplateRootPath(getProjectPath(PROJECT_URI) + "/src/main/resources/templates"))), projectRegistry); // project-b dependends from project-a super.getProjectDependencies().add(projectRegistry.getProject( - new ProjectInfo(QuteProjectA.PROJECT_URI, Collections.emptyList(), ""))); + new ProjectInfo(QuteProjectA.PROJECT_URI, Collections.emptyList(), + Arrays.asList(new TemplateRootPath(""))))); } @Override diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqProject.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqProject.java index 97e3a256e..a407f31df 100644 --- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqProject.java +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/roq/RoqProject.java @@ -31,7 +31,7 @@ * Roq project. */ public class RoqProject extends BaseQuteProject { - + public static final String PROJECT_URI = "roq"; private DataModelProject> dataModel; diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/commands/QuteGenerateTemplateContentCommandHandlerTest.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/commands/QuteGenerateTemplateContentCommandHandlerTest.java index cc0f6ae04..a0b86e802 100644 --- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/commands/QuteGenerateTemplateContentCommandHandlerTest.java +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/commands/QuteGenerateTemplateContentCommandHandlerTest.java @@ -13,6 +13,7 @@ import org.junit.jupiter.api.Test; import com.redhat.qute.commons.ProjectInfo; +import com.redhat.qute.commons.TemplateRootPath; import com.redhat.qute.commons.datamodel.DataModelParameter; import com.redhat.qute.commons.datamodel.GenerateTemplateInfo; import com.redhat.qute.project.MockQuteProjectRegistry; @@ -35,7 +36,8 @@ public void generateItem() throws InterruptedException, ExecutionException, Exce private QuteProjectRegistry createProjectRegistry() { QuteProjectRegistry projectRegistry = new MockQuteProjectRegistry(); - projectRegistry.getProject(new ProjectInfo(PROJECT_URI, Collections.emptyList(), TEMPLATE_BASE_DIR)); + projectRegistry.getProject(new ProjectInfo(PROJECT_URI, Collections.emptyList(), + Arrays.asList(new TemplateRootPath(TEMPLATE_BASE_DIR)))); return projectRegistry; } diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/project/AbstractQuteDiagnosticsInProjectTest.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/project/AbstractQuteDiagnosticsInProjectTest.java index 3b16697cb..8c5cdc64f 100644 --- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/project/AbstractQuteDiagnosticsInProjectTest.java +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/project/AbstractQuteDiagnosticsInProjectTest.java @@ -28,12 +28,13 @@ import org.eclipse.lsp4j.PublishDiagnosticsParams; import org.junit.jupiter.api.Test; +import com.redhat.qute.commons.FileUtils; import com.redhat.qute.commons.ProjectInfo; import com.redhat.qute.commons.QuteProjectParams; +import com.redhat.qute.commons.TemplateRootPath; import com.redhat.qute.project.MockQuteLanguageServer; import com.redhat.qute.project.QuteQuickStartProject; import com.redhat.qute.services.diagnostics.QuteErrorCode; -import com.redhat.qute.utils.FileUtils; import com.redhat.qute.utils.IOUtils; /** @@ -69,7 +70,7 @@ public CompletableFuture> getProjects() { private ProjectInfo createQuickStartProject() { ProjectInfo projectInfo = new ProjectInfo(QuteQuickStartProject.PROJECT_URI, Collections.emptyList(), - FileUtils.toUri(templatesPath)); + Arrays.asList(new TemplateRootPath(FileUtils.toUri(templatesPath)))); return projectInfo; }; diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/project/QuteDiagnosticsInProjectWithLSPDidChangeWatchedFilesTest.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/project/QuteDiagnosticsInProjectWithLSPDidChangeWatchedFilesTest.java index c5e0c45fd..c3e0e7458 100644 --- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/project/QuteDiagnosticsInProjectWithLSPDidChangeWatchedFilesTest.java +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/diagnostics/project/QuteDiagnosticsInProjectWithLSPDidChangeWatchedFilesTest.java @@ -21,8 +21,8 @@ import org.eclipse.lsp4j.FileChangeType; import org.eclipse.lsp4j.FileEvent; +import com.redhat.qute.commons.FileUtils; import com.redhat.qute.project.MockQuteLanguageServer; -import com.redhat.qute.utils.FileUtils; /** * Diagnostics tests with closed/opened Qute template in a given project with diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/references/QuteReferenceWithInsertSectionTest.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/references/QuteReferenceWithInsertSectionTest.java index 0c574ee5e..42363fd74 100644 --- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/references/QuteReferenceWithInsertSectionTest.java +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/services/references/QuteReferenceWithInsertSectionTest.java @@ -17,8 +17,8 @@ import org.junit.jupiter.api.Test; +import com.redhat.qute.commons.FileUtils; import com.redhat.qute.ls.commons.BadLocationException; -import com.redhat.qute.utils.FileUtils; /** * Qute reference with object part.