From 6921dc6971188b84b2a9a5baf5474d2f83bc012b Mon Sep 17 00:00:00 2001 From: Andrey Vokin Date: Tue, 16 Aug 2022 17:31:51 +0200 Subject: [PATCH] DS-3787 Missing "No SDK" panel for Python and Jupyter files Decouple quickfixes from PyEditorNotificationProvider GitOrigin-RevId: 451cbab341b4da1d657685b65b86a1e3eb68ff9d --- .../python/ift/PythonBasedLangSupport.kt | 4 +- .../jetbrains/python/ift/PythonLessonsUtil.kt | 4 +- .../com/jetbrains/python/PythonHelper.java | 19 ++ .../PyStubPackagesCompatibilityInspection.kt | 4 +- .../python/debugger/PyDebugRunner.java | 2 +- .../PyPackageRequirementsInspection.java | 4 +- .../quickfix/sdk/ConfigureInterpreterFix.java | 38 +++ .../sdk/InterpreterSettingsQuickFix.java | 71 ++++++ .../sdk/UseDetectedInterpreterFix.java | 51 ++++ .../sdk/UseExistingInterpreterFix.java | 26 ++ .../quickfix/sdk/UseInterpreterFix.java | 34 +++ .../sdk/UseProvidedInterpreterFix.java | 57 +++++ .../jetbrains/python/run/PythonRunner.java | 2 +- .../PyEditorNotificationProvider.java | 229 +----------------- .../jetbrains/python/sdk/PySdkPopupFactory.kt | 3 +- 15 files changed, 313 insertions(+), 235 deletions(-) create mode 100644 python/src/com/jetbrains/python/inspections/quickfix/sdk/ConfigureInterpreterFix.java create mode 100644 python/src/com/jetbrains/python/inspections/quickfix/sdk/InterpreterSettingsQuickFix.java create mode 100644 python/src/com/jetbrains/python/inspections/quickfix/sdk/UseDetectedInterpreterFix.java create mode 100644 python/src/com/jetbrains/python/inspections/quickfix/sdk/UseExistingInterpreterFix.java create mode 100644 python/src/com/jetbrains/python/inspections/quickfix/sdk/UseInterpreterFix.java create mode 100644 python/src/com/jetbrains/python/inspections/quickfix/sdk/UseProvidedInterpreterFix.java rename python/src/com/jetbrains/python/{inspections => sdk}/PyEditorNotificationProvider.java (68%) diff --git a/python/python-features-trainer/src/com/jetbrains/python/ift/PythonBasedLangSupport.kt b/python/python-features-trainer/src/com/jetbrains/python/ift/PythonBasedLangSupport.kt index 984bf881473e..e4cebe36a5bd 100644 --- a/python/python-features-trainer/src/com/jetbrains/python/ift/PythonBasedLangSupport.kt +++ b/python/python-features-trainer/src/com/jetbrains/python/ift/PythonBasedLangSupport.kt @@ -15,7 +15,7 @@ import com.intellij.util.ui.FormBuilder import com.jetbrains.python.PyBundle import com.jetbrains.python.PySdkBundle import com.jetbrains.python.configuration.PyConfigurableInterpreterList -import com.jetbrains.python.sdk.PyEditorNotificationProvider +import com.jetbrains.python.inspections.quickfix.sdk.InterpreterSettingsQuickFix import com.jetbrains.python.newProject.steps.ProjectSpecificSettingsStep import com.jetbrains.python.sdk.* import com.jetbrains.python.sdk.add.PySdkPathChoosingComboBox @@ -152,7 +152,7 @@ abstract class PythonBasedLangSupport : AbstractLangSupport() { } val configureCallbackId = LearningUiManager.addCallback { val module = project.modules.singleOrNull() ?: return@addCallback - PyEditorNotificationProvider.InterpreterSettingsQuickFix.showPythonInterpreterSettings(project, module) + InterpreterSettingsQuickFix.showPythonInterpreterSettings(project, module) } if (useUserProjects || isLearningProject(project, this@PythonBasedLangSupport)) { showWarning(PythonLessonsBundle.message("no.interpreter.in.learning.project", configureCallbackId), diff --git a/python/python-features-trainer/src/com/jetbrains/python/ift/PythonLessonsUtil.kt b/python/python-features-trainer/src/com/jetbrains/python/ift/PythonLessonsUtil.kt index 5233a0d7db16..64d75f3836fe 100644 --- a/python/python-features-trainer/src/com/jetbrains/python/ift/PythonLessonsUtil.kt +++ b/python/python-features-trainer/src/com/jetbrains/python/ift/PythonLessonsUtil.kt @@ -7,7 +7,7 @@ import com.intellij.openapi.util.NlsSafe import com.intellij.openapi.util.UserDataHolderBase import com.intellij.ui.dsl.builder.Panel import com.jetbrains.python.configuration.PyConfigurableInterpreterList -import com.jetbrains.python.sdk.PyEditorNotificationProvider +import com.jetbrains.python.inspections.quickfix.sdk.InterpreterSettingsQuickFix import com.jetbrains.python.newProject.steps.ProjectSpecificSettingsStep import com.jetbrains.python.sdk.findBaseSdks import com.jetbrains.python.sdk.flavors.PythonSdkFlavor @@ -33,7 +33,7 @@ object PythonLessonsUtil { fun LessonContext.showWarningIfPython3NotFound() { task { val callbackId = LearningUiManager.addCallback { - PyEditorNotificationProvider.InterpreterSettingsQuickFix.showPythonInterpreterSettings(project, project.modules.first()) + InterpreterSettingsQuickFix.showPythonInterpreterSettings(project, project.modules.first()) } stateCheck { isPython3Installed(project) } showWarning(PythonLessonsBundle.message("python.3.required.warning.message", callbackId)) { diff --git a/python/src/com/jetbrains/python/PythonHelper.java b/python/src/com/jetbrains/python/PythonHelper.java index 2e5307c2cea4..a117009939f1 100644 --- a/python/src/com/jetbrains/python/PythonHelper.java +++ b/python/src/com/jetbrains/python/PythonHelper.java @@ -3,13 +3,18 @@ package com.jetbrains.python; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.configurations.ParamsGroup; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.psi.PsiElement; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.psi.LanguageLevel; import com.jetbrains.python.sdk.PythonEnvUtil; import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.File; import java.util.ArrayList; @@ -302,4 +307,18 @@ public enum PythonHelper implements HelperPackage { public GeneralCommandLine newCommandLine(@NotNull Sdk pythonSdk, @NotNull List parameters) { return myModule.newCommandLine(pythonSdk, parameters); } + + @Nullable + public static Module guessModule(@NotNull PsiElement element) { + Module module = ModuleUtilCore.findModuleForPsiElement(element); + if (module == null) { + Module[] modules = ModuleManager.getInstance(element.getProject()).getModules(); + if (modules.length != 1) { + return null; + } + module = modules[0]; + } + return module; + } + } diff --git a/python/src/com/jetbrains/python/codeInsight/typing/PyStubPackagesCompatibilityInspection.kt b/python/src/com/jetbrains/python/codeInsight/typing/PyStubPackagesCompatibilityInspection.kt index 6c11313501c3..c96c1f5e3d4d 100644 --- a/python/src/com/jetbrains/python/codeInsight/typing/PyStubPackagesCompatibilityInspection.kt +++ b/python/src/com/jetbrains/python/codeInsight/typing/PyStubPackagesCompatibilityInspection.kt @@ -15,7 +15,7 @@ import com.intellij.psi.PsiElementVisitor import com.jetbrains.python.PyPsiBundle import com.jetbrains.python.inspections.PyInspection import com.jetbrains.python.inspections.PyInspectionVisitor -import com.jetbrains.python.sdk.PyEditorNotificationProvider +import com.jetbrains.python.inspections.quickfix.sdk.InterpreterSettingsQuickFix import com.jetbrains.python.packaging.PyPackage import com.jetbrains.python.packaging.PyPackageManager import com.jetbrains.python.packaging.requirement.PyRequirementRelation @@ -97,7 +97,7 @@ class PyStubPackagesCompatibilityInspection : PyInspection() { runtimePkgName, specsToString) registerProblem(node, message, - PyEditorNotificationProvider.InterpreterSettingsQuickFix(module), + InterpreterSettingsQuickFix(module), createIgnoreStubPackageQuickFix(stubPkgName, ignoredStubPackages)) } } diff --git a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java index 94d663b37246..972fb2c2a87a 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java @@ -68,7 +68,7 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.jetbrains.python.sdk.PyEditorNotificationProvider.InterpreterSettingsQuickFix.showPythonInterpreterSettings; +import static com.jetbrains.python.inspections.quickfix.sdk.InterpreterSettingsQuickFix.showPythonInterpreterSettings; public class PyDebugRunner implements ProgramRunner { diff --git a/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java b/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java index e7c712415b3e..2d34dfd63470 100644 --- a/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java @@ -36,12 +36,12 @@ import com.jetbrains.python.PyPsiPackageUtil; import com.jetbrains.python.PythonLanguage; import com.jetbrains.python.codeInsight.imports.AddImportHelper; import com.jetbrains.python.codeInsight.stdlib.PyStdlibUtil; +import com.jetbrains.python.inspections.quickfix.sdk.ConfigureInterpreterFix; import com.jetbrains.python.packaging.*; import com.jetbrains.python.packaging.ui.PyChooseRequirementsDialog; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyPsiUtils; import com.jetbrains.python.psi.types.TypeEvalContext; -import com.jetbrains.python.sdk.PyEditorNotificationProvider; import com.jetbrains.python.sdk.PySdkExtKt; import com.jetbrains.python.sdk.PySdkProvider; import com.jetbrains.python.sdk.PythonSdkUtil; @@ -353,7 +353,7 @@ public class PyPackageRequirementsInspection extends PyInspection { final int answer = askToConfigureInterpreter(project, sdk); switch (answer) { case Messages.YES: - new PyEditorNotificationProvider.ConfigureInterpreterFix().applyFix(project, descriptor); + new ConfigureInterpreterFix().applyFix(project, descriptor); return true; case Messages.CANCEL: case -1: diff --git a/python/src/com/jetbrains/python/inspections/quickfix/sdk/ConfigureInterpreterFix.java b/python/src/com/jetbrains/python/inspections/quickfix/sdk/ConfigureInterpreterFix.java new file mode 100644 index 000000000000..3a2bc2e52bad --- /dev/null +++ b/python/src/com/jetbrains/python/inspections/quickfix/sdk/ConfigureInterpreterFix.java @@ -0,0 +1,38 @@ +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.jetbrains.python.inspections.quickfix.sdk; + +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.util.IntentionFamilyName; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.jetbrains.python.PyPsiBundle; +import com.jetbrains.python.sdk.PySdkPopupFactory; +import org.jetbrains.annotations.NotNull; + +import static com.jetbrains.python.PythonHelper.guessModule; + +public class ConfigureInterpreterFix implements LocalQuickFix { + + @Override + public @IntentionFamilyName @NotNull String getFamilyName() { + return PyPsiBundle.message("INSP.interpreter.configure.python.interpreter"); + } + + @Override + public boolean startInWriteAction() { + return false; + } + + @Override + public void applyFix(@NotNull final Project project, @NotNull ProblemDescriptor descriptor) { + final PsiElement element = descriptor.getPsiElement(); + if (element == null) return; + + final Module module = guessModule(element); + if (module == null) return; + + PySdkPopupFactory.Companion.createAndShow(project, module); + } +} \ No newline at end of file diff --git a/python/src/com/jetbrains/python/inspections/quickfix/sdk/InterpreterSettingsQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/sdk/InterpreterSettingsQuickFix.java new file mode 100644 index 000000000000..e6cb09d9b6ec --- /dev/null +++ b/python/src/com/jetbrains/python/inspections/quickfix/sdk/InterpreterSettingsQuickFix.java @@ -0,0 +1,71 @@ +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.jetbrains.python.inspections.quickfix.sdk; + +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.ide.actions.ShowSettingsUtilImpl; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.options.ex.ConfigurableExtensionPointUtil; +import com.intellij.openapi.options.ex.ConfigurableVisitor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.roots.ui.configuration.ProjectSettingsService; +import com.intellij.util.PlatformUtils; +import com.jetbrains.python.PyPsiBundle; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; + +public class InterpreterSettingsQuickFix implements LocalQuickFix { + + @NotNull + private final Module myModule; + + public InterpreterSettingsQuickFix(@NotNull Module module) { + myModule = module; + } + + @NotNull + @Override + public String getFamilyName() { + return PlatformUtils.isPyCharm() + ? PyPsiBundle.message("INSP.interpreter.interpreter.settings") + : PyPsiBundle.message("INSP.interpreter.configure.python.interpreter"); + } + + @Override + public boolean startInWriteAction() { + return false; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + showPythonInterpreterSettings(project, myModule); + } + + public static void showPythonInterpreterSettings(@NotNull Project project, @Nullable Module module) { + final var id = "com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable"; + final var group = ConfigurableExtensionPointUtil.getConfigurableGroup(project, true); + if (ConfigurableVisitor.findById(id, Collections.singletonList(group)) != null) { + ShowSettingsUtilImpl.showSettingsDialog(project, id, null); + return; + } + + final ProjectSettingsService settingsService = ProjectSettingsService.getInstance(project); + if (module == null || justOneModuleInheritingSdk(project, module)) { + settingsService.openProjectSettings(); + } + else { + settingsService.openModuleSettings(module); + } + } + + private static boolean justOneModuleInheritingSdk(@NotNull Project project, @NotNull Module module) { + return ProjectRootManager.getInstance(project).getProjectSdk() == null && + ModuleRootManager.getInstance(module).isSdkInherited() && + ModuleManager.getInstance(project).getModules().length < 2; + } +} diff --git a/python/src/com/jetbrains/python/inspections/quickfix/sdk/UseDetectedInterpreterFix.java b/python/src/com/jetbrains/python/inspections/quickfix/sdk/UseDetectedInterpreterFix.java new file mode 100644 index 000000000000..530ab7bf02e5 --- /dev/null +++ b/python/src/com/jetbrains/python/inspections/quickfix/sdk/UseDetectedInterpreterFix.java @@ -0,0 +1,51 @@ +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.jetbrains.python.inspections.quickfix.sdk; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil; +import com.jetbrains.python.sdk.BasePySdkExtKt; +import com.jetbrains.python.sdk.PyDetectedSdk; +import com.jetbrains.python.sdk.PyEditorNotificationProvider; +import com.jetbrains.python.sdk.PySdkExtKt; +import com.jetbrains.python.sdk.configuration.PyProjectSdkConfiguration; +import com.jetbrains.python.ui.PyUiUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class UseDetectedInterpreterFix extends UseInterpreterFix { + + @NotNull + private final List myExistingSdks; + + private final boolean myAssociate; + + @NotNull + private final Module myModule; + + public UseDetectedInterpreterFix(@NotNull PyDetectedSdk detectedSdk, + @NotNull List existingSdks, + boolean associate, + @NotNull Module module) { + super(detectedSdk); + myExistingSdks = existingSdks; + myAssociate = associate; + myModule = module; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + PyUiUtil.clearFileLevelInspectionResults(project); + final Sdk newSdk = myAssociate + ? PySdkExtKt.setupAssociated(mySdk, myExistingSdks, BasePySdkExtKt.getBasePath(myModule)) + : PySdkExtKt.setup(mySdk, myExistingSdks); + if (newSdk == null) return; + + SdkConfigurationUtil.addSdk(newSdk); + if (myAssociate) PySdkExtKt.associateWithModule(newSdk, myModule, null); + PyProjectSdkConfiguration.INSTANCE.setReadyToUseSdk(project, myModule, newSdk); + } +} \ No newline at end of file diff --git a/python/src/com/jetbrains/python/inspections/quickfix/sdk/UseExistingInterpreterFix.java b/python/src/com/jetbrains/python/inspections/quickfix/sdk/UseExistingInterpreterFix.java new file mode 100644 index 000000000000..10ba31956282 --- /dev/null +++ b/python/src/com/jetbrains/python/inspections/quickfix/sdk/UseExistingInterpreterFix.java @@ -0,0 +1,26 @@ +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.jetbrains.python.inspections.quickfix.sdk; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.Sdk; +import com.jetbrains.python.sdk.configuration.PyProjectSdkConfiguration; +import com.jetbrains.python.ui.PyUiUtil; +import org.jetbrains.annotations.NotNull; + +public class UseExistingInterpreterFix extends UseInterpreterFix { + @NotNull + private final Module myModule; + + public UseExistingInterpreterFix(@NotNull Sdk existingSdk, @NotNull Module module) { + super(existingSdk); + myModule = module; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + PyUiUtil.clearFileLevelInspectionResults(project); + PyProjectSdkConfiguration.INSTANCE.setReadyToUseSdk(project, myModule, mySdk); + } +} \ No newline at end of file diff --git a/python/src/com/jetbrains/python/inspections/quickfix/sdk/UseInterpreterFix.java b/python/src/com/jetbrains/python/inspections/quickfix/sdk/UseInterpreterFix.java new file mode 100644 index 000000000000..436fe1711167 --- /dev/null +++ b/python/src/com/jetbrains/python/inspections/quickfix/sdk/UseInterpreterFix.java @@ -0,0 +1,34 @@ +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.jetbrains.python.inspections.quickfix.sdk; + +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.util.IntentionFamilyName; +import com.intellij.codeInspection.util.IntentionName; +import com.intellij.openapi.projectRoots.Sdk; +import com.jetbrains.python.PyPsiBundle; +import com.jetbrains.python.sdk.PySdkPopupFactory; +import org.jetbrains.annotations.NotNull; + +public abstract class UseInterpreterFix implements LocalQuickFix { + @NotNull + protected final T mySdk; + + protected UseInterpreterFix(@NotNull T sdk) { + mySdk = sdk; + } + + @Override + public @IntentionFamilyName @NotNull String getFamilyName() { + return PyPsiBundle.message("INSP.interpreter.use.suggested.interpreter"); + } + + @Override + public @IntentionName @NotNull String getName() { + return PyPsiBundle.message("INSP.interpreter.use.interpreter", PySdkPopupFactory.Companion.shortenNameInPopup(mySdk, 75)); + } + + @Override + public boolean startInWriteAction() { + return false; + } +} \ No newline at end of file diff --git a/python/src/com/jetbrains/python/inspections/quickfix/sdk/UseProvidedInterpreterFix.java b/python/src/com/jetbrains/python/inspections/quickfix/sdk/UseProvidedInterpreterFix.java new file mode 100644 index 000000000000..703f55233d6b --- /dev/null +++ b/python/src/com/jetbrains/python/inspections/quickfix/sdk/UseProvidedInterpreterFix.java @@ -0,0 +1,57 @@ +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.jetbrains.python.inspections.quickfix.sdk; + +import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo; +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.util.IntentionFamilyName; +import com.intellij.codeInspection.util.IntentionName; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.jetbrains.python.PyPsiBundle; +import com.jetbrains.python.sdk.configuration.PyProjectSdkConfiguration; +import com.jetbrains.python.sdk.configuration.PyProjectSdkConfigurationExtension; +import org.jetbrains.annotations.NotNull; + +public class UseProvidedInterpreterFix implements LocalQuickFix { + + @NotNull + private final Module myModule; + + @NotNull + private final PyProjectSdkConfigurationExtension myExtension; + + @NotNull + @IntentionName + private final String myName; + + public UseProvidedInterpreterFix(@NotNull Module module, + @NotNull PyProjectSdkConfigurationExtension extension, + @NotNull @IntentionName String name) { + myModule = module; + myExtension = extension; + myName = name; + } + + @Override + public @IntentionFamilyName @NotNull String getFamilyName() { + return PyPsiBundle.message("INSP.interpreter.use.suggested.interpreter"); + } + + @Override + public @IntentionName @NotNull String getName() { + return myName; + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + PyProjectSdkConfiguration.INSTANCE.configureSdkUsingExtension(myModule, myExtension, + () -> myExtension.createAndAddSdkForInspection(myModule)); + } + + @Override + public @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull ProblemDescriptor previewDescriptor) { + // The quick fix doesn't change the code and is suggested on a file level + return IntentionPreviewInfo.EMPTY; + } +} \ No newline at end of file diff --git a/python/src/com/jetbrains/python/run/PythonRunner.java b/python/src/com/jetbrains/python/run/PythonRunner.java index 5a9c2f1d4f6d..ac7cfcb9c11a 100644 --- a/python/src/com/jetbrains/python/run/PythonRunner.java +++ b/python/src/com/jetbrains/python/run/PythonRunner.java @@ -23,7 +23,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.concurrency.AsyncPromise; import org.jetbrains.concurrency.Promise; -import static com.jetbrains.python.sdk.PyEditorNotificationProvider.InterpreterSettingsQuickFix.showPythonInterpreterSettings; +import static com.jetbrains.python.inspections.quickfix.sdk.InterpreterSettingsQuickFix.showPythonInterpreterSettings; public class PythonRunner extends AsyncProgramRunner { @Override diff --git a/python/src/com/jetbrains/python/inspections/PyEditorNotificationProvider.java b/python/src/com/jetbrains/python/sdk/PyEditorNotificationProvider.java similarity index 68% rename from python/src/com/jetbrains/python/inspections/PyEditorNotificationProvider.java rename to python/src/com/jetbrains/python/sdk/PyEditorNotificationProvider.java index 9a376f9e2b23..c2b73f1c4d00 100644 --- a/python/src/com/jetbrains/python/inspections/PyEditorNotificationProvider.java +++ b/python/src/com/jetbrains/python/sdk/PyEditorNotificationProvider.java @@ -1,44 +1,31 @@ // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -package com.jetbrains.python.inspections; +package com.jetbrains.python.sdk; import com.github.benmanes.caffeine.cache.AsyncLoadingCache; import com.github.benmanes.caffeine.cache.Caffeine; -import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo; import com.intellij.codeInspection.LocalQuickFix; -import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.codeInspection.ProblemDescriptorBase; import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.codeInspection.util.InspectionMessage; -import com.intellij.codeInspection.util.IntentionFamilyName; import com.intellij.codeInspection.util.IntentionName; -import com.intellij.ide.actions.ShowSettingsUtilImpl; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleManager; -import com.intellij.openapi.module.ModuleUtilCore; -import com.intellij.openapi.options.ex.ConfigurableExtensionPointUtil; -import com.intellij.openapi.options.ex.ConfigurableVisitor; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.ProjectJdkTable; import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.projectRoots.impl.SdkConfigurationUtil; -import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.roots.ProjectRootManager; -import com.intellij.openapi.roots.ui.configuration.ProjectSettingsService; import com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectSdksModel; import com.intellij.openapi.util.NlsSafe; import com.intellij.openapi.util.UserDataHolderBase; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiManager; import com.intellij.ui.EditorNotificationPanel; import com.intellij.ui.EditorNotificationProvider; import com.intellij.util.PathUtil; -import com.intellij.util.PlatformUtils; import com.intellij.util.concurrency.AppExecutorUtil; import com.intellij.util.containers.ContainerUtil; import com.intellij.workspaceModel.ide.WorkspaceModelChangeListener; @@ -48,13 +35,12 @@ import com.intellij.workspaceModel.storage.VersionedStorageChange; import com.intellij.workspaceModel.storage.bridgeEntities.api.ModuleEntity; import com.jetbrains.python.PyPsiBundle; import com.jetbrains.python.PythonIdeLanguageCustomization; +import com.jetbrains.python.inspections.PyInspectionExtension; +import com.jetbrains.python.inspections.quickfix.sdk.*; import com.jetbrains.python.psi.LanguageLevel; import com.jetbrains.python.psi.PyFile; -import com.jetbrains.python.sdk.*; import com.jetbrains.python.sdk.conda.PyCondaSdkCustomizer; -import com.jetbrains.python.sdk.configuration.PyProjectSdkConfiguration; import com.jetbrains.python.sdk.configuration.PyProjectSdkConfigurationExtension; -import com.jetbrains.python.ui.PyUiUtil; import kotlin.Pair; import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; @@ -73,6 +59,8 @@ import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static com.jetbrains.python.PythonHelper.guessModule; + public final class PyEditorNotificationProvider implements DumbAware, EditorNotificationProvider { @NotNull @@ -382,214 +370,7 @@ public final class PyEditorNotificationProvider implements DumbAware, EditorNoti } } - @Nullable - private static Module guessModule(@NotNull PsiElement element) { - Module module = ModuleUtilCore.findModuleForPsiElement(element); - if (module == null) { - Module[] modules = ModuleManager.getInstance(element.getProject()).getModules(); - if (modules.length != 1) { - return null; - } - module = modules[0]; - } - return module; - } - private static boolean isFileIgnored(@NotNull PyFile pyFile) { return PyInspectionExtension.EP_NAME.getExtensionList().stream().anyMatch(ep -> ep.ignoreInterpreterWarnings(pyFile)); } - - public static final class InterpreterSettingsQuickFix implements LocalQuickFix { - - @NotNull - private final Module myModule; - - public InterpreterSettingsQuickFix(@NotNull Module module) { - myModule = module; - } - - @NotNull - @Override - public String getFamilyName() { - return PlatformUtils.isPyCharm() - ? PyPsiBundle.message("INSP.interpreter.interpreter.settings") - : PyPsiBundle.message("INSP.interpreter.configure.python.interpreter"); - } - - @Override - public boolean startInWriteAction() { - return false; - } - - @Override - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - showPythonInterpreterSettings(project, myModule); - } - - public static void showPythonInterpreterSettings(@NotNull Project project, @Nullable Module module) { - final var id = "com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable"; - final var group = ConfigurableExtensionPointUtil.getConfigurableGroup(project, true); - if (ConfigurableVisitor.findById(id, Collections.singletonList(group)) != null) { - ShowSettingsUtilImpl.showSettingsDialog(project, id, null); - return; - } - - final ProjectSettingsService settingsService = ProjectSettingsService.getInstance(project); - if (module == null || justOneModuleInheritingSdk(project, module)) { - settingsService.openProjectSettings(); - } - else { - settingsService.openModuleSettings(module); - } - } - - private static boolean justOneModuleInheritingSdk(@NotNull Project project, @NotNull Module module) { - return ProjectRootManager.getInstance(project).getProjectSdk() == null && - ModuleRootManager.getInstance(module).isSdkInherited() && - ModuleManager.getInstance(project).getModules().length < 2; - } - } - - public static final class ConfigureInterpreterFix implements LocalQuickFix { - - @Override - public @IntentionFamilyName @NotNull String getFamilyName() { - return PyPsiBundle.message("INSP.interpreter.configure.python.interpreter"); - } - - @Override - public boolean startInWriteAction() { - return false; - } - - @Override - public void applyFix(@NotNull final Project project, @NotNull ProblemDescriptor descriptor) { - final PsiElement element = descriptor.getPsiElement(); - if (element == null) return; - - final Module module = guessModule(element); - if (module == null) return; - - PySdkPopupFactory.Companion.createAndShow(project, module); - } - } - - private static final class UseProvidedInterpreterFix implements LocalQuickFix { - - @NotNull - private final Module myModule; - - @NotNull - private final PyProjectSdkConfigurationExtension myExtension; - - @NotNull - @IntentionName - private final String myName; - - private UseProvidedInterpreterFix(@NotNull Module module, - @NotNull PyProjectSdkConfigurationExtension extension, - @NotNull @IntentionName String name) { - myModule = module; - myExtension = extension; - myName = name; - } - - @Override - public @IntentionFamilyName @NotNull String getFamilyName() { - return PyPsiBundle.message("INSP.interpreter.use.suggested.interpreter"); - } - - @Override - public @IntentionName @NotNull String getName() { - return myName; - } - - @Override - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - PyProjectSdkConfiguration.INSTANCE.configureSdkUsingExtension(myModule, myExtension, - () -> myExtension.createAndAddSdkForInspection(myModule)); - } - - @Override - public @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull ProblemDescriptor previewDescriptor) { - // The quick fix doesn't change the code and is suggested on a file level - return IntentionPreviewInfo.EMPTY; - } - } - - private static abstract class UseInterpreterFix implements LocalQuickFix { - - @NotNull - protected final T mySdk; - - protected UseInterpreterFix(@NotNull T sdk) { - mySdk = sdk; - } - - @Override - public @IntentionFamilyName @NotNull String getFamilyName() { - return PyPsiBundle.message("INSP.interpreter.use.suggested.interpreter"); - } - - @Override - public @IntentionName @NotNull String getName() { - return PyPsiBundle.message("INSP.interpreter.use.interpreter", PySdkPopupFactory.Companion.shortenNameInPopup(mySdk, 75)); - } - - @Override - public boolean startInWriteAction() { - return false; - } - } - - private static final class UseExistingInterpreterFix extends UseInterpreterFix { - - @NotNull - private final Module myModule; - - private UseExistingInterpreterFix(@NotNull Sdk existingSdk, @NotNull Module module) { - super(existingSdk); - myModule = module; - } - - @Override - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - PyUiUtil.clearFileLevelInspectionResults(project); - PyProjectSdkConfiguration.INSTANCE.setReadyToUseSdk(project, myModule, mySdk); - } - } - - private static final class UseDetectedInterpreterFix extends UseInterpreterFix { - - @NotNull - private final List myExistingSdks; - - private final boolean myAssociate; - - @NotNull - private final Module myModule; - - private UseDetectedInterpreterFix(@NotNull PyDetectedSdk detectedSdk, - @NotNull List existingSdks, - boolean associate, - @NotNull Module module) { - super(detectedSdk); - myExistingSdks = existingSdks; - myAssociate = associate; - myModule = module; - } - - @Override - public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - PyUiUtil.clearFileLevelInspectionResults(project); - final Sdk newSdk = myAssociate - ? PySdkExtKt.setupAssociated(mySdk, myExistingSdks, BasePySdkExtKt.getBasePath(myModule)) - : PySdkExtKt.setup(mySdk, myExistingSdks); - if (newSdk == null) return; - - SdkConfigurationUtil.addSdk(newSdk); - if (myAssociate) PySdkExtKt.associateWithModule(newSdk, myModule, null); - PyProjectSdkConfiguration.INSTANCE.setReadyToUseSdk(project, myModule, newSdk); - } - } } diff --git a/python/src/com/jetbrains/python/sdk/PySdkPopupFactory.kt b/python/src/com/jetbrains/python/sdk/PySdkPopupFactory.kt index 1df60c694b5f..492eeb339138 100644 --- a/python/src/com/jetbrains/python/sdk/PySdkPopupFactory.kt +++ b/python/src/com/jetbrains/python/sdk/PySdkPopupFactory.kt @@ -18,6 +18,7 @@ import com.intellij.util.text.trimMiddle import com.intellij.util.ui.SwingHelper import com.jetbrains.python.PyBundle import com.jetbrains.python.configuration.PyConfigurableInterpreterList +import com.jetbrains.python.inspections.quickfix.sdk.InterpreterSettingsQuickFix import com.jetbrains.python.psi.LanguageLevel class PySdkPopupFactory(val project: Project, val module: Module) { @@ -109,7 +110,7 @@ class PySdkPopupFactory(val project: Project, val module: Module) { private inner class InterpreterSettingsAction : DumbAwareAction(PyBundle.messagePointer("python.sdk.popup.interpreter.settings")) { override fun actionPerformed(e: AnActionEvent) { - PyEditorNotificationProvider.InterpreterSettingsQuickFix.showPythonInterpreterSettings(project, module) + InterpreterSettingsQuickFix.showPythonInterpreterSettings(project, module) } } } \ No newline at end of file