diff --git a/.idea/modules.xml b/.idea/modules.xml index 4d78d45ff1e3..e77f8476248e 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -216,6 +216,7 @@ + diff --git a/python/pluginCore/META-INF/python-community-plugin-core.xml b/python/pluginCore/META-INF/python-community-plugin-core.xml index 722cace68897..b345d3c466db 100644 --- a/python/pluginCore/META-INF/python-community-plugin-core.xml +++ b/python/pluginCore/META-INF/python-community-plugin-core.xml @@ -12,12 +12,16 @@ - + com.jetbrains.python.console.PythonConsoleRunnerFactory com.jetbrains.python.console.PydevConsoleRunnerFactory + + + com.jetbrains.python.facet.PythonSdkTableListener + \ No newline at end of file diff --git a/python/pluginCore/com/jetbrains/python/facet/PythonFacetUtil.java b/python/pluginCore/com/jetbrains/python/facet/PythonFacetUtil.java new file mode 100644 index 000000000000..6cb4fb5407ea --- /dev/null +++ b/python/pluginCore/com/jetbrains/python/facet/PythonFacetUtil.java @@ -0,0 +1,104 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.facet; + +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.*; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.roots.libraries.LibraryTable; + +import static com.jetbrains.python.facet.LibraryContributingFacet.PYTHON_FACET_LIBRARY_NAME_SUFFIX; + +/** + * @author traff + */ +public class PythonFacetUtil { + public static String getFacetLibraryName(final String sdkName) { + return sdkName + PYTHON_FACET_LIBRARY_NAME_SUFFIX; + } + + public static void updateLibrary(Module module, PythonFacetSettings facetSettings) { + ApplicationManager.getApplication().runWriteAction(() -> { + final ModuleRootManager rootManager = ModuleRootManager.getInstance(module); + final ModifiableRootModel model = rootManager.getModifiableModel(); + boolean modelChanged = false; + try { + // Just remove all old facet libraries except one, that is necessary + final Sdk sdk = facetSettings.getSdk(); + final String name = (sdk != null) ? getFacetLibraryName(sdk.getName()) : null; + boolean librarySeen = false; + for (OrderEntry entry : model.getOrderEntries()) { + if (entry instanceof LibraryOrderEntry) { + final String libraryName = ((LibraryOrderEntry)entry).getLibraryName(); + if (name != null && name.equals(libraryName)) { + librarySeen = true; + continue; + } + if (libraryName != null && libraryName.endsWith(PYTHON_FACET_LIBRARY_NAME_SUFFIX)) { + model.removeOrderEntry(entry); + modelChanged = true; + } + } + } + if (name != null) { + final ModifiableModelsProvider provider = ModifiableModelsProvider.SERVICE.getInstance(); + final LibraryTable.ModifiableModel libraryTableModifiableModel = provider.getLibraryTableModifiableModel(); + Library library = libraryTableModifiableModel.getLibraryByName(name); + provider.disposeLibraryTableModifiableModel(libraryTableModifiableModel); + if (library == null) { + // we just create new project library + library = PythonSdkTableListener.addLibrary(sdk); + } + if (!librarySeen) { + model.addLibraryEntry(library); + modelChanged = true; + } + } + } + finally { + if (modelChanged){ + model.commit(); + } + else { + model.dispose(); + } + } + }); + } + + public static void removeLibrary(Module module) { + ApplicationManager.getApplication().runWriteAction(() -> { + final ModuleRootManager rootManager = ModuleRootManager.getInstance(module); + final ModifiableRootModel model = rootManager.getModifiableModel(); + // Just remove all old facet libraries + for (OrderEntry entry : model.getOrderEntries()) { + if (entry instanceof LibraryOrderEntry) { + final Library library = ((LibraryOrderEntry)entry).getLibrary(); + if (library != null) { + final String libraryName = library.getName(); + if (libraryName!=null && libraryName.endsWith(PYTHON_FACET_LIBRARY_NAME_SUFFIX)) { + model.removeOrderEntry(entry); + //PyBuiltinCache.clearInstanceCache(); + } + } + } + } + model.commit(); + }); + } +} diff --git a/python/pluginCore/com/jetbrains/python/facet/PythonSdkTableListener.java b/python/pluginCore/com/jetbrains/python/facet/PythonSdkTableListener.java new file mode 100644 index 000000000000..59beab19baf2 --- /dev/null +++ b/python/pluginCore/com/jetbrains/python/facet/PythonSdkTableListener.java @@ -0,0 +1,104 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.facet; + +import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ModalityState; +import com.intellij.openapi.projectRoots.ProjectJdkTable; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.roots.ModifiableModelsProvider; +import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.roots.libraries.LibraryTable; +import com.intellij.util.messages.MessageBus; +import com.jetbrains.python.sdk.PythonSdkType; + +/** + * @author yole + */ +public class PythonSdkTableListener implements Disposable { + public PythonSdkTableListener(MessageBus messageBus) { + ProjectJdkTable.Listener jdkTableListener = new ProjectJdkTable.Listener() { + @Override + public void jdkAdded(final Sdk sdk) { + if (sdk.getSdkType() instanceof PythonSdkType) { + ApplicationManager.getApplication().invokeLater(() -> ApplicationManager.getApplication().runWriteAction(() -> { + addLibrary(sdk); + })); + } + } + + @Override + public void jdkRemoved(final Sdk sdk) { + if (sdk.getSdkType() instanceof PythonSdkType) { + removeLibrary(sdk); + } + } + + @Override + public void jdkNameChanged(final Sdk sdk, final String previousName) { + if (sdk.getSdkType() instanceof PythonSdkType) { + renameLibrary(sdk, previousName); + } + } + }; + messageBus.connect(this).subscribe(ProjectJdkTable.JDK_TABLE_TOPIC, jdkTableListener); + } + + static Library addLibrary(Sdk sdk) { + final LibraryTable.ModifiableModel libraryTableModel = ModifiableModelsProvider.SERVICE.getInstance().getLibraryTableModifiableModel(); + final Library library = libraryTableModel.createLibrary(PythonFacetUtil.getFacetLibraryName(sdk.getName())); + final Library.ModifiableModel model = library.getModifiableModel(); + for (String url : sdk.getRootProvider().getUrls(OrderRootType.CLASSES)) { + model.addRoot(url, OrderRootType.CLASSES); + model.addRoot(url, OrderRootType.SOURCES); + } + model.commit(); + libraryTableModel.commit(); + return library; + } + + private static void removeLibrary(final Sdk sdk) { + ApplicationManager.getApplication().invokeLater(() -> ApplicationManager.getApplication().runWriteAction(() -> { + final LibraryTable.ModifiableModel libraryTableModel = + ModifiableModelsProvider.SERVICE.getInstance().getLibraryTableModifiableModel(); + final Library library = libraryTableModel.getLibraryByName(PythonFacetUtil.getFacetLibraryName(sdk.getName())); + if (library != null) { + libraryTableModel.removeLibrary(library); + } + libraryTableModel.commit(); + }), ModalityState.NON_MODAL); + } + + private static void renameLibrary(final Sdk sdk, final String previousName) { + ApplicationManager.getApplication().invokeLater(() -> ApplicationManager.getApplication().runWriteAction(() -> { + final LibraryTable.ModifiableModel libraryTableModel = + ModifiableModelsProvider.SERVICE.getInstance().getLibraryTableModifiableModel(); + final Library library = libraryTableModel.getLibraryByName(PythonFacetUtil.getFacetLibraryName(previousName)); + if (library != null) { + final Library.ModifiableModel model = library.getModifiableModel(); + model.setName(PythonFacetUtil.getFacetLibraryName(sdk.getName())); + model.commit(); + } + libraryTableModel.commit(); + }), ModalityState.NON_MODAL); + } + + @Override + public void dispose() { + } +} diff --git a/python/pluginJava/META-INF/python-community-plugin-java.xml b/python/pluginJava/META-INF/python-community-plugin-java.xml index 8e3e2911d2ea..1c5b203a2e94 100644 --- a/python/pluginJava/META-INF/python-community-plugin-java.xml +++ b/python/pluginJava/META-INF/python-community-plugin-java.xml @@ -3,7 +3,7 @@ both Community and Professional versions. --> - + @@ -20,10 +20,4 @@ - - - - com.jetbrains.python.facet.PythonSdkTableListener - - \ No newline at end of file diff --git a/python/pluginJava/com/jetbrains/python/facet/PythonFacet.java b/python/pluginJava/com/jetbrains/python/facet/PythonFacet.java index d27998186b80..defc69eb966b 100644 --- a/python/pluginJava/com/jetbrains/python/facet/PythonFacet.java +++ b/python/pluginJava/com/jetbrains/python/facet/PythonFacet.java @@ -18,12 +18,7 @@ package com.jetbrains.python.facet; import com.intellij.facet.Facet; import com.intellij.facet.FacetType; import com.intellij.facet.FacetTypeId; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; -import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.openapi.roots.*; -import com.intellij.openapi.roots.libraries.Library; -import com.intellij.openapi.roots.libraries.LibraryTable; import org.jetbrains.annotations.NotNull; /** @@ -32,81 +27,20 @@ import org.jetbrains.annotations.NotNull; public class PythonFacet extends LibraryContributingFacet { public static final FacetTypeId ID = new FacetTypeId<>("python"); - public PythonFacet(@NotNull final FacetType facetType, @NotNull final Module module, final @NotNull String name, @NotNull final PythonFacetConfiguration configuration, + public PythonFacet(@NotNull final FacetType facetType, + @NotNull final Module module, + final @NotNull String name, + @NotNull final PythonFacetConfiguration configuration, Facet underlyingFacet) { super(facetType, module, name, configuration, underlyingFacet); } public void updateLibrary() { - ApplicationManager.getApplication().runWriteAction(() -> { - final Module module = getModule(); - final ModuleRootManager rootManager = ModuleRootManager.getInstance(module); - final ModifiableRootModel model = rootManager.getModifiableModel(); - boolean modelChanged = false; - try { - // Just remove all old facet libraries except one, that is necessary - final Sdk sdk = getConfiguration().getSdk(); - final String name = (sdk != null) ? getFacetLibraryName(sdk.getName()) : null; - boolean librarySeen = false; - for (OrderEntry entry : model.getOrderEntries()) { - if (entry instanceof LibraryOrderEntry) { - final String libraryName = ((LibraryOrderEntry)entry).getLibraryName(); - if (name != null && name.equals(libraryName)) { - librarySeen = true; - continue; - } - if (libraryName != null && libraryName.endsWith(PYTHON_FACET_LIBRARY_NAME_SUFFIX)) { - model.removeOrderEntry(entry); - modelChanged = true; - } - } - } - if (name != null) { - final ModifiableModelsProvider provider = ModifiableModelsProvider.SERVICE.getInstance(); - final LibraryTable.ModifiableModel libraryTableModifiableModel = provider.getLibraryTableModifiableModel(); - Library library = libraryTableModifiableModel.getLibraryByName(name); - provider.disposeLibraryTableModifiableModel(libraryTableModifiableModel); - if (library == null) { - // we just create new project library - library = PythonSdkTableListener.addLibrary(sdk); - } - if (!librarySeen) { - model.addLibraryEntry(library); - modelChanged = true; - } - } - } - finally { - if (modelChanged){ - model.commit(); - } - else { - model.dispose(); - } - } - }); + PythonFacetUtil.updateLibrary(getModule(), getConfiguration()); } public void removeLibrary() { - ApplicationManager.getApplication().runWriteAction(() -> { - final Module module = getModule(); - final ModuleRootManager rootManager = ModuleRootManager.getInstance(module); - final ModifiableRootModel model = rootManager.getModifiableModel(); - // Just remove all old facet libraries - for (OrderEntry entry : model.getOrderEntries()) { - if (entry instanceof LibraryOrderEntry) { - final Library library = ((LibraryOrderEntry)entry).getLibrary(); - if (library != null) { - final String libraryName = library.getName(); - if (libraryName!=null && libraryName.endsWith(PYTHON_FACET_LIBRARY_NAME_SUFFIX)) { - model.removeOrderEntry(entry); - //PyBuiltinCache.clearInstanceCache(); - } - } - } - } - model.commit(); - }); + PythonFacetUtil.removeLibrary(getModule()); } public static String getFacetLibraryName(final String sdkName) { diff --git a/python/pluginJava/python-community-plugin-java.iml b/python/pluginJava/python-community-plugin-java.iml index 500f8dd18dbd..c7e72965a758 100644 --- a/python/pluginJava/python-community-plugin-java.iml +++ b/python/pluginJava/python-community-plugin-java.iml @@ -15,5 +15,6 @@ + \ No newline at end of file diff --git a/python/pluginMinor/META-INF/python-community-plugin-minor.xml b/python/pluginMinor/META-INF/python-community-plugin-minor.xml new file mode 100644 index 000000000000..fc8c624ceb35 --- /dev/null +++ b/python/pluginMinor/META-INF/python-community-plugin-minor.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/python/pluginMinor/com/jetbrains/python/facet/PythonFacet.java b/python/pluginMinor/com/jetbrains/python/facet/PythonFacet.java new file mode 100644 index 000000000000..7eeeb6d00297 --- /dev/null +++ b/python/pluginMinor/com/jetbrains/python/facet/PythonFacet.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.facet; + +import com.intellij.facet.Facet; +import com.intellij.facet.FacetType; +import com.intellij.facet.FacetTypeId; +import com.intellij.openapi.module.Module; +import org.jetbrains.annotations.NotNull; + +/** + * This facet is intended to be used in the python plugin for IDEs other then IntelliJ IDEA + * + * @author traff + */ +public class PythonFacet extends LibraryContributingFacet { + public static final FacetTypeId ID = new FacetTypeId<>("python"); + + public PythonFacet(@NotNull final FacetType facetType, @NotNull final Module module, final @NotNull String name, @NotNull final PythonFacetType.PythonFacetConfiguration configuration, + Facet underlyingFacet) { + super(facetType, module, name, configuration, underlyingFacet); + } + + public void updateLibrary() { + PythonFacetUtil.updateLibrary(getModule(), getConfiguration()); + } + + public void removeLibrary() { + PythonFacetUtil.removeLibrary(getModule()); + } + + public void initFacet() { + updateLibrary(); + } +} diff --git a/python/pluginMinor/com/jetbrains/python/facet/PythonFacetType.java b/python/pluginMinor/com/jetbrains/python/facet/PythonFacetType.java new file mode 100644 index 000000000000..223d7e84869d --- /dev/null +++ b/python/pluginMinor/com/jetbrains/python/facet/PythonFacetType.java @@ -0,0 +1,105 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.facet; + +import com.intellij.facet.Facet; +import com.intellij.facet.FacetConfiguration; +import com.intellij.facet.FacetType; +import com.intellij.facet.ui.FacetEditorContext; +import com.intellij.facet.ui.FacetEditorTab; +import com.intellij.facet.ui.FacetValidatorsManager; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleType; +import com.intellij.openapi.projectRoots.ProjectJdkTable; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.util.InvalidDataException; +import com.intellij.openapi.util.WriteExternalException; +import com.intellij.openapi.util.text.StringUtil; +import com.jetbrains.python.sdk.PythonSdkType; +import icons.PythonIcons; +import org.jdom.Element; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.util.List; + +import static com.jetbrains.python.PythonModuleTypeBase.PYTHON_MODULE; + +/** + * @author traff + */ +public class PythonFacetType extends FacetType { + + @NonNls + private static final String ID = "Python"; + + public static PythonFacetType getInstance() { + return findInstance(PythonFacetType.class); + } + + public PythonFacetType() { + super(PythonFacet.ID, ID, "Python"); + } + + public PythonFacetConfiguration createDefaultConfiguration() { + PythonFacetConfiguration result = new PythonFacetConfiguration(); + List sdks = ProjectJdkTable.getInstance().getSdksOfType(PythonSdkType.getInstance()); + if (sdks.size() > 0) { + result.setSdk(sdks.get(0)); + } + return result; + } + + public PythonFacet createFacet(@NotNull Module module, + String name, + @NotNull PythonFacetConfiguration configuration, + @Nullable Facet underlyingFacet) { + return new PythonFacet(this, module, name, configuration, underlyingFacet); + } + + public boolean isSuitableModuleType(ModuleType moduleType) { + return !(moduleType.getId().equals(PYTHON_MODULE)); + } + + @Override + public Icon getIcon() { + return PythonIcons.Python.Python; + } + + public static class PythonFacetConfiguration extends PythonFacetSettings implements FacetConfiguration { + private static final String SDK_NAME = "sdkName"; + + public FacetEditorTab[] createEditorTabs(FacetEditorContext editorContext, FacetValidatorsManager validatorsManager) { + return new FacetEditorTab[]{}; + } + + public void readExternal(Element element) throws InvalidDataException { + String sdkName = element.getAttributeValue(SDK_NAME); + mySdk = StringUtil.isEmpty(sdkName) ? null : ProjectJdkTable.getInstance().findJdk(sdkName, PythonSdkType.getInstance().getName()); + + if (mySdk != null) { + ApplicationManager.getApplication().getMessageBus().syncPublisher(ProjectJdkTable.JDK_TABLE_TOPIC).jdkAdded(mySdk); + } + } + + public void writeExternal(Element element) throws WriteExternalException { + element.setAttribute(SDK_NAME, mySdk == null ? "" : mySdk.getName()); + } + } +} diff --git a/python/pluginMinor/com/jetbrains/python/sdk/PyPluginSdkModuleConfigurable.kt b/python/pluginMinor/com/jetbrains/python/sdk/PyPluginSdkModuleConfigurable.kt new file mode 100644 index 000000000000..930c8cf7693e --- /dev/null +++ b/python/pluginMinor/com/jetbrains/python/sdk/PyPluginSdkModuleConfigurable.kt @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.sdk + +import com.intellij.facet.FacetManager +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.module.Module +import com.intellij.openapi.options.UnnamedConfigurable +import com.intellij.openapi.project.Project +import com.intellij.openapi.projectRoots.Sdk +import com.jetbrains.python.configuration.PyActiveSdkConfigurable +import com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable +import com.jetbrains.python.facet.PythonFacet +import com.jetbrains.python.facet.PythonFacetType +import com.jetbrains.python.facet.PythonFacetUtil + +/** + * @author traff + */ + + +class PyPluginSdkModuleConfigurable(project: Project?) : PyActiveSdkModuleConfigurable(project) { + override fun createModuleConfigurable(module: Module): UnnamedConfigurable { + return object : PyActiveSdkConfigurable(module) { + override fun setSdk(item: Sdk?) { + val facetManager = FacetManager.getInstance(module) + val facet = facetManager.getFacetByType(PythonFacet.ID) + if (facet == null) { + ApplicationManager.getApplication().runWriteAction { + addFacet(facetManager, item, module) + } + } + else { + setFacetSdk(facet, item, module) + } + + } + + override fun getSdk(): Sdk? { + val facetManager = FacetManager.getInstance(module) + val facet = facetManager.getFacetByType(PythonFacet.ID) + return facet?.configuration?.sdk + } + } + } + + private fun setFacetSdk(facet: PythonFacet, + item: Sdk?, + module: Module) { + facet.configuration.sdk = item + PythonFacetUtil.updateLibrary(module, facet.configuration) + } + + private fun addFacet(facetManager: FacetManager, + sdk: Sdk?, + module: Module) { + val facet = facetManager.addFacet(PythonFacetType.getInstance(), "Python facet", null) + setFacetSdk(facet, sdk, module) + } +} \ No newline at end of file diff --git a/python/pluginMinor/python-community-plugin-minor.iml b/python/pluginMinor/python-community-plugin-minor.iml new file mode 100644 index 000000000000..853f6152b5dd --- /dev/null +++ b/python/pluginMinor/python-community-plugin-minor.iml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/python/pluginResources/META-INF/plugin.xml b/python/pluginResources/META-INF/plugin.xml index 61c95c3cb157..b8edee7482b2 100644 --- a/python/pluginResources/META-INF/plugin.xml +++ b/python/pluginResources/META-INF/plugin.xml @@ -19,8 +19,7 @@ The Python plug-in provides smart editing for Python scripts. The feature set of com.intellij.modules.java - com.intellij.modules.clion - com.intellij.modules.webstorm + com.intellij.modules.clion com.intellij.modules.rider