/* * Copyright 2000-2016 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.openapi.components.PersistentStateComponent import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.components.State import com.intellij.openapi.components.Storage import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.options.UnnamedConfigurable import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.util.SystemInfo import com.jetbrains.python.run.PyVirtualEnvReader import com.jetbrains.python.run.findActivateScript import org.jetbrains.plugins.terminal.LocalTerminalCustomizer import java.io.File import javax.swing.JCheckBox /** * @author traff */ class PyVirtualEnvTerminalCustomizer : LocalTerminalCustomizer() { override fun customizeCommandAndEnvironment(project: Project, command: Array, envs: MutableMap): Array { val sdk: Sdk? = findSdk(project) if (sdk != null && (PythonSdkType.isVirtualEnv(sdk) || PythonSdkType.isCondaVirtualEnv( sdk)) && PyVirtualEnvTerminalSettings.getInstance(project).virtualEnvActivate) { // in case of virtualenv sdk on unix we activate virtualenv val path = sdk.homePath if (path != null) { val shellPath = command[0] val shellName = File(shellPath).name if (shellName == "bash" || (SystemInfo.isMac && shellName == "sh") || (shellName == "zsh") || ((shellName == "fish") && PythonSdkType.isVirtualEnv(sdk))) { //fish shell works only for virtualenv and not for conda //for bash we pass activate script to jediterm shell integration (see jediterm-bash.in) to source it there findActivateScript(path, shellPath)?.let { activate -> envs.put("JEDITERM_SOURCE", activate) } } else { //for other shells we read envs from activate script by the default shell and pass them to the process val reader = PyVirtualEnvReader(path) reader.activate?.let { envs.putAll(reader.readShellEnv().mapKeys { k -> k.key.toUpperCase() }.filterKeys { k -> k in arrayOf("PATH", "PS1", "VIRTUAL_ENV", "PYTHONHOME", "PROMPT", "_OLD_VIRTUAL_PROMPT", "_OLD_VIRTUAL_PYTHONHOME", "_OLD_VIRTUAL_PATH") }) } } } } // for some reason virtualenv isn't activated in the rcfile for the login shell, so we make it non-login return command.filter { arg -> arg != "--login" && arg != "-l" }.toTypedArray() } private fun findSdk(project: Project): Sdk? { for (m in ModuleManager.getInstance(project).modules) { val sdk: Sdk? = PythonSdkType.findPythonSdk(m) if (sdk != null && !PythonSdkType.isRemote(sdk)) { return sdk } } return null } override fun getDefaultFolder(): String? { return null } override fun getConfigurable(project: Project) = object : UnnamedConfigurable { val settings = PyVirtualEnvTerminalSettings.getInstance(project) var myCheckbox: JCheckBox = JCheckBox("Activate virtualenv") override fun createComponent() = myCheckbox override fun isModified() = myCheckbox.isSelected != settings.virtualEnvActivate override fun apply() { settings.virtualEnvActivate = myCheckbox.isSelected } override fun reset() { myCheckbox.isSelected = settings.virtualEnvActivate } } } class SettingsState { var virtualEnvActivate = true } @State(name = "PyVirtualEnvTerminalCustomizer", storages = arrayOf(Storage("python-terminal.xml"))) class PyVirtualEnvTerminalSettings : PersistentStateComponent { var myState = SettingsState() var virtualEnvActivate: Boolean get() = myState.virtualEnvActivate set(value) { myState.virtualEnvActivate = value } override fun getState() = myState override fun loadState(state: SettingsState) { myState.virtualEnvActivate = state.virtualEnvActivate } companion object { fun getInstance(project: Project): PyVirtualEnvTerminalSettings { return ServiceManager.getService(project, PyVirtualEnvTerminalSettings::class.java) } } }