From 2ee9cc28fa5a0091b6ddb3acd7a4c59cc5d93d4f Mon Sep 17 00:00:00 2001 From: azerr Date: Tue, 19 Sep 2023 11:06:32 +0200 Subject: [PATCH] Qute support for multi module project Fixes #930 Signed-off-by: azerr --- qute.jdt/com.redhat.qute.jdt/plugin.xml | 1 + .../com/redhat/qute/commons/ProjectInfo.java | 27 ++++- .../qute/jdt/QuteSupportForTemplate.java | 25 ++++ ...portForTemplateDelegateCommandHandler.java | 7 ++ .../qute/jdt/utils/JDTQuteProjectUtils.java | 18 ++- .../com/redhat/qute/commons/ProjectInfo.java | 27 ++++- .../redhat/qute/ls/QuteLanguageServer.java | 58 +++++---- .../qute/ls/api/QuteProjectInfoProvider.java | 34 ++++++ .../template/sections/IncludeSection.java | 27 ++++- .../com/redhat/qute/project/QuteProject.java | 8 ++ .../qute/project/QuteProjectRegistry.java | 110 +++++++++++------- .../redhat/qute/services/QuteDiagnostics.java | 6 +- .../qute/services/QuteDocumentLink.java | 2 +- .../QuteCompletionForTemplateIds.java | 3 + .../test/java/com/redhat/qute/QuteAssert.java | 2 +- .../qute/project/MockQuteLanguageClient.java | 16 +++ .../qute/project/MockQuteProjectRegistry.java | 2 +- ...rateTemplateContentCommandHandlerTest.java | 3 +- .../AbstractQuteDiagnosticsInProjectTest.java | 18 ++- 19 files changed, 312 insertions(+), 82 deletions(-) diff --git a/qute.jdt/com.redhat.qute.jdt/plugin.xml b/qute.jdt/com.redhat.qute.jdt/plugin.xml index 005536026..6e95ae033 100644 --- a/qute.jdt/com.redhat.qute.jdt/plugin.xml +++ b/qute.jdt/com.redhat.qute.jdt/plugin.xml @@ -12,6 +12,7 @@ + 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 2bcb3fc87..e048ca38f 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 @@ -11,6 +11,8 @@ *******************************************************************************/ package com.redhat.qute.commons; +import java.util.List; + /** * Project information where a Qute template belongs to. * @@ -23,11 +25,14 @@ public class ProjectInfo { private String templateBaseDir; + private List projectDependencyUris; + public ProjectInfo() { } - public ProjectInfo(String uri, String templateBaseDir) { - setUri(uri); + public ProjectInfo(String projectUri, List projectDependencies, String templateBaseDir) { + setUri(projectUri); + setProjectDependencyUris(projectDependencies); setTemplateBaseDir(templateBaseDir); } @@ -49,6 +54,24 @@ public void setUri(String uri) { this.uri = uri; } + /** + * Returns the project dependency Uris. + * + * @return the project dependency Uris. + */ + public List getProjectDependencyUris() { + return projectDependencyUris; + } + + /** + * Set the project dependency Uris. + * + * @param projectDependencyUris the project dependency Uris. + */ + public void setProjectDependencyUris(List projectDependencyUris) { + this.projectDependencyUris = projectDependencyUris; + } + /** * Returns the Qute templates base directory and null otherwise. * diff --git a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/QuteSupportForTemplate.java b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/QuteSupportForTemplate.java index 24c8e8872..1dd938e23 100644 --- a/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/QuteSupportForTemplate.java +++ b/qute.jdt/com.redhat.qute.jdt/src/main/java/com/redhat/qute/jdt/QuteSupportForTemplate.java @@ -17,6 +17,7 @@ import java.net.URISyntaxException; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -99,6 +100,18 @@ public static QuteSupportForTemplate getInstance() { return INSTANCE; } + public List getProjects(IJDTUtils utils, IProgressMonitor monitor) { + List quteProjects = new ArrayList<>(); + IProject[] allProjects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); + for (IProject project : allProjects) { + IJavaProject javaProject = getJavaProject(project); + if (isQuteProject(javaProject)) { + quteProjects.add(JDTQuteProjectUtils.getProjectInfo(javaProject)); + } + } + return quteProjects; + } + /** * Returns the project information for the given project Uri. * @@ -405,12 +418,24 @@ private static IProject findProject(String resourceUri, IJDTUtils utils) { */ private static boolean isQuteProject(IProject project) { IJavaProject javaProject = getJavaProject(project); + return isQuteProject(javaProject); + } + + /** + * Returns true if the given Java project is a Java Qute project and false otherwise. + * + * @param project the Java project. + * + * @return true if the given Java project is a Java Qute project and false otherwise. + */ + private static boolean isQuteProject(IJavaProject javaProject) { if (javaProject == null) { return false; } return JDTTypeUtils.findType(javaProject, QuteJavaConstants.TEMPLATE_CLASS) != null; } + /** * Returns the Java project of the given project and null otherwise. * 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 01125ed6c..d73c38999 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 @@ -74,6 +74,7 @@ public class QuteSupportForTemplateDelegateCommandHandler extends AbstractQuteDe private static final String CLASS_NAME_ATTR = "className"; + private static final String QUTE_TEMPLATE_PROJECTS_COMMAND_ID = "qute/template/projects"; private static final String QUTE_TEMPLATE_PROJECT_COMMAND_ID = "qute/template/project"; private static final String QUTE_TEMPLATE_PROJECT_DATA_MODEL_COMMAND_ID = "qute/template/projectDataModel"; @@ -93,6 +94,8 @@ public class QuteSupportForTemplateDelegateCommandHandler extends AbstractQuteDe @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: @@ -113,6 +116,10 @@ public Object executeCommand(String commandId, List arguments, IProgress return null; } + 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); 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 1cdacaeae..291e2154c 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 @@ -11,11 +11,16 @@ *******************************************************************************/ package com.redhat.qute.jdt.utils; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.ITypeRoot; +import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.internal.core.manipulation.dom.ASTResolving; @@ -40,7 +45,18 @@ public static ProjectInfo getProjectInfo(IJavaProject javaProject) { IProject project = javaProject.getProject(); String projectUri = getProjectURI(project); String templateBaseDir = project.getFile(TEMPLATES_BASE_DIR).getLocationURI().toString(); - return new ProjectInfo(projectUri, templateBaseDir); + // Project dependencies + List projectDependencies = Collections.emptyList(); + try { + String[] requiredProjectNames = javaProject.getRequiredProjectNames(); + if (requiredProjectNames != null) { + projectDependencies = Arrays.asList(requiredProjectNames); + } + } catch (JavaModelException e) { + // Should never occurs + e.printStackTrace(); + } + return new ProjectInfo(projectUri, projectDependencies, templateBaseDir); } /** 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 2bcb3fc87..e048ca38f 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 @@ -11,6 +11,8 @@ *******************************************************************************/ package com.redhat.qute.commons; +import java.util.List; + /** * Project information where a Qute template belongs to. * @@ -23,11 +25,14 @@ public class ProjectInfo { private String templateBaseDir; + private List projectDependencyUris; + public ProjectInfo() { } - public ProjectInfo(String uri, String templateBaseDir) { - setUri(uri); + public ProjectInfo(String projectUri, List projectDependencies, String templateBaseDir) { + setUri(projectUri); + setProjectDependencyUris(projectDependencies); setTemplateBaseDir(templateBaseDir); } @@ -49,6 +54,24 @@ public void setUri(String uri) { this.uri = uri; } + /** + * Returns the project dependency Uris. + * + * @return the project dependency Uris. + */ + public List getProjectDependencyUris() { + return projectDependencyUris; + } + + /** + * Set the project dependency Uris. + * + * @param projectDependencyUris the project dependency Uris. + */ + public void setProjectDependencyUris(List projectDependencyUris) { + this.projectDependencyUris = projectDependencyUris; + } + /** * Returns the Qute templates base directory and null otherwise. * diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/ls/QuteLanguageServer.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/ls/QuteLanguageServer.java index 5076dcd54..1ac5353d4 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/ls/QuteLanguageServer.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/ls/QuteLanguageServer.java @@ -32,7 +32,6 @@ import org.eclipse.lsp4j.SetTraceParams; import org.eclipse.lsp4j.WorkDoneProgressCreateParams; import org.eclipse.lsp4j.WorkDoneProgressNotification; -import org.eclipse.lsp4j.WorkspaceFolder; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.lsp4j.services.LanguageClient; import org.eclipse.lsp4j.services.LanguageServer; @@ -108,11 +107,12 @@ public class QuteLanguageServer implements LanguageServer, ProcessLanguageServer private QuteLanguageClientAPI languageClient; private QuteCapabilityManager capabilityManager; - private List workspaceFolders; public QuteLanguageServer() { this.sharedSettings = new SharedSettings(); - this.projectRegistry = new QuteProjectRegistry(this, this, this, this, this, this, this, this); + this.projectRegistry = new QuteProjectRegistry(this, this, this, this, this, this, this, this, // + () -> capabilityManager.getClientCapabilities() + .isWorkDoneProgressSupported() ? this : null); this.quteLanguageService = new QuteLanguageService(projectRegistry); this.textDocumentService = new QuteTextDocumentService(this); this.workspaceService = new QuteWorkspaceService(this); @@ -135,7 +135,6 @@ public CompletableFuture initialize(InitializeParams params) { projectRegistry.setDidChangeWatchedFilesSupported( capabilityManager.getClientCapabilities().isDidChangeWatchedFilesRegistered()); - workspaceFolders = params.getWorkspaceFolders(); InitializeResult initializeResult = new InitializeResult(serverCapabilities); return CompletableFuture.completedFuture(initializeResult); @@ -163,19 +162,13 @@ public void initialized(InitializedParams params) { * Try to load the Qute project for each workspace folder. */ private void loadQuteProjects() { - if (workspaceFolders == null || workspaceFolders.isEmpty()) { - // No workspace folders. - return; - } - CompletableFuture.runAsync(() -> { - for (WorkspaceFolder workspaceFolder : workspaceFolders) { - // Get the LSP client progress support - ProgressSupport progressSupport = capabilityManager.getClientCapabilities() - .isWorkDoneProgressSupported() ? this : null; - // Try to load the Qute project of the current workspace folder - projectRegistry.tryToLoadQuteProject(workspaceFolder, progressSupport); - } - }); + getLanguageClient().getProjects() + .thenAccept(projects -> { + if (projects != null && !projects.isEmpty()) { + // Load qute projects + projectRegistry.loadQuteProjects(projects); + } + }); } /** @@ -267,6 +260,30 @@ public SharedSettings getSharedSettings() { return sharedSettings; } + // Project requests / notifications + + @Override + public CompletableFuture> getProjects() { + return getLanguageClient().getProjects(); + } + + @Override + public void projectAdded(ProjectInfo project) { + projectRegistry.projectAdded(project); + } + + @Override + public void projectRemoved(ProjectInfo project) { + projectRegistry.projectRemoved(project); + } + + @Override + public CompletableFuture getProjectInfo(QuteProjectParams params) { + return getLanguageClient().getProjectInfo(params); + } + + // Other requests / notifications + @Override public CompletableFuture> getJavaTypes(QuteJavaTypesParams params) { return getLanguageClient().getJavaTypes(params); @@ -282,11 +299,6 @@ public CompletableFuture getResolvedJavaType(QuteResolvedJ return getLanguageClient().getResolvedJavaType(params); } - @Override - public CompletableFuture getProjectInfo(QuteProjectParams params) { - return getLanguageClient().getProjectInfo(params); - } - @Override public CompletableFuture getJavadoc(QuteJavadocParams params) { return getLanguageClient().getJavadoc(params); @@ -355,7 +367,7 @@ public void notifyProgress(String progressId, WorkDoneProgressNotification notif } @Override - public void telemetryEvent (Object object) { + public void telemetryEvent(Object object) { getLanguageClient().telemetryEvent(object); } diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/ls/api/QuteProjectInfoProvider.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/ls/api/QuteProjectInfoProvider.java index 29c168327..a64f240f9 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/ls/api/QuteProjectInfoProvider.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/ls/api/QuteProjectInfoProvider.java @@ -11,8 +11,10 @@ *******************************************************************************/ package com.redhat.qute.ls.api; +import java.util.Collection; import java.util.concurrent.CompletableFuture; +import org.eclipse.lsp4j.jsonrpc.services.JsonNotification; import org.eclipse.lsp4j.jsonrpc.services.JsonRequest; import com.redhat.qute.commons.ProjectInfo; @@ -26,6 +28,38 @@ */ public interface QuteProjectInfoProvider { + /** + * Returns all Qute projects from the workspace. + * + * @return all Qute projects from the workspace. + */ + @JsonRequest("qute/template/projects") + CompletableFuture> getProjects(); + + /** + * Notification received when a Qute project is added in the workspace. + * + * @param project the Qute project which is added in the workspace. + */ + @JsonNotification("qute/template/project/added") + void projectAdded(ProjectInfo project); + + /** + * Notification received when a Qute project is closed / removed from the + * workspace. + * + * @param project the Qute project which is closed / removed from the workspace. + */ + @JsonNotification("qute/template/project/removed") + void projectRemoved(ProjectInfo project); + + /** + * Returns the Qute project from the given template file uri parameter. + * + * @param params the template file uri parameter. + * @return + */ @JsonRequest("qute/template/project") CompletableFuture getProjectInfo(QuteProjectParams params); + } 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 53cae4178..14640b099 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 @@ -53,11 +53,36 @@ public Path getReferencedTemplateFile() { if (referencedTemplateId == null) { return null; } - QuteProject project = getOwnerTemplate().getProject(); if (project == null) { return null; } + Path templatePath = getReferencedTemplateFile(referencedTemplateId, project); + if (templatePath != null && Files.exists(templatePath)) { + return templatePath; + } + + for (QuteProject projectDependency : project.getProjectDependencies()) { + Path dependencyTemplatePath = getReferencedTemplateFile(referencedTemplateId, projectDependency); + if (dependencyTemplatePath != null && Files.exists(dependencyTemplatePath)) { + return dependencyTemplatePath; + } + } + + return templatePath; + } + + /** + * Returns the referenced template file defined in the first parameter of the + * section and null otherwise. + * + * @return the referenced template file defined in the first parameter of the + * section and null otherwise. + */ + private static Path getReferencedTemplateFile(String referencedTemplateId, QuteProject project) { + if (referencedTemplateId == null || project == null) { + return null; + } Path templateBaseDir = project.getTemplateBaseDir(); if (templateBaseDir == null) { 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 069b592c6..0f0b00d1c 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 @@ -116,6 +116,8 @@ public class QuteProject { private final JavaDataModelCache javaCache; + private List projectDependencies; + public QuteProject(ProjectInfo projectInfo, QuteProjectRegistry projectRegistry, TemplateValidator validator) { this.uri = projectInfo.getUri(); @@ -132,6 +134,7 @@ public QuteProject(ProjectInfo projectInfo, QuteProjectRegistry projectRegistry, // ONLY if LSP client cannot support DidChangeWatchedFiles. this.watcher = !projectRegistry.isDidChangeWatchedFilesSupported() ? createFilesWatcher(this) : null; this.javaCache = new JavaDataModelCache(this); + this.projectDependencies = new ArrayList<>(); } private static QuteProjectFilesWatcher createFilesWatcher(QuteProject project) { @@ -210,6 +213,10 @@ public boolean isTemplateOpened(String templateId) { public String getUri() { return uri; } + + public List getProjectDependencies() { + return projectDependencies; + } /** * Returns the insert parameter list with the given name @@ -1507,5 +1514,6 @@ public CompletableFuture getJavadoc(JavaMemberInfo javaMemberInfo, JavaT return projectRegistry.getJavadoc(new QuteJavadocParams(typeName, getUri(), javaMemberInfo.getName(), signature, hasMarkdown ? DocumentFormat.Markdown : DocumentFormat.PlainText)); } + } \ No newline at end of file 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 b77864ad2..e38dc2c85 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 @@ -22,6 +22,7 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; import org.eclipse.lsp4j.DidChangeWatchedFilesParams; import org.eclipse.lsp4j.FileEvent; @@ -30,7 +31,6 @@ import org.eclipse.lsp4j.WorkDoneProgressCreateParams; import org.eclipse.lsp4j.WorkDoneProgressEnd; import org.eclipse.lsp4j.WorkDoneProgressReport; -import org.eclipse.lsp4j.WorkspaceFolder; import org.eclipse.lsp4j.jsonrpc.messages.Either; import com.redhat.qute.commons.JavaTypeInfo; @@ -95,13 +95,15 @@ public class QuteProjectRegistry private final TemplateValidator validator; + private final Supplier progressSupportProvider; + private boolean didChangeWatchedFilesSupported; public QuteProjectRegistry(QuteProjectInfoProvider projectInfoProvider, QuteJavaTypesProvider javaTypeProvider, QuteJavaDefinitionProvider definitionProvider, QuteResolvedJavaTypeProvider resolvedClassProvider, QuteDataModelProjectProvider dataModelProvider, QuteUserTagProvider userTagsProvider, QuteJavadocProvider javadocProvider, - TemplateValidator validator) { + TemplateValidator validator, Supplier progressSupportProvider) { this.projectInfoProvider = projectInfoProvider; this.javaTypeProvider = javaTypeProvider; this.definitionProvider = definitionProvider; @@ -112,6 +114,7 @@ public QuteProjectRegistry(QuteProjectInfoProvider projectInfoProvider, QuteJava this.javadocProvider = javadocProvider; this.valueResolversRegistry = new ValueResolversRegistry(); this.validator = validator; + this.progressSupportProvider = progressSupportProvider; } /** @@ -401,64 +404,67 @@ public CompletableFuture getProjectInfo(QuteProjectParams params) { return projectInfoProvider.getProjectInfo(params); } + public void loadQuteProjects(Collection projects) { + for (ProjectInfo projectInfo : projects) { + // Load the Qute project + loadQuteProject(projectInfo); + } + // update project dependencies + for (ProjectInfo projectInfo : projects) { + if (projectInfo.getProjectDependencyUris() != null && !projectInfo.getProjectDependencyUris().isEmpty()) { + QuteProject project = getProject(projectInfo.getUri()); + for (String projectDependencyUri : projectInfo.getProjectDependencyUris()) { + QuteProject projectDependency = getProject(projectDependencyUri); + if (projectDependency != null) { + project.getProjectDependencies().add(projectDependency); + } + } + } + } + + } + /** - * Try to load the Qute project of the given workspace folder. + * Load the Qute project from the given Qute project information. * - * @param workspaceFolder the workspace folder. - * @param progressSupport the LSP client progress support and null otherwise. + * @param projectInfo the project information. */ - public void tryToLoadQuteProject(WorkspaceFolder workspaceFolder, ProgressSupport progressSupport) { - String projectName = workspaceFolder.getName(); - + private QuteProject loadQuteProject(ProjectInfo projectInfo) { + // Get the LSP client progress support (or null if LSP client cannot support + // progress) + ProgressSupport progressSupport = progressSupportProvider.get(); + String projectName = projectInfo.getUri(); String progressId = createAndStartProgress(projectName, progressSupport); - // Load Qute project from the Java component (collect Java data model) - String projectUri = workspaceFolder.getUri(); - QuteProjectParams params = new QuteProjectParams(projectUri); - getProjectInfo(params) - .thenAccept(projectInfo -> { - if (projectInfo == null) { - // The workspace folder is not a Qute project, end the process - endProgress(progressId, progressSupport); - return; - } - - // The workspace folder is a Qute project, load the data model from Java - // component - QuteProject project = getProject(projectInfo, false); + QuteProject project = getProject(projectInfo, false); + if (progressSupport != null) { + WorkDoneProgressReport report = new WorkDoneProgressReport(); + report.setMessage("Loading data model for '" + projectName + "' Qute project."); + report.setPercentage(10); + progressSupport.notifyProgress(progressId, report); + } + project.getDataModelProject() + .thenAccept(dataModel -> { + // The Java data model is collected for the project, validate all templates of + // the project if (progressSupport != null) { WorkDoneProgressReport report = new WorkDoneProgressReport(); - report.setMessage("Loading data model for '" + projectName + "' Qute project."); - report.setPercentage(10); + report.setMessage( + "Validating Qute templates for '" + projectName + "' Qute project."); + report.setPercentage(80); progressSupport.notifyProgress(progressId, report); } - project.getDataModelProject() - .thenAccept(dataModel -> { - // The Java data model is collected for the project, validate all templates of - // the project - if (progressSupport != null) { - WorkDoneProgressReport report = new WorkDoneProgressReport(); - report.setMessage( - "Validating Qute templates for '" + projectName + "' Qute project."); - report.setPercentage(80); - progressSupport.notifyProgress(progressId, report); - } - // Validate Qute templates - project.validateClosedTemplates(); - - // End progress - endProgress(progressId, progressSupport); + // Validate Qute templates + project.validateClosedTemplates(); - }).exceptionally((a) -> { - endProgress(progressId, progressSupport); - return null; - }); + // End progress + endProgress(progressId, progressSupport); }).exceptionally((a) -> { endProgress(progressId, progressSupport); return null; }); - + return project; } private static String createAndStartProgress(String projectName, ProgressSupport progressSupport) { @@ -485,4 +491,18 @@ private static void endProgress(String progressId, ProgressSupport progressSuppo progressSupport.notifyProgress(progressId, end); } } + + public void projectAdded(ProjectInfo project) { + loadQuteProject(project); + } + + public void projectRemoved(ProjectInfo projectInfo) { + String projectUri = projectInfo.getUri(); + QuteProject project = getProject(projectUri); + if (project != null) { + project.dispose(); + projects.remove(projectUri); + } + } + } \ No newline at end of file diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/QuteDiagnostics.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/QuteDiagnostics.java index 1d78856e3..6e87c42ee 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/QuteDiagnostics.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/QuteDiagnostics.java @@ -278,7 +278,7 @@ private void validateDataModel(Node parent, Template template, QuteValidationSet } switch (section.getSectionKind()) { case INCLUDE: - validateIncludeSection((IncludeSection) section, diagnostics); + validateIncludeSection((IncludeSection) section, project, diagnostics); break; case CASE: case IS: @@ -461,13 +461,13 @@ private static boolean canChangeContext(Section section) { * Validate #include section. * * @param includeSection the include section + * @param project * @param diagnostics the diagnostics to fill. */ - private static void validateIncludeSection(IncludeSection includeSection, List diagnostics) { + private static void validateIncludeSection(IncludeSection includeSection, QuteProject project, List diagnostics) { Parameter templateParameter = includeSection.getTemplateParameter(); if (templateParameter != null) { // Validate template id, only if project exists. - QuteProject project = includeSection.getOwnerTemplate().getProject(); if (project != null) { // include defines a template to include // ex : {#include base} diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/QuteDocumentLink.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/QuteDocumentLink.java index e19c62a61..052ff0003 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/QuteDocumentLink.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/QuteDocumentLink.java @@ -78,7 +78,7 @@ private void findDocumentLinks(Node node, Template template, List if (range != null) { Path templateFile = includeSection.getReferencedTemplateFile(); if (templateFile != null) { - String target = templateFile.toUri().toString(); + String target = templateFile.toUri().toASCIIString(); links.add(new DocumentLink(range, target != null ? target : "")); } } diff --git a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/completions/QuteCompletionForTemplateIds.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/completions/QuteCompletionForTemplateIds.java index a4df5e9d2..97105063d 100644 --- a/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/completions/QuteCompletionForTemplateIds.java +++ b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/completions/QuteCompletionForTemplateIds.java @@ -76,6 +76,9 @@ public CompletableFuture doCompleteTemplateId(CompletionRequest Range range = getReplaceRange(completionRequest.getNode(), completionRequest.getOffset(), template); List documents = new ArrayList<>(project.getDocuments()); + for (QuteProject projectDependency : project.getProjectDependencies()) { + documents.addAll(projectDependency.getDocuments()); + } // Sort template ids to show at first the root files of the // src/main/resources/templates folder (ex : base,main). Collections.sort(documents, TEMPLATE_ID_COMPARATOR); 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 637580f1a..020a2ba23 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 @@ -1049,7 +1049,7 @@ 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, templateBaseDir)); + projectRegistry.getProject(new ProjectInfo(projectUri, Collections.emptyList(), templateBaseDir)); template.setProjectRegistry(projectRegistry); return template; } diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/MockQuteLanguageClient.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/MockQuteLanguageClient.java index 54d394fe2..3cffeab2e 100644 --- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/MockQuteLanguageClient.java +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/MockQuteLanguageClient.java @@ -12,6 +12,7 @@ package com.redhat.qute.project; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -167,4 +168,19 @@ public CompletableFuture generateMissingJavaMember(GenerateMissin public CompletableFuture getJavadoc(QuteJavadocParams params) { return CompletableFuture.completedFuture(null); } + + @Override + public CompletableFuture> getProjects() { + return CompletableFuture.completedFuture(null); + } + + @Override + public void projectAdded(ProjectInfo project) { + + } + + @Override + public void projectRemoved(ProjectInfo project) { + + } } \ No newline at end of file diff --git a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/MockQuteProjectRegistry.java b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/MockQuteProjectRegistry.java index df9ebcf93..6a1fa01f8 100644 --- a/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/MockQuteProjectRegistry.java +++ b/qute.ls/com.redhat.qute.ls/src/test/java/com/redhat/qute/project/MockQuteProjectRegistry.java @@ -47,7 +47,7 @@ public class MockQuteProjectRegistry extends QuteProjectRegistry { public static final Range JAVA_STATIC_METHOD_RANGE = new Range(new Position(3, 3), new Position(3, 3)); public MockQuteProjectRegistry() { - super(null, null, null, null, null, null, null, null); + super(null, null, null, null, null, null, null, null, () -> null); super.setDidChangeWatchedFilesSupported(true); } 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 2c5d89239..cc0f6ae04 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 @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; @@ -34,7 +35,7 @@ public void generateItem() throws InterruptedException, ExecutionException, Exce private QuteProjectRegistry createProjectRegistry() { QuteProjectRegistry projectRegistry = new MockQuteProjectRegistry(); - projectRegistry.getProject(new ProjectInfo(PROJECT_URI, TEMPLATE_BASE_DIR)); + projectRegistry.getProject(new ProjectInfo(PROJECT_URI, Collections.emptyList(), 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 1197881d8..3b16697cb 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 @@ -18,6 +18,9 @@ import java.io.IOException; import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -53,10 +56,23 @@ public QuteQuickStartProjectLanguageServer() { @Override public CompletableFuture getProjectInfo(QuteProjectParams params) { + ProjectInfo projectInfo = createQuickStartProject(); + return CompletableFuture.completedFuture(projectInfo); + } + + @Override + public CompletableFuture> getProjects() { + Collection projects = Arrays.asList(createQuickStartProject()); + return CompletableFuture.completedFuture(projects); + } + + private ProjectInfo createQuickStartProject() { ProjectInfo projectInfo = new ProjectInfo(QuteQuickStartProject.PROJECT_URI, + Collections.emptyList(), FileUtils.toUri(templatesPath)); - return CompletableFuture.completedFuture(projectInfo); + return projectInfo; }; + } private final boolean didChangeWatchedFilesSupported;