1 package com.jetbrains.edu.learning;
3 import com.intellij.execution.ExecutionException;
4 import com.intellij.openapi.actionSystem.ActionManager;
5 import com.intellij.openapi.actionSystem.AnActionEvent;
6 import com.intellij.openapi.actionSystem.KeyboardShortcut;
7 import com.intellij.openapi.actionSystem.Presentation;
8 import com.intellij.openapi.application.ApplicationManager;
9 import com.intellij.openapi.command.CommandProcessor;
10 import com.intellij.openapi.diagnostic.Logger;
11 import com.intellij.openapi.keymap.KeymapUtil;
12 import com.intellij.openapi.progress.ProgressManager;
13 import com.intellij.openapi.project.DumbService;
14 import com.intellij.openapi.project.Project;
15 import com.intellij.openapi.ui.MessageType;
16 import com.intellij.openapi.util.Ref;
17 import com.intellij.openapi.vfs.VirtualFile;
18 import com.intellij.openapi.wm.IdeFocusManager;
19 import com.jetbrains.edu.courseFormat.StudyStatus;
20 import com.jetbrains.edu.courseFormat.Task;
21 import com.jetbrains.edu.courseFormat.TaskFile;
22 import com.jetbrains.edu.learning.actions.StudyRunAction;
23 import com.jetbrains.edu.learning.actions.StudyToolbarAction;
24 import com.jetbrains.edu.learning.checker.StudyCheckTask;
25 import com.jetbrains.edu.learning.checker.StudyCheckUtils;
26 import com.jetbrains.edu.learning.checker.StudyTestRunner;
27 import com.jetbrains.edu.learning.checker.StudyTestsOutputParser;
28 import com.jetbrains.edu.learning.editor.StudyEditor;
29 import icons.InteractiveLearningIcons;
30 import org.jetbrains.annotations.NotNull;
31 import org.jetbrains.annotations.Nullable;
36 public class PyStudyCheckAction extends StudyToolbarAction {
37 private static final Logger LOG = Logger.getInstance(PyStudyCheckAction.class);
39 public static final String ACTION_ID = "PyCheckAction";
40 public static final String SHORTCUT = "ctrl alt pressed ENTER";
42 protected Ref<Boolean> myCheckInProgress = new Ref<>(false);
44 public PyStudyCheckAction() {
45 super("Check Task (" + KeymapUtil.getShortcutText(new KeyboardShortcut(KeyStroke.getKeyStroke(SHORTCUT), null)) + ")", "Check current task", InteractiveLearningIcons.Resolve);
49 public void actionPerformed(@NotNull AnActionEvent e) {
50 Project project = e.getProject();
51 if (project == null) {
54 if (DumbService.isDumb(project)) {
55 StudyCheckUtils.showTestResultPopUp("Checking is not available while indexing is in progress", MessageType.WARNING.getPopupBackground(), project);
61 protected void check(@NotNull Project project) {
62 ApplicationManager.getApplication().runWriteAction(() -> {
63 CommandProcessor.getInstance().runUndoTransparentAction(() -> {
64 final StudyEditor selectedEditor = StudyUtils.getSelectedStudyEditor(project);
65 if (selectedEditor == null) return;
66 final StudyState studyState = new StudyState(selectedEditor);
67 if (!studyState.isValid()) {
68 LOG.info("StudyCheckAction was invoked outside study editor");
71 if (StudyCheckUtils.hasBackgroundProcesses(project)) return;
74 if (!runTask(project)) return;
76 final Task task = studyState.getTask();
77 final VirtualFile taskDir = studyState.getTaskDir();
78 StudyCheckUtils.flushWindows(task, taskDir);
81 ApplicationManager.getApplication().invokeLater(
82 () -> IdeFocusManager.getInstance(project).requestFocus(studyState.getEditor().getComponent(), true));
84 final StudyTestRunner testRunner = StudyUtils.getTestRunner(task, taskDir);
85 Process testProcess = null;
86 String commandLine = "";
88 final VirtualFile executablePath = getTaskVirtualFile(studyState, task, taskDir);
89 if (executablePath != null) {
90 commandLine = executablePath.getPath();
91 testProcess = testRunner.createCheckProcess(project, commandLine);
94 catch (ExecutionException e) {
97 if (testProcess == null) {
100 myCheckInProgress.set(true);
101 StudyCheckTask checkTask = getCheckTask(project, studyState, testRunner, testProcess, commandLine);
102 ProgressManager.getInstance().run(checkTask);
107 private static boolean runTask(@NotNull Project project) {
108 final StudyRunAction runAction = (StudyRunAction)ActionManager.getInstance().getAction(StudyRunAction.ACTION_ID);
109 if (runAction == null) {
112 runAction.run(project);
117 private StudyCheckTask getCheckTask(@NotNull final Project project,
118 final StudyState studyState,
119 final StudyTestRunner testRunner,
120 final Process testProcess,
121 final String commandLine) {
122 return new StudyCheckTask(project, studyState, myCheckInProgress, testProcess, commandLine) {
124 protected void onTaskFailed(StudyTestsOutputParser.TestsOutput testsOutput) {
125 ApplicationManager.getApplication().invokeLater(() -> {
126 if (myTaskDir == null) return;
127 myTaskManger.setStatus(myTask, StudyStatus.Failed);
128 for (Map.Entry<String, TaskFile> entry : myTask.getTaskFiles().entrySet()) {
129 final String name = entry.getKey();
130 final TaskFile taskFile = entry.getValue();
131 if (taskFile.getAnswerPlaceholders().size() < 2) {
132 myTaskManger.setStatus(taskFile, StudyStatus.Failed);
135 CommandProcessor.getInstance().runUndoTransparentAction(() -> ApplicationManager.getApplication().runWriteAction(() -> {
136 StudyCheckUtils.runSmartTestProcess(myTaskDir, testRunner, name, taskFile, project);
139 StudyCheckUtils.showTestResultPopUp(testsOutput.getMessage(), MessageType.ERROR.getPopupBackground(), project);
140 StudyCheckUtils.navigateToFailedPlaceholder(myStudyState, myTask, myTaskDir, project);
148 private static VirtualFile getTaskVirtualFile(@NotNull final StudyState studyState,
149 @NotNull final Task task,
150 @NotNull final VirtualFile taskDir) {
151 VirtualFile taskVirtualFile = studyState.getVirtualFile();
152 for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
153 String name = entry.getKey();
154 TaskFile taskFile = entry.getValue();
155 VirtualFile virtualFile = taskDir.findChild(name);
156 if (virtualFile != null) {
157 if (!taskFile.getAnswerPlaceholders().isEmpty()) {
158 taskVirtualFile = virtualFile;
162 return taskVirtualFile;
168 public String getActionId() {
173 public String[] getShortcuts() {
174 return new String[]{SHORTCUT};
178 public void update(AnActionEvent e) {
179 final Presentation presentation = e.getPresentation();
180 StudyUtils.updateAction(e);
181 if (presentation.isEnabled()) {
182 presentation.setEnabled(!myCheckInProgress.get());