diff --git a/build.gradle.kts b/build.gradle.kts
index 817e703e..df498520 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,6 +1,9 @@
+import nl.adaptivity.xmlutil.core.impl.multiplatform.name
import org.jetbrains.changelog.Changelog
import org.jetbrains.changelog.markdownToHTML
import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType
+import org.jetbrains.intellij.platform.gradle.tasks.ComposedJarTask
+import org.jetbrains.intellij.platform.gradle.tasks.InstrumentedJarTask
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
plugins {
@@ -14,6 +17,7 @@ plugins {
val javaVersion = property("javaVersion").toString().toInt()
val lsp4ijVersion: String by project
+val runIdeTarget: String by project
val lsp4ijNightly = property("lsp4ijNightly").toString().toBoolean()
val lsp4ijPluginString = "com.redhat.devtools.lsp4ij:$lsp4ijVersion${if (lsp4ijNightly) "@nightly" else ""}"
@@ -74,7 +78,10 @@ allprojects {
dependencies {
intellijPlatform {
- create(IntelliJPlatformType.IntellijIdeaCommunity, providers.gradleProperty("ideaCommunityVersion"))
+ when(runIdeTarget) {
+ "ideaCommunity" -> create(IntelliJPlatformType.IntellijIdeaCommunity, providers.gradleProperty("ideaCommunityVersion"))
+ "clion" -> create(IntelliJPlatformType.CLion, providers.gradleProperty("clionVersion"))
+ }
pluginVerifier()
zipSigner()
@@ -82,6 +89,7 @@ dependencies {
}
implementation(project(":core"))
+ implementation(project(":cidr"))
}
intellijPlatform {
diff --git a/gradle.properties b/gradle.properties
index b4d04056..732623cc 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,19 +1,22 @@
-pluginName = ZigBrains
-pluginRepositoryUrl = https://github.com/FalsePattern/ZigBrains
+pluginName=ZigBrains
+pluginRepositoryUrl=https://github.com/FalsePattern/ZigBrains
-pluginVersion = 20.0.0-dev
+pluginVersion=20.0.0-dev
-pluginSinceBuild = 242
-pluginUntilBuild =
+pluginSinceBuild=242
+pluginUntilBuild=
-ideaCommunityVersion = 2024.2.4
+ideaCommunityVersion=2024.2.4
+clionVersion=2024.2.3
javaVersion=21
+# ideaCommunity / clion
+runIdeTarget=clion
lsp4jVersion=0.21.1
lsp4ijVersion=0.7.0
lsp4ijNightly=false
-kotlin.stdlib.default.dependency = false
+kotlin.stdlib.default.dependency=false
kotlin.code.style=official
-org.gradle.configuration-cache = true
-org.gradle.caching = true
\ No newline at end of file
+org.gradle.configuration-cache=true
+org.gradle.caching=true
\ No newline at end of file
diff --git a/modules/cidr/build.gradle.kts b/modules/cidr/build.gradle.kts
new file mode 100644
index 00000000..45a98005
--- /dev/null
+++ b/modules/cidr/build.gradle.kts
@@ -0,0 +1,16 @@
+import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType
+
+val lsp4jVersion: String by project
+
+dependencies {
+ intellijPlatform {
+ create(IntelliJPlatformType.CLion, providers.gradleProperty("clionVersion"))
+ bundledPlugins("com.intellij.clion", "com.intellij.cidr.lang", "com.intellij.cidr.base", "com.intellij.nativeDebug")
+ }
+ implementation(project(":core"))
+ implementation("org.eclipse.lsp4j:org.eclipse.lsp4j.debug:$lsp4jVersion") {
+ exclude("org.eclipse.lsp4j", "org.eclipse.lsp4j")
+ exclude("org.eclipse.lsp4j", "org.eclipse.lsp4j.jsonrpc")
+ exclude("com.google.code.gson", "gson")
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugbridge/ZigDebuggerDriverConfigurationProvider.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugbridge/ZigDebuggerDriverConfigurationProvider.kt
new file mode 100644
index 00000000..480b2536
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugbridge/ZigDebuggerDriverConfigurationProvider.kt
@@ -0,0 +1,34 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugbridge
+
+import com.intellij.openapi.extensions.ExtensionPointName
+import com.intellij.openapi.project.Project
+import kotlinx.coroutines.CoroutineScope
+
+interface ZigDebuggerDriverConfigurationProvider {
+ companion object {
+ val EXTENSION_POINT_NAME = ExtensionPointName.create("com.falsepattern.zigbrains.debuggerDriverProvider")
+ }
+ suspend fun getDebuggerConfiguration(project: Project, isElevated: Boolean, emulateTerminal: Boolean, klass: Class): T?
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/DebuggerFeatures.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/DebuggerFeatures.kt
new file mode 100644
index 00000000..0a47ff25
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/DebuggerFeatures.kt
@@ -0,0 +1,31 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger
+
+import com.falsepattern.zigbrains.shared.ZBFeatures
+
+class DebuggerFeatures: ZBFeatures {
+ override fun getDebug(): Boolean {
+ return true
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigDebugBundle.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigDebugBundle.kt
new file mode 100644
index 00000000..56f363d0
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigDebugBundle.kt
@@ -0,0 +1,51 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger
+
+import com.intellij.DynamicBundle
+import org.jetbrains.annotations.Nls
+import org.jetbrains.annotations.NonNls
+import org.jetbrains.annotations.PropertyKey
+import java.util.function.Supplier
+
+
+internal object ZigDebugBundle {
+ @NonNls
+ const val BUNDLE = "zigbrains.debugger.Bundle"
+
+ private val INSTANCE = DynamicBundle(ZigDebugBundle::class.java, BUNDLE)
+
+ fun message(
+ key: @PropertyKey(resourceBundle = BUNDLE) String,
+ vararg params: Any
+ ): @Nls String {
+ return INSTANCE.getMessage(key, *params)
+ }
+
+ fun lazyMessage(
+ key: @PropertyKey(resourceBundle = BUNDLE) String,
+ vararg params: Any
+ ): Supplier<@Nls String> {
+ return INSTANCE.getLazyMessage(key, *params)
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigDebuggerEditorsExtension.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigDebuggerEditorsExtension.kt
new file mode 100644
index 00000000..bf0b1b98
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigDebuggerEditorsExtension.kt
@@ -0,0 +1,28 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger
+
+import com.jetbrains.cidr.execution.debugger.CidrDebuggerEditorsExtensionBase
+
+class ZigDebuggerEditorsExtension: CidrDebuggerEditorsExtensionBase() {
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigDebuggerLanguage.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigDebuggerLanguage.kt
new file mode 100644
index 00000000..1202a1dc
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigDebuggerLanguage.kt
@@ -0,0 +1,31 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger
+
+import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriver.DebuggerLanguage
+
+object ZigDebuggerLanguage: DebuggerLanguage {
+ override fun toString(): String {
+ return "Zig"
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigDebuggerLanguageSupport.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigDebuggerLanguageSupport.kt
new file mode 100644
index 00000000..496bba9f
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigDebuggerLanguageSupport.kt
@@ -0,0 +1,41 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger
+
+import com.falsepattern.zigbrains.project.execution.base.ZigExecConfig
+import com.intellij.execution.configurations.RunProfile
+import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider
+import com.jetbrains.cidr.execution.debugger.CidrDebuggerLanguageSupport
+import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriver
+
+class ZigDebuggerLanguageSupport: CidrDebuggerLanguageSupport() {
+ override fun getSupportedDebuggerLanguages(): Set {
+ return setOf(ZigDebuggerLanguage)
+ }
+
+ override fun createEditor(profile: RunProfile?): XDebuggerEditorsProvider? {
+ if (profile !is ZigExecConfig<*>)
+ return null
+ return createEditorProvider()
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigDefaultDebuggerDriverConfigurationProvider.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigDefaultDebuggerDriverConfigurationProvider.kt
new file mode 100644
index 00000000..509f9bf6
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigDefaultDebuggerDriverConfigurationProvider.kt
@@ -0,0 +1,164 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger
+
+import com.falsepattern.zigbrains.debugbridge.ZigDebuggerDriverConfigurationProvider
+import com.falsepattern.zigbrains.debugger.settings.ZigDebuggerSettings
+import com.falsepattern.zigbrains.debugger.toolchain.*
+import com.falsepattern.zigbrains.debugger.win.MSVCDriverConfiguration
+import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
+import com.falsepattern.zigbrains.zig.ZigLanguage
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.ui.DoNotAskOption
+import com.intellij.openapi.ui.MessageDialogBuilder
+import com.intellij.openapi.ui.Messages
+import com.jetbrains.cidr.ArchitectureType
+import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
+import com.jetbrains.cidr.execution.debugger.backend.gdb.GDBDriverConfiguration
+import com.jetbrains.cidr.execution.debugger.backend.lldb.LLDBDriverConfiguration
+import java.io.File
+import kotlin.io.path.pathString
+
+class ZigDefaultDebuggerDriverConfigurationProvider: ZigDebuggerDriverConfigurationProvider {
+ override suspend fun getDebuggerConfiguration(project: Project, isElevated: Boolean, emulateTerminal: Boolean, klass: Class): T? {
+ if (klass != DebuggerDriverConfiguration::class.java)
+ return null
+ @Suppress("UNCHECKED_CAST")
+ return getDebuggerConfiguration(project, isElevated, emulateTerminal) as T
+ }
+
+ private suspend fun getDebuggerConfiguration(project: Project, isElevated: Boolean, emulateTerminal: Boolean): DebuggerDriverConfiguration? {
+ val settings = ZigDebuggerSettings.instance
+ val service = zigDebuggerToolchainService
+ val kind = settings.debuggerKind
+ if (!availabilityCheck(project, kind))
+ return null
+
+ return when(val availability = service.debuggerAvailability(kind)) {
+ DebuggerAvailability.Bundled -> when(kind) {
+ DebuggerKind.LLDB -> ZigLLDBDriverConfiguration(isElevated, emulateTerminal)
+ DebuggerKind.GDB -> ZigGDBDriverConfiguration(isElevated, emulateTerminal)
+ DebuggerKind.MSVC -> throw AssertionError("MSVC is never bundled")
+ }
+ is DebuggerAvailability.Binaries -> when(val binary = availability.binaries) {
+ is LLDBBinaries -> ZigCustomBinariesLLDBDriverConfiguration(binary, isElevated, emulateTerminal)
+ is GDBBinaries -> ZigCustomBinariesGDBDriverConfiguration(binary, isElevated, emulateTerminal)
+ is MSVCBinaries -> ZigMSVCDriverConfiguration(binary, isElevated, emulateTerminal)
+ else -> throw AssertionError("Unreachable")
+ }
+ DebuggerAvailability.Unavailable,
+ DebuggerAvailability.NeedToDownload,
+ DebuggerAvailability.NeedToUpdate -> throw AssertionError("Unreachable")
+ }
+ }
+}
+
+private suspend fun availabilityCheck(project: Project, kind: DebuggerKind): Boolean {
+ val service = zigDebuggerToolchainService
+ val availability = service.debuggerAvailability(kind)
+ val (message, action) = when(availability) {
+ DebuggerAvailability.Unavailable -> return false
+ DebuggerAvailability.NeedToDownload ->
+ ZigDebugBundle.message("debugger.run.unavailable.reason.download") to ZigDebugBundle.message("debugger.run.unavailable.reason.download.button")
+ DebuggerAvailability.NeedToUpdate ->
+ ZigDebugBundle.message("debugger.run.unavailable.reason.update") to ZigDebugBundle.message("debugger.run.unavailable.reason.update.button")
+ DebuggerAvailability.Bundled,
+ is DebuggerAvailability.Binaries -> return true
+ }
+
+ val downloadDebugger = if (!ZigDebuggerSettings.instance.downloadAutomatically) {
+ showDialog(project, message, action)
+ } else {
+ true
+ }
+
+ if (downloadDebugger) {
+ val result = withEDTContext {
+ service.downloadDebugger(project, kind)
+ }
+ if (result is ZigDebuggerToolchainService.DownloadResult.Ok) {
+ return true
+ }
+ }
+ return false
+}
+
+private suspend fun showDialog(project: Project, message: String, action: String): Boolean {
+ val doNotAsk = object: DoNotAskOption.Adapter() {
+ override fun rememberChoice(isSelected: Boolean, exitCode: Int) {
+ if (exitCode == Messages.OK) {
+ ZigDebuggerSettings.instance.downloadAutomatically = isSelected
+ }
+ }
+ }
+
+ return withEDTContext {
+ MessageDialogBuilder
+ .okCancel(ZigDebugBundle.message("debugger.run.unavailable"), message)
+ .yesText(action)
+ .icon(Messages.getErrorIcon())
+ .doNotAsk(doNotAsk)
+ .ask(project)
+ }
+}
+
+private open class ZigLLDBDriverConfiguration(private val isElevated: Boolean, private val emulateTerminal: Boolean): LLDBDriverConfiguration() {
+ override fun getDriverName() = "Zig LLDB"
+ override fun isElevated() = isElevated
+ override fun emulateTerminal() = emulateTerminal
+}
+private class ZigCustomBinariesLLDBDriverConfiguration(
+ private val binaries: LLDBBinaries,
+ isElevated: Boolean,
+ emulateTerminal: Boolean
+) : ZigLLDBDriverConfiguration(isElevated, emulateTerminal) {
+ override fun useSTLRenderers() = false
+ override fun getLLDBFrameworkFile(architectureType: ArchitectureType): File = binaries.frameworkFile.toFile()
+ override fun getLLDBFrontendFile(architectureType: ArchitectureType): File = binaries.frontendFile.toFile()
+}
+
+private open class ZigGDBDriverConfiguration(private val isElevated: Boolean, private val emulateTerminal: Boolean): GDBDriverConfiguration() {
+ override fun getDriverName() = "Zig GDB"
+ override fun isAttachSupported() = false
+ override fun isElevated() = isElevated
+ override fun emulateTerminal() = emulateTerminal
+}
+private class ZigCustomBinariesGDBDriverConfiguration(
+ private val binaries: GDBBinaries,
+ isElevated: Boolean,
+ emulateTerminal: Boolean
+) : ZigGDBDriverConfiguration(isElevated, emulateTerminal) {
+ override fun getGDBExecutablePath() = binaries.gdbFile.pathString
+}
+
+private class ZigMSVCDriverConfiguration(
+ private val binaries: MSVCBinaries,
+ private val isElevated: Boolean,
+ private val emulateTerminal: Boolean
+): MSVCDriverConfiguration() {
+ override val debuggerExecutable get() = binaries.msvcFile
+ override fun getDriverName() = "Zig MSVC"
+ override fun getConsoleLanguage() = ZigLanguage
+ override fun isElevated() = isElevated
+ override fun emulateTerminal() = emulateTerminal
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigLineBreakpointFileTypesProvider.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigLineBreakpointFileTypesProvider.kt
new file mode 100644
index 00000000..eda6db26
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigLineBreakpointFileTypesProvider.kt
@@ -0,0 +1,33 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger
+
+import com.falsepattern.zigbrains.zig.ZigFileType
+import com.intellij.openapi.fileTypes.FileType
+import com.jetbrains.cidr.execution.debugger.breakpoints.CidrLineBreakpointFileTypesProvider
+
+class ZigLineBreakpointFileTypesProvider: CidrLineBreakpointFileTypesProvider {
+ override fun getFileTypes(): Set {
+ return setOf(ZigFileType)
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigLocalDebugProcess.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigLocalDebugProcess.kt
new file mode 100644
index 00000000..58a74ae5
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigLocalDebugProcess.kt
@@ -0,0 +1,30 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger
+
+import com.intellij.execution.filters.TextConsoleBuilder
+import com.intellij.xdebugger.XDebugSession
+import com.jetbrains.cidr.execution.RunParameters
+import com.jetbrains.cidr.execution.debugger.CidrLocalDebugProcess
+
+class ZigLocalDebugProcess(parameters: RunParameters, session: XDebugSession, consoleBuilder: TextConsoleBuilder) : CidrLocalDebugProcess(parameters, session, consoleBuilder)
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigLocalVariablesFilterHandler.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigLocalVariablesFilterHandler.kt
new file mode 100644
index 00000000..2a0a82b7
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigLocalVariablesFilterHandler.kt
@@ -0,0 +1,49 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger
+
+import com.falsepattern.zigbrains.shared.zigCoroutineScope
+import com.falsepattern.zigbrains.zig.ZigFileType
+import com.intellij.openapi.project.Project
+import com.intellij.xdebugger.XSourcePosition
+import com.jetbrains.cidr.execution.debugger.backend.LLValue
+import com.jetbrains.cidr.execution.debugger.evaluation.LocalVariablesFilterHandler
+import kotlinx.coroutines.async
+import kotlinx.coroutines.future.asCompletableFuture
+import java.util.concurrent.CompletableFuture
+
+class ZigLocalVariablesFilterHandler: LocalVariablesFilterHandler {
+ override fun filterVars(proj: Project, pos: XSourcePosition, vars: List): CompletableFuture> {
+ return proj.zigCoroutineScope.async {
+ val vf = pos.file
+ if (vf.fileType == ZigFileType) {
+ return@async ArrayList(vars)
+ }
+ return@async listOf()
+ }.asCompletableFuture()
+ }
+
+ override fun canFilterAtPos(proj: Project, pos: XSourcePosition): Boolean {
+ return pos.file.fileType == ZigFileType
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/dap/DAPDebuggerDriverConfiguration.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/dap/DAPDebuggerDriverConfiguration.kt
new file mode 100644
index 00000000..7fedc341
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/dap/DAPDebuggerDriverConfiguration.kt
@@ -0,0 +1,43 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.dap
+
+import com.falsepattern.zigbrains.zig.ZigLanguage
+import com.intellij.lang.Language
+import com.intellij.openapi.util.Expirable
+import com.intellij.openapi.util.Pair
+import com.intellij.openapi.util.UserDataHolderEx
+import com.jetbrains.cidr.execution.debugger.backend.*
+import org.eclipse.lsp4j.debug.InitializeRequestArguments
+
+abstract class DAPDebuggerDriverConfiguration: DebuggerDriverConfiguration() {
+ override fun createEvaluationContext(driver: DebuggerDriver, expirable: Expirable?, llThread: LLThread, llFrame: LLFrame, data: UserDataHolderEx): EvaluationContext {
+ return object : EvaluationContext(driver, expirable, llThread, llFrame, data) {
+ override fun convertToRValue(data: LLValueData, pair: Pair): String {
+ return cast(pair.second, pair.first?.type)
+ }
+ }
+ }
+
+ abstract fun customizeInitializeArguments(initArgs: InitializeRequestArguments)
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/execution/binary/ZigConfigTypeBinary.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/execution/binary/ZigConfigTypeBinary.kt
new file mode 100644
index 00000000..774f847d
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/execution/binary/ZigConfigTypeBinary.kt
@@ -0,0 +1,52 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.execution.binary
+
+import com.falsepattern.zigbrains.Icons
+import com.falsepattern.zigbrains.debugger.ZigDebugBundle
+import com.intellij.execution.configurations.ConfigurationFactory
+import com.intellij.execution.configurations.ConfigurationTypeBase
+import com.intellij.execution.configurations.RunConfiguration
+import com.intellij.openapi.project.Project
+
+class ZigConfigTypeBinary: ConfigurationTypeBase(
+ IDENTIFIER,
+ ZigDebugBundle.message("configuration.binary.name"),
+ ZigDebugBundle.message("configuration.binary.description"),
+ Icons.ZIG
+) {
+ init {
+ addFactory(ConfigFactoryBinary(this))
+ }
+ class ConfigFactoryBinary(type: ZigConfigTypeBinary): ConfigurationFactory(type) {
+ override fun createTemplateConfiguration(project: Project): RunConfiguration {
+ return ZigExecConfigBinary(project, this)
+ }
+
+ override fun getId(): String {
+ return IDENTIFIER
+ }
+ }
+}
+
+private const val IDENTIFIER = "ZIGBRAINS_BINARY"
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/execution/binary/ZigExecConfigBinary.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/execution/binary/ZigExecConfigBinary.kt
new file mode 100644
index 00000000..9cdb57a7
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/execution/binary/ZigExecConfigBinary.kt
@@ -0,0 +1,59 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.execution.binary
+
+import com.falsepattern.zigbrains.debugger.ZigDebugBundle
+import com.falsepattern.zigbrains.project.execution.base.*
+import com.intellij.execution.Executor
+import com.intellij.execution.configurations.ConfigurationFactory
+import com.intellij.execution.runners.ExecutionEnvironment
+import com.intellij.openapi.project.Project
+
+class ZigExecConfigBinary(project: Project, factory: ConfigurationFactory) : ZigExecConfig(project, factory, ZigDebugBundle.message("exec.type.binary.label")) {
+ var exePath = FilePathConfigurable("exePath", ZigDebugBundle.message("exec.option.label.binary.exe-path"))
+ private set
+ var args = ArgsConfigurable("args", ZigDebugBundle.message("exec.option.label.binary.args"))
+ private set
+
+ override val suggestedName: String
+ get() = ZigDebugBundle.message("configuration.binary.suggested-name")
+
+ override suspend fun buildCommandLineArgs(debug: Boolean): List {
+ return args.args
+ }
+
+ override fun getConfigurables(): List> {
+ return super.getConfigurables() + listOf(exePath, args)
+ }
+
+ override fun getState(executor: Executor, environment: ExecutionEnvironment): ZigProfileState {
+ return ZigProfileStateBinary(environment, this)
+ }
+
+ override fun clone(): ZigExecConfigBinary {
+ val clone = super.clone()
+ clone.exePath = exePath.clone()
+ clone.args = args.clone()
+ return clone
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/execution/binary/ZigProfileStateBinary.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/execution/binary/ZigProfileStateBinary.kt
new file mode 100644
index 00000000..b6b1c7fc
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/execution/binary/ZigProfileStateBinary.kt
@@ -0,0 +1,43 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.execution.binary
+
+import com.falsepattern.zigbrains.debugger.ZigDebugBundle
+import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
+import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
+import com.intellij.execution.ExecutionException
+import com.intellij.execution.configurations.GeneralCommandLine
+import com.intellij.execution.runners.ExecutionEnvironment
+import kotlin.io.path.pathString
+
+class ZigProfileStateBinary(environment: ExecutionEnvironment, configuration: ZigExecConfigBinary) : ZigProfileState(environment, configuration) {
+ override suspend fun getCommandLine(toolchain: AbstractZigToolchain, debug: Boolean): GeneralCommandLine {
+ val cli = GeneralCommandLine()
+ val cfg = configuration
+ cfg.workingDirectory.path?.let { cli.withWorkingDirectory(it) }
+ cli.withExePath(cfg.exePath.path?.pathString ?: throw ExecutionException(ZigDebugBundle.message("exception.missing-exe-path")))
+ cli.withCharset(Charsets.UTF_8)
+ cli.addParameters(cfg.args.args)
+ return cli
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/PreLaunchAware.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/PreLaunchAware.kt
new file mode 100644
index 00000000..0ff51606
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/PreLaunchAware.kt
@@ -0,0 +1,30 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.runner.base
+
+import com.intellij.execution.ExecutionException
+
+interface PreLaunchAware {
+ @Throws(ExecutionException::class)
+ suspend fun preLaunch(listener: PreLaunchProcessListener)
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/PreLaunchProcessListener.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/PreLaunchProcessListener.kt
new file mode 100644
index 00000000..50d46b5b
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/PreLaunchProcessListener.kt
@@ -0,0 +1,57 @@
+package com.falsepattern.zigbrains.debugger.runner.base
+
+import com.falsepattern.zigbrains.project.run.ZigProcessHandler
+import com.intellij.execution.ExecutionException
+import com.intellij.execution.configurations.GeneralCommandLine
+import com.intellij.execution.process.ProcessEvent
+import com.intellij.execution.process.ProcessHandler
+import com.intellij.execution.process.ProcessListener
+import com.intellij.execution.ui.ConsoleView
+import com.intellij.execution.ui.ConsoleViewContentType
+import com.intellij.platform.util.progress.withProgressText
+import com.intellij.util.io.awaitExit
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runInterruptible
+import kotlinx.coroutines.withContext
+
+class PreLaunchProcessListener(val console: ConsoleView) : ProcessListener {
+ var isBuildFailed: Boolean = false
+ private set
+ lateinit var processHandler: ProcessHandler
+ private set
+
+ @Throws(ExecutionException::class)
+ suspend fun executeCommandLineWithHook(commandLine: GeneralCommandLine): Boolean {
+ return withProgressText(commandLine.commandLineString) {
+ val processHandler = ZigProcessHandler(commandLine)
+ this@PreLaunchProcessListener.processHandler = processHandler
+ hook(processHandler)
+ processHandler.startNotify()
+ withContext(Dispatchers.Default) {
+ processHandler.process.awaitExit()
+ }
+ runInterruptible {
+ processHandler.waitFor()
+ }
+ return@withProgressText isBuildFailed
+ }
+ }
+
+ fun hook(handler: ProcessHandler) {
+ console.attachToProcess(handler)
+ handler.addProcessListener(this)
+ }
+
+ override fun processTerminated(event: ProcessEvent) {
+ if (event.exitCode != 0) {
+ console.print(
+ "Process finished with exit code " + event.exitCode,
+ ConsoleViewContentType.NORMAL_OUTPUT
+ )
+ isBuildFailed = true
+ } else {
+ isBuildFailed = false
+ console.print("Build Successful. Starting debug session. \n", ConsoleViewContentType.NORMAL_OUTPUT)
+ }
+ }
+}
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugEmitBinaryInstaller.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugEmitBinaryInstaller.kt
new file mode 100644
index 00000000..d40cfbe8
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugEmitBinaryInstaller.kt
@@ -0,0 +1,57 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.runner.base
+
+import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
+import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
+import com.falsepattern.zigbrains.shared.coroutine.runModalOrBlocking
+import com.falsepattern.zigbrains.shared.zigCoroutineScope
+import com.intellij.execution.configurations.GeneralCommandLine
+import com.intellij.platform.ide.progress.ModalTaskOwner
+import com.jetbrains.cidr.execution.Installer
+import kotlinx.coroutines.async
+import kotlinx.coroutines.future.asCompletableFuture
+import java.io.File
+
+class ZigDebugEmitBinaryInstaller>(
+ private val profileState: ProfileState,
+ private val toolchain: AbstractZigToolchain,
+ private val executableFile: File,
+ private val exeArgs: List
+): Installer {
+ override fun install(): GeneralCommandLine {
+ val cfg = profileState.configuration
+ val cli = GeneralCommandLine().withExePath(executableFile.absolutePath)
+ cfg.workingDirectory.path?.let { x -> cli.withWorkingDirectory(x) }
+ cli.addParameters(exeArgs)
+ cli.withCharset(Charsets.UTF_8)
+ cli.withRedirectErrorStream(true)
+ return profileState.configuration.project.zigCoroutineScope.async{
+ profileState.configuration.patchCommandLine(cli, toolchain)
+ }.asCompletableFuture().join()
+ }
+
+ override fun getExecutableFile(): File {
+ return executableFile
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugParametersBase.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugParametersBase.kt
new file mode 100644
index 00000000..7cae51d2
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugParametersBase.kt
@@ -0,0 +1,44 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.runner.base
+
+import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
+import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
+import com.intellij.util.system.CpuArch
+import com.jetbrains.cidr.ArchitectureType
+import com.jetbrains.cidr.execution.RunParameters
+import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
+
+abstract class ZigDebugParametersBase>(
+ private val driverConfiguration: DebuggerDriverConfiguration,
+ protected val toolchain: AbstractZigToolchain,
+ protected val profileState: ProfileState
+): RunParameters() {
+ override fun getDebuggerDriverConfiguration(): DebuggerDriverConfiguration {
+ return driverConfiguration
+ }
+
+ override fun getArchitectureId(): String {
+ return ArchitectureType.forVmCpuArch(CpuArch.CURRENT).id
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugParametersEmitBinaryBase.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugParametersEmitBinaryBase.kt
new file mode 100644
index 00000000..5b8e8adb
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugParametersEmitBinaryBase.kt
@@ -0,0 +1,78 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.runner.base
+
+import com.falsepattern.zigbrains.debugger.ZigDebugBundle
+import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
+import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
+import com.intellij.execution.ExecutionException
+import com.intellij.execution.ui.ConsoleViewContentType
+import com.intellij.openapi.util.io.FileUtil
+import com.intellij.platform.util.progress.withProgressText
+import com.intellij.util.containers.orNull
+import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import java.io.File
+import java.nio.file.Files
+import kotlin.io.path.absolutePathString
+import kotlin.io.path.isExecutable
+
+abstract class ZigDebugParametersEmitBinaryBase>(
+ driverConfiguration: DebuggerDriverConfiguration,
+ toolchain: AbstractZigToolchain,
+ profileState: ProfileState,
+) : ZigDebugParametersBase(driverConfiguration, toolchain, profileState), PreLaunchAware {
+ @Volatile
+ protected lateinit var executableFile: File
+ private set
+
+ @Throws(ExecutionException::class)
+ private suspend fun compileExe(listener: PreLaunchProcessListener): File {
+ val commandLine = profileState.getCommandLine(toolchain, true)
+ val tmpDir = FileUtil.createTempDirectory("zigbrains_debug", "", true).toPath()
+
+ val exe = tmpDir.resolve("executable")
+ commandLine.addParameters("-femit-bin=${exe.absolutePathString()}")
+
+ if (listener.executeCommandLineWithHook(commandLine))
+ throw ExecutionException(ZigDebugBundle.message("debug.base.compile.failed.generic"))
+
+ return withContext(Dispatchers.IO) {
+ Files.list(tmpDir).use { stream ->
+ stream.filter { !it.fileName.endsWith(".o") }
+ .filter { it.isExecutable() }
+ .findFirst()
+ .map { it.toFile() }
+ .orNull()
+ }
+ } ?: throw ExecutionException(ZigDebugBundle.message("debug.base.compile.failed.no-exe"))
+ }
+
+ @Throws(ExecutionException::class)
+ override suspend fun preLaunch(listener: PreLaunchProcessListener) {
+ this.executableFile = withProgressText("Compiling executable") {
+ compileExe(listener)
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugRunnerBase.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugRunnerBase.kt
new file mode 100644
index 00000000..0547b1f9
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugRunnerBase.kt
@@ -0,0 +1,131 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.runner.base
+
+import com.falsepattern.zigbrains.debugbridge.ZigDebuggerDriverConfigurationProvider
+import com.falsepattern.zigbrains.debugger.ZigLocalDebugProcess
+import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
+import com.falsepattern.zigbrains.project.run.ZigProgramRunner
+import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
+import com.falsepattern.zigbrains.shared.coroutine.runInterruptibleEDT
+import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
+import com.intellij.execution.DefaultExecutionResult
+import com.intellij.execution.ExecutionException
+import com.intellij.execution.executors.DefaultDebugExecutor
+import com.intellij.execution.filters.Filter
+import com.intellij.execution.filters.TextConsoleBuilder
+import com.intellij.execution.process.ProcessTerminatedListener
+import com.intellij.execution.runners.ExecutionEnvironment
+import com.intellij.execution.runners.RunContentBuilder
+import com.intellij.execution.ui.ConsoleView
+import com.intellij.execution.ui.ConsoleViewContentType
+import com.intellij.execution.ui.RunContentDescriptor
+import com.intellij.platform.util.progress.reportProgress
+import com.intellij.platform.util.progress.withProgressText
+import com.intellij.xdebugger.XDebugProcess
+import com.intellij.xdebugger.XDebugProcessStarter
+import com.intellij.xdebugger.XDebugSession
+import com.intellij.xdebugger.XDebuggerManager
+import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
+import com.jetbrains.rd.util.string.printToString
+
+abstract class ZigDebugRunnerBase> : ZigProgramRunner(DefaultDebugExecutor.EXECUTOR_ID) {
+ @Throws(ExecutionException::class)
+ override suspend fun execute(
+ state: ProfileState,
+ toolchain: AbstractZigToolchain,
+ environment: ExecutionEnvironment
+ ): RunContentDescriptor? {
+ val project = environment.project
+ val driverProviders = ZigDebuggerDriverConfigurationProvider.EXTENSION_POINT_NAME.extensionList
+ for (provider in driverProviders) {
+ val driver = provider.getDebuggerConfiguration(project, isElevated = false, emulateTerminal = false, DebuggerDriverConfiguration::class.java) ?: continue
+ return executeWithDriver(state, toolchain, environment, driver) ?: continue
+ }
+ return null
+ }
+
+ @Throws(ExecutionException::class)
+ private suspend fun executeWithDriver(
+ state: ProfileState,
+ toolchain: AbstractZigToolchain,
+ environment: ExecutionEnvironment,
+ debuggerDriver: DebuggerDriverConfiguration
+ ): RunContentDescriptor? {
+ return reportProgress { reporter ->
+ val runParameters = getDebugParameters(state, debuggerDriver, toolchain)
+ val console = state.consoleBuilder.console
+ if (runParameters is PreLaunchAware) {
+ val listener = PreLaunchProcessListener(console)
+ try {
+ reporter.indeterminateStep {
+ runParameters.preLaunch(listener)
+ }
+ } catch (e: ExecutionException) {
+ console.print("\n", ConsoleViewContentType.ERROR_OUTPUT)
+ e.message?.let { listener.console.print(it, ConsoleViewContentType.SYSTEM_OUTPUT) }
+ }
+ if (listener.isBuildFailed) {
+ val executionResult = DefaultExecutionResult(console, listener.processHandler)
+ return@reportProgress withEDTContext {
+ val runContentBuilder = RunContentBuilder(executionResult, environment)
+ runContentBuilder.showRunContent(null)
+ }
+ }
+ }
+ return@reportProgress runInterruptibleEDT {
+ val debuggerManager = XDebuggerManager.getInstance(environment.project)
+ debuggerManager.startSession(environment, object: XDebugProcessStarter() {
+ override fun start(session: XDebugSession): XDebugProcess {
+ val project = session.project
+ val textConsoleBuilder = SharedConsoleBuilder(console)
+ val debugProcess = ZigLocalDebugProcess(runParameters, session, textConsoleBuilder)
+ ProcessTerminatedListener.attach(debugProcess.processHandler, project)
+ debugProcess.start()
+ return debugProcess
+ }
+ }).runContentDescriptor
+ }
+ }
+ }
+
+ @Throws(ExecutionException::class)
+ protected abstract fun getDebugParameters(
+ state: ProfileState,
+ debuggerDriver: DebuggerDriverConfiguration,
+ toolchain: AbstractZigToolchain
+ ): ZigDebugParametersBase
+
+ private class SharedConsoleBuilder(private val console: ConsoleView) : TextConsoleBuilder() {
+ override fun getConsole(): ConsoleView {
+ return console
+ }
+
+ override fun addFilter(filter: Filter) {
+ }
+
+ override fun setViewer(isViewer: Boolean) {
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/binary/ZigDebugParametersBinary.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/binary/ZigDebugParametersBinary.kt
new file mode 100644
index 00000000..18db6999
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/binary/ZigDebugParametersBinary.kt
@@ -0,0 +1,41 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.runner.binary
+
+import com.falsepattern.zigbrains.debugger.ZigDebugBundle
+import com.falsepattern.zigbrains.debugger.execution.binary.ZigProfileStateBinary
+import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugEmitBinaryInstaller
+import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase
+import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
+import com.intellij.execution.ExecutionException
+import com.jetbrains.cidr.execution.Installer
+import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
+
+
+class ZigDebugParametersBinary @Throws(ExecutionException::class) constructor(driverConfiguration: DebuggerDriverConfiguration, toolchain: AbstractZigToolchain, profileState: ZigProfileStateBinary) :
+ ZigDebugParametersBase(driverConfiguration, toolchain, profileState) {
+ private val executableFile = profileState.configuration.exePath.path?.toFile() ?: throw ExecutionException(ZigDebugBundle.message("exception.missing-exe-path"))
+ override fun getInstaller(): Installer {
+ return ZigDebugEmitBinaryInstaller(profileState, toolchain, executableFile, profileState.configuration.args.args)
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/binary/ZigDebugRunnerBinary.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/binary/ZigDebugRunnerBinary.kt
new file mode 100644
index 00000000..d82ba469
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/binary/ZigDebugRunnerBinary.kt
@@ -0,0 +1,55 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.runner.binary
+
+import com.falsepattern.zigbrains.debugger.execution.binary.ZigExecConfigBinary
+import com.falsepattern.zigbrains.debugger.execution.binary.ZigProfileStateBinary
+import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase
+import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugRunnerBase
+import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
+import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
+import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain
+import com.intellij.execution.configurations.RunProfile
+import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
+
+class ZigDebugRunnerBinary: ZigDebugRunnerBase() {
+ override fun getDebugParameters(
+ state: ZigProfileStateBinary,
+ debuggerDriver: DebuggerDriverConfiguration,
+ toolchain: AbstractZigToolchain
+ ): ZigDebugParametersBase {
+ return ZigDebugParametersBinary(debuggerDriver, LocalZigToolchain.ensureLocal(toolchain), state)
+ }
+
+ override fun castProfileState(state: ZigProfileState<*>): ZigProfileStateBinary? {
+ return state as? ZigProfileStateBinary
+ }
+
+ override fun canRun(executorId: String, profile: RunProfile): Boolean {
+ return this.executorId == executorId && profile is ZigExecConfigBinary
+ }
+
+ override fun getRunnerId(): String {
+ return "ZigDebugRunnerBinary"
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/build/ZigDebugParametersBuild.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/build/ZigDebugParametersBuild.kt
new file mode 100644
index 00000000..fd1972e4
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/build/ZigDebugParametersBuild.kt
@@ -0,0 +1,117 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.runner.build
+
+import com.falsepattern.zigbrains.debugger.ZigDebugBundle
+import com.falsepattern.zigbrains.debugger.runner.base.PreLaunchAware
+import com.falsepattern.zigbrains.debugger.runner.base.PreLaunchProcessListener
+import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugEmitBinaryInstaller
+import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase
+import com.falsepattern.zigbrains.project.execution.build.ZigProfileStateBuild
+import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
+import com.intellij.execution.ExecutionException
+import com.intellij.execution.ui.ConsoleViewContentType
+import com.intellij.openapi.util.SystemInfo
+import com.intellij.platform.util.progress.withProgressText
+import com.jetbrains.cidr.execution.Installer
+import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import org.jetbrains.annotations.PropertyKey
+import java.io.File
+import java.nio.file.Files
+import java.nio.file.Path
+import java.util.stream.Stream
+import kotlin.io.path.isExecutable
+import kotlin.io.path.isRegularFile
+import kotlin.io.path.notExists
+
+class ZigDebugParametersBuild(
+ driverConfiguration: DebuggerDriverConfiguration,
+ toolchain: AbstractZigToolchain,
+ profileState: ZigProfileStateBuild
+) : ZigDebugParametersBase(driverConfiguration, toolchain, profileState), PreLaunchAware {
+ @Volatile
+ private lateinit var executableFile: File
+
+ override fun getInstaller(): Installer {
+ return ZigDebugEmitBinaryInstaller(profileState, toolchain, executableFile, profileState.configuration.exeArgs.args)
+ }
+
+ @Throws(ExecutionException::class)
+ override suspend fun preLaunch(listener: PreLaunchProcessListener) {
+ withProgressText("Building zig project") {
+ withContext(Dispatchers.IO) {
+ val commandLine = profileState.getCommandLine(toolchain, true)
+ if (listener.executeCommandLineWithHook(commandLine))
+ throw ExecutionException(ZigDebugBundle.message("debug.build.compile.failed.generic"))
+ val cfg = profileState.configuration
+ val workingDir = cfg.workingDirectory.path
+ val exe = profileState.configuration.exePath.path ?: run {
+ //Attempt autodetect, should work for trivial cases, and make most users happy, while advanced
+ // users can use manual executable paths.
+ if (workingDir == null) {
+ fail("debug.build.compile.failed.no-workdir")
+ }
+ val expectedOutputDir = workingDir.resolve(Path.of("zig-out", "bin"))
+ if (expectedOutputDir.notExists()) {
+ fail("debug.build.compile.failed.autodetect")
+ }
+
+ withContext(Dispatchers.IO) {
+ Files.list(expectedOutputDir).use { getExe(it) }
+ }
+ }
+
+ if (exe.notExists())
+ fail("debug.build.compile.failed.no-file", exe)
+ else if (!exe.isExecutable())
+ fail("debug.build.compile.failed.non-exec-file", exe)
+
+ executableFile = exe.toFile()
+ }
+ }
+ }
+
+}
+
+@Throws(ExecutionException::class)
+private fun getExe(files: Stream): Path {
+ var fileStream = files.filter { it.isRegularFile() }
+ if (SystemInfo.isWindows) {
+ fileStream = fileStream.filter { it.fileName.endsWith(".exe") }
+ } else {
+ fileStream = fileStream.filter { it.isExecutable() }
+ }
+ val executables = fileStream.toList()
+ return when(executables.size) {
+ 0 -> fail("debug.base.compile.failed.no-exe")
+ 1 -> executables[0]
+ else -> fail("debug.build.compile.failed.multiple-exe")
+ }
+}
+
+@Throws(ExecutionException::class)
+private fun fail(@PropertyKey(resourceBundle = ZigDebugBundle.BUNDLE) messageKey: String, vararg params: Any): Nothing {
+ throw ExecutionException(ZigDebugBundle.message("debug.build.compile.failed.boilerplate", ZigDebugBundle.message(messageKey, params)))
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/build/ZigDebugRunnerBuild.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/build/ZigDebugRunnerBuild.kt
new file mode 100644
index 00000000..0098c8be
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/build/ZigDebugRunnerBuild.kt
@@ -0,0 +1,55 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.runner.build
+
+import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase
+import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugRunnerBase
+import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
+import com.falsepattern.zigbrains.project.execution.build.ZigExecConfigBuild
+import com.falsepattern.zigbrains.project.execution.build.ZigProfileStateBuild
+import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
+import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain
+import com.intellij.execution.configurations.RunProfile
+import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
+
+class ZigDebugRunnerBuild: ZigDebugRunnerBase() {
+ override fun getDebugParameters(
+ state: ZigProfileStateBuild,
+ debuggerDriver: DebuggerDriverConfiguration,
+ toolchain: AbstractZigToolchain
+ ): ZigDebugParametersBase {
+ return ZigDebugParametersBuild(debuggerDriver, LocalZigToolchain.ensureLocal(toolchain), state)
+ }
+
+ override fun castProfileState(state: ZigProfileState<*>): ZigProfileStateBuild? {
+ return state as? ZigProfileStateBuild
+ }
+
+ override fun canRun(executorId: String, profile: RunProfile): Boolean {
+ return this.executorId == executorId && profile is ZigExecConfigBuild
+ }
+
+ override fun getRunnerId(): String {
+ return "ZigDebugRunnerBuild"
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/run/ZigDebugParametersRun.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/run/ZigDebugParametersRun.kt
new file mode 100644
index 00000000..f840f45e
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/run/ZigDebugParametersRun.kt
@@ -0,0 +1,37 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.runner.run
+
+import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugEmitBinaryInstaller
+import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersEmitBinaryBase
+import com.falsepattern.zigbrains.project.execution.run.ZigProfileStateRun
+import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
+import com.jetbrains.cidr.execution.Installer
+import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
+
+class ZigDebugParametersRun(driverConfiguration: DebuggerDriverConfiguration, toolchain: AbstractZigToolchain, profileState: ZigProfileStateRun) :
+ ZigDebugParametersEmitBinaryBase(driverConfiguration, toolchain, profileState) {
+ override fun getInstaller(): Installer {
+ return ZigDebugEmitBinaryInstaller(profileState, toolchain, executableFile, profileState.configuration.exeArgs.args)
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/run/ZigDebugRunnerRun.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/run/ZigDebugRunnerRun.kt
new file mode 100644
index 00000000..6c3e4b13
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/run/ZigDebugRunnerRun.kt
@@ -0,0 +1,55 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.runner.run
+
+import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase
+import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugRunnerBase
+import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
+import com.falsepattern.zigbrains.project.execution.run.ZigExecConfigRun
+import com.falsepattern.zigbrains.project.execution.run.ZigProfileStateRun
+import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
+import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain
+import com.intellij.execution.configurations.RunProfile
+import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
+
+class ZigDebugRunnerRun: ZigDebugRunnerBase() {
+ override fun getDebugParameters(
+ state: ZigProfileStateRun,
+ debuggerDriver: DebuggerDriverConfiguration,
+ toolchain: AbstractZigToolchain
+ ): ZigDebugParametersBase {
+ return ZigDebugParametersRun(debuggerDriver, LocalZigToolchain.ensureLocal(toolchain), state)
+ }
+
+ override fun castProfileState(state: ZigProfileState<*>): ZigProfileStateRun? {
+ return state as? ZigProfileStateRun
+ }
+
+ override fun canRun(executorId: String, profile: RunProfile): Boolean {
+ return this.executorId == executorId && (profile is ZigExecConfigRun)
+ }
+
+ override fun getRunnerId(): String {
+ return "ZigDebugRunnerRun"
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/test/ZigDebugParametersTest.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/test/ZigDebugParametersTest.kt
new file mode 100644
index 00000000..e263037c
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/test/ZigDebugParametersTest.kt
@@ -0,0 +1,37 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.runner.test
+
+import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugEmitBinaryInstaller
+import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersEmitBinaryBase
+import com.falsepattern.zigbrains.project.execution.test.ZigProfileStateTest
+import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
+import com.jetbrains.cidr.execution.Installer
+import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
+
+class ZigDebugParametersTest(driverConfiguration: DebuggerDriverConfiguration, toolchain: AbstractZigToolchain, profileState: ZigProfileStateTest) :
+ ZigDebugParametersEmitBinaryBase(driverConfiguration, toolchain, profileState) {
+ override fun getInstaller(): Installer {
+ return ZigDebugEmitBinaryInstaller(profileState, toolchain, executableFile, listOf())
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/test/ZigDebugRunnerTest.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/test/ZigDebugRunnerTest.kt
new file mode 100644
index 00000000..caab3d25
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/test/ZigDebugRunnerTest.kt
@@ -0,0 +1,55 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.runner.test
+
+import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase
+import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugRunnerBase
+import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
+import com.falsepattern.zigbrains.project.execution.test.ZigExecConfigTest
+import com.falsepattern.zigbrains.project.execution.test.ZigProfileStateTest
+import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
+import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain
+import com.intellij.execution.configurations.RunProfile
+import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration
+
+class ZigDebugRunnerTest: ZigDebugRunnerBase() {
+ override fun getDebugParameters(
+ state: ZigProfileStateTest,
+ debuggerDriver: DebuggerDriverConfiguration,
+ toolchain: AbstractZigToolchain
+ ): ZigDebugParametersBase {
+ return ZigDebugParametersTest(debuggerDriver, LocalZigToolchain.ensureLocal(toolchain), state)
+ }
+
+ override fun castProfileState(state: ZigProfileState<*>): ZigProfileStateTest? {
+ return state as? ZigProfileStateTest
+ }
+
+ override fun canRun(executorId: String, profile: RunProfile): Boolean {
+ return this.executorId == executorId && profile is ZigExecConfigTest
+ }
+
+ override fun getRunnerId(): String {
+ return "ZigDebugRunnerTest"
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/settings/ZigDebuggerGeneralSettingsConfigurableUi.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/settings/ZigDebuggerGeneralSettingsConfigurableUi.kt
new file mode 100644
index 00000000..7c6d3101
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/settings/ZigDebuggerGeneralSettingsConfigurableUi.kt
@@ -0,0 +1,54 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.settings
+
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.options.ConfigurableUi
+import com.intellij.openapi.util.Disposer
+import com.intellij.ui.dsl.builder.panel
+import javax.swing.JComponent
+
+class ZigDebuggerGeneralSettingsConfigurableUi: ConfigurableUi, Disposable {
+ private val components = listOf(ZigDebuggerToolchainConfigurableUi()).onEach { Disposer.register(this, it) }
+
+ override fun reset(settings: ZigDebuggerSettings) {
+ components.forEach { it.reset(settings) }
+ }
+
+ override fun isModified(settings: ZigDebuggerSettings): Boolean {
+ return components.any { it.isModified(settings) }
+ }
+
+ override fun apply(settings: ZigDebuggerSettings) {
+ components.forEach { it.apply(settings) }
+ }
+
+ override fun getComponent(): JComponent {
+ return panel {
+ components.forEach { it.buildUi(this) }
+ }
+ }
+
+ override fun dispose() {
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/settings/ZigDebuggerSettings.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/settings/ZigDebuggerSettings.kt
new file mode 100644
index 00000000..82dbfbcd
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/settings/ZigDebuggerSettings.kt
@@ -0,0 +1,70 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.settings
+
+import com.falsepattern.zigbrains.debugger.ZigDebugBundle
+import com.falsepattern.zigbrains.debugger.toolchain.DebuggerKind
+import com.intellij.openapi.options.Configurable
+import com.intellij.openapi.options.SimpleConfigurable
+import com.intellij.util.xmlb.XmlSerializerUtil
+import com.intellij.xdebugger.settings.DebuggerSettingsCategory
+import com.intellij.xdebugger.settings.XDebuggerSettings
+
+class ZigDebuggerSettings: XDebuggerSettings("Zig") {
+ var debuggerKind = DebuggerKind.default
+
+ var downloadAutomatically = false
+ var useClion = true
+
+ override fun getState(): ZigDebuggerSettings? {
+ return this
+ }
+
+ override fun loadState(p0: ZigDebuggerSettings) {
+ XmlSerializerUtil.copyBean(p0, this)
+ }
+
+ override fun createConfigurables(category: DebuggerSettingsCategory): Collection {
+ val configurable = when(category) {
+ DebuggerSettingsCategory.GENERAL -> createGeneralSettingsConfigurable()
+ else -> null
+ }
+ return configurable?.let { listOf(configurable) } ?: emptyList()
+ }
+
+ private fun createGeneralSettingsConfigurable(): Configurable {
+ return SimpleConfigurable.create(
+ GENERAL_SETTINGS_ID,
+ ZigDebugBundle.message("settings.debugger.title"),
+ ZigDebuggerGeneralSettingsConfigurableUi::class.java,
+ ) {
+ instance
+ }
+ }
+
+ companion object {
+ val instance: ZigDebuggerSettings get() = getInstance(ZigDebuggerSettings::class.java)
+ }
+}
+
+private const val GENERAL_SETTINGS_ID = "Debugger.Zig.General"
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/settings/ZigDebuggerToolchainConfigurableUi.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/settings/ZigDebuggerToolchainConfigurableUi.kt
new file mode 100644
index 00000000..d7804ba5
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/settings/ZigDebuggerToolchainConfigurableUi.kt
@@ -0,0 +1,161 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.settings
+
+import com.falsepattern.zigbrains.debugger.ZigDebugBundle
+import com.falsepattern.zigbrains.debugger.toolchain.DebuggerAvailability
+import com.falsepattern.zigbrains.debugger.toolchain.DebuggerKind
+import com.falsepattern.zigbrains.debugger.toolchain.ZigDebuggerToolchainService
+import com.falsepattern.zigbrains.debugger.toolchain.zigDebuggerToolchainService
+import com.falsepattern.zigbrains.shared.coroutine.launchWithEDT
+import com.falsepattern.zigbrains.shared.coroutine.runModalOrBlocking
+import com.falsepattern.zigbrains.shared.zigCoroutineScope
+import com.intellij.ide.plugins.PluginManager
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.application.EDT
+import com.intellij.openapi.application.ModalityState
+import com.intellij.openapi.extensions.PluginId
+import com.intellij.openapi.observable.util.whenItemSelected
+import com.intellij.openapi.options.ConfigurableUi
+import com.intellij.openapi.ui.ComboBox
+import com.intellij.openapi.util.SystemInfo
+import com.intellij.platform.ide.progress.ModalTaskOwner
+import com.intellij.platform.ide.progress.TaskCancellation
+import com.intellij.platform.ide.progress.withModalProgress
+import com.intellij.ui.components.JBCheckBox
+import com.intellij.ui.dsl.builder.DEFAULT_COMMENT_WIDTH
+import com.intellij.ui.dsl.builder.Panel
+import com.intellij.util.concurrency.annotations.RequiresEdt
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.asContextElement
+import kotlinx.coroutines.job
+import kotlinx.coroutines.launch
+import javax.swing.ComboBoxModel
+import javax.swing.DefaultComboBoxModel
+import javax.swing.JEditorPane
+
+class ZigDebuggerToolchainConfigurableUi : ZigDebuggerUiComponent {
+ private val debuggerKindComboBox = ComboBox(
+ runModalOrBlocking({ ModalTaskOwner.guess() }, { "ZigDebuggerToolchainConfigurableUi" }) {
+ createDebuggerKindComboBoxModel()
+ }
+ )
+ private val downloadAutomaticallyCheckBox = JBCheckBox(
+ ZigDebugBundle.message("settings.debugger.toolchain.download.debugger.automatically.checkbox"),
+ ZigDebuggerSettings.instance.downloadAutomatically
+ )
+
+ private val useClion = JBCheckBox(
+ ZigDebugBundle.message("settings.debugger.toolchain.use.clion.toolchains"),
+ ZigDebuggerSettings.instance.useClion
+ )
+
+ private var comment: JEditorPane? = null
+
+ private val currentDebuggerKind get() = debuggerKindComboBox.item
+
+ override fun reset(settings: ZigDebuggerSettings) {
+ debuggerKindComboBox.item = settings.debuggerKind
+ downloadAutomaticallyCheckBox.isSelected = settings.downloadAutomatically
+ useClion.isSelected = settings.useClion
+ }
+
+ override fun isModified(settings: ZigDebuggerSettings): Boolean {
+ return settings.debuggerKind != debuggerKindComboBox.item ||
+ settings.downloadAutomatically != downloadAutomaticallyCheckBox.isSelected ||
+ settings.useClion != useClion.isSelected
+ }
+
+ override fun apply(settings: ZigDebuggerSettings) {
+ settings.debuggerKind = debuggerKindComboBox.item
+ settings.downloadAutomatically = downloadAutomaticallyCheckBox.isSelected
+ settings.useClion = useClion.isSelected
+ }
+
+ override fun buildUi(panel: Panel): Unit = with(panel) {
+ row(ZigDebugBundle.message("settings.debugger.toolchain.debugger.label")) {
+ comment = cell(debuggerKindComboBox)
+ .comment("", DEFAULT_COMMENT_WIDTH) {
+ zigCoroutineScope.launchWithEDT {
+ withModalProgress(ModalTaskOwner.component(debuggerKindComboBox), "Downloading debugger", TaskCancellation.cancellable()) {
+ downloadDebugger()
+ }
+ }
+ }
+ .applyToComponent {
+ whenItemSelected(null) {
+ zigCoroutineScope.launchWithEDT {
+ this@ZigDebuggerToolchainConfigurableUi.update()
+ }
+ }
+ }
+ .comment
+ }
+ row {
+ cell(downloadAutomaticallyCheckBox)
+ }
+// if (PluginManager.isPluginInstalled(PluginId.getId("com.intellij.modules.clion")) && !SystemInfo.isWindows) {
+// row {
+// cell(useClion)
+// }
+// }
+ zigCoroutineScope.launchWithEDT {
+ update()
+ }
+ }
+
+ override fun dispose() {
+
+ }
+
+ @RequiresEdt
+ private suspend fun downloadDebugger() {
+ val result = zigDebuggerToolchainService.downloadDebugger(null, currentDebuggerKind)
+ if (result is ZigDebuggerToolchainService.DownloadResult.Ok) {
+ update()
+ }
+ }
+
+ @RequiresEdt
+ private suspend fun update() {
+ val availability = zigDebuggerToolchainService.debuggerAvailability(currentDebuggerKind)
+ val text = when (availability) {
+ is DebuggerAvailability.NeedToDownload -> ZigDebugBundle.message("settings.debugger.toolchain.download.comment")
+ is DebuggerAvailability.NeedToUpdate -> ZigDebugBundle.message("settings.debugger.toolchain.update.comment")
+ else -> null
+ }
+ comment?.let {
+ it.text = text
+ it.isVisible = text != null
+ }
+ }
+
+ companion object {
+ private suspend fun createDebuggerKindComboBoxModel(): ComboBoxModel {
+ val toolchainService = zigDebuggerToolchainService
+ val availableKinds = DebuggerKind.entries.filter { toolchainService.debuggerAvailability(it) !is DebuggerAvailability.Unavailable }
+ return DefaultComboBoxModel(availableKinds.toTypedArray()).also { it.selectedItem = ZigDebuggerSettings.instance.debuggerKind }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/settings/ZigDebuggerUiComponent.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/settings/ZigDebuggerUiComponent.kt
new file mode 100644
index 00000000..2019d17c
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/settings/ZigDebuggerUiComponent.kt
@@ -0,0 +1,39 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.settings
+
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.options.ConfigurableUi
+import com.intellij.ui.dsl.builder.Panel
+import com.intellij.ui.dsl.builder.panel
+import javax.swing.JComponent
+
+interface ZigDebuggerUiComponent: ConfigurableUi, Disposable {
+ fun buildUi(panel: Panel)
+
+ override fun getComponent(): JComponent {
+ return panel {
+ buildUi(this)
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/toolchain/DebuggerAvailability.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/toolchain/DebuggerAvailability.kt
new file mode 100644
index 00000000..a662e645
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/toolchain/DebuggerAvailability.kt
@@ -0,0 +1,37 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.toolchain
+
+import java.nio.file.Path
+
+sealed class DebuggerAvailability {
+ data object Unavailable: DebuggerAvailability()
+ data object NeedToDownload: DebuggerAvailability()
+ data object NeedToUpdate: DebuggerAvailability()
+ data object Bundled: DebuggerAvailability()
+ data class Binaries (val binaries: T): DebuggerAvailability()
+}
+
+data class LLDBBinaries(val frameworkFile: Path, val frontendFile: Path)
+data class GDBBinaries(val gdbFile: Path)
+data class MSVCBinaries(val msvcFile: Path)
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/toolchain/DebuggerKind.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/toolchain/DebuggerKind.kt
new file mode 100644
index 00000000..09d8fc38
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/toolchain/DebuggerKind.kt
@@ -0,0 +1,35 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.toolchain
+
+import com.intellij.openapi.util.SystemInfo
+
+enum class DebuggerKind {
+ LLDB,
+ GDB,
+ MSVC;
+
+ companion object {
+ val default get() = if (SystemInfo.isWindows) MSVC else LLDB
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/toolchain/MSVCMetadataProvider.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/toolchain/MSVCMetadataProvider.kt
new file mode 100644
index 00000000..03b71b77
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/toolchain/MSVCMetadataProvider.kt
@@ -0,0 +1,131 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.toolchain
+
+import com.falsepattern.zigbrains.debugger.ZigDebugBundle
+import com.falsepattern.zigbrains.debugger.settings.ZigDebuggerSettings
+import com.falsepattern.zigbrains.debugger.toolchain.ZigDebuggerToolchainService.Companion.downloadPath
+import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
+import com.falsepattern.zigbrains.shared.zigCoroutineScope
+import com.intellij.notification.Notification
+import com.intellij.notification.NotificationType
+import com.intellij.openapi.application.EDT
+import com.intellij.openapi.application.ModalityState
+import com.intellij.openapi.application.asContextElement
+import com.intellij.openapi.progress.coroutineToIndicator
+import com.intellij.openapi.ui.DialogBuilder
+import com.intellij.platform.ide.progress.ModalTaskOwner
+import com.intellij.platform.ide.progress.TaskCancellation
+import com.intellij.platform.ide.progress.withModalProgress
+import com.intellij.platform.util.progress.withProgressText
+import com.intellij.ui.components.JBLabel
+import com.intellij.ui.components.JBPanel
+import com.intellij.util.concurrency.annotations.RequiresEdt
+import com.intellij.util.download.DownloadableFileService
+import com.intellij.util.suspendingLazy
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runInterruptible
+import kotlinx.coroutines.sync.Mutex
+import kotlinx.coroutines.sync.withLock
+import kotlinx.coroutines.withContext
+import kotlinx.coroutines.withTimeoutOrNull
+import java.io.IOException
+import java.util.*
+import javax.swing.BoxLayout
+
+private val mutex = Mutex()
+private var cache: Properties? = null
+
+suspend fun msvcMetadata(): Properties {
+ cache?.let { return it }
+ mutex.withLock {
+ cache?.let { return it }
+ val allowDownload = withEDTContext(ModalityState.current()) {
+ val dialog = DialogBuilder()
+ dialog.setTitle(ZigDebugBundle.message("msvc.consent.title"))
+ dialog.addCancelAction().setText(ZigDebugBundle.message("msvc.consent.deny"))
+ dialog.addOkAction().setText(ZigDebugBundle.message("msvc.consent.allow"))
+ val centerPanel = JBPanel>()
+ centerPanel.setLayout(BoxLayout(centerPanel, BoxLayout.Y_AXIS))
+ val lines = ZigDebugBundle.message("msvc.consent.body").split('\n')
+ for (line in lines) {
+ centerPanel.add(JBLabel(line))
+ }
+ dialog.centerPanel(centerPanel)
+ dialog.showAndGet()
+ }
+ val data = if (allowDownload) {
+ withTimeoutOrNull(3000L) {
+ downloadMSVCProps()
+ } ?: run {
+ Notification(
+ "zigbrains",
+ ZigDebugBundle.message("notification.title.debugger"),
+ ZigDebugBundle.message("notification.content.debugger.metadata.downloading.failed"),
+ NotificationType.ERROR
+ ).notify(null)
+ fetchBuiltinMSVCProps()
+ }
+ } else {
+ fetchBuiltinMSVCProps()
+ }
+ cache = data
+ return data
+ }
+}
+
+private suspend fun downloadMSVCProps(): Properties {
+ return withProgressText("Downloading debugger metadata") {
+ val service = DownloadableFileService.getInstance()
+ val desc = service.createFileDescription("https://falsepattern.com/zigbrains/msvc.properties", "msvc.properties")
+ val downloader = service.createDownloader(listOf(desc), "Debugger metadata downloading")
+ val downloadDirectory = downloadPath().toFile()
+ val prop = Properties()
+ val downloadResults = coroutineToIndicator {
+ downloader.download(downloadDirectory)
+ }
+ for (result in downloadResults) {
+ if (result.second.defaultFileName == "msvc.properties") {
+ result.first.reader().use { prop.load(it) }
+ }
+ }
+ return@withProgressText prop
+ }
+}
+
+private fun fetchBuiltinMSVCProps(): Properties {
+ val prop = Properties()
+ try {
+ val resource = ZigDebuggerToolchainService::class.java.getResourceAsStream("/msvc.properties") ?: throw IOException("null")
+ resource.reader().use { prop.load(it) }
+ } catch (ex: IOException) {
+ ex.printStackTrace()
+ Notification(
+ "zigbrains",
+ ZigDebugBundle.message("notification.title.debugger"),
+ ZigDebugBundle.message("notification.content.debugger.metadata.fallback.parse.failed"),
+ NotificationType.ERROR
+ ).notify(null)
+ }
+ return prop
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/toolchain/ZigDebuggerToolchainService.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/toolchain/ZigDebuggerToolchainService.kt
new file mode 100644
index 00000000..55fc883b
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/toolchain/ZigDebuggerToolchainService.kt
@@ -0,0 +1,383 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.toolchain
+
+import com.falsepattern.zigbrains.debugger.ZigDebugBundle
+import com.falsepattern.zigbrains.shared.coroutine.runInterruptibleEDT
+import com.falsepattern.zigbrains.shared.coroutine.runModalOrBlocking
+import com.intellij.execution.ExecutionModes.ModalProgressMode
+import com.intellij.notification.Notification
+import com.intellij.notification.NotificationType
+import com.intellij.openapi.application.EDT
+import com.intellij.openapi.application.PathManager
+import com.intellij.openapi.components.Service
+import com.intellij.openapi.components.service
+import com.intellij.openapi.diagnostic.logger
+import com.intellij.openapi.progress.coroutineToIndicator
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.ui.DialogBuilder
+import com.intellij.openapi.util.SystemInfo
+import com.intellij.openapi.util.io.toNioPathOrNull
+import com.intellij.platform.ide.progress.ModalTaskOwner
+import com.intellij.platform.ide.progress.TaskCancellation
+import com.intellij.platform.ide.progress.withModalProgress
+import com.intellij.ui.BrowserHyperlinkListener
+import com.intellij.ui.HyperlinkLabel
+import com.intellij.ui.components.JBPanel
+import com.intellij.util.application
+import com.intellij.util.concurrency.annotations.RequiresEdt
+import com.intellij.util.download.DownloadableFileService
+import com.intellij.util.io.Decompressor
+import com.intellij.util.system.CpuArch
+import com.intellij.util.system.OS
+import com.jetbrains.cidr.execution.debugger.CidrDebuggerPathManager
+import com.jetbrains.cidr.execution.debugger.backend.bin.UrlProvider
+import com.jetbrains.cidr.execution.debugger.backend.lldb.LLDBDriverConfiguration
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runInterruptible
+import kotlinx.coroutines.withContext
+import java.io.File
+import java.io.IOException
+import java.net.URL
+import java.nio.file.Path
+import java.util.Properties
+import kotlin.io.path.name
+import kotlin.io.path.notExists
+
+@Service
+class ZigDebuggerToolchainService {
+ suspend fun debuggerAvailability(kind: DebuggerKind): DebuggerAvailability<*> {
+ return when(kind) {
+ DebuggerKind.LLDB -> lldbAvailability()
+ DebuggerKind.GDB -> gdbAvailability()
+ DebuggerKind.MSVC -> msvcAvailability()
+ }
+ }
+
+ fun lldbAvailability(): DebuggerAvailability {
+// if (LLDBDriverConfiguration.hasBundledLLDB()) return DebuggerAvailability.Bundled
+
+ val (frameworkPath, frontendPath) = when {
+ SystemInfo.isMac -> "LLDB.framework" to "LLDBFrontend"
+ SystemInfo.isUnix -> "lib/liblldb.so" to "bin/LLDBFrontend"
+ SystemInfo.isWindows -> "bin/liblldb.dll" to "bin/LLDBFrontend.exe"
+ else -> return DebuggerAvailability.Unavailable
+ }
+
+ val lldbPath = lldbPath()
+ val frameworkFile = lldbPath.resolve(frameworkPath)
+ val frontendFile = lldbPath.resolve(frontendPath)
+ if (frameworkFile.notExists() || frontendFile.notExists()) return DebuggerAvailability.NeedToDownload
+
+ val versions = loadDebuggerVersions(DebuggerKind.LLDB)
+ val (lldbFrameworkUrl, lldbFrontendUrl) = lldbUrls() ?: return DebuggerAvailability.Unavailable
+
+ val lldbFrameworkVersion = fileNameWithoutExtension(lldbFrameworkUrl.toString())
+ val lldbFrontendVersion = fileNameWithoutExtension(lldbFrontendUrl.toString())
+
+ if (versions[LLDB_FRAMEWORK_PROPERTY_NAME] != lldbFrameworkVersion ||
+ versions[LLDB_FRONTEND_PROPERTY_NAME] != lldbFrontendVersion) return DebuggerAvailability.NeedToUpdate
+
+ return DebuggerAvailability.Binaries(LLDBBinaries(frameworkFile, frontendFile))
+ }
+
+ fun gdbAvailability(): DebuggerAvailability {
+ if (SystemInfo.isMac) return DebuggerAvailability.Unavailable
+// if (CidrDebuggerPathManager.getBundledGDBBinary().exists()) return DebuggerAvailability.Bundled
+
+ val gdbBinaryPath = when {
+ SystemInfo.isUnix -> "bin/gdb"
+ SystemInfo.isWindows -> "bin/gdb.exe"
+ else -> return DebuggerAvailability.Unavailable
+ }
+
+ val gdbFile = gdbPath().resolve(gdbBinaryPath)
+ if (gdbFile.notExists()) return DebuggerAvailability.NeedToDownload
+
+ val versions = loadDebuggerVersions(DebuggerKind.GDB)
+ val gdbUrl = gdbUrl() ?: return DebuggerAvailability.Unavailable
+
+ val gdbVersion = fileNameWithoutExtension(gdbUrl.toString())
+
+ if (versions[GDB_PROPERTY_NAME] != gdbVersion) return DebuggerAvailability.NeedToUpdate
+
+ return DebuggerAvailability.Binaries(GDBBinaries(gdbFile))
+ }
+
+ suspend fun msvcAvailability(): DebuggerAvailability {
+// if (!SystemInfo.isWindows) return DebuggerAvailability.Unavailable
+
+ val msvcBinaryPath = "vsdbg.exe"
+
+ val msvcFile = msvcPath().resolve(msvcBinaryPath)
+ if (msvcFile.notExists()) return DebuggerAvailability.NeedToDownload
+
+ val msvcUrl = msvcUrl() ?: return DebuggerAvailability.Binaries(MSVCBinaries(msvcFile))
+
+ val versions = loadDebuggerVersions(DebuggerKind.MSVC)
+
+ if (versions[MSVC_PROPERTY_NAME] != msvcUrl.version) return DebuggerAvailability.NeedToUpdate
+
+ return DebuggerAvailability.Binaries(MSVCBinaries(msvcFile))
+ }
+
+ @RequiresEdt
+ private suspend fun doDownloadDebugger(project: Project? = null, debuggerKind: DebuggerKind): DownloadResult {
+ val baseDir = debuggerKind.basePath()
+ val downloadableBinaries = when(debuggerKind) {
+ DebuggerKind.LLDB -> {
+ val (lldbFrameworkUrl, lldbFrontendUrl) = lldbUrls()?.run { first.toString() to second.toString() } ?: return DownloadResult.NoUrls
+ listOf(
+ DownloadableDebuggerBinary(lldbFrameworkUrl, LLDB_FRAMEWORK_PROPERTY_NAME, fileNameWithoutExtension(lldbFrameworkUrl)),
+ DownloadableDebuggerBinary(lldbFrontendUrl, LLDB_FRONTEND_PROPERTY_NAME, fileNameWithoutExtension(lldbFrontendUrl))
+ )
+ }
+ DebuggerKind.GDB -> {
+ val gdbUrl = gdbUrl()?.run { toString() } ?: return DownloadResult.NoUrls
+ listOf(DownloadableDebuggerBinary(gdbUrl, GDB_PROPERTY_NAME, fileNameWithoutExtension(gdbUrl)))
+ }
+ DebuggerKind.MSVC -> {
+ val msvcUrl = msvcUrl() ?: return DownloadResult.NoUrls
+
+ val dialog = DialogBuilder()
+ dialog.setTitle(msvcUrl.dialogTitle)
+ dialog.addCancelAction().setText("Reject")
+ dialog.addOkAction().setText("Accept")
+ val centerPanel = JBPanel>()
+ val hyperlink = HyperlinkLabel()
+ hyperlink.setTextWithHyperlink(msvcUrl.dialogBody)
+ hyperlink.setHyperlinkText(msvcUrl.dialogLink)
+ hyperlink.addHyperlinkListener(BrowserHyperlinkListener())
+ centerPanel.add(hyperlink)
+ dialog.centerPanel(centerPanel)
+ if (!dialog.showAndGet()) return DownloadResult.NoUrls
+
+ listOf(DownloadableDebuggerBinary(msvcUrl.url, MSVC_PROPERTY_NAME, msvcUrl.version, "extension/debugAdapters/vsdbg/bin"))
+ }
+ }
+
+ try {
+ downloadAndUnArchive(project, baseDir, downloadableBinaries)
+ return DownloadResult.Ok(baseDir)
+ } catch (e: IOException) {
+ //TODO logging
+ e.printStackTrace()
+ return DownloadResult.Failed(e.message)
+ }
+ }
+
+ @RequiresEdt
+ suspend fun downloadDebugger(project: Project? = null, debuggerKind: DebuggerKind): DownloadResult {
+ val result = doDownloadDebugger(project, debuggerKind)
+
+ when(result) {
+ is DownloadResult.Ok -> {
+ Notification(
+ "zigbrains",
+ ZigDebugBundle.message("notification.title.debugger"),
+ ZigDebugBundle.message("notification.content.debugger.successfully.downloaded"),
+ NotificationType.INFORMATION
+ ).notify(project)
+ }
+ is DownloadResult.Failed -> {
+ Notification(
+ "zigbrains",
+ ZigDebugBundle.message("notification.title.debugger"),
+ ZigDebugBundle.message("notification.content.debugger.downloading.failed"),
+ NotificationType.ERROR
+ ).notify(project)
+ }
+ else -> Unit
+ }
+
+ return result
+ }
+
+ @Throws(IOException::class)
+ @RequiresEdt
+ private suspend fun downloadAndUnArchive(project: Project?, baseDir: Path, binariesToDownload: List) {
+ val service = DownloadableFileService.getInstance()
+
+ val downloadDir = baseDir.toFile()
+ downloadDir.deleteRecursively()
+
+ val descriptions = binariesToDownload.map {
+ service.createFileDescription(it.url, fileName(it.url))
+ }
+
+ val downloader = service.createDownloader(descriptions, "Debugger downloading")
+ val downloadDirectory = downloadPath().toFile()
+ val downloadResults = withContext(Dispatchers.IO) {
+ coroutineToIndicator {
+ downloader.download(downloadDirectory)
+ }
+ }
+ val versions = Properties()
+ for (result in downloadResults) {
+ val downloadUrl = result.second.downloadUrl
+ val binaryToDownload = binariesToDownload.first { it.url == downloadUrl }
+ val propertyName = binaryToDownload.propertyName
+ val archiveFile = result.first
+ Unarchiver.unarchive(archiveFile, downloadDir)
+ archiveFile.delete()
+ versions[propertyName] = binaryToDownload.version
+ }
+
+ saveVersionsFile(baseDir, versions)
+ }
+
+ private fun lldbUrls(): Pair? {
+ val lldb = UrlProvider.lldb(OS.CURRENT, CpuArch.CURRENT) ?: return null
+ val lldbFrontend = UrlProvider.lldbFrontend(OS.CURRENT, CpuArch.CURRENT) ?: return null
+ return lldb to lldbFrontend
+ }
+
+ private fun gdbUrl(): URL? = UrlProvider.gdb(OS.CURRENT, CpuArch.CURRENT)
+
+ private suspend fun msvcUrl(): MSVCUrl? {
+ val dlKey = when(CpuArch.CURRENT) {
+ CpuArch.X86 -> "downloadX86"
+ CpuArch.X86_64 -> "downloadX86_64"
+ CpuArch.ARM64 -> "downloadARM64"
+ else -> return null
+ }
+
+ val props = msvcMetadata()
+ val version = props.getProperty("version") ?: return null
+ val url = props.getProperty(dlKey) ?: return null
+ return MSVCUrl(url, version, props.getProperty("dialogTitle")!!, props.getProperty("dialogBody")!!, props.getProperty("dialogLink")!!)
+ }
+
+ private data class MSVCUrl(
+ val url: String,
+ val version: String,
+ val dialogTitle: String,
+ val dialogBody: String,
+ val dialogLink: String
+ )
+
+ private fun loadDebuggerVersions(kind: DebuggerKind): Properties = loadVersions(kind.basePath())
+
+ private fun saveVersionsFile(basePath: Path, versions: Properties) {
+ val file = basePath.resolve(DEBUGGER_VERSIONS).toFile()
+ try {
+ versions.store(file.bufferedWriter(), "")
+ } catch (e: IOException) {
+ LOG.warn("Failed to save `${basePath.name}/${file.name}`", e)
+ }
+ }
+
+ private fun loadVersions(basePath: Path): Properties {
+ val versions = Properties()
+ val versionsFile = basePath.resolve(DEBUGGER_VERSIONS).toFile()
+
+ if (versionsFile.exists()) {
+ try {
+ versionsFile.bufferedReader().use { versions.load(it) }
+ } catch (e: IOException) {
+ LOG.warn("Failed to load `${basePath.name}/${versionsFile.name}`", e)
+ }
+ }
+
+ return versions
+ }
+
+ private fun DebuggerKind.basePath(): Path {
+ return when(this) {
+ DebuggerKind.LLDB -> lldbPath()
+ DebuggerKind.GDB -> gdbPath()
+ DebuggerKind.MSVC -> msvcPath()
+ }
+ }
+
+ companion object {
+ private val LOG = logger()
+
+ private const val DEBUGGER_VERSIONS: String = "versions.properties"
+
+ private const val LLDB_FRONTEND_PROPERTY_NAME = "lldbFrontend"
+ private const val LLDB_FRAMEWORK_PROPERTY_NAME = "lldbFramework"
+ private const val GDB_PROPERTY_NAME = "gdb"
+ private const val MSVC_PROPERTY_NAME = "msvc"
+
+ fun downloadPath() = tempPluginDir
+ private fun lldbPath() = pluginDir.resolve("lldb")
+ private fun gdbPath() = pluginDir.resolve("gdb")
+ private fun msvcPath() = pluginDir.resolve("msvc")
+
+ private val pluginDir get() = PathManager.getSystemDir().resolve("zigbrains")
+
+ private val tempPluginDir get() = PathManager.getTempPath().toNioPathOrNull()!!.resolve("zigbrains")
+
+ private fun fileNameWithoutExtension(url: String): String {
+ return url.substringAfterLast("/").removeSuffix(".zip").removeSuffix(".tar.gz")
+ }
+
+ private fun fileName(url: String): String {
+ return url.substringAfterLast("/")
+ }
+ }
+
+ private enum class Unarchiver {
+ ZIP {
+ override val extension = "zip"
+ override fun createDecompressor(file: File) = Decompressor.Zip(file)
+ },
+ TAR {
+ override val extension = "tar.gz"
+ override fun createDecompressor(file: File) = Decompressor.Tar(file)
+ },
+ VSIX {
+ override val extension = "vsix"
+ override fun createDecompressor(file: File) = Decompressor.Zip(file)
+ };
+
+ protected abstract val extension: String
+ protected abstract fun createDecompressor(file: File): Decompressor
+
+ companion object {
+ @Throws(IOException::class)
+ suspend fun unarchive(archivePath: File, dst: File, prefix: String? = null) {
+ runInterruptible {
+ val unarchiver = entries.find { archivePath.name.endsWith(it.extension) } ?: error("Unexpected archive type: $archivePath")
+ val dec = unarchiver.createDecompressor(archivePath)
+ if (prefix != null) {
+ dec.removePrefixPath(prefix)
+ }
+ dec.extract(dst)
+ }
+ }
+ }
+ }
+
+ sealed class DownloadResult {
+ class Ok(val baseDir: Path): DownloadResult()
+ data object NoUrls: DownloadResult()
+ class Failed(val message: String?): DownloadResult()
+ }
+
+ @JvmRecord
+ private data class DownloadableDebuggerBinary(val url: String, val propertyName: String, val version: String, val prefix: String? = null)
+}
+
+val zigDebuggerToolchainService get() = application.service()
diff --git a/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/win/MSVCDriverConfiguration.kt b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/win/MSVCDriverConfiguration.kt
new file mode 100644
index 00000000..d998e02b
--- /dev/null
+++ b/modules/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/win/MSVCDriverConfiguration.kt
@@ -0,0 +1,53 @@
+/*
+ * This file is part of ZigBrains.
+ *
+ * Copyright (C) 2023-2024 FalsePattern
+ * All Rights Reserved
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * ZigBrains is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, only version 3 of the License.
+ *
+ * ZigBrains is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with ZigBrains. If not, see .
+ */
+
+package com.falsepattern.zigbrains.debugger.win
+
+import com.falsepattern.zigbrains.debugger.dap.DAPDebuggerDriverConfiguration
+import com.intellij.execution.configurations.GeneralCommandLine
+import com.jetbrains.cidr.ArchitectureType
+import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriver
+import org.eclipse.lsp4j.debug.InitializeRequestArguments
+import java.nio.file.Path
+import kotlin.io.path.pathString
+
+abstract class MSVCDriverConfiguration: DAPDebuggerDriverConfiguration() {
+ protected abstract val debuggerExecutable: Path
+
+ override fun createDriver(handler: DebuggerDriver.Handler, arch: ArchitectureType): DebuggerDriver {
+ TODO("Not yet implemented")
+ }
+
+ override fun createDriverCommandLine(driver: DebuggerDriver, arch: ArchitectureType): GeneralCommandLine {
+ val path = debuggerExecutable
+ val cli = GeneralCommandLine()
+ cli.exePath = path.pathString
+ cli.addParameters("--interpreter=vscode", "--extconfigdir=%USERPROFILE\\.cppvsdbg\\extensions")
+ cli.withWorkingDirectory(path.parent)
+ return cli
+ }
+
+ override fun customizeInitializeArguments(initArgs: InitializeRequestArguments) {
+ initArgs.pathFormat = "path"
+ initArgs.adapterID = "cppvsdbg"
+ }
+}
\ No newline at end of file
diff --git a/modules/cidr/src/main/resources/META-INF/zigbrains-debugger.xml b/modules/cidr/src/main/resources/META-INF/zigbrains-debugger.xml
new file mode 100644
index 00000000..86bfdd93
--- /dev/null
+++ b/modules/cidr/src/main/resources/META-INF/zigbrains-debugger.xml
@@ -0,0 +1,60 @@
+
+ com.intellij.modules.cidr.debugger
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/cidr/src/main/resources/zigbrains/debugger/Bundle.properties b/modules/cidr/src/main/resources/zigbrains/debugger/Bundle.properties
new file mode 100644
index 00000000..43918aef
--- /dev/null
+++ b/modules/cidr/src/main/resources/zigbrains/debugger/Bundle.properties
@@ -0,0 +1,43 @@
+dialog.title.download.debugger=Download Debugger
+notification.nativedebug.title=Zig native debugger
+notification.nativedebug.text=You need to install the "Native Debugging Support" plugin for Zig debugging in this IDE!
+notification.nativedebug.market=Install from Marketplace
+notification.nativedebug.browser=Open in Browser
+notification.title.debugger=Debugger
+notification.content.debugger.successfully.downloaded=Debugger successfully downloaded
+notification.content.debugger.downloading.failed=Debugger downloading failed
+notification.content.debugger.metadata.downloading.failed=Debugger metadata downloading failed, switching to fallback
+notification.content.debugger.metadata.fallback.fetch.failed=Debugger fallback metadata fetch failed
+notification.content.debugger.metadata.fallback.parse.failed=Debugger fallback metadata parse failed
+settings.debugger.toolchain.download.debugger.automatically.checkbox=Download and update the debugger automatically
+settings.debugger.title=Zig
+settings.debugger.toolchain.debugger.label=Debugger:
+settings.debugger.toolchain.download.comment=Need to be downloaded
+settings.debugger.toolchain.update.comment=Need to be updated
+settings.debugger.toolchain.use.clion.toolchains=Use Clion toolchains instead
+notification.content.debugger.need.download=You need to download/update the debugger before you can run debugging! (Settings | Build, Execution, Deployment | Debugging -> Zig)
+debugger.run.unavailable=Unable to Run Debugger
+debugger.run.unavailable.reason.download=Debugger is not downloaded yet
+debugger.run.unavailable.reason.download.button=Download
+debugger.run.unavailable.reason.update=Debugger is outdated
+debugger.run.unavailable.reason.update.button=Update
+debug.build.compile.failed.boilerplate={0}\nPlease edit this intellij build configuration and specify the path of the executable created by "zig build" directly!
+debug.base.compile.failed.generic=Failed to compile executable
+debug.base.compile.failed.no-exe=Failed to find compiled binary
+debug.build.compile.failed.multiple-exe=Multiple compiled binaries found
+debug.build.compile.failed.no-workdir=Cannot find working directory to run debugged executable
+debug.build.compile.failed.autodetect=Could not auto-detect default executable output directory "zig-out/bin"
+debug.build.compile.failed.no-file=File `{0}` does not exist
+debug.build.compile.failed.non-exec-file=File `{0}` is not executable
+debug.build.compile.failed.generic=Failed to build project
+exec.type.binary.label=Zig-compiled native executable
+exec.option.label.binary.exe-path=Executable program path (not the zig compiler)
+exec.option.label.binary.args=Command line arguments
+exception.missing-exe-path=Missing executable path
+configuration.binary.name=Native Application (Zig)
+configuration.binary.suggested-name=Executable
+configuration.binary.description=Binary executable compiled from zig code (useful for debugging on Windows)
+msvc.consent.title=Network Request Consent
+msvc.consent.deny=Use Bundled
+msvc.consent.allow=Download
+msvc.consent.body=Debugging on Windows requires downloading extra metadata from the internet.\nThe bundled fallback metadata will be used if the request is denied.
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/direnv/DirenvCmd.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/direnv/DirenvCmd.kt
index 0a142733..0aa48b15 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/direnv/DirenvCmd.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/direnv/DirenvCmd.kt
@@ -32,6 +32,7 @@ import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.progress.runBlockingCancellable
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.guessProjectDir
+import com.intellij.platform.util.progress.withProgressText
import com.intellij.util.io.awaitExit
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.sync.withLock
@@ -72,12 +73,14 @@ object DirenvCmd {
private suspend fun run(project: Project, workDir: Path, vararg args: String): DirenvOutput {
val cli = GeneralCommandLine("direnv", *args).withWorkingDirectory(workDir)
- val process: Process
- val exitCode: Int
-
- project.direnvService.mutex.withLock {
- process = cli.createProcess()
- exitCode = process.awaitExit()
+ val (process, exitCode) = withProgressText("Running ${cli.commandLineString}") {
+ withContext(Dispatchers.IO) {
+ project.direnvService.mutex.withLock {
+ val process = cli.createProcess()
+ val exitCode = process.awaitExit()
+ process to exitCode
+ }
+ }
}
if (exitCode != 0) {
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZLSStreamConnectionProvider.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZLSStreamConnectionProvider.kt
index 466a4bf9..b73433ca 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZLSStreamConnectionProvider.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZLSStreamConnectionProvider.kt
@@ -80,30 +80,6 @@ class ZLSStreamConnectionProvider private constructor(private val project: Proje
return ZLSStreamConnectionProvider(project, commandLine)
}
- suspend fun validate(project: Project): Boolean {
- val svc = project.zlsSettings
- val state = svc.state
- val zlsPath: Path = state.zlsPath.let { zlsPath ->
- if (zlsPath.isEmpty()) {
- val env = if (state.direnv) project.getDirenv() else emptyEnv
- env.findExecutableOnPATH("zls") ?: run {
- return false
- }
- } else {
- zlsPath.toNioPathOrNull() ?: run {
- return false
- }
- }
- }
- if (zlsPath.notExists()) {
- return false
- }
- if (!zlsPath.isRegularFile() || !zlsPath.isExecutable()) {
- return false
- }
- return true
- }
-
@OptIn(ExperimentalSerializationApi::class)
suspend fun getCommand(project: Project): List? {
val svc = project.zlsSettings
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZigLanguageServerFactory.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZigLanguageServerFactory.kt
index 0f639125..7e648348 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZigLanguageServerFactory.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/ZigLanguageServerFactory.kt
@@ -22,6 +22,7 @@
package com.falsepattern.zigbrains.lsp
+import com.falsepattern.zigbrains.lsp.settings.zlsSettings
import com.falsepattern.zigbrains.shared.zigCoroutineScope
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
@@ -51,19 +52,11 @@ class ZigLanguageServerFactory: LanguageServerFactory, LanguageServerEnablementS
}
override fun isEnabled(project: Project): Boolean {
- return (project.getUserData(ENABLED_KEY) ?: true) && if (application.isDispatchThread) {
- runWithModalProgressBlocking(ModalTaskOwner.project(project), ZLSBundle.message("progress.title.validate")) {
- ZLSStreamConnectionProvider.validate(project)
- }
- } else {
- runBlocking {
- ZLSStreamConnectionProvider.validate(project)
- }
- }
+ return (project.getUserData(ENABLED_KEY) ?: true) && project.zlsSettings.validate()
}
override fun setEnabled(enabled: Boolean, project: Project) {
- project.putUserData(ENABLED_KEY, true)
+ project.putUserData(ENABLED_KEY, enabled)
}
}
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSProjectSettingsService.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSProjectSettingsService.kt
index 1c8eaf22..d52f8674 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSProjectSettingsService.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSProjectSettingsService.kt
@@ -22,32 +22,101 @@
package com.falsepattern.zigbrains.lsp.settings
+import com.falsepattern.zigbrains.direnv.emptyEnv
+import com.falsepattern.zigbrains.direnv.getDirenv
+import com.falsepattern.zigbrains.lsp.ZLSBundle
+import com.falsepattern.zigbrains.lsp.ZLSStreamConnectionProvider
import com.intellij.openapi.components.*
import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.io.toNioPathOrNull
+import com.intellij.platform.ide.progress.ModalTaskOwner
+import com.intellij.platform.ide.progress.runWithModalProgressBlocking
+import com.intellij.util.application
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.sync.Mutex
+import java.nio.file.Path
+import java.util.concurrent.locks.ReentrantLock
+import kotlin.concurrent.withLock
+import kotlin.io.path.isExecutable
+import kotlin.io.path.isRegularFile
+import kotlin.io.path.notExists
@Service(Service.Level.PROJECT)
@State(
name = "ZLSSettings",
storages = [Storage(value = "zigbrains.xml")]
)
-class ZLSProjectSettingsService: PersistentStateComponent {
+class ZLSProjectSettingsService(val project: Project): PersistentStateComponent {
@Volatile
private var state = ZLSSettings()
+ @Volatile
+ private var dirty = true
+ @Volatile
+ private var valid = false
+
+ private val mutex = ReentrantLock()
override fun getState(): ZLSSettings {
return state.copy()
}
fun setState(value: ZLSSettings) {
- this.state = value
+ mutex.withLock {
+ this.state = value
+ dirty = true
+ }
}
override fun loadState(state: ZLSSettings) {
- this.state = state
+ mutex.withLock {
+ this.state = state
+ dirty = true
+ }
}
fun isModified(otherData: ZLSSettings): Boolean {
return state != otherData
}
+
+ fun validate(): Boolean {
+ mutex.withLock {
+ if (dirty) {
+ val state = this.state
+ valid = if (application.isDispatchThread) {
+ runWithModalProgressBlocking(ModalTaskOwner.project(project), ZLSBundle.message("progress.title.validate")) {
+ doValidate(project, state)
+ }
+ } else {
+ runBlocking {
+ doValidate(project, state)
+ }
+ }
+ dirty = false
+ }
+ return valid
+ }
+ }
+}
+
+private suspend fun doValidate(project: Project, state: ZLSSettings): Boolean {
+ val zlsPath: Path = state.zlsPath.let { zlsPath ->
+ if (zlsPath.isEmpty()) {
+ val env = if (state.direnv) project.getDirenv() else emptyEnv
+ env.findExecutableOnPATH("zls") ?: run {
+ return false
+ }
+ } else {
+ zlsPath.toNioPathOrNull() ?: run {
+ return false
+ }
+ }
+ }
+ if (zlsPath.notExists()) {
+ return false
+ }
+ if (!zlsPath.isRegularFile() || !zlsPath.isExecutable()) {
+ return false
+ }
+ return true
}
val Project.zlsSettings get() = service()
\ No newline at end of file
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsPanel.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsPanel.kt
index 1b9432f9..a50ba0ee 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsPanel.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsPanel.kt
@@ -24,18 +24,26 @@ package com.falsepattern.zigbrains.lsp.settings
import com.falsepattern.zigbrains.direnv.*
import com.falsepattern.zigbrains.lsp.ZLSBundle
+import com.falsepattern.zigbrains.shared.coroutine.launchWithEDT
import com.falsepattern.zigbrains.shared.zigCoroutineScope
import com.intellij.openapi.Disposable
+import com.intellij.openapi.application.ModalityState
+import com.intellij.openapi.application.asContextElement
import com.intellij.openapi.components.service
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Disposer
+import com.intellij.platform.ide.progress.ModalTaskOwner
+import com.intellij.platform.ide.progress.TaskCancellation
+import com.intellij.platform.ide.progress.runWithModalProgressBlocking
+import com.intellij.platform.ide.progress.withModalProgress
import com.intellij.ui.components.JBCheckBox
import com.intellij.ui.components.fields.ExtendableTextField
import com.intellij.ui.components.textFieldWithBrowseButton
import com.intellij.ui.dsl.builder.AlignX
import com.intellij.ui.dsl.builder.Panel
import com.intellij.util.application
+import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlin.io.path.pathString
@@ -66,12 +74,14 @@ class ZLSSettingsPanel(private val project: Project?) : Disposable {
group(ZLSBundle.message("settings.group.title")) {
row(ZLSBundle.message("settings.zls-path.label")) {
cell(zlsPath).resizableColumn().align(AlignX.FILL)
- if (DirenvCmd.direnvInstalled() && project != null) {
+ if (DirenvCmd.direnvInstalled() && project != null && !project.isDefault) {
cell(direnv)
}
button(ZLSBundle.message("settings.zls-path.autodetect.label")) {
- project.zigCoroutineScope.launch {
- autodetect()
+ project.zigCoroutineScope.launchWithEDT {
+ withModalProgress(ModalTaskOwner.component(zlsPath), "Detecting ZLS...", TaskCancellation.cancellable()) {
+ autodetect()
+ }
}
}
}
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigExecConfig.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigExecConfig.kt
index 20ba08db..38bec30e 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigExecConfig.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigExecConfig.kt
@@ -25,6 +25,7 @@ package com.falsepattern.zigbrains.project.execution.base
import com.falsepattern.zigbrains.ZigBrainsBundle
import com.falsepattern.zigbrains.direnv.DirenvCmd
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
+import com.intellij.execution.ExecutionException
import com.intellij.execution.Executor
import com.intellij.execution.configurations.ConfigurationFactory
import com.intellij.execution.configurations.GeneralCommandLine
@@ -37,8 +38,9 @@ import com.intellij.openapi.project.guessProjectDir
import com.intellij.openapi.util.NlsActions.ActionText
import com.intellij.openapi.vfs.toNioPathOrNull
import org.jdom.Element
+import org.jetbrains.annotations.Nls
-abstract class ZigExecConfig>(project: Project, factory: ConfigurationFactory, name: String): LocatableConfigurationBase>(project, factory, name) {
+abstract class ZigExecConfig>(project: Project, factory: ConfigurationFactory, @Nls name: String): LocatableConfigurationBase>(project, factory, name) {
var workingDirectory = WorkDirectoryConfigurable("workingDirectory").apply { path = project.guessProjectDir()?.toNioPathOrNull() }
private set
var pty = CheckboxConfigurable("pty", ZigBrainsBundle.message("exec.option.label.emulate-terminal"), false)
@@ -47,6 +49,7 @@ abstract class ZigExecConfig>(project: Project, factory: Con
private set
abstract val suggestedName: @ActionText String
+ @Throws(ExecutionException::class)
abstract suspend fun buildCommandLineArgs(debug: Boolean): List
abstract override fun getState(executor: Executor, environment: ExecutionEnvironment): ZigProfileState
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigProfileState.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigProfileState.kt
index aa679c67..59123175 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigProfileState.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigProfileState.kt
@@ -58,7 +58,7 @@ abstract class ZigProfileState> (
}
@Throws(ExecutionException::class)
- suspend fun getCommandLine(toolchain: AbstractZigToolchain, debug: Boolean): GeneralCommandLine {
+ open suspend fun getCommandLine(toolchain: AbstractZigToolchain, debug: Boolean): GeneralCommandLine {
val workingDir = configuration.workingDirectory
val zigExePath = toolchain.zig.path()
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/build/ZigConfigTypeBuild.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/build/ZigConfigTypeBuild.kt
index 3e01a0b6..ac5c41f1 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/build/ZigConfigTypeBuild.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/build/ZigConfigTypeBuild.kt
@@ -36,10 +36,10 @@ class ZigConfigTypeBuild : ConfigurationTypeBase(
Icons.ZIG
) {
init {
- addFactory(ConfigFactoryRun())
+ addFactory(ConfigFactoryRun(this))
}
- inner class ConfigFactoryRun: ConfigurationFactory(this@ZigConfigTypeBuild) {
+ class ConfigFactoryRun(type: ZigConfigTypeBuild): ConfigurationFactory(type) {
override fun createTemplateConfiguration(project: Project): RunConfiguration {
return ZigExecConfigBuild(project, this)
}
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/build/ZigExecConfigBuild.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/build/ZigExecConfigBuild.kt
index cf86b9b3..792f73c0 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/build/ZigExecConfigBuild.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/build/ZigExecConfigBuild.kt
@@ -32,7 +32,7 @@ import com.intellij.execution.configurations.ConfigurationFactory
import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.openapi.project.Project
-class ZigExecConfigBuild(project: Project, factory: ConfigurationFactory): ZigExecConfig(project, factory, "Zig Run") {
+class ZigExecConfigBuild(project: Project, factory: ConfigurationFactory): ZigExecConfig(project, factory, ZigBrainsBundle.message("exec.type.build.label")) {
var buildSteps = ArgsConfigurable("buildSteps", ZigBrainsBundle.message("exec.option.label.build.steps"))
private set
var extraArgs = ArgsConfigurable("compilerArgs", ZigBrainsBundle.message("exec.option.label.build.args"))
@@ -44,10 +44,11 @@ class ZigExecConfigBuild(project: Project, factory: ConfigurationFactory): ZigEx
var exeArgs = ArgsConfigurable("exeArgs", ZigBrainsBundle.message("exec.option.label.build.exe-args-debug"))
private set
+ @Throws(ExecutionException::class)
override suspend fun buildCommandLineArgs(debug: Boolean): List {
val result = ArrayList()
result.add("build")
- var steps = buildSteps.args
+ val steps = buildSteps.args
if (debug) {
val truncatedSteps = ArrayList()
for (step in steps) {
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/run/ZigConfigTypeRun.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/run/ZigConfigTypeRun.kt
index 4bc1d6c6..bf975e0c 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/run/ZigConfigTypeRun.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/run/ZigConfigTypeRun.kt
@@ -36,10 +36,10 @@ class ZigConfigTypeRun : ConfigurationTypeBase(
Icons.ZIG
) {
init {
- addFactory(ConfigFactoryRun())
+ addFactory(ConfigFactoryRun(this))
}
- inner class ConfigFactoryRun: ConfigurationFactory(this@ZigConfigTypeRun) {
+ class ConfigFactoryRun(type: ZigConfigTypeRun): ConfigurationFactory(type) {
override fun createTemplateConfiguration(project: Project): RunConfiguration {
return ZigExecConfigRun(project, this)
}
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/run/ZigExecConfigRun.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/run/ZigExecConfigRun.kt
index c01bbf6e..5b0862e3 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/run/ZigExecConfigRun.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/run/ZigExecConfigRun.kt
@@ -25,13 +25,14 @@ package com.falsepattern.zigbrains.project.execution.run
import com.falsepattern.zigbrains.ZigBrainsBundle
import com.falsepattern.zigbrains.project.execution.base.*
import com.falsepattern.zigbrains.shared.cli.coloredCliFlags
+import com.intellij.execution.ExecutionException
import com.intellij.execution.Executor
import com.intellij.execution.configurations.ConfigurationFactory
import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.openapi.project.Project
import kotlin.io.path.pathString
-class ZigExecConfigRun(project: Project, factory: ConfigurationFactory): ZigExecConfig(project, factory, "Zig Run") {
+class ZigExecConfigRun(project: Project, factory: ConfigurationFactory): ZigExecConfig(project, factory, ZigBrainsBundle.message("exec.type.run.label")) {
var filePath = FilePathConfigurable("filePath", ZigBrainsBundle.message("exec.option.label.file-path"))
private set
var colored = ColoredConfigurable("colored")
@@ -47,7 +48,7 @@ class ZigExecConfigRun(project: Project, factory: ConfigurationFactory): ZigExec
val result = ArrayList()
result.add(if (debug) "build-exe" else "run")
result.addAll(coloredCliFlags(colored.value, debug))
- result.add(filePath.path?.pathString ?: throw IllegalArgumentException("Empty file path!"))
+ result.add(filePath.path?.pathString ?: throw ExecutionException(ZigBrainsBundle.message("exception.zig.empty-file-path")))
if (!debug || optimization.forced) {
result.addAll(listOf("-O", optimization.level.name))
}
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/test/ZigConfigTypeTest.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/test/ZigConfigTypeTest.kt
index 49d7684e..0bee020f 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/test/ZigConfigTypeTest.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/test/ZigConfigTypeTest.kt
@@ -36,10 +36,10 @@ class ZigConfigTypeTest : ConfigurationTypeBase(
Icons.ZIG
) {
init {
- addFactory(ConfigFactoryRun())
+ addFactory(ConfigFactoryRun(this))
}
- inner class ConfigFactoryRun: ConfigurationFactory(this@ZigConfigTypeTest) {
+ class ConfigFactoryRun(type: ZigConfigTypeTest): ConfigurationFactory(type) {
override fun createTemplateConfiguration(project: Project): RunConfiguration {
return ZigExecConfigTest(project, this)
}
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/test/ZigExecConfigTest.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/test/ZigExecConfigTest.kt
index 576e1bf8..df48ad57 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/test/ZigExecConfigTest.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/test/ZigExecConfigTest.kt
@@ -25,13 +25,14 @@ package com.falsepattern.zigbrains.project.execution.test
import com.falsepattern.zigbrains.ZigBrainsBundle
import com.falsepattern.zigbrains.project.execution.base.*
import com.falsepattern.zigbrains.shared.cli.coloredCliFlags
+import com.intellij.execution.ExecutionException
import com.intellij.execution.Executor
import com.intellij.execution.configurations.ConfigurationFactory
import com.intellij.execution.runners.ExecutionEnvironment
import com.intellij.openapi.project.Project
import kotlin.io.path.pathString
-class ZigExecConfigTest(project: Project, factory: ConfigurationFactory): ZigExecConfig(project, factory, "Zig Run") {
+class ZigExecConfigTest(project: Project, factory: ConfigurationFactory): ZigExecConfig(project, factory, ZigBrainsBundle.message("exec.type.test.label")) {
var filePath = FilePathConfigurable("filePath", ZigBrainsBundle.message("exec.option.label.file-path"))
private set
var colored = ColoredConfigurable("colored")
@@ -41,11 +42,12 @@ class ZigExecConfigTest(project: Project, factory: ConfigurationFactory): ZigExe
var compilerArgs = ArgsConfigurable("compilerArgs", ZigBrainsBundle.message("exec.option.label.compiler-args"))
private set
+ @Throws(ExecutionException::class)
override suspend fun buildCommandLineArgs(debug: Boolean): List {
val result = ArrayList()
result.add(if (debug) "build-exe" else "run")
result.addAll(coloredCliFlags(colored.value, debug))
- result.add(filePath.path?.pathString ?: throw IllegalArgumentException("Empty file path!"))
+ result.add(filePath.path?.pathString ?: throw ExecutionException(ZigBrainsBundle.message("exception.zig.empty-file-path")))
if (!debug || optimization.forced) {
result.addAll(listOf("-O", optimization.level.name))
}
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/module/ZigModuleBuilder.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/module/ZigModuleBuilder.kt
index b1376cef..7e2d2450 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/module/ZigModuleBuilder.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/module/ZigModuleBuilder.kt
@@ -24,6 +24,7 @@ package com.falsepattern.zigbrains.project.module
import com.falsepattern.zigbrains.project.newproject.ZigProjectConfigurationData
import com.falsepattern.zigbrains.project.newproject.ZigProjectGeneratorPeer
+import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
import com.intellij.ide.util.projectWizard.ModuleBuilder
import com.intellij.ide.util.projectWizard.ModuleWizardStep
import com.intellij.ide.util.projectWizard.WizardContext
@@ -61,7 +62,7 @@ class ZigModuleBuilder: ModuleBuilder() {
val root = contentEntry.file ?: return
val config = configurationData ?: return
config.generateProject(this, rootModel.project, root, forceGitignore)
- withContext(Dispatchers.EDT) {
+ withEDTContext {
root.refresh(false, true)
}
}
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/newproject/ZigProjectConfigurationData.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/newproject/ZigProjectConfigurationData.kt
index 27fa1f2b..ef42fb33 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/newproject/ZigProjectConfigurationData.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/newproject/ZigProjectConfigurationData.kt
@@ -28,6 +28,7 @@ import com.falsepattern.zigbrains.project.settings.ZigProjectSettings
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
import com.falsepattern.zigbrains.project.template.ZigInitTemplate
import com.falsepattern.zigbrains.project.template.ZigProjectTemplate
+import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
import com.intellij.notification.Notification
import com.intellij.notification.NotificationType
import com.intellij.openapi.GitRepositoryInitializer
@@ -36,6 +37,7 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.toNioPathOrNull
+import com.intellij.platform.util.progress.withProgressText
import com.intellij.util.ResourceUtil
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@@ -48,7 +50,7 @@ data class ZigProjectConfigurationData(
val selectedTemplate: ZigProjectTemplate
) {
suspend fun generateProject(requestor: Any, project: Project, baseDir: VirtualFile, forceGitignore: Boolean): Boolean {
- withContext(Dispatchers.EDT) {
+ withEDTContext {
project.zigProjectSettings.loadState(projConf)
project.zlsSettings.loadState(zlsConf)
}
@@ -89,7 +91,7 @@ data class ZigProjectConfigurationData(
val (fileName, parentDir) = fileTemplate.key.let {
if (it.contains("/")) {
val slashIndex = it.indexOf("/")
- val parentDir = withContext(Dispatchers.EDT) {
+ val parentDir = withEDTContext {
baseDir.createChildDirectory(requestor, it.substring(0, slashIndex))
}
Pair(it.substring(slashIndex + 1), parentDir)
@@ -101,7 +103,7 @@ data class ZigProjectConfigurationData(
val resourceData = getResourceString("project-gen/$templateDir/$fileName.template")
?.replace("@@PROJECT_NAME@@", projectName)
?: continue
- withContext(Dispatchers.EDT) {
+ withEDTContext {
val targetFile = parentDir.createChildData(requestor, fileName)
VfsUtil.saveText(targetFile, resourceData)
}
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/run/ZigProgramRunner.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/run/ZigProgramRunner.kt
index 737358f7..5f286c75 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/run/ZigProgramRunner.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/run/ZigProgramRunner.kt
@@ -25,7 +25,9 @@ package com.falsepattern.zigbrains.project.run
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
+import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
import com.falsepattern.zigbrains.shared.zigCoroutineScope
+import com.intellij.execution.ExecutionException
import com.intellij.execution.configurations.RunProfileState
import com.intellij.execution.configurations.RunnerSettings
import com.intellij.execution.runners.AsyncProgramRunner
@@ -34,6 +36,13 @@ import com.intellij.execution.ui.RunContentDescriptor
import com.intellij.openapi.application.EDT
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.rd.util.toPromise
+import com.intellij.platform.ide.progress.ModalTaskOwner
+import com.intellij.platform.ide.progress.TaskCancellation
+import com.intellij.platform.ide.progress.withModalProgress
+import com.intellij.platform.util.progress.ProgressReporter
+import com.intellij.platform.util.progress.SequentialProgressReporter
+import com.intellij.platform.util.progress.reportProgress
+import com.intellij.platform.util.progress.withProgressText
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.async
@@ -44,26 +53,35 @@ abstract class ZigProgramRunner>(protected val
@OptIn(ExperimentalCoroutinesApi::class)
override fun execute(environment: ExecutionEnvironment, state: RunProfileState): Promise {
return environment.project.zigCoroutineScope.async {
- executeAsync(environment, state)
+ withModalProgress(ModalTaskOwner.project(environment.project), "Starting zig program...", TaskCancellation.cancellable()) {
+ executeAsync(environment, state)
+ }
}.toPromise()
}
- private suspend inline fun executeAsync(environment: ExecutionEnvironment, state: RunProfileState): RunContentDescriptor? {
- if (state !is ZigProfileState<*>)
+ private suspend inline fun executeAsync(environment: ExecutionEnvironment, baseState: RunProfileState): RunContentDescriptor? {
+ if (baseState !is ZigProfileState<*>)
return null
- val state = castProfileState(state) ?: return null
+ val state = castProfileState(baseState) ?: return null
val toolchain = environment.project.zigProjectSettings.state.toolchain ?: return null
- withContext(Dispatchers.EDT) {
- FileDocumentManager.getInstance().saveAllDocuments()
+ return reportProgress { reporter ->
+ reporter.indeterminateStep("Saving all documents") {
+ withEDTContext {
+ FileDocumentManager.getInstance().saveAllDocuments()
+ }
+ }
+ return@reportProgress reporter.indeterminateStep {
+ return@indeterminateStep execute(state, toolchain, environment)
+ }
}
- return execute(state, toolchain, environment)
}
protected abstract fun castProfileState(state: ZigProfileState<*>): ProfileState?
+ @Throws(ExecutionException::class)
abstract suspend fun execute(state: ProfileState, toolchain: AbstractZigToolchain, environment: ExecutionEnvironment): RunContentDescriptor?
}
\ No newline at end of file
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/run/ZigRegularRunner.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/run/ZigRegularRunner.kt
index f2e690bc..9c00194c 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/run/ZigRegularRunner.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/run/ZigRegularRunner.kt
@@ -26,23 +26,23 @@ import com.falsepattern.zigbrains.project.execution.base.ZigExecConfig
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
import com.falsepattern.zigbrains.project.execution.base.executeCommandLine
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
-import com.falsepattern.zigbrains.shared.zigCoroutineScope
+import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
import com.intellij.execution.configurations.RunProfile
import com.intellij.execution.executors.DefaultRunExecutor
import com.intellij.execution.runners.ExecutionEnvironment
-import com.intellij.execution.runners.showRunContent
+import com.intellij.execution.runners.RunContentBuilder
import com.intellij.execution.ui.RunContentDescriptor
import com.intellij.openapi.application.EDT
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class ZigRegularRunner: ZigProgramRunner>(DefaultRunExecutor.EXECUTOR_ID) {
override suspend fun execute(state: ZigProfileState<*>, toolchain: AbstractZigToolchain, environment: ExecutionEnvironment): RunContentDescriptor? {
val cli = state.getCommandLine(toolchain, false)
val exec = executeCommandLine(cli, environment)
- return withContext(Dispatchers.EDT) {
- showRunContent(exec, environment)
+ return withEDTContext {
+ val runContentBuilder = RunContentBuilder(exec, environment)
+ runContentBuilder.showRunContent(null)
}
}
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectSettingsPanel.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectSettingsPanel.kt
index 717d04ad..e3547541 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectSettingsPanel.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectSettingsPanel.kt
@@ -26,6 +26,8 @@ import com.falsepattern.zigbrains.ZigBrainsBundle
import com.falsepattern.zigbrains.direnv.DirenvCmd
import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainProvider
+import com.falsepattern.zigbrains.shared.coroutine.launchWithEDT
+import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
import com.falsepattern.zigbrains.shared.zigCoroutineScope
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.EDT
@@ -35,6 +37,9 @@ import com.intellij.openapi.project.ProjectManager
import com.intellij.openapi.util.Disposer
import com.intellij.openapi.util.UserDataHolderBase
import com.intellij.openapi.util.io.toNioPathOrNull
+import com.intellij.platform.ide.progress.ModalTaskOwner
+import com.intellij.platform.ide.progress.TaskCancellation
+import com.intellij.platform.ide.progress.withModalProgress
import com.intellij.ui.DocumentAdapter
import com.intellij.ui.JBColor
import com.intellij.ui.components.JBCheckBox
@@ -115,8 +120,10 @@ class ZigProjectSettingsPanel(private val project: Project?) : Disposable {
cell(direnv)
}
button(ZigBrainsBundle.message("settings.project.label.toolchain-autodetect")) {
- this@ZigProjectSettingsPanel.project.zigCoroutineScope.launch {
- autodetect()
+ project.zigCoroutineScope.launchWithEDT {
+ withModalProgress(ModalTaskOwner.component(pathToToolchain), "Detecting Zig...", TaskCancellation.cancellable()) {
+ autodetect()
+ }
}
}
}
@@ -146,7 +153,7 @@ class ZigProjectSettingsPanel(private val project: Project?) : Disposable {
val env = zig?.getEnv(project)
val version = env?.version
val stdPath = env?.stdPath(toolchain)
- withContext(Dispatchers.EDT) {
+ withEDTContext {
toolchainVersion.text = version ?: ""
toolchainVersion.foreground = JBColor.foreground()
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/steps/discovery/ZigStepDiscoveryService.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/steps/discovery/ZigStepDiscoveryService.kt
index 59b8179a..82499ac6 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/steps/discovery/ZigStepDiscoveryService.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/steps/discovery/ZigStepDiscoveryService.kt
@@ -24,6 +24,7 @@ package com.falsepattern.zigbrains.project.steps.discovery
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
import com.falsepattern.zigbrains.project.steps.discovery.ZigStepDiscoveryListener.ErrorType
+import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
import com.falsepattern.zigbrains.shared.zigCoroutineScope
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.EDT
@@ -120,7 +121,7 @@ class ZigStepDiscoveryService(private val project: Project) {
}
private suspend fun dispatchReload() {
- withContext(Dispatchers.EDT) {
+ withEDTContext {
FileDocumentManager.getInstance().saveAllDocuments()
}
doReload()
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/steps/ui/BuildToolWindowContext.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/steps/ui/BuildToolWindowContext.kt
index 6424712e..8f313c68 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/steps/ui/BuildToolWindowContext.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/steps/ui/BuildToolWindowContext.kt
@@ -29,6 +29,7 @@ import com.falsepattern.zigbrains.project.execution.build.ZigExecConfigBuild
import com.falsepattern.zigbrains.project.execution.firstConfigFactory
import com.falsepattern.zigbrains.project.steps.discovery.ZigStepDiscoveryListener
import com.falsepattern.zigbrains.project.steps.discovery.zigStepDiscovery
+import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
import com.intellij.execution.ProgramRunnerUtil
import com.intellij.execution.RunManager
import com.intellij.execution.RunnerAndConfigurationSettings
@@ -137,7 +138,7 @@ class BuildToolWindowContext(private val project: Project): Disposable {
companion object {
suspend fun create(project: Project, window: ToolWindow) {
- withContext(Dispatchers.EDT) {
+ withEDTContext {
val context = BuildToolWindowContext(project)
Disposer.register(context, project.zigStepDiscovery.register(context.BuildReloadListener()))
Disposer.register(window.disposable, context)
@@ -161,13 +162,13 @@ class BuildToolWindowContext(private val project: Project): Disposable {
}
buildZig.add(DefaultMutableTreeNode(StepNodeDescriptor(project, task, icon, description)))
}
- withContext(Dispatchers.EDT) {
+ withEDTContext {
getViewport(project)?.let { setViewportTree(it) }
}
}
override suspend fun errorReload(type: ZigStepDiscoveryListener.ErrorType, details: String?) {
- withContext(Dispatchers.EDT) {
+ withEDTContext {
getViewport(project)?.setViewportError(ZigBrainsBundle.message(when(type) {
ZigStepDiscoveryListener.ErrorType.MissingToolchain -> "build.tool.window.status.error.missing-toolchain"
ZigStepDiscoveryListener.ErrorType.MissingBuildZig -> "build.tool.window.status.error.missing-build-zig"
@@ -177,7 +178,7 @@ class BuildToolWindowContext(private val project: Project): Disposable {
}
override suspend fun timeoutReload(seconds: Int) {
- withContext(Dispatchers.EDT) {
+ withEDTContext {
getViewport(project)?.setViewportError(ZigBrainsBundle.message("build.tool.window.status.timeout", seconds), null)
}
}
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/LocalZigToolchain.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/LocalZigToolchain.kt
index 111876ec..b8d276d8 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/LocalZigToolchain.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/LocalZigToolchain.kt
@@ -24,6 +24,7 @@ package com.falsepattern.zigbrains.project.toolchain
import com.falsepattern.zigbrains.direnv.DirenvCmd
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
+import com.intellij.execution.ExecutionException
import com.intellij.execution.configurations.GeneralCommandLine
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.guessProjectDir
@@ -52,5 +53,15 @@ class LocalZigToolchain(val location: Path): AbstractZigToolchain() {
companion object {
val DIRENV_KEY = KeyWithDefaultValue.create("ZIG_LOCAL_DIRENV")
+
+ @Throws(ExecutionException::class)
+ fun ensureLocal(toolchain: AbstractZigToolchain): LocalZigToolchain {
+ if (toolchain is LocalZigToolchain) {
+ return toolchain
+ } else {
+ // TODO
+ throw ExecutionException("The debugger only supports local zig toolchain")
+ }
+ }
}
}
\ No newline at end of file
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/tools/ZigTool.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/tools/ZigTool.kt
index 6271f29a..133dbcb6 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/tools/ZigTool.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/project/toolchain/tools/ZigTool.kt
@@ -26,7 +26,9 @@ import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
import com.intellij.execution.configurations.GeneralCommandLine
import com.intellij.execution.process.ProcessOutput
import com.intellij.util.io.awaitExit
+import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runInterruptible
+import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull
import java.nio.file.Path
@@ -34,10 +36,14 @@ abstract class ZigTool(val toolchain: AbstractZigToolchain) {
abstract val toolName: String
suspend fun callWithArgs(workingDirectory: Path?, vararg parameters: String, timeoutMillis: Long = Long.MAX_VALUE): ProcessOutput {
- val process = createBaseCommandLine(workingDirectory, *parameters).createProcess()
+ val cli = createBaseCommandLine(workingDirectory, *parameters)
- val exitCode = withTimeoutOrNull(timeoutMillis) {
- process.awaitExit()
+ val (process, exitCode) = withContext(Dispatchers.IO) {
+ val process = cli.createProcess()
+ val exit = withTimeoutOrNull(timeoutMillis) {
+ process.awaitExit()
+ }
+ process to exit
}
return runInterruptible {
ProcessOutput(
@@ -50,8 +56,10 @@ abstract class ZigTool(val toolchain: AbstractZigToolchain) {
}
}
- private suspend fun createBaseCommandLine(workingDirectory: Path?,
- vararg parameters: String): GeneralCommandLine {
+ private suspend fun createBaseCommandLine(
+ workingDirectory: Path?,
+ vararg parameters: String
+ ): GeneralCommandLine {
val cli = GeneralCommandLine()
.withExePath(toolchain.pathToExecutable(toolName).toString())
.withWorkDirectory(workingDirectory?.toString())
diff --git a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/shared/coroutine/CoroutinesUtil.kt b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/shared/coroutine/CoroutinesUtil.kt
index 618637c7..ad21a6f6 100644
--- a/modules/core/src/main/kotlin/com/falsepattern/zigbrains/shared/coroutine/CoroutinesUtil.kt
+++ b/modules/core/src/main/kotlin/com/falsepattern/zigbrains/shared/coroutine/CoroutinesUtil.kt
@@ -22,13 +22,17 @@
package com.falsepattern.zigbrains.shared.coroutine
+import com.intellij.openapi.application.EDT
+import com.intellij.openapi.application.ModalityState
+import com.intellij.openapi.application.asContextElement
import com.intellij.platform.ide.progress.ModalTaskOwner
import com.intellij.platform.ide.progress.TaskCancellation
import com.intellij.platform.ide.progress.runWithModalProgressBlocking
+import com.intellij.platform.ide.progress.withModalProgress
+import com.intellij.platform.util.progress.withProgressText
import com.intellij.util.SuspendingLazy
import com.intellij.util.application
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.*
inline fun runModalOrBlocking(taskOwnerFactory: () -> ModalTaskOwner, titleFactory: () -> String, cancellationFactory: () -> TaskCancellation = TaskCancellation::cancellable, noinline action: suspend CoroutineScope.() -> T): T {
return if (application.isDispatchThread) {
@@ -46,4 +50,16 @@ inline fun SuspendingLazy.getOrAwaitModalOrBlocking(taskOwnerFactory: ()
getValue()
}
}
+}
+
+suspend inline fun withEDTContext(state: ModalityState = ModalityState.defaultModalityState(), noinline block: suspend CoroutineScope.() -> T): T {
+ return withContext(Dispatchers.EDT + state.asContextElement(), block = block)
+}
+
+suspend inline fun runInterruptibleEDT(state: ModalityState = ModalityState.defaultModalityState(), noinline targetAction: () -> T): T {
+ return runInterruptible(Dispatchers.EDT + state.asContextElement(), block = targetAction)
+}
+
+fun CoroutineScope.launchWithEDT(state: ModalityState = ModalityState.defaultModalityState(), block: suspend CoroutineScope.() -> Unit) {
+ launch(Dispatchers.EDT + state.asContextElement(), block = block)
}
\ No newline at end of file
diff --git a/modules/core/src/main/resources/zigbrains/Bundle.properties b/modules/core/src/main/resources/zigbrains/Bundle.properties
index f8809b62..0faa0150 100644
--- a/modules/core/src/main/resources/zigbrains/Bundle.properties
+++ b/modules/core/src/main/resources/zigbrains/Bundle.properties
@@ -71,6 +71,9 @@ notification.content.native-debug.browser=Open in Browser
dialog.title.working-directory=Select Working Directory
dialog.title.zig-toolchain=Path to the Zig Toolchain
dialog.title.zig-std=Path to the Standard Library
+exec.type.run.label=Zig Run
+exec.type.test.label=Zig Test
+exec.type.build.label=Zig Build
exec.option.label.working-directory=&Working directory:
exec.option.label.colored-terminal=Colored terminal
exec.option.label.direnv=Use direnv
@@ -84,6 +87,7 @@ exec.option.label.build.steps=Build steps
exec.option.label.build.args=Extra command line arguments
exec.option.label.build.exe-args-debug=Output program command line arguments (debug only)
exec.option.label.build.exe-path-debug=Output executable created by the build (debug only, autodetect if empty)
+exception.zig.empty-file-path=Empty file path
exception.translate-command-line.unbalanced-quotes=Unbalanced quotes in {0}
exception.zig-profile-state.start-process.no-toolchain=Failed to get zig toolchain from project
exception.zig-build.debug.test-not-supported=Debugging "zig build test" is not yet supported
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 0d1e0c3c..066b7da9 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -3,7 +3,7 @@ plugins {
}
rootProject.name = "ZigBrains"
-for (module in arrayOf("core")) {
+for (module in arrayOf("core", "cidr")) {
include(module)
project(":$module").projectDir = file("modules/$module")
}
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index f9140bda..f011c137 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -5,6 +5,7 @@
com.intellij.modules.platform
com.redhat.devtools.lsp4ij
+ com.intellij.modules.cidr.debugger
zigbrains.Bundle
@@ -24,5 +25,10 @@
dynamic="true"
name="featureProvider"
/>
+
\ No newline at end of file