<action id="UnpackCourse" class="com.jetbrains.edu.coursecreator.actions.CCFromCourseArchive"/>
<action id="GetCourse" class="com.jetbrains.edu.coursecreator.actions.CCGetCourseFromStepic"/>
+ <action class="com.jetbrains.edu.coursecreator.actions.CCNewSubtaskAction" id="CC.NewStep">
+ <add-to-group group-id="AnswerPlaceholderGroup" relative-to-action="DeleteAllPlaceholders" anchor="after"/>
+ </action>
</actions>
import com.intellij.lang.LanguageExtension;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
+import com.jetbrains.edu.learning.courseFormat.Task;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
default boolean isTestFile(VirtualFile file) {
return false;
}
+
+ default void createTestsForNewSubtask(@NotNull Project project, @NotNull Task task) {}
}
FileDocumentManager.getInstance().saveDocument(document);
final SelectionModel model = editor.getSelectionModel();
final int offset = model.hasSelection() ? model.getSelectionStart() : editor.getCaretModel().getOffset();
- int stepIndex = state.getTaskFile().getTask().getActiveStepIndex();
+ int stepIndex = state.getTaskFile().getTask().getActiveSubtaskIndex();
final AnswerPlaceholder answerPlaceholder = new AnswerPlaceholder();
answerPlaceholder.getSubtaskInfos().put(stepIndex, new AnswerPlaceholderSubtaskInfo());
TaskFile taskFile = state.getTaskFile();
--- /dev/null
+package com.jetbrains.edu.coursecreator.actions;
+
+import com.intellij.ide.fileTemplates.FileTemplate;
+import com.intellij.ide.fileTemplates.FileTemplateManager;
+import com.intellij.ide.fileTemplates.FileTemplateUtil;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.DumbAwareAction;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.io.FileUtilRt;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiManager;
+import com.jetbrains.edu.coursecreator.CCLanguageManager;
+import com.jetbrains.edu.coursecreator.CCUtils;
+import com.jetbrains.edu.coursecreator.settings.CCSettings;
+import com.jetbrains.edu.learning.StudyTaskManager;
+import com.jetbrains.edu.learning.StudyUtils;
+import com.jetbrains.edu.learning.core.EduNames;
+import com.jetbrains.edu.learning.courseFormat.Course;
+import com.jetbrains.edu.learning.courseFormat.Task;
+import com.jetbrains.edu.learning.courseFormat.TaskFile;
+import org.jetbrains.annotations.NotNull;
+
+
+public class CCNewSubtaskAction extends DumbAwareAction {
+ private static final Logger LOG = Logger.getInstance(CCNewSubtaskAction.class);
+ public static final String NEW_SUBTASK = "New Subtask";
+
+ public CCNewSubtaskAction() {
+ super(NEW_SUBTASK);
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ DataContext dataContext = e.getDataContext();
+ VirtualFile virtualFile = CommonDataKeys.VIRTUAL_FILE.getData(dataContext);
+ Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
+ Project project = CommonDataKeys.PROJECT.getData(dataContext);
+ if (virtualFile == null || project == null || editor == null) {
+ return;
+ }
+ addSubtask(virtualFile, project);
+ }
+
+ public static void addSubtask(@NotNull VirtualFile virtualFile, @NotNull Project project) {
+ TaskFile taskFile = StudyUtils.getTaskFile(project, virtualFile);
+ if (taskFile == null) {
+ return;
+ }
+ VirtualFile taskDir = StudyUtils.getTaskDir(virtualFile);
+ if (taskDir == null) {
+ return;
+ }
+ Task task = taskFile.getTask();
+ createTestsForNewSubtask(project, task);
+ int num = task.getSubtaskNum();
+ createTaskDescriptionFile(project, taskDir, num);
+ task.setSubtaskNum(num + 1);
+ task.setActiveSubtaskIndex(num);
+ //TODO: switch subtask
+ }
+
+ private static void createTestsForNewSubtask(Project project, Task task) {
+ Course course = StudyTaskManager.getInstance(project).getCourse();
+ if (course == null) {
+ return;
+ }
+ CCLanguageManager manager = CCUtils.getStudyLanguageManager(course);
+ if (manager == null) {
+ return;
+ }
+ manager.createTestsForNewSubtask(project, task);
+ }
+
+ private static void createTaskDescriptionFile(Project project, VirtualFile taskDir, int index) {
+ String taskDescriptionFileName = StudyUtils.getTaskDescriptionFileName(CCSettings.getInstance().useHtmlAsDefaultTaskFormat());
+ FileTemplate taskTextTemplate = FileTemplateManager.getInstance(project).getInternalTemplate(taskDescriptionFileName);
+ PsiDirectory taskPsiDir = PsiManager.getInstance(project).findDirectory(taskDir);
+ if (taskTextTemplate != null && taskPsiDir != null) {
+ String nextTaskTextName = FileUtil.getNameWithoutExtension(taskDescriptionFileName) +
+ EduNames.SUBTASK_MARKER +
+ index + "." +
+ FileUtilRt.getExtension(taskDescriptionFileName);
+ try {
+ FileTemplateUtil.createFromTemplate(taskTextTemplate, nextTaskTextName, null, taskPsiDir);
+ }
+ catch (Exception e) {
+ LOG.error(e);
+ }
+ }
+ }
+
+ @Override
+ public void update(AnActionEvent e) {
+ DataContext dataContext = e.getDataContext();
+ Presentation presentation = e.getPresentation();
+ presentation.setEnabledAndVisible(false);
+ VirtualFile virtualFile = CommonDataKeys.VIRTUAL_FILE.getData(dataContext);
+ Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
+ Project project = CommonDataKeys.PROJECT.getData(dataContext);
+ if (virtualFile == null || project == null || editor == null) {
+ return;
+ }
+ if (CCUtils.isCourseCreator(project) && StudyUtils.getTaskForFile(project, virtualFile) != null) {
+ presentation.setEnabledAndVisible(true);
+ }
+ }
+}
\ No newline at end of file
public static final String ANSWER_PLACEHOLDER = "Answer Placeholder";
public static final String SRC = "src";
+ public static final String SUBTASK_MARKER = "_subtask";
+
private EduNames() {
}
if (myTaskFile == null || myTaskFile.getTask() == null) {
return mySubtaskInfos.get(0);
}
- int activeStepIndex = myTaskFile.getTask().getActiveStepIndex();
+ int activeStepIndex = myTaskFile.getTask().getActiveSubtaskIndex();
return mySubtaskInfos.get(activeStepIndex);
}
}
@Transient private Lesson myLesson;
@Expose @SerializedName("update_date") private Date myUpdateDate;
- private int myActiveStepIndex = 0;
+ private int myActiveSubtaskIndex = 0;
+ @Expose private int mySubtaskNum = 1;
public Task() {}
return !date.after(myUpdateDate);
}
- public int getActiveStepIndex() {
- return myActiveStepIndex;
+ public int getActiveSubtaskIndex() {
+ return myActiveSubtaskIndex;
}
- public void setActiveStepIndex(int activeStepIndex) {
- myActiveStepIndex = activeStepIndex;
+ public void setActiveSubtaskIndex(int activeSubtaskIndex) {
+ myActiveSubtaskIndex = activeSubtaskIndex;
+ }
+
+ public int getSubtaskNum() {
+ return mySubtaskNum;
+ }
+
+ public void setSubtaskNum(int subtaskNum) {
+ mySubtaskNum = subtaskNum;
}
}
import com.intellij.ide.fileTemplates.FileTemplate;
import com.intellij.ide.fileTemplates.FileTemplateManager;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.DocumentUtil;
+import com.jetbrains.edu.learning.StudyTaskManager;
import com.jetbrains.edu.learning.core.EduNames;
+import com.jetbrains.edu.learning.courseFormat.Task;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
+import java.io.IOException;
public class PyCCLanguageManager implements CCLanguageManager {
+ private static final Logger LOG = Logger.getInstance(PyCCLanguageManager.class);
@Nullable
@Override
@Override
public boolean isTestFile(VirtualFile file) {
- return EduNames.TESTS_FILE.equals(file.getName());
+ String name = file.getName();
+ if (EduNames.TESTS_FILE.equals(name)) {
+ return true;
+ }
+ return name.contains(FileUtil.getNameWithoutExtension(EduNames.TESTS_FILE)) && name.contains(EduNames.SUBTASK_MARKER);
+ }
+
+ @Override
+ public void createTestsForNewSubtask(@NotNull Project project, @NotNull Task task) {
+ VirtualFile taskDir = task.getTaskDir(project);
+ if (taskDir == null) {
+ return;
+ }
+
+ int prevSubtaskIndex = task.getActiveSubtaskIndex();
+ String name = prevSubtaskIndex == 0 ? EduNames.TESTS_FILE : getSubtaskTestsFileName(prevSubtaskIndex);
+ VirtualFile testsFile = taskDir.findChild(name);
+ if (testsFile == null) {
+ return;
+ }
+ Document document = FileDocumentManager.getInstance().getDocument(testsFile);
+ if (document == null) {
+ return;
+ }
+ CharSequence prevTestText = document.getCharsSequence();
+ int nextSubtaskIndex = prevSubtaskIndex + 1;
+ String nextSubtaskTestsFileName = getSubtaskTestsFileName(nextSubtaskIndex);
+ ApplicationManager.getApplication().runWriteAction(() -> {
+ try {
+ VirtualFile nextSubtaskTestsFile = taskDir.createChildData(this, nextSubtaskTestsFileName);
+ StudyTaskManager.getInstance(project).addInvisibleFiles(nextSubtaskTestsFile.getPath());
+ Document nextSubtaskDocument = FileDocumentManager.getInstance().getDocument(nextSubtaskTestsFile);
+ if (nextSubtaskDocument == null) {
+ return;
+ }
+ String header = "# This is test for subtask " + nextSubtaskIndex + ". We've already copied tests from previous subtask here.\n\n";
+ DocumentUtil.writeInRunUndoTransparentAction(() -> {
+ nextSubtaskDocument.insertString(0, header);
+ nextSubtaskDocument.insertString(header.length(), prevTestText);
+ FileDocumentManager.getInstance().saveDocument(nextSubtaskDocument);
+ });
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ });
+ }
+
+ @NotNull
+ public static String getSubtaskTestsFileName(int index) {
+ return index == 0 ? EduNames.TESTS_FILE : FileUtil.getNameWithoutExtension(EduNames.TESTS_FILE) +
+ EduNames.SUBTASK_MARKER +
+ index + "." +
+ FileUtilRt.getExtension(EduNames.TESTS_FILE);
}
-}
+}
\ No newline at end of file