2 * Copyright 2000-2016 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.jetbrains.python.sdk
18 import com.intellij.openapi.components.PersistentStateComponent
19 import com.intellij.openapi.components.ServiceManager
20 import com.intellij.openapi.components.State
21 import com.intellij.openapi.components.Storage
22 import com.intellij.openapi.module.ModuleManager
23 import com.intellij.openapi.options.UnnamedConfigurable
24 import com.intellij.openapi.project.Project
25 import com.intellij.openapi.projectRoots.Sdk
26 import com.intellij.openapi.util.SystemInfo
27 import com.jetbrains.python.run.PyVirtualEnvReader
28 import com.jetbrains.python.run.findActivateScript
29 import org.jetbrains.plugins.terminal.LocalTerminalCustomizer
31 import javax.swing.JCheckBox
38 class PyVirtualEnvTerminalCustomizer : LocalTerminalCustomizer() {
39 override fun customizeCommandAndEnvironment(project: Project,
40 command: Array<out String>,
41 envs: MutableMap<String, String>): Array<out String> {
42 val sdk: Sdk? = findSdk(project)
44 if (sdk != null && (PythonSdkType.isVirtualEnv(sdk) || PythonSdkType.isCondaVirtualEnv(
45 sdk)) && PyVirtualEnvTerminalSettings.getInstance(project).virtualEnvActivate) {
46 // in case of virtualenv sdk on unix we activate virtualenv
47 val path = sdk.homePath
51 val shellPath = command[0]
52 val shellName = File(shellPath).name
54 if (shellName == "bash" || (SystemInfo.isMac && shellName == "sh") || (shellName == "zsh") ||
55 ((shellName == "fish") && PythonSdkType.isVirtualEnv(sdk))) { //fish shell works only for virtualenv and not for conda
56 //for bash we pass activate script to jediterm shell integration (see jediterm-bash.in) to source it there
57 findActivateScript(path, shellPath)?.let { activate -> envs.put("JEDITERM_SOURCE", activate) }
60 //for other shells we read envs from activate script by the default shell and pass them to the process
61 val reader = PyVirtualEnvReader(path)
62 reader.activate?.let {
63 envs.putAll(reader.readShellEnv().mapKeys { k -> k.key.toUpperCase() }.filterKeys { k ->
64 k in arrayOf("PATH", "PS1", "VIRTUAL_ENV", "PYTHONHOME", "PROMPT", "_OLD_VIRTUAL_PROMPT", "_OLD_VIRTUAL_PYTHONHOME", "_OLD_VIRTUAL_PATH")
71 // for some reason virtualenv isn't activated in the rcfile for the login shell, so we make it non-login
72 return command.filter { arg -> arg != "--login" && arg != "-l" }.toTypedArray()
76 private fun findSdk(project: Project): Sdk? {
77 for (m in ModuleManager.getInstance(project).modules) {
78 val sdk: Sdk? = PythonSdkType.findPythonSdk(m)
79 if (sdk != null && !PythonSdkType.isRemote(sdk)) {
88 override fun getDefaultFolder(): String? {
92 override fun getConfigurable(project: Project) = object : UnnamedConfigurable {
93 val settings = PyVirtualEnvTerminalSettings.getInstance(project)
95 var myCheckbox: JCheckBox = JCheckBox("Activate virtualenv")
97 override fun createComponent() = myCheckbox
99 override fun isModified() = myCheckbox.isSelected != settings.virtualEnvActivate
101 override fun apply() {
102 settings.virtualEnvActivate = myCheckbox.isSelected
105 override fun reset() {
106 myCheckbox.isSelected = settings.virtualEnvActivate
113 class SettingsState {
114 var virtualEnvActivate = true
117 @State(name = "PyVirtualEnvTerminalCustomizer", storages = arrayOf(Storage("python-terminal.xml")))
118 class PyVirtualEnvTerminalSettings : PersistentStateComponent<SettingsState> {
119 var myState = SettingsState()
121 var virtualEnvActivate: Boolean
122 get() = myState.virtualEnvActivate
124 myState.virtualEnvActivate = value
127 override fun getState() = myState
129 override fun loadState(state: SettingsState) {
130 myState.virtualEnvActivate = state.virtualEnvActivate
134 fun getInstance(project: Project): PyVirtualEnvTerminalSettings {
135 return ServiceManager.getService(project, PyVirtualEnvTerminalSettings::class.java)