feat: detect language of submitted file
This commit is contained in:
parent
d991bef7ab
commit
de8e4282f5
|
@ -6,9 +6,10 @@ It isn't a full replacement for the web interface yet, but already matches or su
|
|||
- Simple, one-click submissions and feedback (no need for File Explorer or reloading!)
|
||||
- View problems and problem statements without leaving your IDE
|
||||
- Unobtrusive and integrated
|
||||
- Detects the language of submitted files
|
||||
|
||||
## Potential future features
|
||||
- Support detecting the language of files (don't just force C++)
|
||||
- Display how much time is left in a contest or whether it's already over
|
||||
- Implement reading detailed results
|
||||
- Show scoreboards
|
||||
- Maybe even download test cases and scaffold sources
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package io.gitlab.jfronny.sdom
|
||||
|
||||
import com.intellij.ide.util.PropertiesComponent
|
||||
import com.intellij.notification.NotificationGroupManager
|
||||
import com.intellij.notification.NotificationType
|
||||
import com.intellij.openapi.actionSystem.*
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.diagnostic.LogLevel
|
||||
|
@ -8,6 +10,8 @@ import com.intellij.openapi.diagnostic.Logger
|
|||
import com.intellij.openapi.project.Project
|
||||
import io.gitlab.jfronny.sdom.actions.SDGetContestsAction
|
||||
import io.gitlab.jfronny.sdom.actions.SDGetProblemsAction
|
||||
import io.gitlab.jfronny.sdom.actions.SDProblemSelectionNotificationAction
|
||||
import io.gitlab.jfronny.sdom.actions.SDSubmitAction
|
||||
import io.gitlab.jfronny.sdom.model.*
|
||||
import io.ktor.client.*
|
||||
import io.ktor.client.call.*
|
||||
|
@ -23,7 +27,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
|
|||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.util.Base64
|
||||
import java.util.*
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
|
||||
|
@ -127,6 +131,7 @@ object SDom {
|
|||
var problems: List<Problem> = listOf()
|
||||
var currentProblem: Problem? = null
|
||||
var judgementTypes: Map<String, SDJudgementType>? = null
|
||||
private var languages: Map<String, SDLanguage>? = null
|
||||
|
||||
suspend fun getContests() {
|
||||
val result = authenticatedClient.get(SDCredentials.url) {
|
||||
|
@ -146,22 +151,13 @@ object SDom {
|
|||
val contestId = propertiesComponent?.getValue(CONTEST_ID_PROPERTY, "")?.takeIf { it != "" }
|
||||
val contest = contests.find { it.id == contestId }
|
||||
if (contestId != null && contest != null) {
|
||||
currentContest = contest
|
||||
|
||||
SDGetProblemsAction().actionPerformed(
|
||||
AnActionEvent(
|
||||
null,
|
||||
DataContext.EMPTY_CONTEXT,
|
||||
ActionPlaces.UNKNOWN,
|
||||
Presentation(),
|
||||
ActionManager.getInstance(),
|
||||
0
|
||||
)
|
||||
)
|
||||
CoroutineScope(Job() + Dispatchers.IO).launch {
|
||||
selectContest(contest, project)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getProblems() {
|
||||
suspend fun fetchProblems() {
|
||||
val contest = currentContest ?: return
|
||||
val result = authenticatedClient.get(SDCredentials.url) {
|
||||
url {
|
||||
|
@ -175,13 +171,50 @@ object SDom {
|
|||
currentProblem = null
|
||||
}
|
||||
}
|
||||
judgementTypes = authenticatedClient.get(SDCredentials.url) {
|
||||
url {
|
||||
appendPathSegments("contests", contest.id, "judgement-types")
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun selectContest(contest: Contest, context: Project?) {
|
||||
currentContest = contest
|
||||
|
||||
SDGetProblemsAction().actionPerformed(
|
||||
AnActionEvent(
|
||||
null,
|
||||
DataContext.EMPTY_CONTEXT,
|
||||
ActionPlaces.UNKNOWN,
|
||||
Presentation(),
|
||||
ActionManager.getInstance(),
|
||||
0
|
||||
)
|
||||
)
|
||||
|
||||
try {
|
||||
judgementTypes = authenticatedClient.get(SDCredentials.url) {
|
||||
url {
|
||||
appendPathSegments("contests", contest.id, "judgement-types")
|
||||
}
|
||||
}
|
||||
.body<List<SDJudgementType>>()
|
||||
.associateBy { it.id }
|
||||
|
||||
languages = authenticatedClient.get(SDCredentials.url) {
|
||||
url {
|
||||
appendPathSegments("contests", contest.id, "languages")
|
||||
}
|
||||
contentType(ContentType.Application.Json)
|
||||
}
|
||||
.body<List<SDLanguage>>()
|
||||
.flatMap { l -> l.extensions.map { it to l } }
|
||||
.toMap()
|
||||
} catch (e: Exception) {
|
||||
NotificationGroupManager.getInstance()
|
||||
.getNotificationGroup("sdom.notifications")
|
||||
.createNotification("You have to select a problem", NotificationType.ERROR)
|
||||
.setTitle("No problem selected")
|
||||
.addAction(SDProblemSelectionNotificationAction("Select Problem"))
|
||||
.addAction(SDSubmitAction("Retry"))
|
||||
.notify(context)
|
||||
return
|
||||
}
|
||||
.body<List<SDJudgementType>>()
|
||||
.associateBy { it.id }
|
||||
}
|
||||
|
||||
suspend fun downloadProblemStatement(contest: Contest, problem: Problem): ByteArray? {
|
||||
|
@ -195,10 +228,15 @@ object SDom {
|
|||
return response
|
||||
}
|
||||
|
||||
fun identifyLanguage(extension: String): SDLanguage? {
|
||||
return languages?.get(extension)
|
||||
}
|
||||
|
||||
suspend fun submitSolution(
|
||||
contest: Contest, problem: Problem, solution: String, fileName: String
|
||||
contest: Contest, problem: Problem, solution: String, fileName: String, language: SDLanguage
|
||||
): SharedFlow<Result<SDJudgement>> = coroutineScope {
|
||||
val resultFlow: MutableSharedFlow<Result<SDJudgement>> = MutableSharedFlow()
|
||||
|
||||
launch {
|
||||
try {
|
||||
val response: SDSubmission = authenticatedClient.post(SDCredentials.url) {
|
||||
|
@ -210,8 +248,8 @@ object SDom {
|
|||
SDAddSubmission(
|
||||
problem = problem.id,
|
||||
problemId = problem.id,
|
||||
language = "cpp",
|
||||
languageId = "cpp",
|
||||
language = language.id,
|
||||
languageId = language.id,
|
||||
entryPoint = null,
|
||||
files = listOf(SDAddSubmissionFile(zip(fileName, solution)))
|
||||
)
|
||||
|
|
|
@ -12,6 +12,10 @@ import com.intellij.openapi.ui.popup.JBPopupFactory
|
|||
import com.intellij.openapi.util.Condition
|
||||
import io.gitlab.jfronny.sdom.SDom
|
||||
import io.gitlab.jfronny.sdom.model.Contest
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import java.awt.Dimension
|
||||
import javax.swing.JComponent
|
||||
|
||||
|
@ -70,17 +74,9 @@ class SDContestSelectionComboBoxAction : ComboBoxAction(), DumbAware {
|
|||
override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT
|
||||
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
SDom.currentContest = contest
|
||||
SDGetProblemsAction().actionPerformed(
|
||||
AnActionEvent(
|
||||
null,
|
||||
DataContext.EMPTY_CONTEXT,
|
||||
ActionPlaces.UNKNOWN,
|
||||
Presentation(),
|
||||
ActionManager.getInstance(),
|
||||
0
|
||||
)
|
||||
)
|
||||
CoroutineScope(Job() + Dispatchers.IO).launch {
|
||||
SDom.selectContest(contest, e.project)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ class SDGetProblemsAction : DumbAwareAction() {
|
|||
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
CoroutineScope(Job() + Dispatchers.IO).launch {
|
||||
SDom.getProblems()
|
||||
SDom.fetchProblems()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
package io.gitlab.jfronny.sdom.actions
|
||||
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.notification.Notification
|
||||
import com.intellij.notification.NotificationAction
|
||||
import com.intellij.notification.NotificationGroupManager
|
||||
|
@ -40,6 +39,16 @@ class SDSubmitAction(text: String) : NotificationAction(text) {
|
|||
}
|
||||
val currentFile = virtualFile.readText()
|
||||
val fileName = virtualFile.name
|
||||
val language = virtualFile.extension?.let { SDom.identifyLanguage(it) }
|
||||
|
||||
if (language == null) {
|
||||
NotificationGroupManager.getInstance()
|
||||
.getNotificationGroup("sdom.notifications")
|
||||
.createNotification("Could not identify the language of that file", NotificationType.ERROR)
|
||||
.setTitle("Unknown file extension")
|
||||
.notify(e.project)
|
||||
return
|
||||
}
|
||||
|
||||
val contest = SDom.currentContest
|
||||
if (contest == null) {
|
||||
|
@ -64,7 +73,7 @@ class SDSubmitAction(text: String) : NotificationAction(text) {
|
|||
return
|
||||
}
|
||||
CoroutineScope(Job() + Dispatchers.IO).launch {
|
||||
val result = SDom.submitSolution(contest, problem, currentFile, fileName)
|
||||
val result = SDom.submitSolution(contest, problem, currentFile, fileName, language)
|
||||
println(result.first())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package io.gitlab.jfronny.sdom.model
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class SDLanguage(
|
||||
@SerialName("compile_executable_hash") val compileExecutableHash: String?,
|
||||
val id: String,
|
||||
val name: String,
|
||||
val extensions: List<String>,
|
||||
@SerialName("filter_compiler_files") val filterCompilerFiles: Boolean,
|
||||
@SerialName("allow_judge") val allowJudge: Boolean,
|
||||
@SerialName("time_factor") val timeFactor: Double,
|
||||
@SerialName("entry_point_required") val entryPointRequired: Boolean,
|
||||
@SerialName("entry_point_name") val entryPointName: String?,
|
||||
)
|
Loading…
Reference in New Issue