diff options
Diffstat (limited to 'python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java')
-rw-r--r-- | python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java | 378 |
1 files changed, 157 insertions, 221 deletions
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java index f8e10c9c4521..5d02f7149aab 100644 --- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java +++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyCheckAction.java @@ -1,7 +1,6 @@ package com.jetbrains.python.edu.actions; import com.intellij.execution.ExecutionException; -import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.ide.projectView.ProjectView; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.AnActionEvent; @@ -13,93 +12,81 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; -import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.popup.Balloon; import com.intellij.openapi.ui.popup.BalloonBuilder; import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.Disposer; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.ui.JBColor; +import com.intellij.openapi.wm.IdeFocusManager; import com.jetbrains.python.edu.StudyDocumentListener; -import com.jetbrains.python.edu.StudyTaskManager; +import com.jetbrains.python.edu.StudyState; +import com.jetbrains.python.edu.StudyTestRunner; import com.jetbrains.python.edu.StudyUtils; -import com.jetbrains.python.edu.course.*; +import com.jetbrains.python.edu.course.StudyStatus; +import com.jetbrains.python.edu.course.Task; +import com.jetbrains.python.edu.course.TaskFile; +import com.jetbrains.python.edu.course.TaskWindow; import com.jetbrains.python.edu.editor.StudyEditor; -import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; -import java.io.*; -import java.util.*; -import java.util.List; +import java.io.IOException; +import java.util.Map; public class StudyCheckAction extends DumbAwareAction { private static final Logger LOG = Logger.getInstance(StudyCheckAction.class.getName()); - public static final String PYTHONPATH = "PYTHONPATH"; + private static final String ANSWERS_POSTFIX = "_answers.py"; - static class StudyTestRunner { - public static final String TEST_OK = "#study_plugin test OK"; - private static final String TEST_FAILED = "#study_plugin FAILED + "; - private final Task myTask; - private final VirtualFile myTaskDir; - StudyTestRunner(Task task, VirtualFile taskDir) { - myTask = task; - myTaskDir = taskDir; + private static void flushWindows(@NotNull final Task task, @NotNull final VirtualFile taskDir) { + for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) { + String name = entry.getKey(); + TaskFile taskFile = entry.getValue(); + VirtualFile virtualFile = taskDir.findChild(name); + if (virtualFile == null) { + continue; + } + StudyUtils.flushWindows(taskFile, virtualFile); } + } - Process launchTests(Project project, String executablePath) throws ExecutionException { - Sdk sdk = PythonSdkType.findPythonSdk(ModuleManager.getInstance(project).getModules()[0]); - File testRunner = new File(myTaskDir.getPath(), myTask.getTestFile()); - GeneralCommandLine commandLine = new GeneralCommandLine(); - commandLine.setWorkDirectory(myTaskDir.getPath()); - final Map<String, String> env = commandLine.getEnvironment(); - final VirtualFile courseDir = project.getBaseDir(); - if (courseDir != null) - env.put(PYTHONPATH, courseDir.getPath()); - if (sdk != null) { - String pythonPath = sdk.getHomePath(); - if (pythonPath != null) { - commandLine.setExePath(pythonPath); - commandLine.addParameter(testRunner.getPath()); - final Course course = StudyTaskManager.getInstance(project).getCourse(); - assert course != null; - commandLine.addParameter(new File(course.getResourcePath()).getParent()); - commandLine.addParameter(FileUtil.toSystemDependentName(executablePath)); - return commandLine.createProcess(); - } + private static void deleteWindowDescriptions(@NotNull final Task task, @NotNull final VirtualFile taskDir) { + for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) { + String name = entry.getKey(); + VirtualFile virtualFile = taskDir.findChild(name); + if (virtualFile == null) { + continue; + } + String windowsFileName = virtualFile.getNameWithoutExtension() + "_windows"; + VirtualFile windowsFile = taskDir.findChild(windowsFileName); + if (windowsFile != null) { + StudyUtils.deleteFile(windowsFile); } - return null; } + } - - String getPassedTests(Process p) { - InputStream testOutput = p.getInputStream(); - BufferedReader testOutputReader = new BufferedReader(new InputStreamReader(testOutput)); - String line; - try { - while ((line = testOutputReader.readLine()) != null) { - if (line.contains(TEST_FAILED)) { - return line.substring(TEST_FAILED.length(), line.length()); - } - } - } - catch (IOException e) { - LOG.error(e); + private static void drawAllTaskWindows(@NotNull final Project project, @NotNull final Task task, @NotNull final VirtualFile taskDir) { + for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) { + String name = entry.getKey(); + TaskFile taskFile = entry.getValue(); + VirtualFile virtualFile = taskDir.findChild(name); + if (virtualFile == null) { + continue; } - finally { - StudyUtils.closeSilently(testOutputReader); + FileEditor fileEditor = FileEditorManager.getInstance(project).getSelectedEditor(virtualFile); + if (fileEditor instanceof StudyEditor) { + StudyEditor studyEditor = (StudyEditor)fileEditor; + taskFile.drawAllWindows(studyEditor.getEditor()); } - return TEST_OK; } } + public void check(@NotNull final Project project) { ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override @@ -107,188 +94,138 @@ public class StudyCheckAction extends DumbAwareAction { CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() { @Override public void run() { - final Editor selectedEditor = StudyEditor.getSelectedEditor(project); - if (selectedEditor != null) { - final FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance(); - final VirtualFile openedFile = fileDocumentManager.getFile(selectedEditor.getDocument()); - if (openedFile != null) { - StudyTaskManager taskManager = StudyTaskManager.getInstance(project); - final TaskFile selectedTaskFile = taskManager.getTaskFile(openedFile); - List<VirtualFile> filesToDelete = new ArrayList<VirtualFile>(); - if (selectedTaskFile != null) { - final VirtualFile taskDir = openedFile.getParent(); - Task currentTask = selectedTaskFile.getTask(); - StudyStatus oldStatus = currentTask.getStatus(); - Map<String, TaskFile> taskFiles = selectedTaskFile.getTask().getTaskFiles(); + final StudyEditor selectedEditor = StudyEditor.getSelectedStudyEditor(project); + final StudyState studyState = new StudyState(selectedEditor); + if (!studyState.isValid()) { + LOG.error("StudyCheckAction was invokes outside study editor"); + return; + } + Task task = studyState.getTask(); + StudyStatus oldStatus = task.getStatus(); + Map<String, TaskFile> taskFiles = task.getTaskFiles(); + VirtualFile taskDir = studyState.getTaskDir(); + flushWindows(task, taskDir); + StudyRunAction runAction = (StudyRunAction)ActionManager.getInstance().getAction(StudyRunAction.ACTION_ID); + if (runAction != null && taskFiles.size() == 1) { + runAction.run(project); + } + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + IdeFocusManager.getInstance(project).requestFocus(studyState.getEditor().getComponent(), true); + } + }); + final StudyTestRunner testRunner = new StudyTestRunner(task, taskDir); + Process testProcess = null; + try { + testProcess = testRunner.launchTests(project, studyState.getVirtualFile().getPath()); + } + catch (ExecutionException e) { + LOG.error(e); + } + if (testProcess == null) { + return; + } + String failedMessage = testRunner.getPassedTests(testProcess); + if (failedMessage.equals(StudyTestRunner.TEST_OK)) { + task.setStatus(StudyStatus.Solved, oldStatus); + createTestResultPopUp("Congratulations!", MessageType.INFO.getPopupBackground(), project); + } + else { + task.setStatus(StudyStatus.Failed, oldStatus); for (Map.Entry<String, TaskFile> entry : taskFiles.entrySet()) { String name = entry.getKey(); TaskFile taskFile = entry.getValue(); - VirtualFile virtualFile = taskDir.findChild(name); - if (virtualFile == null) { + if (taskFile.getTaskWindows().size() < 2) { + taskFile.setStatus(StudyStatus.Failed, StudyStatus.Unchecked); continue; } - VirtualFile windowFile = StudyUtils.flushWindows(FileDocumentManager.getInstance().getDocument(virtualFile), taskFile, virtualFile); - filesToDelete.add(windowFile); - FileDocumentManager.getInstance().saveAllDocuments(); - } - - StudyRunAction runAction = (StudyRunAction)ActionManager.getInstance().getAction(StudyRunAction.ACTION_ID); - if (runAction != null && currentTask.getTaskFiles().size() == 1) { - runAction.run(project); - } - final StudyTestRunner testRunner = new StudyTestRunner(currentTask, taskDir); - Process testProcess = null; - try { - testProcess = testRunner.launchTests(project, openedFile.getPath()); - } - catch (ExecutionException e) { - LOG.error(e); - } - if (testProcess != null) { - String failedMessage = testRunner.getPassedTests(testProcess); - if (failedMessage.equals(StudyTestRunner.TEST_OK)) { - currentTask.setStatus(StudyStatus.Solved, oldStatus); - StudyUtils.updateStudyToolWindow(project); - selectedTaskFile.drawAllWindows(selectedEditor); - ProjectView.getInstance(project).refresh(); - for (VirtualFile file:filesToDelete) { - try { - file.delete(this); - } - catch (IOException e) { - LOG.error(e); - } - } - createTestResultPopUp("Congratulations!", JBColor.GREEN, project); - return; - } - for (Map.Entry<String, TaskFile> entry : taskFiles.entrySet()) { - String name = entry.getKey(); - TaskFile taskFile = entry.getValue(); - TaskFile answerTaskFile = new TaskFile(); - VirtualFile virtualFile = taskDir.findChild(name); - if (virtualFile == null) { - continue; - } - VirtualFile answerFile = getCopyWithAnswers(taskDir, virtualFile, taskFile, answerTaskFile); - for (TaskWindow taskWindow : answerTaskFile.getTaskWindows()) { - Document document = FileDocumentManager.getInstance().getDocument(virtualFile); - if (document == null) { - continue; - } - if (!taskWindow.isValid(document)) { - continue; - } - check(project, taskWindow, answerFile, answerTaskFile, taskFile, document, testRunner, virtualFile); - } - FileEditor fileEditor = FileEditorManager.getInstance(project).getSelectedEditor(virtualFile); - Editor editor = null; - if (fileEditor instanceof StudyEditor) { - StudyEditor studyEditor = (StudyEditor) fileEditor; - editor = studyEditor.getEditor(); - } - - if (editor != null) { - taskFile.drawAllWindows(editor); - StudyUtils.synchronize(); - } - try { - answerFile.delete(this); - } - catch (IOException e) { - LOG.error(e); - } - } - for (VirtualFile file:filesToDelete) { - try { - file.delete(this); - } - catch (IOException e) { - LOG.error(e); - } - } - currentTask.setStatus(StudyStatus.Failed, oldStatus); - StudyUtils.updateStudyToolWindow(project); - createTestResultPopUp(failedMessage, JBColor.RED, project); + runSmartTestProcess(taskDir, testRunner, name, taskFile, project); } + createTestResultPopUp(failedMessage, MessageType.ERROR.getPopupBackground(), project); + navigateToFailedTaskWindow(studyState, task, taskDir, project); } + StudyUtils.updateStudyToolWindow(project); + drawAllTaskWindows(project, task, taskDir); + ProjectView.getInstance(project).refresh(); + deleteWindowDescriptions(task, taskDir); } - } - - } - }); + }); } }); } - private void check(Project project, - TaskWindow taskWindow, - VirtualFile answerFile, - TaskFile answerTaskFile, - TaskFile usersTaskFile, - Document usersDocument, - StudyTestRunner testRunner, - VirtualFile openedFile) { - - try { - VirtualFile windowCopy = answerFile.copy(this, answerFile.getParent(), answerFile.getNameWithoutExtension() + "_window" + taskWindow.getIndex() + ".py"); - final FileDocumentManager documentManager = FileDocumentManager.getInstance(); - final Document windowDocument = documentManager.getDocument(windowCopy); - if (windowDocument != null) { - StudyTaskManager taskManager = StudyTaskManager.getInstance(project); - Course course = taskManager.getCourse(); - Task task = usersTaskFile.getTask(); - int taskNum = task.getIndex() + 1; - int lessonNum = task.getLesson().getIndex() + 1; - assert course != null; - String pathToResource = FileUtil.join(new File(course.getResourcePath()).getParent(), Lesson.LESSON_DIR + lessonNum, Task.TASK_DIR + taskNum); - File resourceFile = new File(pathToResource, windowCopy.getName()); - FileUtil.copy(new File(pathToResource, openedFile.getName()), resourceFile); - TaskFile windowTaskFile = new TaskFile(); - TaskFile.copy(answerTaskFile, windowTaskFile); - StudyDocumentListener listener = new StudyDocumentListener(windowTaskFile); - windowDocument.addDocumentListener(listener); - int start = taskWindow.getRealStartOffset(windowDocument); - int end = start + taskWindow.getLength(); - TaskWindow userTaskWindow = usersTaskFile.getTaskWindows().get(taskWindow.getIndex()); - int userStart = userTaskWindow.getRealStartOffset(usersDocument); - int userEnd = userStart + userTaskWindow.getLength(); - String text = usersDocument.getText(new TextRange(userStart, userEnd)); - windowDocument.replaceString(start, end, text); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - @Override - public void run() { - documentManager.saveDocument(windowDocument); + private static void navigateToFailedTaskWindow(@NotNull final StudyState studyState, + @NotNull final Task task, + @NotNull final VirtualFile taskDir, + @NotNull final Project project) { + TaskFile selectedTaskFile = studyState.getTaskFile(); + Editor editor = studyState.getEditor(); + TaskFile taskFileToNavigate = selectedTaskFile; + VirtualFile fileToNavigate = studyState.getVirtualFile(); + if (!selectedTaskFile.hasFailedTaskWindows()) { + for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) { + String name = entry.getKey(); + TaskFile taskFile = entry.getValue(); + if (taskFile.hasFailedTaskWindows()) { + taskFileToNavigate = taskFile; + VirtualFile virtualFile = taskDir.findChild(name); + if (virtualFile == null) { + continue; } - }); - VirtualFile fileWindows = StudyUtils.flushWindows(windowDocument, windowTaskFile, windowCopy); - Process smartTestProcess = testRunner.launchTests(project, windowCopy.getPath()); - boolean res = testRunner.getPassedTests(smartTestProcess).equals(StudyTestRunner.TEST_OK); - userTaskWindow.setStatus(res ? StudyStatus.Solved : StudyStatus.Failed, StudyStatus.Unchecked); - windowCopy.delete(this); - fileWindows.delete(this); - if (!resourceFile.delete()) { - LOG.error("failed to delete", resourceFile.getPath()); + FileEditor fileEditor = FileEditorManager.getInstance(project).getSelectedEditor(virtualFile); + if (fileEditor instanceof StudyEditor) { + StudyEditor studyEditor = (StudyEditor)fileEditor; + editor = studyEditor.getEditor(); + } + fileToNavigate = virtualFile; + break; } } } - catch (IOException e) { - LOG.error(e); + FileEditorManager.getInstance(project).openFile(fileToNavigate, true); + final Editor editorToNavigate = editor; + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + IdeFocusManager.getInstance(project).requestFocus(editorToNavigate.getContentComponent(), true); + } + }); + taskFileToNavigate.navigateToFirstFailedTaskWindow(editor); + } + + private void runSmartTestProcess(@NotNull final VirtualFile taskDir, + @NotNull final StudyTestRunner testRunner, + final String taskFileName, + @NotNull final TaskFile taskFile, + @NotNull final Project project) { + TaskFile answerTaskFile = new TaskFile(); + VirtualFile virtualFile = taskDir.findChild(taskFileName); + if (virtualFile == null) { + return; } - catch (ExecutionException e) { - LOG.error(e); + VirtualFile answerFile = getCopyWithAnswers(taskDir, virtualFile, taskFile, answerTaskFile); + for (TaskWindow taskWindow : answerTaskFile.getTaskWindows()) { + Document document = FileDocumentManager.getInstance().getDocument(virtualFile); + if (document == null) { + continue; + } + if (!taskWindow.isValid(document)) { + continue; + } + taskWindow.smartCheck(project, answerFile, answerTaskFile, taskFile, testRunner, virtualFile, document); } + StudyUtils.deleteFile(answerFile); } - - private VirtualFile getCopyWithAnswers(final VirtualFile taskDir, - final VirtualFile file, - final TaskFile source, - TaskFile target) { + private VirtualFile getCopyWithAnswers(@NotNull final VirtualFile taskDir, + @NotNull final VirtualFile file, + @NotNull final TaskFile source, + @NotNull final TaskFile target) { VirtualFile copy = null; try { - copy = file.copy(this, taskDir, file.getNameWithoutExtension() +"_answers.py"); + copy = file.copy(this, taskDir, file.getNameWithoutExtension() + ANSWERS_POSTFIX); final FileDocumentManager documentManager = FileDocumentManager.getInstance(); final Document document = documentManager.getDocument(copy); if (document != null) { @@ -315,19 +252,18 @@ public class StudyCheckAction extends DumbAwareAction { catch (IOException e) { LOG.error(e); } - - return copy; } private static void createTestResultPopUp(final String text, Color color, @NotNull final Project project) { BalloonBuilder balloonBuilder = JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(text, null, color, null); - Balloon balloon = balloonBuilder.createBalloon(); + final Balloon balloon = balloonBuilder.createBalloon(); StudyEditor studyEditor = StudyEditor.getSelectedStudyEditor(project); assert studyEditor != null; JButton checkButton = studyEditor.getCheckButton(); balloon.showInCenterOf(checkButton); + Disposer.register(project, balloon); } @Override |