From 12f5b2094c5d13e06b1ffa4d25c2dd493fc4936a Mon Sep 17 00:00:00 2001 From: tandemdude Date: Fri, 21 Jun 2024 15:28:10 +0100 Subject: [PATCH] Structural rewrite for better file data loading --- ...CommandParameterCompletionContributor.java | 3 +- .../LightbulbPackageManagerListener.java | 93 +--------------- .../hklbsupport/ProjectDataService.java | 103 ++++++++++++++++++ .../actions/CacheRefreshAction.java | 8 +- .../hklbsupport/models/LightbulbData.java | 5 + .../hklbsupport/models/ParamData.java | 5 + .../tandemdude/hklbsupport/utils/Utils.java | 12 +- .../tandemdude/hklbsupport/StartupActivity.kt | 14 +++ src/main/resources/META-INF/plugin.xml | 1 + 9 files changed, 140 insertions(+), 104 deletions(-) create mode 100644 src/main/java/io/github/tandemdude/hklbsupport/ProjectDataService.java create mode 100644 src/main/java/io/github/tandemdude/hklbsupport/models/LightbulbData.java create mode 100644 src/main/java/io/github/tandemdude/hklbsupport/models/ParamData.java create mode 100644 src/main/kotlin/io/github/tandemdude/hklbsupport/StartupActivity.kt diff --git a/src/main/java/io/github/tandemdude/hklbsupport/CommandParameterCompletionContributor.java b/src/main/java/io/github/tandemdude/hklbsupport/CommandParameterCompletionContributor.java index 33eeae6..f67ddc6 100644 --- a/src/main/java/io/github/tandemdude/hklbsupport/CommandParameterCompletionContributor.java +++ b/src/main/java/io/github/tandemdude/hklbsupport/CommandParameterCompletionContributor.java @@ -44,7 +44,8 @@ protected void addCompletions( return; } - var moduleLightbulbData = LightbulbPackageManagerListener.getDataFor(sdk); + var dataService = parameters.getOriginalFile().getProject().getService(ProjectDataService.class); + var moduleLightbulbData = dataService.getLightbulbData(sdk); if (moduleLightbulbData == null) { // We don't have the data for the specified module - maybe it isn't part of this project? // Alternatively, lightbulb may not be installed - a filesystem listener will load the diff --git a/src/main/java/io/github/tandemdude/hklbsupport/LightbulbPackageManagerListener.java b/src/main/java/io/github/tandemdude/hklbsupport/LightbulbPackageManagerListener.java index 7577ea3..cf25f75 100644 --- a/src/main/java/io/github/tandemdude/hklbsupport/LightbulbPackageManagerListener.java +++ b/src/main/java/io/github/tandemdude/hklbsupport/LightbulbPackageManagerListener.java @@ -1,109 +1,18 @@ package io.github.tandemdude.hklbsupport; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.fileTypes.FileTypeManager; -import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.search.FileTypeIndex; -import com.intellij.psi.search.GlobalSearchScope; -import com.jetbrains.python.packaging.PyPackageManager; import com.jetbrains.python.packaging.common.PythonPackageManagementListener; -import com.jetbrains.python.sdk.PythonSdkUtil; -import io.github.tandemdude.hklbsupport.utils.Notifier; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import org.jetbrains.annotations.NotNull; public class LightbulbPackageManagerListener implements PythonPackageManagementListener { - private static final ObjectMapper MAPPER = new ObjectMapper(); - - public record ParamData(Map required, Map optional) {} - - public record LightbulbData(String version, Map paramData) {} - - private static final ConcurrentHashMap sdkLightbulbData = new ConcurrentHashMap<>(); - - public static LightbulbData getDataFor(Sdk sdk) { - return sdkLightbulbData.get(sdk); - } - - public static void flush() { - sdkLightbulbData.clear(); - } - - LightbulbData readMetaparamsFile(String version, VirtualFile vf) { - try { - var parsedParamData = MAPPER.readValue(vf.getInputStream(), new TypeReference>() {}); - return new LightbulbData(version, parsedParamData); - } catch (IOException e) { - return null; - } - } - @Override public void packagesChanged(@NotNull Sdk sdk) { ApplicationManager.getApplication().runReadAction(() -> { - var packages = PyPackageManager.getInstance(sdk).getPackages(); - if (packages == null) { - return; - } - - var lightbulb = packages.stream() - .filter(p -> p.getName().equals("hikari-lightbulb")) - .findFirst(); - - if (lightbulb.isEmpty()) { - return; - } - - var existingData = sdkLightbulbData.get(sdk); - if (existingData != null - && existingData.version().equals(lightbulb.get().getVersion())) { - // The cache is still up-to-date - do not refresh - return; - } - - var lightbulbLocation = lightbulb.get().getLocation(); - if (lightbulbLocation == null) { - return; - } - - var searchScopes = new ArrayList(); for (var project : ProjectManager.getInstance().getOpenProjects()) { - Arrays.stream(ModuleManager.getInstance(project).getModules()).forEach(module -> { - var maybeSdk = PythonSdkUtil.findPythonSdk(module); - if (maybeSdk == sdk) { - searchScopes.add(GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module)); - } - }); + project.getService(ProjectDataService.class).notifyChange(sdk); } - - FileTypeIndex.processFiles( - FileTypeManager.getInstance().getFileTypeByExtension("json"), - file -> { - if (file.getPath().endsWith("metaparams.json") - && file.getPath().contains("lightbulb") - && file.getPath().contains(lightbulbLocation)) { - var data = readMetaparamsFile(lightbulb.get().getVersion(), file); - if (data == null) { - return false; - } - - sdkLightbulbData.put(sdk, data); - Notifier.notifyInformation( - null, "Lightbulb configuration loaded successfully (%s)", sdk.getName()); - return false; - } - return true; - }, - GlobalSearchScope.union(searchScopes)); }); } } diff --git a/src/main/java/io/github/tandemdude/hklbsupport/ProjectDataService.java b/src/main/java/io/github/tandemdude/hklbsupport/ProjectDataService.java new file mode 100644 index 0000000..c4923a6 --- /dev/null +++ b/src/main/java/io/github/tandemdude/hklbsupport/ProjectDataService.java @@ -0,0 +1,103 @@ +package io.github.tandemdude.hklbsupport; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.intellij.openapi.components.Service; +import com.intellij.openapi.fileTypes.FileTypeManager; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.search.FileTypeIndex; +import com.intellij.psi.search.GlobalSearchScope; +import com.jetbrains.python.sdk.PythonSdkUtil; +import io.github.tandemdude.hklbsupport.models.LightbulbData; +import io.github.tandemdude.hklbsupport.models.ParamData; +import io.github.tandemdude.hklbsupport.utils.Notifier; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Pattern; + +@Service(Service.Level.PROJECT) +public final class ProjectDataService { + private static final ObjectMapper MAPPER = new ObjectMapper(); + private static final Pattern VERSION_PATTERN = Pattern.compile("__version__\\s*=\\s*\"([^\"]+)\""); + + private final Project project; + + private final ConcurrentHashMap sdkCache = new ConcurrentHashMap<>(); + + public ProjectDataService(Project project) { + this.project = project; + } + + public void loadModules() { + Arrays.stream(ModuleManager.getInstance(project).getModules()).forEach(module -> { + var maybeSdk = PythonSdkUtil.findPythonSdk(module); + if (maybeSdk != null) { + sdkCache.put(maybeSdk, new LightbulbData("-1", Collections.emptyMap())); + } + }); + } + + public void flush() { + this.sdkCache.clear(); + } + + public LightbulbData getLightbulbData(Sdk sdk) { + return sdkCache.get(sdk); + } + + LightbulbData readMetaparamsFile(String version, VirtualFile vf) throws IOException { + var parsedParamData = MAPPER.readValue(vf.getInputStream(), new TypeReference>() {}); + return new LightbulbData(version, parsedParamData); + } + + public void notifyChange(Sdk sdk) { + if (!sdkCache.containsKey(sdk)) { + return; + } + + FileTypeIndex.processFiles( + FileTypeManager.getInstance().getFileTypeByExtension("json"), + file -> { + if (!file.getName().equals("metaparams.json") + || !file.getParent().getName().equals("lightbulb")) { + return true; + } + + var initFile = file.getParent().findChild("__init__.py"); + if (initFile == null) { + return true; + } + + try { + var matcher = VERSION_PATTERN.matcher(new String(initFile.contentsToByteArray())); + String version = null; + while (matcher.find()) { + version = matcher.group(1); + } + + if (version == null) { + return true; + } + + if (version.equals(sdkCache.get(sdk).version())) { + return false; + } + + var data = readMetaparamsFile(version, file); + sdkCache.put(sdk, data); + Notifier.notifyInformation(project, "Lightbulb configuration loaded successfully (%s)", sdk.getName()); + } catch (IOException e) { + throw new RuntimeException(e); + } + return false; + }, + GlobalSearchScope.allScope(project)); + } +} diff --git a/src/main/java/io/github/tandemdude/hklbsupport/actions/CacheRefreshAction.java b/src/main/java/io/github/tandemdude/hklbsupport/actions/CacheRefreshAction.java index 8c59544..6072eb3 100644 --- a/src/main/java/io/github/tandemdude/hklbsupport/actions/CacheRefreshAction.java +++ b/src/main/java/io/github/tandemdude/hklbsupport/actions/CacheRefreshAction.java @@ -5,7 +5,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.module.ModuleManager; import com.jetbrains.python.sdk.PythonSdkUtil; -import io.github.tandemdude.hklbsupport.LightbulbPackageManagerListener; +import io.github.tandemdude.hklbsupport.ProjectDataService; import org.jetbrains.annotations.NotNull; public class CacheRefreshAction extends AnAction { @@ -20,14 +20,14 @@ public void actionPerformed(@NotNull AnActionEvent e) { return; } - LightbulbPackageManagerListener.flush(); - var listenerInstance = new LightbulbPackageManagerListener(); + var dataService = e.getProject().getService(ProjectDataService.class); + dataService.flush(); var modules = ModuleManager.getInstance(e.getProject()).getModules(); for (var module : modules) { var sdk = PythonSdkUtil.findPythonSdk(module); if (sdk != null) { - listenerInstance.packagesChanged(sdk); + dataService.notifyChange(sdk); } } } diff --git a/src/main/java/io/github/tandemdude/hklbsupport/models/LightbulbData.java b/src/main/java/io/github/tandemdude/hklbsupport/models/LightbulbData.java new file mode 100644 index 0000000..207a4a5 --- /dev/null +++ b/src/main/java/io/github/tandemdude/hklbsupport/models/LightbulbData.java @@ -0,0 +1,5 @@ +package io.github.tandemdude.hklbsupport.models; + +import java.util.Map; + +public record LightbulbData(String version, Map paramData) {} diff --git a/src/main/java/io/github/tandemdude/hklbsupport/models/ParamData.java b/src/main/java/io/github/tandemdude/hklbsupport/models/ParamData.java new file mode 100644 index 0000000..b0a0124 --- /dev/null +++ b/src/main/java/io/github/tandemdude/hklbsupport/models/ParamData.java @@ -0,0 +1,5 @@ +package io.github.tandemdude.hklbsupport.models; + +import java.util.Map; + +public record ParamData(Map required, Map optional) {} diff --git a/src/main/java/io/github/tandemdude/hklbsupport/utils/Utils.java b/src/main/java/io/github/tandemdude/hklbsupport/utils/Utils.java index 481120b..9b9a568 100644 --- a/src/main/java/io/github/tandemdude/hklbsupport/utils/Utils.java +++ b/src/main/java/io/github/tandemdude/hklbsupport/utils/Utils.java @@ -7,7 +7,8 @@ import com.jetbrains.python.psi.PyKeywordArgument; import com.jetbrains.python.psi.types.TypeEvalContext; import com.jetbrains.python.sdk.PythonSdkUtil; -import io.github.tandemdude.hklbsupport.LightbulbPackageManagerListener; +import io.github.tandemdude.hklbsupport.ProjectDataService; +import io.github.tandemdude.hklbsupport.models.LightbulbData; import java.util.Arrays; import java.util.Map; import java.util.stream.Collectors; @@ -29,9 +30,7 @@ public class Utils { * @return the Lightbulb superclass as a {@link PyClass}, or {@code null} if none was found. */ public static @Nullable PyClass getLightbulbSuperclass( - @NotNull TypeEvalContext context, - @NotNull PyClass pyClass, - @NotNull LightbulbPackageManagerListener.LightbulbData moduleData) { + @NotNull TypeEvalContext context, @NotNull PyClass pyClass, @NotNull LightbulbData moduleData) { PyClass commandSuperClass = null; for (var superClass : pyClass.getSuperClasses(context)) { if (moduleData.paramData().containsKey(superClass.getQualifiedName())) { @@ -42,8 +41,7 @@ public class Utils { return commandSuperClass; } - public static @Nullable LightbulbPackageManagerListener.LightbulbData getLightbulbDataForNode( - @NotNull PyClass node) { + public static @Nullable LightbulbData getLightbulbDataForNode(@NotNull PyClass node) { var module = ModuleUtilCore.findModuleForFile(node.getContainingFile()); if (module == null) { return null; @@ -54,7 +52,7 @@ public class Utils { return null; } - return LightbulbPackageManagerListener.getDataFor(sdk); + return module.getProject().getService(ProjectDataService.class).getLightbulbData(sdk); } public static Map getKeywordSuperclassExpressions(PyClass node) { diff --git a/src/main/kotlin/io/github/tandemdude/hklbsupport/StartupActivity.kt b/src/main/kotlin/io/github/tandemdude/hklbsupport/StartupActivity.kt new file mode 100644 index 0000000..c9d5fde --- /dev/null +++ b/src/main/kotlin/io/github/tandemdude/hklbsupport/StartupActivity.kt @@ -0,0 +1,14 @@ +package io.github.tandemdude.hklbsupport + +import com.intellij.openapi.project.Project +import com.intellij.openapi.startup.ProjectActivity + +/** + * Startup activity that causes module Lightbulb configurations to attempt to be loaded when the + * user opens a new project. + */ +class StartupActivity : ProjectActivity { + override suspend fun execute(project: Project) { + project.getService(ProjectDataService::class.java).loadModules() + } +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 824fe96..2cbe989 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -33,6 +33,7 @@ +