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.console;
18 import com.google.common.base.Function;
19 import com.google.common.base.Joiner;
20 import com.google.common.collect.Collections2;
21 import com.intellij.execution.configurations.GeneralCommandLine;
22 import com.intellij.execution.console.LanguageConsoleView;
23 import com.intellij.lang.ASTNode;
24 import com.intellij.openapi.module.Module;
25 import com.intellij.openapi.module.ModuleManager;
26 import com.intellij.openapi.project.Project;
27 import com.intellij.openapi.projectRoots.Sdk;
28 import com.intellij.openapi.util.Key;
29 import com.intellij.openapi.util.Pair;
30 import com.intellij.openapi.vfs.VirtualFile;
31 import com.intellij.openapi.vfs.encoding.EncodingProjectManager;
32 import com.intellij.psi.PsiElement;
33 import com.intellij.psi.PsiFile;
34 import com.intellij.util.PathMappingSettings;
35 import com.jetbrains.python.console.completion.PydevConsoleElement;
36 import com.jetbrains.python.console.parsing.PythonConsoleData;
37 import com.jetbrains.python.console.pydev.ConsoleCommunication;
38 import com.jetbrains.python.remote.PyRemotePathMapper;
39 import com.jetbrains.python.remote.PyRemoteSdkAdditionalDataBase;
40 import com.jetbrains.python.remote.PythonRemoteInterpreterManager;
41 import com.jetbrains.python.run.PythonCommandLineState;
42 import com.jetbrains.python.sdk.PySdkUtil;
43 import com.jetbrains.python.sdk.PythonSdkType;
44 import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
45 import org.jetbrains.annotations.NotNull;
46 import org.jetbrains.annotations.Nullable;
48 import java.nio.charset.Charset;
49 import java.util.Collection;
52 import static com.jetbrains.python.sdk.PythonEnvUtil.setPythonIOEncoding;
53 import static com.jetbrains.python.sdk.PythonEnvUtil.setPythonUnbuffered;
56 * Created by Yuli Fiterman on 9/13/2016.
58 public interface PydevConsoleRunner {
60 Key<ConsoleCommunication> CONSOLE_KEY = new Key<>("PYDEV_CONSOLE_KEY");
61 Key<Sdk> CONSOLE_SDK = new Key<>("PYDEV_CONSOLE_SDK_KEY");
63 public interface ConsoleListener {
64 void handleConsoleInitialized(LanguageConsoleView consoleView);
69 static PyRemotePathMapper getPathMapper(@NotNull Project project, Sdk sdk, PyConsoleOptions.PyConsoleSettings consoleSettings) {
70 if (PySdkUtil.isRemote(sdk)) {
71 PythonRemoteInterpreterManager instance = PythonRemoteInterpreterManager.getInstance();
72 if (instance != null) {
73 //noinspection ConstantConditions
74 PyRemotePathMapper remotePathMapper =
75 instance.setupMappings(project, (PyRemoteSdkAdditionalDataBase)sdk.getSdkAdditionalData(), null);
77 PathMappingSettings mappingSettings = consoleSettings.getMappingSettings();
79 remotePathMapper.addAll(mappingSettings.getPathMappings(), PyRemotePathMapper.PyPathMappingType.USER_DEFINED);
81 return remotePathMapper;
88 static Pair<Sdk, Module> findPythonSdkAndModule(@NotNull Project project, @Nullable Module contextModule) {
91 PyConsoleOptions.PyConsoleSettings settings = PyConsoleOptions.getInstance(project).getPythonConsoleSettings();
92 String sdkHome = settings.getSdkHome();
93 if (sdkHome != null) {
94 sdk = PythonSdkType.findSdkByPath(sdkHome);
95 if (settings.getModuleName() != null) {
96 module = ModuleManager.getInstance(project).findModuleByName(settings.getModuleName());
99 module = contextModule;
100 if (module == null && ModuleManager.getInstance(project).getModules().length > 0) {
101 module = ModuleManager.getInstance(project).getModules()[0];
105 if (sdk == null && settings.isUseModuleSdk()) {
106 if (contextModule != null) {
107 module = contextModule;
109 else if (settings.getModuleName() != null) {
110 module = ModuleManager.getInstance(project).findModuleByName(settings.getModuleName());
112 if (module != null) {
113 if (PythonSdkType.findPythonSdk(module) != null) {
114 sdk = PythonSdkType.findPythonSdk(module);
118 else if (contextModule != null) {
119 if (module == null) {
120 module = contextModule;
123 sdk = PythonSdkType.findPythonSdk(module);
128 for (Module m : ModuleManager.getInstance(project).getModules()) {
129 if (PythonSdkType.findPythonSdk(m) != null) {
130 sdk = PythonSdkType.findPythonSdk(m);
137 if (PythonSdkType.getAllSdks().size() > 0) {
138 //noinspection UnusedAssignment
139 sdk = PythonSdkType.getAllSdks().get(0); //take any python sdk
142 return Pair.create(sdk, module);
145 static String constructPythonPathCommand(Collection<String> pythonPath, String command) {
146 final String path = Joiner.on(", ").join(Collections2.transform(pythonPath, new Function<String, String>() {
148 public String apply(String input) {
149 return "'" + input.replace("\\", "\\\\").replace("'", "\\'") + "'";
153 return command.replace(PydevConsoleRunnerImpl.WORKING_DIR_ENV, path);
156 static Map<String, String> addDefaultEnvironments(Sdk sdk, Map<String, String> envs, @NotNull Project project) {
157 setCorrectStdOutEncoding(envs, project);
159 PythonSdkFlavor.initPythonPath(envs, true, PythonCommandLineState.getAddedPaths(sdk));
164 * Add required ENV var to Python task to set its stdout charset to current project charset to allow it print correctly.
166 * @param envs map of envs to add variable
167 * @param project current project
169 static void setCorrectStdOutEncoding(@NotNull Map<String, String> envs, @NotNull Project project) {
170 final Charset defaultCharset = EncodingProjectManager.getInstance(project).getDefaultCharset();
171 final String encoding = defaultCharset.name();
172 setPythonIOEncoding(setPythonUnbuffered(envs), encoding);
176 * Set command line charset as current project charset.
177 * Add required ENV var to Python task to set its stdout charset to current project charset to allow it print correctly.
179 * @param commandLine command line
180 * @param project current project
182 static void setCorrectStdOutEncoding(@NotNull GeneralCommandLine commandLine, @NotNull Project project) {
183 final Charset defaultCharset = EncodingProjectManager.getInstance(project).getDefaultCharset();
184 commandLine.setCharset(defaultCharset);
185 setPythonIOEncoding(commandLine.getEnvironment(), defaultCharset.name());
188 static boolean isInPydevConsole(PsiElement element) {
189 return element instanceof PydevConsoleElement || getConsoleCommunication(element) != null;
192 static boolean isPythonConsole(@Nullable ASTNode element) {
193 return getPythonConsoleData(element) != null;
197 static PythonConsoleData getPythonConsoleData(@Nullable ASTNode element) {
198 if (element == null || element.getPsi() == null || element.getPsi().getContainingFile() == null) {
202 VirtualFile file = PydevConsoleRunnerImpl.getConsoleFile(element.getPsi().getContainingFile());
207 return file.getUserData(PyConsoleUtil.PYTHON_CONSOLE_DATA);
211 static ConsoleCommunication getConsoleCommunication(PsiElement element) {
212 final PsiFile containingFile = element.getContainingFile();
213 return containingFile != null ? containingFile.getCopyableUserData(CONSOLE_KEY) : null;
217 static Sdk getConsoleSdk(PsiElement element) {
218 final PsiFile containingFile = element.getContainingFile();
219 return containingFile != null ? containingFile.getCopyableUserData(CONSOLE_SDK) : null;
226 PydevConsoleCommunication getPydevConsoleCommunication();
228 void addConsoleListener(PydevConsoleRunnerImpl.ConsoleListener consoleListener);
230 PydevConsoleExecuteActionHandler getConsoleExecuteActionHandler();
232 PyConsoleProcessHandler getProcessHandler();
234 PythonConsoleView getConsoleView();