From c5ec2e7cb95f415ed61751d98ecc9ca630c99903 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 + .../qute/jdt/QuteSupportForTemplate.java | 25 +++++++ ...portForTemplateDelegateCommandHandler.java | 7 ++ .../redhat/qute/ls/QuteLanguageServer.java | 58 +++++++++------ .../qute/ls/api/QuteProjectInfoProvider.java | 34 +++++++++ .../qute/project/QuteProjectRegistry.java | 71 ++++++++----------- .../qute/project/MockQuteLanguageClient.java | 16 +++++ .../AbstractQuteDiagnosticsInProjectTest.java | 9 +++ 8 files changed, 159 insertions(+), 62 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/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.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..3829584b0 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 @@ -108,8 +108,6 @@ 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); @@ -135,7 +133,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 +160,18 @@ 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()) { + for (ProjectInfo projectInfo : projects) { + // 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(projectInfo, progressSupport); + } + } + }); } /** @@ -267,6 +263,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 +302,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); @@ -359,4 +374,5 @@ 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/project/QuteProjectRegistry.java b/qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/QuteProjectRegistry.java index b77864ad2..c80ca4235 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 @@ -30,7 +30,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; @@ -407,58 +406,38 @@ public CompletableFuture getProjectInfo(QuteProjectParams params) { * @param workspaceFolder the workspace folder. * @param progressSupport the LSP client progress support and null otherwise. */ - public void tryToLoadQuteProject(WorkspaceFolder workspaceFolder, ProgressSupport progressSupport) { - String projectName = workspaceFolder.getName(); - + public void tryToLoadQuteProject(ProjectInfo projectInfo, ProgressSupport progressSupport) { + 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; }); - } private static String createAndStartProgress(String projectName, ProgressSupport progressSupport) { @@ -485,4 +464,14 @@ private static void endProgress(String progressId, ProgressSupport progressSuppo progressSupport.notifyProgress(progressId, end); } } + + public void projectAdded(ProjectInfo project) { + // TODO Auto-generated method stub + + } + + public void projectRemoved(ProjectInfo project) { + // TODO Auto-generated method stub + + } } \ No newline at end of file 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/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..8822f0664 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,8 @@ import java.io.IOException; import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -57,6 +59,13 @@ public CompletableFuture getProjectInfo(QuteProjectParams params) { FileUtils.toUri(templatesPath)); return CompletableFuture.completedFuture(projectInfo); }; + + @Override + public CompletableFuture> getProjects() { + Collection projects = Arrays.asList(new ProjectInfo(QuteQuickStartProject.PROJECT_URI, + FileUtils.toUri(templatesPath))); + return CompletableFuture.completedFuture(projects); + } } private final boolean didChangeWatchedFilesSupported;