diff --git a/ij-plugin/src/main/kotlin/org/jetbrains/research/tasktracker/config/content/TaskContentConfig.kt b/ij-plugin/src/main/kotlin/org/jetbrains/research/tasktracker/config/content/TaskContentConfig.kt index 442d6d00..7a955b4b 100644 --- a/ij-plugin/src/main/kotlin/org/jetbrains/research/tasktracker/config/content/TaskContentConfig.kt +++ b/ij-plugin/src/main/kotlin/org/jetbrains/research/tasktracker/config/content/TaskContentConfig.kt @@ -4,6 +4,7 @@ import kotlinx.serialization.Serializable import org.jetbrains.research.tasktracker.config.BaseConfig import org.jetbrains.research.tasktracker.config.YamlConfigLoadStrategy import org.jetbrains.research.tasktracker.config.content.task.ProgrammingTask +import org.jetbrains.research.tasktracker.config.content.task.base.TaskFileInfo import org.jetbrains.research.tasktracker.handler.content.TaskContentHandler import java.io.File @@ -24,16 +25,19 @@ data class TaskContentConfig(val tasks: List) : BaseConfig { fun buildConfig(configFile: File): TaskContentConfig { val config = YamlConfigLoadStrategy.load(configFile.readText(), serializer()) - config.tasks.forEach { t -> - t.language?.let { - t.files.forEach { f -> - f.extension = it - f.relativePath = "${t.name}/${f.relativePath}" - f.content = f.gatherContent() + config.tasks.forEach { task -> + task.language?.let { + task.files.forEach { fileInfo -> + fileInfo.extension = it + fileInfo.relativePath = getRelativePath(task, fileInfo) + fileInfo.content = fileInfo.gatherContent() } } } return config } + + private fun getRelativePath(task: ProgrammingTask, fileInfo: TaskFileInfo) = + "${if (fileInfo.isInternal) "${task.name}/" else ""}${fileInfo.relativePath}" } } diff --git a/ij-plugin/src/main/kotlin/org/jetbrains/research/tasktracker/config/content/task/base/TaskFileInfo.kt b/ij-plugin/src/main/kotlin/org/jetbrains/research/tasktracker/config/content/task/base/TaskFileInfo.kt index 475b5946..b88bf15d 100644 --- a/ij-plugin/src/main/kotlin/org/jetbrains/research/tasktracker/config/content/task/base/TaskFileInfo.kt +++ b/ij-plugin/src/main/kotlin/org/jetbrains/research/tasktracker/config/content/task/base/TaskFileInfo.kt @@ -36,6 +36,13 @@ interface ITaskFileInfo { * id is intended for quick access to the corresponding VirtualFile. */ val id: String? + + /** + * If file is default then it will be created in plugin directory and will be filled by the default code. + * + * @return true if the file needs to be created in plugin directory, false otherwise. + */ + val isInternal: Boolean } @Serializable @@ -47,6 +54,7 @@ data class TaskFileInfo(override val filename: String, override val sourceSet: S // TODO: can we avoid using var here? override var content: String? = gatherContent() override val id: String? = null + override val isInternal: Boolean = true fun gatherContent() = extension?.let { templateFile?.getTemplate(relativePath, it) ?: DefaultContentProvider.getDefaultContent( diff --git a/ij-plugin/src/main/kotlin/org/jetbrains/research/tasktracker/tracking/TaskFileHandler.kt b/ij-plugin/src/main/kotlin/org/jetbrains/research/tasktracker/tracking/TaskFileHandler.kt index 7b8d7af6..c686309d 100644 --- a/ij-plugin/src/main/kotlin/org/jetbrains/research/tasktracker/tracking/TaskFileHandler.kt +++ b/ij-plugin/src/main/kotlin/org/jetbrains/research/tasktracker/tracking/TaskFileHandler.kt @@ -92,7 +92,9 @@ object TaskFileHandler { val files = task.files.map { taskFile -> val path = getPath(project, taskFile, task) val file = File(path) - file.writeDefaultContent(taskFile, task.name) + if (!file.exists()) { + file.writeDefaultContent(taskFile, task.name) + } LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file)?.also { taskFile.id?.let { id -> projectTaskIdToFile[project]?.get(task)?.putIfAbsent(id, it) @@ -108,7 +110,7 @@ object TaskFileHandler { private fun addSourceFolders(project: Project, task: TaskWithFiles) { val sourceFolders = task.files.map { Pair(it.extension, it.sourceSet) }.toSet().map { - "$PLUGIN_NAME/${it.first?.getFolderName()}/${task.root.pathOrEmpty()}/${it.second.path}" + "$PLUGIN_NAME/${it.first?.getDirectoryName()}/${task.root.pathOrEmpty()}/${it.second.path}" } sourceFolders.forEach { ApplicationManager.getApplication().runWriteAction { @@ -132,8 +134,11 @@ object TaskFileHandler { } private fun getPath(project: Project, taskFile: ITaskFileInfo, task: TaskWithFiles): String = buildString { - append("${project.basePath}/$PLUGIN_NAME/${taskFile.extension?.getFolderName() ?: ""}") - append("${task.root.pathOrEmpty()}/${taskFile.sourceSet.path}") + append("${project.basePath}/") + if (taskFile.isInternal) { + append("$PLUGIN_NAME/${taskFile.extension?.getDirectoryName() ?: ""}") + append("${task.root.pathOrEmpty()}/${taskFile.sourceSet.path}") + } append("${taskFile.relativePath.toPackageName().pathOrEmpty()}/") append("${taskFile.filename}${taskFile.extension?.ext ?: ""}") } diff --git a/ij-plugin/src/main/kotlin/org/jetbrains/research/tasktracker/tracking/Util.kt b/ij-plugin/src/main/kotlin/org/jetbrains/research/tasktracker/tracking/Util.kt index ccd07dc4..941e7ed1 100644 --- a/ij-plugin/src/main/kotlin/org/jetbrains/research/tasktracker/tracking/Util.kt +++ b/ij-plugin/src/main/kotlin/org/jetbrains/research/tasktracker/tracking/Util.kt @@ -6,4 +6,4 @@ import java.util.* fun String.toPackageName() = listOf(" ", "-", "_").fold(this) { acc, s -> acc.replace(s, "") }.lowercase(Locale.getDefault()) -fun Extension.getFolderName() = this.name.lowercase(Locale.getDefault()) +fun Extension.getDirectoryName() = this.name.lowercase(Locale.getDefault()) diff --git a/ij-plugin/src/main/resources/org/jetbrains/research/tasktracker/config/final_page_default.yaml b/ij-plugin/src/main/resources/org/jetbrains/research/tasktracker/config/final_page_default.yaml index 8e1a3ce5..93c34cca 100644 --- a/ij-plugin/src/main/resources/org/jetbrains/research/tasktracker/config/final_page_default.yaml +++ b/ij-plugin/src/main/resources/org/jetbrains/research/tasktracker/config/final_page_default.yaml @@ -1,2 +1,2 @@ -text: " We’ve turned off all tracking. +text: "Thank you for taking part in our research. We’ve turned off all tracking. If you wish, you can remove the plugin at any time from the plugins section in the IDE settings." \ No newline at end of file diff --git a/ij-plugin/src/main/resources/org/jetbrains/research/tasktracker/config/info_default.yaml b/ij-plugin/src/main/resources/org/jetbrains/research/tasktracker/config/info_default.yaml index 768fd2c5..43252476 100644 --- a/ij-plugin/src/main/resources/org/jetbrains/research/tasktracker/config/info_default.yaml +++ b/ij-plugin/src/main/resources/org/jetbrains/research/tasktracker/config/info_default.yaml @@ -1,2 +1,2 @@ -pluginName: TaskTracker -pluginDescription: "TaskTracker is a plugin designed to track code changes during programming problem-solving. It monitors the modifications made to the code throughout the process of problem resolution." \ No newline at end of file +pluginName: Refactoring course +pluginDescription: "We want to track your progress through the code refactoring course in order to collect data on file changes during the course completion. Please, when you are ready, press the next button." \ No newline at end of file diff --git a/ij-plugin/src/main/resources/org/jetbrains/research/tasktracker/config/scenario_default.yaml b/ij-plugin/src/main/resources/org/jetbrains/research/tasktracker/config/scenario_default.yaml index f7fc01a7..0ee49c97 100644 --- a/ij-plugin/src/main/resources/org/jetbrains/research/tasktracker/config/scenario_default.yaml +++ b/ij-plugin/src/main/resources/org/jetbrains/research/tasktracker/config/scenario_default.yaml @@ -2,31 +2,4 @@ scenario: steps: - units: - ! - id: "hello" - - ! - id: "default" - mode: SHUFFLED - ideConfig: - settingsConfig: - theme: LIGHT - inspectionConfig: - mode: DISABLE_SELECTED - inspectionNames: - - "EmptyFinallyBlock" - - units: - - ! - mainIdeConfig: - settingsConfig: - enableCodeCompletion: OFF - - ! - taskIds: - - "hello" - - "example" - - units: - - ! - taskIds: - - "hello" - - "example" - - "style" - - ! - url: "https://github.com/JetBrains-Research/tasktracker-3" \ No newline at end of file + id: "main" diff --git a/ij-plugin/src/main/resources/org/jetbrains/research/tasktracker/config/task_content_default.yaml b/ij-plugin/src/main/resources/org/jetbrains/research/tasktracker/config/task_content_default.yaml index a95e0907..ec10f550 100644 --- a/ij-plugin/src/main/resources/org/jetbrains/research/tasktracker/config/task_content_default.yaml +++ b/ij-plugin/src/main/resources/org/jetbrains/research/tasktracker/config/task_content_default.yaml @@ -1,37 +1,162 @@ tasks: - - name: hello world - description: Write a program that will print 'hello world' to the console. + - name: Refactoring course + description: "Take the refactoring course, and after that, press the next button." language: "KOTLIN" - focusFileId: "main" files: - - filename: main - sourceSet: "SRC" - id: "main" - id: "hello" - - name: "Example with several files" - description: "In this task, we kindly request you to review three provided files and determine which one is the most readable and which one is the least readable. Files: [a.java](a), [b.java](b), [c.java](c)" - language: "JAVA" - id: "example" - files: - - filename: a - sourceSet: "SRC" - templateFile: "a" - id: "a" - - filename: b - sourceSet: "SRC" - templateFile: "b" - id: "b" - - filename: c - sourceSet: "SRC" - templateFile: "c" - id: "c" - - name: "python style checker" - description: "Modify the file to be more readable and compliant with PEP 8" - language: "PYTHON" - id: "style" - focusFileId: "main" - files: - - filename: "main" + - filename: "Task" + relativePath: "RefactoringAndItsPurpose/Practice/RefactoringAndItsPurposePractice/src/main/kotlin/jetbrains/refactoring/course/refactoring/purpose" + sourceSet: "SRC" + isInternal: false + - filename: "Task" + relativePath: "CodeStyleAndFormatting/WhatIsFormatting/ReformatTheCode/src/main/kotlin/jetbrains/refactoring/course/formatting" + sourceSet: "SRC" + isInternal: false + - filename: "Task" + relativePath: "CodeStyleAndFormatting/WhatIsFormatting/ReformatTheCodeUsingIDE/src/main/kotlin/jetbrains/refactoring/course/formatting" + sourceSet: "SRC" + isInternal: false + - filename: "Task" + relativePath: "CodeStyleAndFormatting/CodeSchemasAndEditorConfig/task/src/main/kotlin/jetbrains/refactoring/course/formatting" + sourceSet: "SRC" + isInternal: false + - filename: ".editorconfig" + relativePath: "CodeStyleAndFormatting/CodeSchemasAndEditorConfig/task" + sourceSet: "SRC" + isInternal: false + - filename: "Student" + relativePath: "RenamingCode/RenameRefactoringInIDE/FixTypos/src/main/kotlin/jetbrains/refactoring/course/renaming" + sourceSet: "SRC" + isInternal: false + - filename: "University" + relativePath: "RenamingCode/RenameRefactoringInIDE/FixTypos/src/main/kotlin/jetbrains/refactoring/course/renaming" + sourceSet: "SRC" + isInternal: false + - filename: "Main" + relativePath: "MovingCode/WhatIsMoveMethodRefactoring/task/src/main/kotlin/jetbrains/refactoring/course/moving" + sourceSet: "SRC" + isInternal: false + - filename: "Driver" + relativePath: "MovingCode/WhatIsMoveMethodRefactoring/task/src/main/kotlin/jetbrains/refactoring/course/moving/driver" + sourceSet: "SRC" + isInternal: false + - filename: "Car" + relativePath: "MovingCode/WhatIsMoveMethodRefactoring/task/src/main/kotlin/jetbrains/refactoring/course/moving/car" + sourceSet: "SRC" + isInternal: false + - filename: "Animal" + relativePath: "MovingCode/WhatArePullUpAndPushDownRefactorings/task/src/main/kotlin/jetbrains/refactoring/course/moving" + sourceSet: "SRC" + isInternal: false + - filename: "Cat" + relativePath: "MovingCode/WhatArePullUpAndPushDownRefactorings/task/src/main/kotlin/jetbrains/refactoring/course/moving" + sourceSet: "SRC" + isInternal: false + - filename: "Dog" + relativePath: "MovingCode/WhatArePullUpAndPushDownRefactorings/task/src/main/kotlin/jetbrains/refactoring/course/moving" + sourceSet: "SRC" + isInternal: false + - filename: "Task" + relativePath: "ExtractingCode/WhatIsExtractMethodRefactoring/ExtractDuplicatedCode/src/main/kotlin/jetbrains/refactoring/course/extracting" + sourceSet: "SRC" + isInternal: false + - filename: "Task" + relativePath: "ExtractingCode/WhatIsExtractVariableRefactoring/ExtractMagicConstants/src/main/kotlin/jetbrains/refactoring/course/extracting" + sourceSet: "SRC" + isInternal: false + - filename: "Task" + relativePath: "InliningCode/WhatIsInlineVariableRefactoring/InlineVariables/src/main/kotlin/jetbrains/refactoring/course/inlining" + sourceSet: "SRC" + isInternal: false + - filename: "Task" + relativePath: "InliningCode/InlineMethodRefactoring/InlineMethodAndVariables/src/main/kotlin/jetbrains/refactoring/course/inlining" + sourceSet: "SRC" + isInternal: false + - filename: "MiddleMan" + relativePath: "InliningCode/MiddleManCodeSmell/task/src/main/kotlin/jetbrains/refactoring/course/inlining" + sourceSet: "SRC" + isInternal: false + - filename: "Main" + relativePath: "RefactoringToDesignPatterns/FacadePatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns" + sourceSet: "SRC" + isInternal: false + - filename: "VideoConversionFacade" + relativePath: "RefactoringToDesignPatterns/FacadePatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns" + sourceSet: "SRC" + isInternal: false + - filename: "VideoEncoder" + relativePath: "RefactoringToDesignPatterns/FacadePatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns" + sourceSet: "SRC" + isInternal: false + - filename: "VideoLoader" + relativePath: "RefactoringToDesignPatterns/FacadePatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns" + sourceSet: "SRC" + isInternal: false + - filename: "VideoProcessor" + relativePath: "RefactoringToDesignPatterns/FacadePatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns" + sourceSet: "SRC" + isInternal: false + - filename: "VideoSaver" + relativePath: "RefactoringToDesignPatterns/FacadePatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns" + sourceSet: "SRC" + isInternal: false + - filename: "EncodedVideo" + relativePath: "RefactoringToDesignPatterns/FacadePatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns/video" + sourceSet: "SRC" + isInternal: false + - filename: "ProcessedVideo" + relativePath: "RefactoringToDesignPatterns/FacadePatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns/video" + sourceSet: "SRC" + isInternal: false + - filename: "Video" + relativePath: "RefactoringToDesignPatterns/FacadePatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns/video" + sourceSet: "SRC" + isInternal: false + - filename: "Main" + relativePath: "RefactoringToDesignPatterns/StrategyPatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns" + sourceSet: "SRC" + isInternal: false + - filename: "Order" + relativePath: "RefactoringToDesignPatterns/StrategyPatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns" + sourceSet: "SRC" + isInternal: false + - filename: "PaymentProcessor" + relativePath: "RefactoringToDesignPatterns/StrategyPatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns/processor" + sourceSet: "SRC" + isInternal: false + - filename: "BitcoinPayment" + relativePath: "RefactoringToDesignPatterns/StrategyPatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns/strategy" + sourceSet: "SRC" + isInternal: false + - filename: "CreditCardPayment" + relativePath: "RefactoringToDesignPatterns/StrategyPatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns/strategy" + sourceSet: "SRC" + isInternal: false + - filename: "PaymentStrategy" + relativePath: "RefactoringToDesignPatterns/StrategyPatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns/strategy" + sourceSet: "SRC" + isInternal: false + - filename: "PayPalPayment" + relativePath: "RefactoringToDesignPatterns/StrategyPatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns/strategy" + sourceSet: "SRC" + isInternal: false + - filename: "Bicycle" + relativePath: "RefactoringToDesignPatterns/FactoryMethodPatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns" + sourceSet: "SRC" + isInternal: false + - filename: "Car" + relativePath: "RefactoringToDesignPatterns/FactoryMethodPatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns" + sourceSet: "SRC" + isInternal: false + - filename: "Main" + relativePath: "RefactoringToDesignPatterns/FactoryMethodPatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns" + sourceSet: "SRC" + isInternal: false + - filename: "Transport" + relativePath: "RefactoringToDesignPatterns/FactoryMethodPatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns" + sourceSet: "SRC" + isInternal: false + - filename: "TransportationServiceFactory" + relativePath: "RefactoringToDesignPatterns/FactoryMethodPatternPractice/task/src/main/kotlin/jetbrains/refactoring/course/patterns" sourceSet: "SRC" - templateFile: "comparison" - id: "main" + isInternal: false + id: "main" diff --git a/ij-plugin/src/test/kotlin/org/jetbrains/research/tasktracker/tracking/mock/MockTask.kt b/ij-plugin/src/test/kotlin/org/jetbrains/research/tasktracker/tracking/mock/MockTask.kt index fce93b5d..770d18e3 100644 --- a/ij-plugin/src/test/kotlin/org/jetbrains/research/tasktracker/tracking/mock/MockTask.kt +++ b/ij-plugin/src/test/kotlin/org/jetbrains/research/tasktracker/tracking/mock/MockTask.kt @@ -28,6 +28,8 @@ data class MockTaskFile( override val templateFile: String? = null, ) : ITaskFileInfo { override val sourceSet: SourceSet = SourceSet.SRC + override val isInternal: Boolean + get() = true } fun List.toMockTask(project: Project): MockTask {