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.actions;
18 import com.google.common.collect.Lists;
19 import com.intellij.execution.ExecutionHelper;
20 import com.intellij.execution.console.LanguageConsoleView;
21 import com.intellij.execution.process.ProcessHandler;
22 import com.intellij.execution.ui.RunContentDescriptor;
23 import com.intellij.openapi.actionSystem.*;
24 import com.intellij.openapi.editor.*;
25 import com.intellij.openapi.editor.ex.util.EditorUtil;
26 import com.intellij.openapi.module.Module;
27 import com.intellij.openapi.project.Project;
28 import com.intellij.openapi.util.Pair;
29 import com.intellij.openapi.util.text.StringUtil;
30 import com.intellij.psi.PsiDocumentManager;
31 import com.intellij.psi.PsiFile;
32 import com.intellij.util.Consumer;
33 import com.jetbrains.python.console.PyCodeExecutor;
34 import com.jetbrains.python.console.PydevConsoleRunner;
35 import com.jetbrains.python.console.PythonConsoleRunnerFactory;
36 import com.jetbrains.python.psi.PyFile;
37 import org.jetbrains.annotations.NotNull;
38 import org.jetbrains.annotations.Nullable;
40 import java.util.Collection;
41 import java.util.List;
43 public class PyExecuteSelectionAction extends AnAction {
45 public static final String EXECUTE_SELECTION_IN_CONSOLE = "Execute Selection in Console";
47 public PyExecuteSelectionAction() {
48 super(EXECUTE_SELECTION_IN_CONSOLE);
51 public void actionPerformed(AnActionEvent e) {
52 Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext());
54 final String selectionText = getSelectionText(editor);
55 if (selectionText != null) {
56 execute(e, selectionText);
59 String line = getLineUnderCaret(editor);
62 moveCaretDown(editor);
68 private static void moveCaretDown(Editor editor) {
69 VisualPosition pos = editor.getCaretModel().getVisualPosition();
70 Pair<LogicalPosition, LogicalPosition> lines = EditorUtil.calcSurroundingRange(editor, pos, pos);
71 int offset = editor.getCaretModel().getOffset();
73 LogicalPosition lineStart = lines.first;
74 LogicalPosition nextLineStart = lines.second;
76 int start = editor.logicalPositionToOffset(lineStart);
77 int end = editor.logicalPositionToOffset(nextLineStart);
79 Document document = editor.getDocument();
81 if (nextLineStart.line < document.getLineCount()) {
83 int newOffset = end + offset - start;
85 int nextLineEndOffset = document.getLineEndOffset(nextLineStart.line);
86 if (newOffset >= nextLineEndOffset) {
87 newOffset = nextLineEndOffset;
90 editor.getCaretModel().moveToOffset(newOffset);
91 editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
95 private static void execute(final AnActionEvent e, final String selectionText) {
96 final Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext());
97 Project project = e.getProject();
98 Module module = e.getData(LangDataKeys.MODULE);
100 findCodeExecutor(e, codeExecutor -> executeInConsole(codeExecutor, selectionText, editor), editor, project, module);
103 private static String getLineUnderCaret(Editor editor) {
104 VisualPosition caretPos = editor.getCaretModel().getVisualPosition();
106 Pair<LogicalPosition, LogicalPosition> lines = EditorUtil.calcSurroundingRange(editor, caretPos, caretPos);
108 LogicalPosition lineStart = lines.first;
109 LogicalPosition nextLineStart = lines.second;
110 int start = editor.logicalPositionToOffset(lineStart);
111 int end = editor.logicalPositionToOffset(nextLineStart);
115 return editor.getDocument().getCharsSequence().subSequence(start, end).toString();
119 private static String getSelectionText(@NotNull Editor editor) {
120 if (editor.getSelectionModel().hasSelection()) {
121 SelectionModel model = editor.getSelectionModel();
123 return model.getSelectedText();
130 public void update(AnActionEvent e) {
131 Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext());
132 Presentation presentation = e.getPresentation();
134 boolean enabled = false;
135 if (editor != null && isPython(editor)) {
136 String text = getSelectionText(editor);
138 presentation.setText(EXECUTE_SELECTION_IN_CONSOLE);
141 text = getLineUnderCaret(editor);
143 presentation.setText("Execute Line in Console");
147 enabled = !StringUtil.isEmpty(text);
150 presentation.setEnabled(enabled);
151 presentation.setVisible(enabled);
154 private static boolean isPython(Editor editor) {
155 if (editor == null) {
159 Project project = editor.getProject();
161 if (project == null) {
165 PsiFile psi = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
166 return psi instanceof PyFile;
169 private static void selectConsole(@NotNull DataContext dataContext, @NotNull Project project,
170 final Consumer<PyCodeExecutor> consumer) {
171 Collection<RunContentDescriptor> consoles = getConsoles(project);
174 .selectContentDescriptor(dataContext, project, consoles, "Select console to execute in", descriptor -> {
175 if (descriptor != null && descriptor.getExecutionConsole() instanceof PyCodeExecutor) {
176 consumer.consume((PyCodeExecutor)descriptor.getExecutionConsole());
181 private static Collection<RunContentDescriptor> getConsoles(Project project) {
184 return ExecutionHelper.findRunningConsole(project, dom -> dom.getExecutionConsole() instanceof PyCodeExecutor && isAlive(dom));
187 private static boolean isAlive(RunContentDescriptor dom) {
188 ProcessHandler processHandler = dom.getProcessHandler();
189 return processHandler != null && !processHandler.isProcessTerminated();
192 private static void findCodeExecutor(AnActionEvent e, Consumer<PyCodeExecutor> consumer, Editor editor, Project project, Module module) {
193 if (project != null && editor != null) {
194 if (canFindConsole(e)) {
195 selectConsole(e.getDataContext(), project, consumer);
198 startConsole(project, consumer, module);
203 private static void startConsole(final Project project,
204 final Consumer<PyCodeExecutor> consumer,
207 PythonConsoleRunnerFactory consoleRunnerFactory = PythonConsoleRunnerFactory.getInstance();
208 PydevConsoleRunner runner = consoleRunnerFactory.createConsoleRunner(project, null);
209 runner.addConsoleListener(new PydevConsoleRunner.ConsoleListener() {
211 public void handleConsoleInitialized(LanguageConsoleView consoleView) {
212 if (consoleView instanceof PyCodeExecutor) {
213 consumer.consume((PyCodeExecutor)consoleView);
221 private static boolean canFindConsole(AnActionEvent e) {
222 Project project = e.getProject();
223 if (project != null) {
224 Collection<RunContentDescriptor> descriptors = getConsoles(project);
225 return descriptors.size() > 0;
232 private static void executeInConsole(@NotNull PyCodeExecutor codeExecutor, @NotNull String text, Editor editor) {
233 codeExecutor.executeCode(text, editor);