Debugging and some coroutine fixes here and there
This commit is contained in:
parent
a7e3f3e161
commit
3b628467f7
68 changed files with 2866 additions and 102 deletions
|
@ -1,6 +1,9 @@
|
||||||
|
import nl.adaptivity.xmlutil.core.impl.multiplatform.name
|
||||||
import org.jetbrains.changelog.Changelog
|
import org.jetbrains.changelog.Changelog
|
||||||
import org.jetbrains.changelog.markdownToHTML
|
import org.jetbrains.changelog.markdownToHTML
|
||||||
import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType
|
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
|
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
|
@ -14,6 +17,7 @@ plugins {
|
||||||
|
|
||||||
val javaVersion = property("javaVersion").toString().toInt()
|
val javaVersion = property("javaVersion").toString().toInt()
|
||||||
val lsp4ijVersion: String by project
|
val lsp4ijVersion: String by project
|
||||||
|
val runIdeTarget: String by project
|
||||||
val lsp4ijNightly = property("lsp4ijNightly").toString().toBoolean()
|
val lsp4ijNightly = property("lsp4ijNightly").toString().toBoolean()
|
||||||
val lsp4ijPluginString = "com.redhat.devtools.lsp4ij:$lsp4ijVersion${if (lsp4ijNightly) "@nightly" else ""}"
|
val lsp4ijPluginString = "com.redhat.devtools.lsp4ij:$lsp4ijVersion${if (lsp4ijNightly) "@nightly" else ""}"
|
||||||
|
|
||||||
|
@ -74,7 +78,10 @@ allprojects {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
intellijPlatform {
|
intellijPlatform {
|
||||||
create(IntelliJPlatformType.IntellijIdeaCommunity, providers.gradleProperty("ideaCommunityVersion"))
|
when(runIdeTarget) {
|
||||||
|
"ideaCommunity" -> create(IntelliJPlatformType.IntellijIdeaCommunity, providers.gradleProperty("ideaCommunityVersion"))
|
||||||
|
"clion" -> create(IntelliJPlatformType.CLion, providers.gradleProperty("clionVersion"))
|
||||||
|
}
|
||||||
|
|
||||||
pluginVerifier()
|
pluginVerifier()
|
||||||
zipSigner()
|
zipSigner()
|
||||||
|
@ -82,6 +89,7 @@ dependencies {
|
||||||
}
|
}
|
||||||
|
|
||||||
implementation(project(":core"))
|
implementation(project(":core"))
|
||||||
|
implementation(project(":cidr"))
|
||||||
}
|
}
|
||||||
|
|
||||||
intellijPlatform {
|
intellijPlatform {
|
||||||
|
|
|
@ -1,19 +1,22 @@
|
||||||
pluginName = ZigBrains
|
pluginName=ZigBrains
|
||||||
pluginRepositoryUrl = https://github.com/FalsePattern/ZigBrains
|
pluginRepositoryUrl=https://github.com/FalsePattern/ZigBrains
|
||||||
|
|
||||||
pluginVersion = 20.0.0-dev
|
pluginVersion=20.0.0-dev
|
||||||
|
|
||||||
pluginSinceBuild = 242
|
pluginSinceBuild=242
|
||||||
pluginUntilBuild =
|
pluginUntilBuild=
|
||||||
|
|
||||||
ideaCommunityVersion = 2024.2.4
|
ideaCommunityVersion=2024.2.4
|
||||||
|
clionVersion=2024.2.3
|
||||||
javaVersion=21
|
javaVersion=21
|
||||||
|
# ideaCommunity / clion
|
||||||
|
runIdeTarget=clion
|
||||||
|
|
||||||
lsp4jVersion=0.21.1
|
lsp4jVersion=0.21.1
|
||||||
lsp4ijVersion=0.7.0
|
lsp4ijVersion=0.7.0
|
||||||
lsp4ijNightly=false
|
lsp4ijNightly=false
|
||||||
|
|
||||||
kotlin.stdlib.default.dependency = false
|
kotlin.stdlib.default.dependency=false
|
||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
org.gradle.configuration-cache = true
|
org.gradle.configuration-cache=true
|
||||||
org.gradle.caching = true
|
org.gradle.caching=true
|
16
modules/cidr/build.gradle.kts
Normal file
16
modules/cidr/build.gradle.kts
Normal file
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<ZigDebuggerDriverConfigurationProvider>("com.falsepattern.zigbrains.debuggerDriverProvider")
|
||||||
|
}
|
||||||
|
suspend fun <T> getDebuggerConfiguration(project: Project, isElevated: Boolean, emulateTerminal: Boolean, klass: Class<T>): T?
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.falsepattern.zigbrains.debugger
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.shared.ZBFeatures
|
||||||
|
|
||||||
|
class DebuggerFeatures: ZBFeatures {
|
||||||
|
override fun getDebug(): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.falsepattern.zigbrains.debugger
|
||||||
|
|
||||||
|
import com.jetbrains.cidr.execution.debugger.CidrDebuggerEditorsExtensionBase
|
||||||
|
|
||||||
|
class ZigDebuggerEditorsExtension: CidrDebuggerEditorsExtensionBase() {
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.falsepattern.zigbrains.debugger
|
||||||
|
|
||||||
|
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriver.DebuggerLanguage
|
||||||
|
|
||||||
|
object ZigDebuggerLanguage: DebuggerLanguage {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "Zig"
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<DebuggerDriver.DebuggerLanguage> {
|
||||||
|
return setOf(ZigDebuggerLanguage)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createEditor(profile: RunProfile?): XDebuggerEditorsProvider? {
|
||||||
|
if (profile !is ZigExecConfig<*>)
|
||||||
|
return null
|
||||||
|
return createEditorProvider()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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 <T> getDebuggerConfiguration(project: Project, isElevated: Boolean, emulateTerminal: Boolean, klass: Class<T>): 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
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<FileType> {
|
||||||
|
return setOf(ZigFileType)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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)
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<LLValue>): CompletableFuture<List<LLValue>> {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<LLValue, String>): String {
|
||||||
|
return cast(pair.second, pair.first?.type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun customizeInitializeArguments(initArgs: InitializeRequestArguments)
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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"
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<ZigExecConfigBinary>(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<String> {
|
||||||
|
return args.args
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getConfigurables(): List<ZigConfigurable<*>> {
|
||||||
|
return super.getConfigurables() + listOf(exePath, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getState(executor: Executor, environment: ExecutionEnvironment): ZigProfileState<ZigExecConfigBinary> {
|
||||||
|
return ZigProfileStateBinary(environment, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clone(): ZigExecConfigBinary {
|
||||||
|
val clone = super.clone()
|
||||||
|
clone.exePath = exePath.clone()
|
||||||
|
clone.args = args.clone()
|
||||||
|
return clone
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<ZigExecConfigBinary>(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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.falsepattern.zigbrains.debugger.runner.base
|
||||||
|
|
||||||
|
import com.intellij.execution.ExecutionException
|
||||||
|
|
||||||
|
interface PreLaunchAware {
|
||||||
|
@Throws(ExecutionException::class)
|
||||||
|
suspend fun preLaunch(listener: PreLaunchProcessListener)
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<ProfileState: ZigProfileState<*>>(
|
||||||
|
private val profileState: ProfileState,
|
||||||
|
private val toolchain: AbstractZigToolchain,
|
||||||
|
private val executableFile: File,
|
||||||
|
private val exeArgs: List<String>
|
||||||
|
): 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<ProfileState: ZigProfileState<*>>(
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<ProfileState: ZigProfileState<*>>(
|
||||||
|
driverConfiguration: DebuggerDriverConfiguration,
|
||||||
|
toolchain: AbstractZigToolchain,
|
||||||
|
profileState: ProfileState,
|
||||||
|
) : ZigDebugParametersBase<ProfileState>(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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<ProfileState : ZigProfileState<*>> : ZigProgramRunner<ProfileState>(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<ProfileState>
|
||||||
|
|
||||||
|
private class SharedConsoleBuilder(private val console: ConsoleView) : TextConsoleBuilder() {
|
||||||
|
override fun getConsole(): ConsoleView {
|
||||||
|
return console
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addFilter(filter: Filter) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setViewer(isViewer: Boolean) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<ZigProfileStateBinary>(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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<ZigProfileStateBinary>() {
|
||||||
|
override fun getDebugParameters(
|
||||||
|
state: ZigProfileStateBinary,
|
||||||
|
debuggerDriver: DebuggerDriverConfiguration,
|
||||||
|
toolchain: AbstractZigToolchain
|
||||||
|
): ZigDebugParametersBase<ZigProfileStateBinary> {
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<ZigProfileStateBuild>(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>): 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)))
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<ZigProfileStateBuild>() {
|
||||||
|
override fun getDebugParameters(
|
||||||
|
state: ZigProfileStateBuild,
|
||||||
|
debuggerDriver: DebuggerDriverConfiguration,
|
||||||
|
toolchain: AbstractZigToolchain
|
||||||
|
): ZigDebugParametersBase<ZigProfileStateBuild> {
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<ZigProfileStateRun>(driverConfiguration, toolchain, profileState) {
|
||||||
|
override fun getInstaller(): Installer {
|
||||||
|
return ZigDebugEmitBinaryInstaller(profileState, toolchain, executableFile, profileState.configuration.exeArgs.args)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<ZigProfileStateRun>() {
|
||||||
|
override fun getDebugParameters(
|
||||||
|
state: ZigProfileStateRun,
|
||||||
|
debuggerDriver: DebuggerDriverConfiguration,
|
||||||
|
toolchain: AbstractZigToolchain
|
||||||
|
): ZigDebugParametersBase<ZigProfileStateRun> {
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<ZigProfileStateTest>(driverConfiguration, toolchain, profileState) {
|
||||||
|
override fun getInstaller(): Installer {
|
||||||
|
return ZigDebugEmitBinaryInstaller(profileState, toolchain, executableFile, listOf())
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<ZigProfileStateTest>() {
|
||||||
|
override fun getDebugParameters(
|
||||||
|
state: ZigProfileStateTest,
|
||||||
|
debuggerDriver: DebuggerDriverConfiguration,
|
||||||
|
toolchain: AbstractZigToolchain
|
||||||
|
): ZigDebugParametersBase<ZigProfileStateTest> {
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<ZigDebuggerSettings>, Disposable {
|
||||||
|
private val components = listOf<ZigDebuggerUiComponent>(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() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<ZigDebuggerSettings>("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<Configurable> {
|
||||||
|
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"
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<DebuggerKind> {
|
||||||
|
val toolchainService = zigDebuggerToolchainService
|
||||||
|
val availableKinds = DebuggerKind.entries.filter { toolchainService.debuggerAvailability(it) !is DebuggerAvailability.Unavailable }
|
||||||
|
return DefaultComboBoxModel(availableKinds.toTypedArray()).also { it.selectedItem = ZigDebuggerSettings.instance.debuggerKind }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<ZigDebuggerSettings>, Disposable {
|
||||||
|
fun buildUi(panel: Panel)
|
||||||
|
|
||||||
|
override fun getComponent(): JComponent {
|
||||||
|
return panel {
|
||||||
|
buildUi(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.falsepattern.zigbrains.debugger.toolchain
|
||||||
|
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
sealed class DebuggerAvailability<out T> {
|
||||||
|
data object Unavailable: DebuggerAvailability<Nothing>()
|
||||||
|
data object NeedToDownload: DebuggerAvailability<Nothing>()
|
||||||
|
data object NeedToUpdate: DebuggerAvailability<Nothing>()
|
||||||
|
data object Bundled: DebuggerAvailability<Nothing>()
|
||||||
|
data class Binaries<T> (val binaries: T): DebuggerAvailability<T>()
|
||||||
|
}
|
||||||
|
|
||||||
|
data class LLDBBinaries(val frameworkFile: Path, val frontendFile: Path)
|
||||||
|
data class GDBBinaries(val gdbFile: Path)
|
||||||
|
data class MSVCBinaries(val msvcFile: Path)
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<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
|
||||||
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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<LLDBBinaries> {
|
||||||
|
// 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<GDBBinaries> {
|
||||||
|
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<MSVCBinaries> {
|
||||||
|
// 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<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<DownloadableDebuggerBinary>) {
|
||||||
|
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<URL, URL>? {
|
||||||
|
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<ZigDebuggerToolchainService>()
|
||||||
|
|
||||||
|
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<ZigDebuggerToolchainService>()
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
<idea-plugin package="com.falsepattern.zigbrains.debugger">
|
||||||
|
<depends>com.intellij.modules.cidr.debugger</depends>
|
||||||
|
|
||||||
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
|
<configurationType
|
||||||
|
implementation="com.falsepattern.zigbrains.debugger.execution.binary.ZigConfigTypeBinary"
|
||||||
|
/>
|
||||||
|
<programRunner
|
||||||
|
id="ZigDebugRunnerRun"
|
||||||
|
implementation="com.falsepattern.zigbrains.debugger.runner.run.ZigDebugRunnerRun"
|
||||||
|
/>
|
||||||
|
<programRunner
|
||||||
|
id="ZigDebugRunnerTest"
|
||||||
|
implementation="com.falsepattern.zigbrains.debugger.runner.test.ZigDebugRunnerTest"
|
||||||
|
/>
|
||||||
|
<programRunner
|
||||||
|
id="ZigDebugRunnerBuild"
|
||||||
|
implementation="com.falsepattern.zigbrains.debugger.runner.build.ZigDebugRunnerBuild"
|
||||||
|
/>
|
||||||
|
<programRunner
|
||||||
|
id="ZigDebugRunnerBinary"
|
||||||
|
implementation="com.falsepattern.zigbrains.debugger.runner.binary.ZigDebugRunnerBinary"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<xdebugger.settings
|
||||||
|
implementation="com.falsepattern.zigbrains.debugger.settings.ZigDebuggerSettings"
|
||||||
|
/>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<extensions defaultExtensionNs="com.falsepattern.zigbrains">
|
||||||
|
<featureProvider
|
||||||
|
implementation="com.falsepattern.zigbrains.debugger.DebuggerFeatures"
|
||||||
|
/>
|
||||||
|
<debuggerDriverProvider
|
||||||
|
id="DefaultProvider"
|
||||||
|
implementation="com.falsepattern.zigbrains.debugger.ZigDefaultDebuggerDriverConfigurationProvider"
|
||||||
|
order="last"
|
||||||
|
/>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<extensions defaultExtensionNs="cidr.debugger">
|
||||||
|
<languageSupport
|
||||||
|
language="Zig"
|
||||||
|
implementationClass="com.falsepattern.zigbrains.debugger.ZigDebuggerLanguageSupport"
|
||||||
|
/>
|
||||||
|
<editorsExtension
|
||||||
|
language="Zig"
|
||||||
|
implementationClass="com.falsepattern.zigbrains.debugger.ZigDebuggerEditorsExtension"
|
||||||
|
/>
|
||||||
|
<lineBreakpointFileTypesProvider
|
||||||
|
implementation="com.falsepattern.zigbrains.debugger.ZigLineBreakpointFileTypesProvider"
|
||||||
|
/>
|
||||||
|
<localVariablesFilterHandler
|
||||||
|
implementation="com.falsepattern.zigbrains.debugger.ZigLocalVariablesFilterHandler"
|
||||||
|
/>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<extensionPoints>
|
||||||
|
</extensionPoints>
|
||||||
|
</idea-plugin>
|
|
@ -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 <a>downloaded</a>
|
||||||
|
settings.debugger.toolchain.update.comment=Need to be <a>updated</a>
|
||||||
|
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.
|
|
@ -32,6 +32,7 @@ import com.intellij.openapi.diagnostic.logger
|
||||||
import com.intellij.openapi.progress.runBlockingCancellable
|
import com.intellij.openapi.progress.runBlockingCancellable
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.project.guessProjectDir
|
import com.intellij.openapi.project.guessProjectDir
|
||||||
|
import com.intellij.platform.util.progress.withProgressText
|
||||||
import com.intellij.util.io.awaitExit
|
import com.intellij.util.io.awaitExit
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
@ -72,12 +73,14 @@ object DirenvCmd {
|
||||||
private suspend fun run(project: Project, workDir: Path, vararg args: String): DirenvOutput {
|
private suspend fun run(project: Project, workDir: Path, vararg args: String): DirenvOutput {
|
||||||
val cli = GeneralCommandLine("direnv", *args).withWorkingDirectory(workDir)
|
val cli = GeneralCommandLine("direnv", *args).withWorkingDirectory(workDir)
|
||||||
|
|
||||||
val process: Process
|
val (process, exitCode) = withProgressText("Running ${cli.commandLineString}") {
|
||||||
val exitCode: Int
|
withContext(Dispatchers.IO) {
|
||||||
|
project.direnvService.mutex.withLock {
|
||||||
project.direnvService.mutex.withLock {
|
val process = cli.createProcess()
|
||||||
process = cli.createProcess()
|
val exitCode = process.awaitExit()
|
||||||
exitCode = process.awaitExit()
|
process to exitCode
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exitCode != 0) {
|
if (exitCode != 0) {
|
||||||
|
|
|
@ -80,30 +80,6 @@ class ZLSStreamConnectionProvider private constructor(private val project: Proje
|
||||||
return ZLSStreamConnectionProvider(project, commandLine)
|
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)
|
@OptIn(ExperimentalSerializationApi::class)
|
||||||
suspend fun getCommand(project: Project): List<String>? {
|
suspend fun getCommand(project: Project): List<String>? {
|
||||||
val svc = project.zlsSettings
|
val svc = project.zlsSettings
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.lsp
|
package com.falsepattern.zigbrains.lsp
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.lsp.settings.zlsSettings
|
||||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||||
import com.intellij.openapi.components.service
|
import com.intellij.openapi.components.service
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
@ -51,19 +52,11 @@ class ZigLanguageServerFactory: LanguageServerFactory, LanguageServerEnablementS
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isEnabled(project: Project): Boolean {
|
override fun isEnabled(project: Project): Boolean {
|
||||||
return (project.getUserData(ENABLED_KEY) ?: true) && if (application.isDispatchThread) {
|
return (project.getUserData(ENABLED_KEY) ?: true) && project.zlsSettings.validate()
|
||||||
runWithModalProgressBlocking(ModalTaskOwner.project(project), ZLSBundle.message("progress.title.validate")) {
|
|
||||||
ZLSStreamConnectionProvider.validate(project)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
runBlocking {
|
|
||||||
ZLSStreamConnectionProvider.validate(project)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setEnabled(enabled: Boolean, project: Project) {
|
override fun setEnabled(enabled: Boolean, project: Project) {
|
||||||
project.putUserData(ENABLED_KEY, true)
|
project.putUserData(ENABLED_KEY, enabled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,32 +22,101 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.lsp.settings
|
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.components.*
|
||||||
import com.intellij.openapi.project.Project
|
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)
|
@Service(Service.Level.PROJECT)
|
||||||
@State(
|
@State(
|
||||||
name = "ZLSSettings",
|
name = "ZLSSettings",
|
||||||
storages = [Storage(value = "zigbrains.xml")]
|
storages = [Storage(value = "zigbrains.xml")]
|
||||||
)
|
)
|
||||||
class ZLSProjectSettingsService: PersistentStateComponent<ZLSSettings> {
|
class ZLSProjectSettingsService(val project: Project): PersistentStateComponent<ZLSSettings> {
|
||||||
@Volatile
|
@Volatile
|
||||||
private var state = ZLSSettings()
|
private var state = ZLSSettings()
|
||||||
|
@Volatile
|
||||||
|
private var dirty = true
|
||||||
|
@Volatile
|
||||||
|
private var valid = false
|
||||||
|
|
||||||
|
private val mutex = ReentrantLock()
|
||||||
override fun getState(): ZLSSettings {
|
override fun getState(): ZLSSettings {
|
||||||
return state.copy()
|
return state.copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setState(value: ZLSSettings) {
|
fun setState(value: ZLSSettings) {
|
||||||
this.state = value
|
mutex.withLock {
|
||||||
|
this.state = value
|
||||||
|
dirty = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadState(state: ZLSSettings) {
|
override fun loadState(state: ZLSSettings) {
|
||||||
this.state = state
|
mutex.withLock {
|
||||||
|
this.state = state
|
||||||
|
dirty = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isModified(otherData: ZLSSettings): Boolean {
|
fun isModified(otherData: ZLSSettings): Boolean {
|
||||||
return state != otherData
|
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<ZLSProjectSettingsService>()
|
val Project.zlsSettings get() = service<ZLSProjectSettingsService>()
|
|
@ -24,18 +24,26 @@ package com.falsepattern.zigbrains.lsp.settings
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.direnv.*
|
import com.falsepattern.zigbrains.direnv.*
|
||||||
import com.falsepattern.zigbrains.lsp.ZLSBundle
|
import com.falsepattern.zigbrains.lsp.ZLSBundle
|
||||||
|
import com.falsepattern.zigbrains.shared.coroutine.launchWithEDT
|
||||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||||
import com.intellij.openapi.Disposable
|
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.components.service
|
||||||
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
|
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.util.Disposer
|
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.JBCheckBox
|
||||||
import com.intellij.ui.components.fields.ExtendableTextField
|
import com.intellij.ui.components.fields.ExtendableTextField
|
||||||
import com.intellij.ui.components.textFieldWithBrowseButton
|
import com.intellij.ui.components.textFieldWithBrowseButton
|
||||||
import com.intellij.ui.dsl.builder.AlignX
|
import com.intellij.ui.dsl.builder.AlignX
|
||||||
import com.intellij.ui.dsl.builder.Panel
|
import com.intellij.ui.dsl.builder.Panel
|
||||||
import com.intellij.util.application
|
import com.intellij.util.application
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlin.io.path.pathString
|
import kotlin.io.path.pathString
|
||||||
|
|
||||||
|
@ -66,12 +74,14 @@ class ZLSSettingsPanel(private val project: Project?) : Disposable {
|
||||||
group(ZLSBundle.message("settings.group.title")) {
|
group(ZLSBundle.message("settings.group.title")) {
|
||||||
row(ZLSBundle.message("settings.zls-path.label")) {
|
row(ZLSBundle.message("settings.zls-path.label")) {
|
||||||
cell(zlsPath).resizableColumn().align(AlignX.FILL)
|
cell(zlsPath).resizableColumn().align(AlignX.FILL)
|
||||||
if (DirenvCmd.direnvInstalled() && project != null) {
|
if (DirenvCmd.direnvInstalled() && project != null && !project.isDefault) {
|
||||||
cell(direnv)
|
cell(direnv)
|
||||||
}
|
}
|
||||||
button(ZLSBundle.message("settings.zls-path.autodetect.label")) {
|
button(ZLSBundle.message("settings.zls-path.autodetect.label")) {
|
||||||
project.zigCoroutineScope.launch {
|
project.zigCoroutineScope.launchWithEDT {
|
||||||
autodetect()
|
withModalProgress(ModalTaskOwner.component(zlsPath), "Detecting ZLS...", TaskCancellation.cancellable()) {
|
||||||
|
autodetect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ package com.falsepattern.zigbrains.project.execution.base
|
||||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||||
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
||||||
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
|
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
|
||||||
|
import com.intellij.execution.ExecutionException
|
||||||
import com.intellij.execution.Executor
|
import com.intellij.execution.Executor
|
||||||
import com.intellij.execution.configurations.ConfigurationFactory
|
import com.intellij.execution.configurations.ConfigurationFactory
|
||||||
import com.intellij.execution.configurations.GeneralCommandLine
|
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.util.NlsActions.ActionText
|
||||||
import com.intellij.openapi.vfs.toNioPathOrNull
|
import com.intellij.openapi.vfs.toNioPathOrNull
|
||||||
import org.jdom.Element
|
import org.jdom.Element
|
||||||
|
import org.jetbrains.annotations.Nls
|
||||||
|
|
||||||
abstract class ZigExecConfig<T: ZigExecConfig<T>>(project: Project, factory: ConfigurationFactory, name: String): LocatableConfigurationBase<ZigProfileState<T>>(project, factory, name) {
|
abstract class ZigExecConfig<T: ZigExecConfig<T>>(project: Project, factory: ConfigurationFactory, @Nls name: String): LocatableConfigurationBase<ZigProfileState<T>>(project, factory, name) {
|
||||||
var workingDirectory = WorkDirectoryConfigurable("workingDirectory").apply { path = project.guessProjectDir()?.toNioPathOrNull() }
|
var workingDirectory = WorkDirectoryConfigurable("workingDirectory").apply { path = project.guessProjectDir()?.toNioPathOrNull() }
|
||||||
private set
|
private set
|
||||||
var pty = CheckboxConfigurable("pty", ZigBrainsBundle.message("exec.option.label.emulate-terminal"), false)
|
var pty = CheckboxConfigurable("pty", ZigBrainsBundle.message("exec.option.label.emulate-terminal"), false)
|
||||||
|
@ -47,6 +49,7 @@ abstract class ZigExecConfig<T: ZigExecConfig<T>>(project: Project, factory: Con
|
||||||
private set
|
private set
|
||||||
|
|
||||||
abstract val suggestedName: @ActionText String
|
abstract val suggestedName: @ActionText String
|
||||||
|
@Throws(ExecutionException::class)
|
||||||
abstract suspend fun buildCommandLineArgs(debug: Boolean): List<String>
|
abstract suspend fun buildCommandLineArgs(debug: Boolean): List<String>
|
||||||
abstract override fun getState(executor: Executor, environment: ExecutionEnvironment): ZigProfileState<T>
|
abstract override fun getState(executor: Executor, environment: ExecutionEnvironment): ZigProfileState<T>
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ abstract class ZigProfileState<T: ZigExecConfig<T>> (
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(ExecutionException::class)
|
@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 workingDir = configuration.workingDirectory
|
||||||
val zigExePath = toolchain.zig.path()
|
val zigExePath = toolchain.zig.path()
|
||||||
|
|
||||||
|
|
|
@ -36,10 +36,10 @@ class ZigConfigTypeBuild : ConfigurationTypeBase(
|
||||||
Icons.ZIG
|
Icons.ZIG
|
||||||
) {
|
) {
|
||||||
init {
|
init {
|
||||||
addFactory(ConfigFactoryRun())
|
addFactory(ConfigFactoryRun(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ConfigFactoryRun: ConfigurationFactory(this@ZigConfigTypeBuild) {
|
class ConfigFactoryRun(type: ZigConfigTypeBuild): ConfigurationFactory(type) {
|
||||||
override fun createTemplateConfiguration(project: Project): RunConfiguration {
|
override fun createTemplateConfiguration(project: Project): RunConfiguration {
|
||||||
return ZigExecConfigBuild(project, this)
|
return ZigExecConfigBuild(project, this)
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ import com.intellij.execution.configurations.ConfigurationFactory
|
||||||
import com.intellij.execution.runners.ExecutionEnvironment
|
import com.intellij.execution.runners.ExecutionEnvironment
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
|
||||||
class ZigExecConfigBuild(project: Project, factory: ConfigurationFactory): ZigExecConfig<ZigExecConfigBuild>(project, factory, "Zig Run") {
|
class ZigExecConfigBuild(project: Project, factory: ConfigurationFactory): ZigExecConfig<ZigExecConfigBuild>(project, factory, ZigBrainsBundle.message("exec.type.build.label")) {
|
||||||
var buildSteps = ArgsConfigurable("buildSteps", ZigBrainsBundle.message("exec.option.label.build.steps"))
|
var buildSteps = ArgsConfigurable("buildSteps", ZigBrainsBundle.message("exec.option.label.build.steps"))
|
||||||
private set
|
private set
|
||||||
var extraArgs = ArgsConfigurable("compilerArgs", ZigBrainsBundle.message("exec.option.label.build.args"))
|
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"))
|
var exeArgs = ArgsConfigurable("exeArgs", ZigBrainsBundle.message("exec.option.label.build.exe-args-debug"))
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
@Throws(ExecutionException::class)
|
||||||
override suspend fun buildCommandLineArgs(debug: Boolean): List<String> {
|
override suspend fun buildCommandLineArgs(debug: Boolean): List<String> {
|
||||||
val result = ArrayList<String>()
|
val result = ArrayList<String>()
|
||||||
result.add("build")
|
result.add("build")
|
||||||
var steps = buildSteps.args
|
val steps = buildSteps.args
|
||||||
if (debug) {
|
if (debug) {
|
||||||
val truncatedSteps = ArrayList<String>()
|
val truncatedSteps = ArrayList<String>()
|
||||||
for (step in steps) {
|
for (step in steps) {
|
||||||
|
|
|
@ -36,10 +36,10 @@ class ZigConfigTypeRun : ConfigurationTypeBase(
|
||||||
Icons.ZIG
|
Icons.ZIG
|
||||||
) {
|
) {
|
||||||
init {
|
init {
|
||||||
addFactory(ConfigFactoryRun())
|
addFactory(ConfigFactoryRun(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ConfigFactoryRun: ConfigurationFactory(this@ZigConfigTypeRun) {
|
class ConfigFactoryRun(type: ZigConfigTypeRun): ConfigurationFactory(type) {
|
||||||
override fun createTemplateConfiguration(project: Project): RunConfiguration {
|
override fun createTemplateConfiguration(project: Project): RunConfiguration {
|
||||||
return ZigExecConfigRun(project, this)
|
return ZigExecConfigRun(project, this)
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,13 +25,14 @@ package com.falsepattern.zigbrains.project.execution.run
|
||||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||||
import com.falsepattern.zigbrains.project.execution.base.*
|
import com.falsepattern.zigbrains.project.execution.base.*
|
||||||
import com.falsepattern.zigbrains.shared.cli.coloredCliFlags
|
import com.falsepattern.zigbrains.shared.cli.coloredCliFlags
|
||||||
|
import com.intellij.execution.ExecutionException
|
||||||
import com.intellij.execution.Executor
|
import com.intellij.execution.Executor
|
||||||
import com.intellij.execution.configurations.ConfigurationFactory
|
import com.intellij.execution.configurations.ConfigurationFactory
|
||||||
import com.intellij.execution.runners.ExecutionEnvironment
|
import com.intellij.execution.runners.ExecutionEnvironment
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import kotlin.io.path.pathString
|
import kotlin.io.path.pathString
|
||||||
|
|
||||||
class ZigExecConfigRun(project: Project, factory: ConfigurationFactory): ZigExecConfig<ZigExecConfigRun>(project, factory, "Zig Run") {
|
class ZigExecConfigRun(project: Project, factory: ConfigurationFactory): ZigExecConfig<ZigExecConfigRun>(project, factory, ZigBrainsBundle.message("exec.type.run.label")) {
|
||||||
var filePath = FilePathConfigurable("filePath", ZigBrainsBundle.message("exec.option.label.file-path"))
|
var filePath = FilePathConfigurable("filePath", ZigBrainsBundle.message("exec.option.label.file-path"))
|
||||||
private set
|
private set
|
||||||
var colored = ColoredConfigurable("colored")
|
var colored = ColoredConfigurable("colored")
|
||||||
|
@ -47,7 +48,7 @@ class ZigExecConfigRun(project: Project, factory: ConfigurationFactory): ZigExec
|
||||||
val result = ArrayList<String>()
|
val result = ArrayList<String>()
|
||||||
result.add(if (debug) "build-exe" else "run")
|
result.add(if (debug) "build-exe" else "run")
|
||||||
result.addAll(coloredCliFlags(colored.value, debug))
|
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) {
|
if (!debug || optimization.forced) {
|
||||||
result.addAll(listOf("-O", optimization.level.name))
|
result.addAll(listOf("-O", optimization.level.name))
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,10 +36,10 @@ class ZigConfigTypeTest : ConfigurationTypeBase(
|
||||||
Icons.ZIG
|
Icons.ZIG
|
||||||
) {
|
) {
|
||||||
init {
|
init {
|
||||||
addFactory(ConfigFactoryRun())
|
addFactory(ConfigFactoryRun(this))
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class ConfigFactoryRun: ConfigurationFactory(this@ZigConfigTypeTest) {
|
class ConfigFactoryRun(type: ZigConfigTypeTest): ConfigurationFactory(type) {
|
||||||
override fun createTemplateConfiguration(project: Project): RunConfiguration {
|
override fun createTemplateConfiguration(project: Project): RunConfiguration {
|
||||||
return ZigExecConfigTest(project, this)
|
return ZigExecConfigTest(project, this)
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,13 +25,14 @@ package com.falsepattern.zigbrains.project.execution.test
|
||||||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||||
import com.falsepattern.zigbrains.project.execution.base.*
|
import com.falsepattern.zigbrains.project.execution.base.*
|
||||||
import com.falsepattern.zigbrains.shared.cli.coloredCliFlags
|
import com.falsepattern.zigbrains.shared.cli.coloredCliFlags
|
||||||
|
import com.intellij.execution.ExecutionException
|
||||||
import com.intellij.execution.Executor
|
import com.intellij.execution.Executor
|
||||||
import com.intellij.execution.configurations.ConfigurationFactory
|
import com.intellij.execution.configurations.ConfigurationFactory
|
||||||
import com.intellij.execution.runners.ExecutionEnvironment
|
import com.intellij.execution.runners.ExecutionEnvironment
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import kotlin.io.path.pathString
|
import kotlin.io.path.pathString
|
||||||
|
|
||||||
class ZigExecConfigTest(project: Project, factory: ConfigurationFactory): ZigExecConfig<ZigExecConfigTest>(project, factory, "Zig Run") {
|
class ZigExecConfigTest(project: Project, factory: ConfigurationFactory): ZigExecConfig<ZigExecConfigTest>(project, factory, ZigBrainsBundle.message("exec.type.test.label")) {
|
||||||
var filePath = FilePathConfigurable("filePath", ZigBrainsBundle.message("exec.option.label.file-path"))
|
var filePath = FilePathConfigurable("filePath", ZigBrainsBundle.message("exec.option.label.file-path"))
|
||||||
private set
|
private set
|
||||||
var colored = ColoredConfigurable("colored")
|
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"))
|
var compilerArgs = ArgsConfigurable("compilerArgs", ZigBrainsBundle.message("exec.option.label.compiler-args"))
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
@Throws(ExecutionException::class)
|
||||||
override suspend fun buildCommandLineArgs(debug: Boolean): List<String> {
|
override suspend fun buildCommandLineArgs(debug: Boolean): List<String> {
|
||||||
val result = ArrayList<String>()
|
val result = ArrayList<String>()
|
||||||
result.add(if (debug) "build-exe" else "run")
|
result.add(if (debug) "build-exe" else "run")
|
||||||
result.addAll(coloredCliFlags(colored.value, debug))
|
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) {
|
if (!debug || optimization.forced) {
|
||||||
result.addAll(listOf("-O", optimization.level.name))
|
result.addAll(listOf("-O", optimization.level.name))
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ package com.falsepattern.zigbrains.project.module
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.newproject.ZigProjectConfigurationData
|
import com.falsepattern.zigbrains.project.newproject.ZigProjectConfigurationData
|
||||||
import com.falsepattern.zigbrains.project.newproject.ZigProjectGeneratorPeer
|
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.ModuleBuilder
|
||||||
import com.intellij.ide.util.projectWizard.ModuleWizardStep
|
import com.intellij.ide.util.projectWizard.ModuleWizardStep
|
||||||
import com.intellij.ide.util.projectWizard.WizardContext
|
import com.intellij.ide.util.projectWizard.WizardContext
|
||||||
|
@ -61,7 +62,7 @@ class ZigModuleBuilder: ModuleBuilder() {
|
||||||
val root = contentEntry.file ?: return
|
val root = contentEntry.file ?: return
|
||||||
val config = configurationData ?: return
|
val config = configurationData ?: return
|
||||||
config.generateProject(this, rootModel.project, root, forceGitignore)
|
config.generateProject(this, rootModel.project, root, forceGitignore)
|
||||||
withContext(Dispatchers.EDT) {
|
withEDTContext {
|
||||||
root.refresh(false, true)
|
root.refresh(false, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import com.falsepattern.zigbrains.project.settings.ZigProjectSettings
|
||||||
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.ZigInitTemplate
|
||||||
import com.falsepattern.zigbrains.project.template.ZigProjectTemplate
|
import com.falsepattern.zigbrains.project.template.ZigProjectTemplate
|
||||||
|
import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
|
||||||
import com.intellij.notification.Notification
|
import com.intellij.notification.Notification
|
||||||
import com.intellij.notification.NotificationType
|
import com.intellij.notification.NotificationType
|
||||||
import com.intellij.openapi.GitRepositoryInitializer
|
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.VfsUtil
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import com.intellij.openapi.vfs.toNioPathOrNull
|
import com.intellij.openapi.vfs.toNioPathOrNull
|
||||||
|
import com.intellij.platform.util.progress.withProgressText
|
||||||
import com.intellij.util.ResourceUtil
|
import com.intellij.util.ResourceUtil
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
@ -48,7 +50,7 @@ data class ZigProjectConfigurationData(
|
||||||
val selectedTemplate: ZigProjectTemplate
|
val selectedTemplate: ZigProjectTemplate
|
||||||
) {
|
) {
|
||||||
suspend fun generateProject(requestor: Any, project: Project, baseDir: VirtualFile, forceGitignore: Boolean): Boolean {
|
suspend fun generateProject(requestor: Any, project: Project, baseDir: VirtualFile, forceGitignore: Boolean): Boolean {
|
||||||
withContext(Dispatchers.EDT) {
|
withEDTContext {
|
||||||
project.zigProjectSettings.loadState(projConf)
|
project.zigProjectSettings.loadState(projConf)
|
||||||
project.zlsSettings.loadState(zlsConf)
|
project.zlsSettings.loadState(zlsConf)
|
||||||
}
|
}
|
||||||
|
@ -89,7 +91,7 @@ data class ZigProjectConfigurationData(
|
||||||
val (fileName, parentDir) = fileTemplate.key.let {
|
val (fileName, parentDir) = fileTemplate.key.let {
|
||||||
if (it.contains("/")) {
|
if (it.contains("/")) {
|
||||||
val slashIndex = it.indexOf("/")
|
val slashIndex = it.indexOf("/")
|
||||||
val parentDir = withContext(Dispatchers.EDT) {
|
val parentDir = withEDTContext {
|
||||||
baseDir.createChildDirectory(requestor, it.substring(0, slashIndex))
|
baseDir.createChildDirectory(requestor, it.substring(0, slashIndex))
|
||||||
}
|
}
|
||||||
Pair(it.substring(slashIndex + 1), parentDir)
|
Pair(it.substring(slashIndex + 1), parentDir)
|
||||||
|
@ -101,7 +103,7 @@ data class ZigProjectConfigurationData(
|
||||||
val resourceData = getResourceString("project-gen/$templateDir/$fileName.template")
|
val resourceData = getResourceString("project-gen/$templateDir/$fileName.template")
|
||||||
?.replace("@@PROJECT_NAME@@", projectName)
|
?.replace("@@PROJECT_NAME@@", projectName)
|
||||||
?: continue
|
?: continue
|
||||||
withContext(Dispatchers.EDT) {
|
withEDTContext {
|
||||||
val targetFile = parentDir.createChildData(requestor, fileName)
|
val targetFile = parentDir.createChildData(requestor, fileName)
|
||||||
VfsUtil.saveText(targetFile, resourceData)
|
VfsUtil.saveText(targetFile, resourceData)
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,9 @@ package com.falsepattern.zigbrains.project.run
|
||||||
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
||||||
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
||||||
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
|
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
|
||||||
|
import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
|
||||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||||
|
import com.intellij.execution.ExecutionException
|
||||||
import com.intellij.execution.configurations.RunProfileState
|
import com.intellij.execution.configurations.RunProfileState
|
||||||
import com.intellij.execution.configurations.RunnerSettings
|
import com.intellij.execution.configurations.RunnerSettings
|
||||||
import com.intellij.execution.runners.AsyncProgramRunner
|
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.application.EDT
|
||||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||||
import com.intellij.openapi.rd.util.toPromise
|
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.Dispatchers
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
|
@ -44,26 +53,35 @@ abstract class ZigProgramRunner<ProfileState: ZigProfileState<*>>(protected val
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
override fun execute(environment: ExecutionEnvironment, state: RunProfileState): Promise<RunContentDescriptor?> {
|
override fun execute(environment: ExecutionEnvironment, state: RunProfileState): Promise<RunContentDescriptor?> {
|
||||||
return environment.project.zigCoroutineScope.async {
|
return environment.project.zigCoroutineScope.async {
|
||||||
executeAsync(environment, state)
|
withModalProgress(ModalTaskOwner.project(environment.project), "Starting zig program...", TaskCancellation.cancellable()) {
|
||||||
|
executeAsync(environment, state)
|
||||||
|
}
|
||||||
}.toPromise()
|
}.toPromise()
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend inline fun executeAsync(environment: ExecutionEnvironment, state: RunProfileState): RunContentDescriptor? {
|
private suspend inline fun executeAsync(environment: ExecutionEnvironment, baseState: RunProfileState): RunContentDescriptor? {
|
||||||
if (state !is ZigProfileState<*>)
|
if (baseState !is ZigProfileState<*>)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
val state = castProfileState(state) ?: return null
|
val state = castProfileState(baseState) ?: return null
|
||||||
|
|
||||||
val toolchain = environment.project.zigProjectSettings.state.toolchain ?: return null
|
val toolchain = environment.project.zigProjectSettings.state.toolchain ?: return null
|
||||||
|
|
||||||
withContext(Dispatchers.EDT) {
|
return reportProgress { reporter ->
|
||||||
FileDocumentManager.getInstance().saveAllDocuments()
|
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?
|
protected abstract fun castProfileState(state: ZigProfileState<*>): ProfileState?
|
||||||
|
|
||||||
|
@Throws(ExecutionException::class)
|
||||||
abstract suspend fun execute(state: ProfileState, toolchain: AbstractZigToolchain, environment: ExecutionEnvironment): RunContentDescriptor?
|
abstract suspend fun execute(state: ProfileState, toolchain: AbstractZigToolchain, environment: ExecutionEnvironment): RunContentDescriptor?
|
||||||
}
|
}
|
|
@ -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.ZigProfileState
|
||||||
import com.falsepattern.zigbrains.project.execution.base.executeCommandLine
|
import com.falsepattern.zigbrains.project.execution.base.executeCommandLine
|
||||||
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
|
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.configurations.RunProfile
|
||||||
import com.intellij.execution.executors.DefaultRunExecutor
|
import com.intellij.execution.executors.DefaultRunExecutor
|
||||||
import com.intellij.execution.runners.ExecutionEnvironment
|
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.execution.ui.RunContentDescriptor
|
||||||
import com.intellij.openapi.application.EDT
|
import com.intellij.openapi.application.EDT
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class ZigRegularRunner: ZigProgramRunner<ZigProfileState<*>>(DefaultRunExecutor.EXECUTOR_ID) {
|
class ZigRegularRunner: ZigProgramRunner<ZigProfileState<*>>(DefaultRunExecutor.EXECUTOR_ID) {
|
||||||
override suspend fun execute(state: ZigProfileState<*>, toolchain: AbstractZigToolchain, environment: ExecutionEnvironment): RunContentDescriptor? {
|
override suspend fun execute(state: ZigProfileState<*>, toolchain: AbstractZigToolchain, environment: ExecutionEnvironment): RunContentDescriptor? {
|
||||||
val cli = state.getCommandLine(toolchain, false)
|
val cli = state.getCommandLine(toolchain, false)
|
||||||
val exec = executeCommandLine(cli, environment)
|
val exec = executeCommandLine(cli, environment)
|
||||||
return withContext(Dispatchers.EDT) {
|
return withEDTContext {
|
||||||
showRunContent(exec, environment)
|
val runContentBuilder = RunContentBuilder(exec, environment)
|
||||||
|
runContentBuilder.showRunContent(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,8 @@ import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||||
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
||||||
import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain
|
import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain
|
||||||
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainProvider
|
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.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||||
import com.intellij.openapi.Disposable
|
import com.intellij.openapi.Disposable
|
||||||
import com.intellij.openapi.application.EDT
|
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.Disposer
|
||||||
import com.intellij.openapi.util.UserDataHolderBase
|
import com.intellij.openapi.util.UserDataHolderBase
|
||||||
import com.intellij.openapi.util.io.toNioPathOrNull
|
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.DocumentAdapter
|
||||||
import com.intellij.ui.JBColor
|
import com.intellij.ui.JBColor
|
||||||
import com.intellij.ui.components.JBCheckBox
|
import com.intellij.ui.components.JBCheckBox
|
||||||
|
@ -115,8 +120,10 @@ class ZigProjectSettingsPanel(private val project: Project?) : Disposable {
|
||||||
cell(direnv)
|
cell(direnv)
|
||||||
}
|
}
|
||||||
button(ZigBrainsBundle.message("settings.project.label.toolchain-autodetect")) {
|
button(ZigBrainsBundle.message("settings.project.label.toolchain-autodetect")) {
|
||||||
this@ZigProjectSettingsPanel.project.zigCoroutineScope.launch {
|
project.zigCoroutineScope.launchWithEDT {
|
||||||
autodetect()
|
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 env = zig?.getEnv(project)
|
||||||
val version = env?.version
|
val version = env?.version
|
||||||
val stdPath = env?.stdPath(toolchain)
|
val stdPath = env?.stdPath(toolchain)
|
||||||
withContext(Dispatchers.EDT) {
|
withEDTContext {
|
||||||
toolchainVersion.text = version ?: ""
|
toolchainVersion.text = version ?: ""
|
||||||
toolchainVersion.foreground = JBColor.foreground()
|
toolchainVersion.foreground = JBColor.foreground()
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ package com.falsepattern.zigbrains.project.steps.discovery
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
||||||
import com.falsepattern.zigbrains.project.steps.discovery.ZigStepDiscoveryListener.ErrorType
|
import com.falsepattern.zigbrains.project.steps.discovery.ZigStepDiscoveryListener.ErrorType
|
||||||
|
import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
|
||||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||||
import com.intellij.openapi.Disposable
|
import com.intellij.openapi.Disposable
|
||||||
import com.intellij.openapi.application.EDT
|
import com.intellij.openapi.application.EDT
|
||||||
|
@ -120,7 +121,7 @@ class ZigStepDiscoveryService(private val project: Project) {
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun dispatchReload() {
|
private suspend fun dispatchReload() {
|
||||||
withContext(Dispatchers.EDT) {
|
withEDTContext {
|
||||||
FileDocumentManager.getInstance().saveAllDocuments()
|
FileDocumentManager.getInstance().saveAllDocuments()
|
||||||
}
|
}
|
||||||
doReload()
|
doReload()
|
||||||
|
|
|
@ -29,6 +29,7 @@ import com.falsepattern.zigbrains.project.execution.build.ZigExecConfigBuild
|
||||||
import com.falsepattern.zigbrains.project.execution.firstConfigFactory
|
import com.falsepattern.zigbrains.project.execution.firstConfigFactory
|
||||||
import com.falsepattern.zigbrains.project.steps.discovery.ZigStepDiscoveryListener
|
import com.falsepattern.zigbrains.project.steps.discovery.ZigStepDiscoveryListener
|
||||||
import com.falsepattern.zigbrains.project.steps.discovery.zigStepDiscovery
|
import com.falsepattern.zigbrains.project.steps.discovery.zigStepDiscovery
|
||||||
|
import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
|
||||||
import com.intellij.execution.ProgramRunnerUtil
|
import com.intellij.execution.ProgramRunnerUtil
|
||||||
import com.intellij.execution.RunManager
|
import com.intellij.execution.RunManager
|
||||||
import com.intellij.execution.RunnerAndConfigurationSettings
|
import com.intellij.execution.RunnerAndConfigurationSettings
|
||||||
|
@ -137,7 +138,7 @@ class BuildToolWindowContext(private val project: Project): Disposable {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
suspend fun create(project: Project, window: ToolWindow) {
|
suspend fun create(project: Project, window: ToolWindow) {
|
||||||
withContext(Dispatchers.EDT) {
|
withEDTContext {
|
||||||
val context = BuildToolWindowContext(project)
|
val context = BuildToolWindowContext(project)
|
||||||
Disposer.register(context, project.zigStepDiscovery.register(context.BuildReloadListener()))
|
Disposer.register(context, project.zigStepDiscovery.register(context.BuildReloadListener()))
|
||||||
Disposer.register(window.disposable, context)
|
Disposer.register(window.disposable, context)
|
||||||
|
@ -161,13 +162,13 @@ class BuildToolWindowContext(private val project: Project): Disposable {
|
||||||
}
|
}
|
||||||
buildZig.add(DefaultMutableTreeNode(StepNodeDescriptor(project, task, icon, description)))
|
buildZig.add(DefaultMutableTreeNode(StepNodeDescriptor(project, task, icon, description)))
|
||||||
}
|
}
|
||||||
withContext(Dispatchers.EDT) {
|
withEDTContext {
|
||||||
getViewport(project)?.let { setViewportTree(it) }
|
getViewport(project)?.let { setViewportTree(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun errorReload(type: ZigStepDiscoveryListener.ErrorType, details: String?) {
|
override suspend fun errorReload(type: ZigStepDiscoveryListener.ErrorType, details: String?) {
|
||||||
withContext(Dispatchers.EDT) {
|
withEDTContext {
|
||||||
getViewport(project)?.setViewportError(ZigBrainsBundle.message(when(type) {
|
getViewport(project)?.setViewportError(ZigBrainsBundle.message(when(type) {
|
||||||
ZigStepDiscoveryListener.ErrorType.MissingToolchain -> "build.tool.window.status.error.missing-toolchain"
|
ZigStepDiscoveryListener.ErrorType.MissingToolchain -> "build.tool.window.status.error.missing-toolchain"
|
||||||
ZigStepDiscoveryListener.ErrorType.MissingBuildZig -> "build.tool.window.status.error.missing-build-zig"
|
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) {
|
override suspend fun timeoutReload(seconds: Int) {
|
||||||
withContext(Dispatchers.EDT) {
|
withEDTContext {
|
||||||
getViewport(project)?.setViewportError(ZigBrainsBundle.message("build.tool.window.status.timeout", seconds), null)
|
getViewport(project)?.setViewportError(ZigBrainsBundle.message("build.tool.window.status.timeout", seconds), null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ package com.falsepattern.zigbrains.project.toolchain
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
||||||
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
||||||
|
import com.intellij.execution.ExecutionException
|
||||||
import com.intellij.execution.configurations.GeneralCommandLine
|
import com.intellij.execution.configurations.GeneralCommandLine
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.project.guessProjectDir
|
import com.intellij.openapi.project.guessProjectDir
|
||||||
|
@ -52,5 +53,15 @@ class LocalZigToolchain(val location: Path): AbstractZigToolchain() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val DIRENV_KEY = KeyWithDefaultValue.create<Boolean>("ZIG_LOCAL_DIRENV")
|
val DIRENV_KEY = KeyWithDefaultValue.create<Boolean>("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")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -26,7 +26,9 @@ import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
|
||||||
import com.intellij.execution.configurations.GeneralCommandLine
|
import com.intellij.execution.configurations.GeneralCommandLine
|
||||||
import com.intellij.execution.process.ProcessOutput
|
import com.intellij.execution.process.ProcessOutput
|
||||||
import com.intellij.util.io.awaitExit
|
import com.intellij.util.io.awaitExit
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.runInterruptible
|
import kotlinx.coroutines.runInterruptible
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.coroutines.withTimeoutOrNull
|
import kotlinx.coroutines.withTimeoutOrNull
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
@ -34,10 +36,14 @@ abstract class ZigTool(val toolchain: AbstractZigToolchain) {
|
||||||
abstract val toolName: String
|
abstract val toolName: String
|
||||||
|
|
||||||
suspend fun callWithArgs(workingDirectory: Path?, vararg parameters: String, timeoutMillis: Long = Long.MAX_VALUE): ProcessOutput {
|
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) {
|
val (process, exitCode) = withContext(Dispatchers.IO) {
|
||||||
process.awaitExit()
|
val process = cli.createProcess()
|
||||||
|
val exit = withTimeoutOrNull(timeoutMillis) {
|
||||||
|
process.awaitExit()
|
||||||
|
}
|
||||||
|
process to exit
|
||||||
}
|
}
|
||||||
return runInterruptible {
|
return runInterruptible {
|
||||||
ProcessOutput(
|
ProcessOutput(
|
||||||
|
@ -50,8 +56,10 @@ abstract class ZigTool(val toolchain: AbstractZigToolchain) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun createBaseCommandLine(workingDirectory: Path?,
|
private suspend fun createBaseCommandLine(
|
||||||
vararg parameters: String): GeneralCommandLine {
|
workingDirectory: Path?,
|
||||||
|
vararg parameters: String
|
||||||
|
): GeneralCommandLine {
|
||||||
val cli = GeneralCommandLine()
|
val cli = GeneralCommandLine()
|
||||||
.withExePath(toolchain.pathToExecutable(toolName).toString())
|
.withExePath(toolchain.pathToExecutable(toolName).toString())
|
||||||
.withWorkDirectory(workingDirectory?.toString())
|
.withWorkDirectory(workingDirectory?.toString())
|
||||||
|
|
|
@ -22,13 +22,17 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.shared.coroutine
|
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.ModalTaskOwner
|
||||||
import com.intellij.platform.ide.progress.TaskCancellation
|
import com.intellij.platform.ide.progress.TaskCancellation
|
||||||
import com.intellij.platform.ide.progress.runWithModalProgressBlocking
|
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.SuspendingLazy
|
||||||
import com.intellij.util.application
|
import com.intellij.util.application
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
|
|
||||||
inline fun <T> runModalOrBlocking(taskOwnerFactory: () -> ModalTaskOwner, titleFactory: () -> String, cancellationFactory: () -> TaskCancellation = TaskCancellation::cancellable, noinline action: suspend CoroutineScope.() -> T): T {
|
inline fun <T> runModalOrBlocking(taskOwnerFactory: () -> ModalTaskOwner, titleFactory: () -> String, cancellationFactory: () -> TaskCancellation = TaskCancellation::cancellable, noinline action: suspend CoroutineScope.() -> T): T {
|
||||||
return if (application.isDispatchThread) {
|
return if (application.isDispatchThread) {
|
||||||
|
@ -47,3 +51,15 @@ inline fun <T> SuspendingLazy<T>.getOrAwaitModalOrBlocking(taskOwnerFactory: ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend inline fun <T> withEDTContext(state: ModalityState = ModalityState.defaultModalityState(), noinline block: suspend CoroutineScope.() -> T): T {
|
||||||
|
return withContext(Dispatchers.EDT + state.asContextElement(), block = block)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend inline fun <T> 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)
|
||||||
|
}
|
|
@ -71,6 +71,9 @@ notification.content.native-debug.browser=Open in Browser
|
||||||
dialog.title.working-directory=Select Working Directory
|
dialog.title.working-directory=Select Working Directory
|
||||||
dialog.title.zig-toolchain=Path to the Zig Toolchain
|
dialog.title.zig-toolchain=Path to the Zig Toolchain
|
||||||
dialog.title.zig-std=Path to the Standard Library
|
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.working-directory=&Working directory:
|
||||||
exec.option.label.colored-terminal=Colored terminal
|
exec.option.label.colored-terminal=Colored terminal
|
||||||
exec.option.label.direnv=Use direnv
|
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.args=Extra command line arguments
|
||||||
exec.option.label.build.exe-args-debug=Output program command line arguments (debug only)
|
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)
|
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.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-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
|
exception.zig-build.debug.test-not-supported=Debugging "zig build test" is not yet supported
|
||||||
|
|
|
@ -3,7 +3,7 @@ plugins {
|
||||||
}
|
}
|
||||||
rootProject.name = "ZigBrains"
|
rootProject.name = "ZigBrains"
|
||||||
|
|
||||||
for (module in arrayOf("core")) {
|
for (module in arrayOf("core", "cidr")) {
|
||||||
include(module)
|
include(module)
|
||||||
project(":$module").projectDir = file("modules/$module")
|
project(":$module").projectDir = file("modules/$module")
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
<depends config-file="zigbrains-core.xml">com.intellij.modules.platform</depends>
|
<depends config-file="zigbrains-core.xml">com.intellij.modules.platform</depends>
|
||||||
<depends config-file="zigbrains-lsp.xml">com.redhat.devtools.lsp4ij</depends>
|
<depends config-file="zigbrains-lsp.xml">com.redhat.devtools.lsp4ij</depends>
|
||||||
|
<depends config-file="zigbrains-debugger.xml">com.intellij.modules.cidr.debugger</depends>
|
||||||
|
|
||||||
<resource-bundle>zigbrains.Bundle</resource-bundle>
|
<resource-bundle>zigbrains.Bundle</resource-bundle>
|
||||||
|
|
||||||
|
@ -24,5 +25,10 @@
|
||||||
dynamic="true"
|
dynamic="true"
|
||||||
name="featureProvider"
|
name="featureProvider"
|
||||||
/>
|
/>
|
||||||
|
<extensionPoint
|
||||||
|
interface="com.falsepattern.zigbrains.debugbridge.ZigDebuggerDriverConfigurationProvider"
|
||||||
|
dynamic="true"
|
||||||
|
name="debuggerDriverProvider"
|
||||||
|
/>
|
||||||
</extensionPoints>
|
</extensionPoints>
|
||||||
</idea-plugin>
|
</idea-plugin>
|
Loading…
Add table
Reference in a new issue