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.markdownToHTML
|
||||
import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType
|
||||
import org.jetbrains.intellij.platform.gradle.tasks.ComposedJarTask
|
||||
import org.jetbrains.intellij.platform.gradle.tasks.InstrumentedJarTask
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
|
||||
|
||||
plugins {
|
||||
|
@ -14,6 +17,7 @@ plugins {
|
|||
|
||||
val javaVersion = property("javaVersion").toString().toInt()
|
||||
val lsp4ijVersion: String by project
|
||||
val runIdeTarget: String by project
|
||||
val lsp4ijNightly = property("lsp4ijNightly").toString().toBoolean()
|
||||
val lsp4ijPluginString = "com.redhat.devtools.lsp4ij:$lsp4ijVersion${if (lsp4ijNightly) "@nightly" else ""}"
|
||||
|
||||
|
@ -74,7 +78,10 @@ allprojects {
|
|||
|
||||
dependencies {
|
||||
intellijPlatform {
|
||||
create(IntelliJPlatformType.IntellijIdeaCommunity, providers.gradleProperty("ideaCommunityVersion"))
|
||||
when(runIdeTarget) {
|
||||
"ideaCommunity" -> create(IntelliJPlatformType.IntellijIdeaCommunity, providers.gradleProperty("ideaCommunityVersion"))
|
||||
"clion" -> create(IntelliJPlatformType.CLion, providers.gradleProperty("clionVersion"))
|
||||
}
|
||||
|
||||
pluginVerifier()
|
||||
zipSigner()
|
||||
|
@ -82,6 +89,7 @@ dependencies {
|
|||
}
|
||||
|
||||
implementation(project(":core"))
|
||||
implementation(project(":cidr"))
|
||||
}
|
||||
|
||||
intellijPlatform {
|
||||
|
|
|
@ -1,19 +1,22 @@
|
|||
pluginName = ZigBrains
|
||||
pluginRepositoryUrl = https://github.com/FalsePattern/ZigBrains
|
||||
pluginName=ZigBrains
|
||||
pluginRepositoryUrl=https://github.com/FalsePattern/ZigBrains
|
||||
|
||||
pluginVersion = 20.0.0-dev
|
||||
pluginVersion=20.0.0-dev
|
||||
|
||||
pluginSinceBuild = 242
|
||||
pluginUntilBuild =
|
||||
pluginSinceBuild=242
|
||||
pluginUntilBuild=
|
||||
|
||||
ideaCommunityVersion = 2024.2.4
|
||||
ideaCommunityVersion=2024.2.4
|
||||
clionVersion=2024.2.3
|
||||
javaVersion=21
|
||||
# ideaCommunity / clion
|
||||
runIdeTarget=clion
|
||||
|
||||
lsp4jVersion=0.21.1
|
||||
lsp4ijVersion=0.7.0
|
||||
lsp4ijNightly=false
|
||||
|
||||
kotlin.stdlib.default.dependency = false
|
||||
kotlin.stdlib.default.dependency=false
|
||||
kotlin.code.style=official
|
||||
org.gradle.configuration-cache = true
|
||||
org.gradle.caching = true
|
||||
org.gradle.configuration-cache=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.project.Project
|
||||
import com.intellij.openapi.project.guessProjectDir
|
||||
import com.intellij.platform.util.progress.withProgressText
|
||||
import com.intellij.util.io.awaitExit
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
@ -72,12 +73,14 @@ object DirenvCmd {
|
|||
private suspend fun run(project: Project, workDir: Path, vararg args: String): DirenvOutput {
|
||||
val cli = GeneralCommandLine("direnv", *args).withWorkingDirectory(workDir)
|
||||
|
||||
val process: Process
|
||||
val exitCode: Int
|
||||
|
||||
project.direnvService.mutex.withLock {
|
||||
process = cli.createProcess()
|
||||
exitCode = process.awaitExit()
|
||||
val (process, exitCode) = withProgressText("Running ${cli.commandLineString}") {
|
||||
withContext(Dispatchers.IO) {
|
||||
project.direnvService.mutex.withLock {
|
||||
val process = cli.createProcess()
|
||||
val exitCode = process.awaitExit()
|
||||
process to exitCode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exitCode != 0) {
|
||||
|
|
|
@ -80,30 +80,6 @@ class ZLSStreamConnectionProvider private constructor(private val project: Proje
|
|||
return ZLSStreamConnectionProvider(project, commandLine)
|
||||
}
|
||||
|
||||
suspend fun validate(project: Project): Boolean {
|
||||
val svc = project.zlsSettings
|
||||
val state = svc.state
|
||||
val zlsPath: Path = state.zlsPath.let { zlsPath ->
|
||||
if (zlsPath.isEmpty()) {
|
||||
val env = if (state.direnv) project.getDirenv() else emptyEnv
|
||||
env.findExecutableOnPATH("zls") ?: run {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
zlsPath.toNioPathOrNull() ?: run {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
if (zlsPath.notExists()) {
|
||||
return false
|
||||
}
|
||||
if (!zlsPath.isRegularFile() || !zlsPath.isExecutable()) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
suspend fun getCommand(project: Project): List<String>? {
|
||||
val svc = project.zlsSettings
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
package com.falsepattern.zigbrains.lsp
|
||||
|
||||
import com.falsepattern.zigbrains.lsp.settings.zlsSettings
|
||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.project.Project
|
||||
|
@ -51,19 +52,11 @@ class ZigLanguageServerFactory: LanguageServerFactory, LanguageServerEnablementS
|
|||
}
|
||||
|
||||
override fun isEnabled(project: Project): Boolean {
|
||||
return (project.getUserData(ENABLED_KEY) ?: true) && if (application.isDispatchThread) {
|
||||
runWithModalProgressBlocking(ModalTaskOwner.project(project), ZLSBundle.message("progress.title.validate")) {
|
||||
ZLSStreamConnectionProvider.validate(project)
|
||||
}
|
||||
} else {
|
||||
runBlocking {
|
||||
ZLSStreamConnectionProvider.validate(project)
|
||||
}
|
||||
}
|
||||
return (project.getUserData(ENABLED_KEY) ?: true) && project.zlsSettings.validate()
|
||||
}
|
||||
|
||||
override fun setEnabled(enabled: Boolean, project: Project) {
|
||||
project.putUserData(ENABLED_KEY, true)
|
||||
project.putUserData(ENABLED_KEY, enabled)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,32 +22,101 @@
|
|||
|
||||
package com.falsepattern.zigbrains.lsp.settings
|
||||
|
||||
import com.falsepattern.zigbrains.direnv.emptyEnv
|
||||
import com.falsepattern.zigbrains.direnv.getDirenv
|
||||
import com.falsepattern.zigbrains.lsp.ZLSBundle
|
||||
import com.falsepattern.zigbrains.lsp.ZLSStreamConnectionProvider
|
||||
import com.intellij.openapi.components.*
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.io.toNioPathOrNull
|
||||
import com.intellij.platform.ide.progress.ModalTaskOwner
|
||||
import com.intellij.platform.ide.progress.runWithModalProgressBlocking
|
||||
import com.intellij.util.application
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import java.nio.file.Path
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.concurrent.withLock
|
||||
import kotlin.io.path.isExecutable
|
||||
import kotlin.io.path.isRegularFile
|
||||
import kotlin.io.path.notExists
|
||||
|
||||
@Service(Service.Level.PROJECT)
|
||||
@State(
|
||||
name = "ZLSSettings",
|
||||
storages = [Storage(value = "zigbrains.xml")]
|
||||
)
|
||||
class ZLSProjectSettingsService: PersistentStateComponent<ZLSSettings> {
|
||||
class ZLSProjectSettingsService(val project: Project): PersistentStateComponent<ZLSSettings> {
|
||||
@Volatile
|
||||
private var state = ZLSSettings()
|
||||
@Volatile
|
||||
private var dirty = true
|
||||
@Volatile
|
||||
private var valid = false
|
||||
|
||||
private val mutex = ReentrantLock()
|
||||
override fun getState(): ZLSSettings {
|
||||
return state.copy()
|
||||
}
|
||||
|
||||
fun setState(value: ZLSSettings) {
|
||||
this.state = value
|
||||
mutex.withLock {
|
||||
this.state = value
|
||||
dirty = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun loadState(state: ZLSSettings) {
|
||||
this.state = state
|
||||
mutex.withLock {
|
||||
this.state = state
|
||||
dirty = true
|
||||
}
|
||||
}
|
||||
|
||||
fun isModified(otherData: ZLSSettings): Boolean {
|
||||
return state != otherData
|
||||
}
|
||||
|
||||
fun validate(): Boolean {
|
||||
mutex.withLock {
|
||||
if (dirty) {
|
||||
val state = this.state
|
||||
valid = if (application.isDispatchThread) {
|
||||
runWithModalProgressBlocking(ModalTaskOwner.project(project), ZLSBundle.message("progress.title.validate")) {
|
||||
doValidate(project, state)
|
||||
}
|
||||
} else {
|
||||
runBlocking {
|
||||
doValidate(project, state)
|
||||
}
|
||||
}
|
||||
dirty = false
|
||||
}
|
||||
return valid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun doValidate(project: Project, state: ZLSSettings): Boolean {
|
||||
val zlsPath: Path = state.zlsPath.let { zlsPath ->
|
||||
if (zlsPath.isEmpty()) {
|
||||
val env = if (state.direnv) project.getDirenv() else emptyEnv
|
||||
env.findExecutableOnPATH("zls") ?: run {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
zlsPath.toNioPathOrNull() ?: run {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
if (zlsPath.notExists()) {
|
||||
return false
|
||||
}
|
||||
if (!zlsPath.isRegularFile() || !zlsPath.isExecutable()) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
val Project.zlsSettings get() = service<ZLSProjectSettingsService>()
|
|
@ -24,18 +24,26 @@ package com.falsepattern.zigbrains.lsp.settings
|
|||
|
||||
import com.falsepattern.zigbrains.direnv.*
|
||||
import com.falsepattern.zigbrains.lsp.ZLSBundle
|
||||
import com.falsepattern.zigbrains.shared.coroutine.launchWithEDT
|
||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ModalityState
|
||||
import com.intellij.openapi.application.asContextElement
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.platform.ide.progress.ModalTaskOwner
|
||||
import com.intellij.platform.ide.progress.TaskCancellation
|
||||
import com.intellij.platform.ide.progress.runWithModalProgressBlocking
|
||||
import com.intellij.platform.ide.progress.withModalProgress
|
||||
import com.intellij.ui.components.JBCheckBox
|
||||
import com.intellij.ui.components.fields.ExtendableTextField
|
||||
import com.intellij.ui.components.textFieldWithBrowseButton
|
||||
import com.intellij.ui.dsl.builder.AlignX
|
||||
import com.intellij.ui.dsl.builder.Panel
|
||||
import com.intellij.util.application
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.io.path.pathString
|
||||
|
||||
|
@ -66,12 +74,14 @@ class ZLSSettingsPanel(private val project: Project?) : Disposable {
|
|||
group(ZLSBundle.message("settings.group.title")) {
|
||||
row(ZLSBundle.message("settings.zls-path.label")) {
|
||||
cell(zlsPath).resizableColumn().align(AlignX.FILL)
|
||||
if (DirenvCmd.direnvInstalled() && project != null) {
|
||||
if (DirenvCmd.direnvInstalled() && project != null && !project.isDefault) {
|
||||
cell(direnv)
|
||||
}
|
||||
button(ZLSBundle.message("settings.zls-path.autodetect.label")) {
|
||||
project.zigCoroutineScope.launch {
|
||||
autodetect()
|
||||
project.zigCoroutineScope.launchWithEDT {
|
||||
withModalProgress(ModalTaskOwner.component(zlsPath), "Detecting ZLS...", TaskCancellation.cancellable()) {
|
||||
autodetect()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ package com.falsepattern.zigbrains.project.execution.base
|
|||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
||||
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.execution.Executor
|
||||
import com.intellij.execution.configurations.ConfigurationFactory
|
||||
import com.intellij.execution.configurations.GeneralCommandLine
|
||||
|
@ -37,8 +38,9 @@ import com.intellij.openapi.project.guessProjectDir
|
|||
import com.intellij.openapi.util.NlsActions.ActionText
|
||||
import com.intellij.openapi.vfs.toNioPathOrNull
|
||||
import org.jdom.Element
|
||||
import org.jetbrains.annotations.Nls
|
||||
|
||||
abstract class ZigExecConfig<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() }
|
||||
private set
|
||||
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
|
||||
|
||||
abstract val suggestedName: @ActionText String
|
||||
@Throws(ExecutionException::class)
|
||||
abstract suspend fun buildCommandLineArgs(debug: Boolean): List<String>
|
||||
abstract override fun getState(executor: Executor, environment: ExecutionEnvironment): ZigProfileState<T>
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ abstract class ZigProfileState<T: ZigExecConfig<T>> (
|
|||
}
|
||||
|
||||
@Throws(ExecutionException::class)
|
||||
suspend fun getCommandLine(toolchain: AbstractZigToolchain, debug: Boolean): GeneralCommandLine {
|
||||
open suspend fun getCommandLine(toolchain: AbstractZigToolchain, debug: Boolean): GeneralCommandLine {
|
||||
val workingDir = configuration.workingDirectory
|
||||
val zigExePath = toolchain.zig.path()
|
||||
|
||||
|
|
|
@ -36,10 +36,10 @@ class ZigConfigTypeBuild : ConfigurationTypeBase(
|
|||
Icons.ZIG
|
||||
) {
|
||||
init {
|
||||
addFactory(ConfigFactoryRun())
|
||||
addFactory(ConfigFactoryRun(this))
|
||||
}
|
||||
|
||||
inner class ConfigFactoryRun: ConfigurationFactory(this@ZigConfigTypeBuild) {
|
||||
class ConfigFactoryRun(type: ZigConfigTypeBuild): ConfigurationFactory(type) {
|
||||
override fun createTemplateConfiguration(project: Project): RunConfiguration {
|
||||
return ZigExecConfigBuild(project, this)
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ import com.intellij.execution.configurations.ConfigurationFactory
|
|||
import com.intellij.execution.runners.ExecutionEnvironment
|
||||
import com.intellij.openapi.project.Project
|
||||
|
||||
class ZigExecConfigBuild(project: Project, factory: ConfigurationFactory): ZigExecConfig<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"))
|
||||
private set
|
||||
var extraArgs = ArgsConfigurable("compilerArgs", ZigBrainsBundle.message("exec.option.label.build.args"))
|
||||
|
@ -44,10 +44,11 @@ class ZigExecConfigBuild(project: Project, factory: ConfigurationFactory): ZigEx
|
|||
var exeArgs = ArgsConfigurable("exeArgs", ZigBrainsBundle.message("exec.option.label.build.exe-args-debug"))
|
||||
private set
|
||||
|
||||
@Throws(ExecutionException::class)
|
||||
override suspend fun buildCommandLineArgs(debug: Boolean): List<String> {
|
||||
val result = ArrayList<String>()
|
||||
result.add("build")
|
||||
var steps = buildSteps.args
|
||||
val steps = buildSteps.args
|
||||
if (debug) {
|
||||
val truncatedSteps = ArrayList<String>()
|
||||
for (step in steps) {
|
||||
|
|
|
@ -36,10 +36,10 @@ class ZigConfigTypeRun : ConfigurationTypeBase(
|
|||
Icons.ZIG
|
||||
) {
|
||||
init {
|
||||
addFactory(ConfigFactoryRun())
|
||||
addFactory(ConfigFactoryRun(this))
|
||||
}
|
||||
|
||||
inner class ConfigFactoryRun: ConfigurationFactory(this@ZigConfigTypeRun) {
|
||||
class ConfigFactoryRun(type: ZigConfigTypeRun): ConfigurationFactory(type) {
|
||||
override fun createTemplateConfiguration(project: Project): RunConfiguration {
|
||||
return ZigExecConfigRun(project, this)
|
||||
}
|
||||
|
|
|
@ -25,13 +25,14 @@ package com.falsepattern.zigbrains.project.execution.run
|
|||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||
import com.falsepattern.zigbrains.project.execution.base.*
|
||||
import com.falsepattern.zigbrains.shared.cli.coloredCliFlags
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.execution.Executor
|
||||
import com.intellij.execution.configurations.ConfigurationFactory
|
||||
import com.intellij.execution.runners.ExecutionEnvironment
|
||||
import com.intellij.openapi.project.Project
|
||||
import kotlin.io.path.pathString
|
||||
|
||||
class ZigExecConfigRun(project: Project, factory: ConfigurationFactory): ZigExecConfig<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"))
|
||||
private set
|
||||
var colored = ColoredConfigurable("colored")
|
||||
|
@ -47,7 +48,7 @@ class ZigExecConfigRun(project: Project, factory: ConfigurationFactory): ZigExec
|
|||
val result = ArrayList<String>()
|
||||
result.add(if (debug) "build-exe" else "run")
|
||||
result.addAll(coloredCliFlags(colored.value, debug))
|
||||
result.add(filePath.path?.pathString ?: throw IllegalArgumentException("Empty file path!"))
|
||||
result.add(filePath.path?.pathString ?: throw ExecutionException(ZigBrainsBundle.message("exception.zig.empty-file-path")))
|
||||
if (!debug || optimization.forced) {
|
||||
result.addAll(listOf("-O", optimization.level.name))
|
||||
}
|
||||
|
|
|
@ -36,10 +36,10 @@ class ZigConfigTypeTest : ConfigurationTypeBase(
|
|||
Icons.ZIG
|
||||
) {
|
||||
init {
|
||||
addFactory(ConfigFactoryRun())
|
||||
addFactory(ConfigFactoryRun(this))
|
||||
}
|
||||
|
||||
inner class ConfigFactoryRun: ConfigurationFactory(this@ZigConfigTypeTest) {
|
||||
class ConfigFactoryRun(type: ZigConfigTypeTest): ConfigurationFactory(type) {
|
||||
override fun createTemplateConfiguration(project: Project): RunConfiguration {
|
||||
return ZigExecConfigTest(project, this)
|
||||
}
|
||||
|
|
|
@ -25,13 +25,14 @@ package com.falsepattern.zigbrains.project.execution.test
|
|||
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||
import com.falsepattern.zigbrains.project.execution.base.*
|
||||
import com.falsepattern.zigbrains.shared.cli.coloredCliFlags
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.execution.Executor
|
||||
import com.intellij.execution.configurations.ConfigurationFactory
|
||||
import com.intellij.execution.runners.ExecutionEnvironment
|
||||
import com.intellij.openapi.project.Project
|
||||
import kotlin.io.path.pathString
|
||||
|
||||
class ZigExecConfigTest(project: Project, factory: ConfigurationFactory): ZigExecConfig<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"))
|
||||
private set
|
||||
var colored = ColoredConfigurable("colored")
|
||||
|
@ -41,11 +42,12 @@ class ZigExecConfigTest(project: Project, factory: ConfigurationFactory): ZigExe
|
|||
var compilerArgs = ArgsConfigurable("compilerArgs", ZigBrainsBundle.message("exec.option.label.compiler-args"))
|
||||
private set
|
||||
|
||||
@Throws(ExecutionException::class)
|
||||
override suspend fun buildCommandLineArgs(debug: Boolean): List<String> {
|
||||
val result = ArrayList<String>()
|
||||
result.add(if (debug) "build-exe" else "run")
|
||||
result.addAll(coloredCliFlags(colored.value, debug))
|
||||
result.add(filePath.path?.pathString ?: throw IllegalArgumentException("Empty file path!"))
|
||||
result.add(filePath.path?.pathString ?: throw ExecutionException(ZigBrainsBundle.message("exception.zig.empty-file-path")))
|
||||
if (!debug || optimization.forced) {
|
||||
result.addAll(listOf("-O", optimization.level.name))
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ package com.falsepattern.zigbrains.project.module
|
|||
|
||||
import com.falsepattern.zigbrains.project.newproject.ZigProjectConfigurationData
|
||||
import com.falsepattern.zigbrains.project.newproject.ZigProjectGeneratorPeer
|
||||
import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
|
||||
import com.intellij.ide.util.projectWizard.ModuleBuilder
|
||||
import com.intellij.ide.util.projectWizard.ModuleWizardStep
|
||||
import com.intellij.ide.util.projectWizard.WizardContext
|
||||
|
@ -61,7 +62,7 @@ class ZigModuleBuilder: ModuleBuilder() {
|
|||
val root = contentEntry.file ?: return
|
||||
val config = configurationData ?: return
|
||||
config.generateProject(this, rootModel.project, root, forceGitignore)
|
||||
withContext(Dispatchers.EDT) {
|
||||
withEDTContext {
|
||||
root.refresh(false, true)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import com.falsepattern.zigbrains.project.settings.ZigProjectSettings
|
|||
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
||||
import com.falsepattern.zigbrains.project.template.ZigInitTemplate
|
||||
import com.falsepattern.zigbrains.project.template.ZigProjectTemplate
|
||||
import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
|
||||
import com.intellij.notification.Notification
|
||||
import com.intellij.notification.NotificationType
|
||||
import com.intellij.openapi.GitRepositoryInitializer
|
||||
|
@ -36,6 +37,7 @@ import com.intellij.openapi.project.Project
|
|||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.toNioPathOrNull
|
||||
import com.intellij.platform.util.progress.withProgressText
|
||||
import com.intellij.util.ResourceUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
@ -48,7 +50,7 @@ data class ZigProjectConfigurationData(
|
|||
val selectedTemplate: ZigProjectTemplate
|
||||
) {
|
||||
suspend fun generateProject(requestor: Any, project: Project, baseDir: VirtualFile, forceGitignore: Boolean): Boolean {
|
||||
withContext(Dispatchers.EDT) {
|
||||
withEDTContext {
|
||||
project.zigProjectSettings.loadState(projConf)
|
||||
project.zlsSettings.loadState(zlsConf)
|
||||
}
|
||||
|
@ -89,7 +91,7 @@ data class ZigProjectConfigurationData(
|
|||
val (fileName, parentDir) = fileTemplate.key.let {
|
||||
if (it.contains("/")) {
|
||||
val slashIndex = it.indexOf("/")
|
||||
val parentDir = withContext(Dispatchers.EDT) {
|
||||
val parentDir = withEDTContext {
|
||||
baseDir.createChildDirectory(requestor, it.substring(0, slashIndex))
|
||||
}
|
||||
Pair(it.substring(slashIndex + 1), parentDir)
|
||||
|
@ -101,7 +103,7 @@ data class ZigProjectConfigurationData(
|
|||
val resourceData = getResourceString("project-gen/$templateDir/$fileName.template")
|
||||
?.replace("@@PROJECT_NAME@@", projectName)
|
||||
?: continue
|
||||
withContext(Dispatchers.EDT) {
|
||||
withEDTContext {
|
||||
val targetFile = parentDir.createChildData(requestor, fileName)
|
||||
VfsUtil.saveText(targetFile, resourceData)
|
||||
}
|
||||
|
|
|
@ -25,7 +25,9 @@ package com.falsepattern.zigbrains.project.run
|
|||
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
||||
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
||||
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
|
||||
import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
|
||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.execution.configurations.RunProfileState
|
||||
import com.intellij.execution.configurations.RunnerSettings
|
||||
import com.intellij.execution.runners.AsyncProgramRunner
|
||||
|
@ -34,6 +36,13 @@ import com.intellij.execution.ui.RunContentDescriptor
|
|||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
import com.intellij.openapi.rd.util.toPromise
|
||||
import com.intellij.platform.ide.progress.ModalTaskOwner
|
||||
import com.intellij.platform.ide.progress.TaskCancellation
|
||||
import com.intellij.platform.ide.progress.withModalProgress
|
||||
import com.intellij.platform.util.progress.ProgressReporter
|
||||
import com.intellij.platform.util.progress.SequentialProgressReporter
|
||||
import com.intellij.platform.util.progress.reportProgress
|
||||
import com.intellij.platform.util.progress.withProgressText
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.async
|
||||
|
@ -44,26 +53,35 @@ abstract class ZigProgramRunner<ProfileState: ZigProfileState<*>>(protected val
|
|||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
override fun execute(environment: ExecutionEnvironment, state: RunProfileState): Promise<RunContentDescriptor?> {
|
||||
return environment.project.zigCoroutineScope.async {
|
||||
executeAsync(environment, state)
|
||||
withModalProgress(ModalTaskOwner.project(environment.project), "Starting zig program...", TaskCancellation.cancellable()) {
|
||||
executeAsync(environment, state)
|
||||
}
|
||||
}.toPromise()
|
||||
}
|
||||
|
||||
private suspend inline fun executeAsync(environment: ExecutionEnvironment, state: RunProfileState): RunContentDescriptor? {
|
||||
if (state !is ZigProfileState<*>)
|
||||
private suspend inline fun executeAsync(environment: ExecutionEnvironment, baseState: RunProfileState): RunContentDescriptor? {
|
||||
if (baseState !is ZigProfileState<*>)
|
||||
return null
|
||||
|
||||
val state = castProfileState(state) ?: return null
|
||||
val state = castProfileState(baseState) ?: return null
|
||||
|
||||
val toolchain = environment.project.zigProjectSettings.state.toolchain ?: return null
|
||||
|
||||
withContext(Dispatchers.EDT) {
|
||||
FileDocumentManager.getInstance().saveAllDocuments()
|
||||
return reportProgress { reporter ->
|
||||
reporter.indeterminateStep("Saving all documents") {
|
||||
withEDTContext {
|
||||
FileDocumentManager.getInstance().saveAllDocuments()
|
||||
}
|
||||
}
|
||||
return@reportProgress reporter.indeterminateStep {
|
||||
return@indeterminateStep execute(state, toolchain, environment)
|
||||
}
|
||||
}
|
||||
|
||||
return execute(state, toolchain, environment)
|
||||
}
|
||||
|
||||
protected abstract fun castProfileState(state: ZigProfileState<*>): ProfileState?
|
||||
|
||||
@Throws(ExecutionException::class)
|
||||
abstract suspend fun execute(state: ProfileState, toolchain: AbstractZigToolchain, environment: ExecutionEnvironment): RunContentDescriptor?
|
||||
}
|
|
@ -26,23 +26,23 @@ import com.falsepattern.zigbrains.project.execution.base.ZigExecConfig
|
|||
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
||||
import com.falsepattern.zigbrains.project.execution.base.executeCommandLine
|
||||
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
|
||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||
import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
|
||||
import com.intellij.execution.configurations.RunProfile
|
||||
import com.intellij.execution.executors.DefaultRunExecutor
|
||||
import com.intellij.execution.runners.ExecutionEnvironment
|
||||
import com.intellij.execution.runners.showRunContent
|
||||
import com.intellij.execution.runners.RunContentBuilder
|
||||
import com.intellij.execution.ui.RunContentDescriptor
|
||||
import com.intellij.openapi.application.EDT
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class ZigRegularRunner: ZigProgramRunner<ZigProfileState<*>>(DefaultRunExecutor.EXECUTOR_ID) {
|
||||
override suspend fun execute(state: ZigProfileState<*>, toolchain: AbstractZigToolchain, environment: ExecutionEnvironment): RunContentDescriptor? {
|
||||
val cli = state.getCommandLine(toolchain, false)
|
||||
val exec = executeCommandLine(cli, environment)
|
||||
return withContext(Dispatchers.EDT) {
|
||||
showRunContent(exec, environment)
|
||||
return withEDTContext {
|
||||
val runContentBuilder = RunContentBuilder(exec, environment)
|
||||
runContentBuilder.showRunContent(null)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@ import com.falsepattern.zigbrains.ZigBrainsBundle
|
|||
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
||||
import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain
|
||||
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainProvider
|
||||
import com.falsepattern.zigbrains.shared.coroutine.launchWithEDT
|
||||
import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
|
||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.EDT
|
||||
|
@ -35,6 +37,9 @@ import com.intellij.openapi.project.ProjectManager
|
|||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.UserDataHolderBase
|
||||
import com.intellij.openapi.util.io.toNioPathOrNull
|
||||
import com.intellij.platform.ide.progress.ModalTaskOwner
|
||||
import com.intellij.platform.ide.progress.TaskCancellation
|
||||
import com.intellij.platform.ide.progress.withModalProgress
|
||||
import com.intellij.ui.DocumentAdapter
|
||||
import com.intellij.ui.JBColor
|
||||
import com.intellij.ui.components.JBCheckBox
|
||||
|
@ -115,8 +120,10 @@ class ZigProjectSettingsPanel(private val project: Project?) : Disposable {
|
|||
cell(direnv)
|
||||
}
|
||||
button(ZigBrainsBundle.message("settings.project.label.toolchain-autodetect")) {
|
||||
this@ZigProjectSettingsPanel.project.zigCoroutineScope.launch {
|
||||
autodetect()
|
||||
project.zigCoroutineScope.launchWithEDT {
|
||||
withModalProgress(ModalTaskOwner.component(pathToToolchain), "Detecting Zig...", TaskCancellation.cancellable()) {
|
||||
autodetect()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +153,7 @@ class ZigProjectSettingsPanel(private val project: Project?) : Disposable {
|
|||
val env = zig?.getEnv(project)
|
||||
val version = env?.version
|
||||
val stdPath = env?.stdPath(toolchain)
|
||||
withContext(Dispatchers.EDT) {
|
||||
withEDTContext {
|
||||
toolchainVersion.text = version ?: ""
|
||||
toolchainVersion.foreground = JBColor.foreground()
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ package com.falsepattern.zigbrains.project.steps.discovery
|
|||
|
||||
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
||||
import com.falsepattern.zigbrains.project.steps.discovery.ZigStepDiscoveryListener.ErrorType
|
||||
import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
|
||||
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.EDT
|
||||
|
@ -120,7 +121,7 @@ class ZigStepDiscoveryService(private val project: Project) {
|
|||
}
|
||||
|
||||
private suspend fun dispatchReload() {
|
||||
withContext(Dispatchers.EDT) {
|
||||
withEDTContext {
|
||||
FileDocumentManager.getInstance().saveAllDocuments()
|
||||
}
|
||||
doReload()
|
||||
|
|
|
@ -29,6 +29,7 @@ import com.falsepattern.zigbrains.project.execution.build.ZigExecConfigBuild
|
|||
import com.falsepattern.zigbrains.project.execution.firstConfigFactory
|
||||
import com.falsepattern.zigbrains.project.steps.discovery.ZigStepDiscoveryListener
|
||||
import com.falsepattern.zigbrains.project.steps.discovery.zigStepDiscovery
|
||||
import com.falsepattern.zigbrains.shared.coroutine.withEDTContext
|
||||
import com.intellij.execution.ProgramRunnerUtil
|
||||
import com.intellij.execution.RunManager
|
||||
import com.intellij.execution.RunnerAndConfigurationSettings
|
||||
|
@ -137,7 +138,7 @@ class BuildToolWindowContext(private val project: Project): Disposable {
|
|||
|
||||
companion object {
|
||||
suspend fun create(project: Project, window: ToolWindow) {
|
||||
withContext(Dispatchers.EDT) {
|
||||
withEDTContext {
|
||||
val context = BuildToolWindowContext(project)
|
||||
Disposer.register(context, project.zigStepDiscovery.register(context.BuildReloadListener()))
|
||||
Disposer.register(window.disposable, context)
|
||||
|
@ -161,13 +162,13 @@ class BuildToolWindowContext(private val project: Project): Disposable {
|
|||
}
|
||||
buildZig.add(DefaultMutableTreeNode(StepNodeDescriptor(project, task, icon, description)))
|
||||
}
|
||||
withContext(Dispatchers.EDT) {
|
||||
withEDTContext {
|
||||
getViewport(project)?.let { setViewportTree(it) }
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun errorReload(type: ZigStepDiscoveryListener.ErrorType, details: String?) {
|
||||
withContext(Dispatchers.EDT) {
|
||||
withEDTContext {
|
||||
getViewport(project)?.setViewportError(ZigBrainsBundle.message(when(type) {
|
||||
ZigStepDiscoveryListener.ErrorType.MissingToolchain -> "build.tool.window.status.error.missing-toolchain"
|
||||
ZigStepDiscoveryListener.ErrorType.MissingBuildZig -> "build.tool.window.status.error.missing-build-zig"
|
||||
|
@ -177,7 +178,7 @@ class BuildToolWindowContext(private val project: Project): Disposable {
|
|||
}
|
||||
|
||||
override suspend fun timeoutReload(seconds: Int) {
|
||||
withContext(Dispatchers.EDT) {
|
||||
withEDTContext {
|
||||
getViewport(project)?.setViewportError(ZigBrainsBundle.message("build.tool.window.status.timeout", seconds), null)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ package com.falsepattern.zigbrains.project.toolchain
|
|||
|
||||
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
||||
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
||||
import com.intellij.execution.ExecutionException
|
||||
import com.intellij.execution.configurations.GeneralCommandLine
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.guessProjectDir
|
||||
|
@ -52,5 +53,15 @@ class LocalZigToolchain(val location: Path): AbstractZigToolchain() {
|
|||
|
||||
companion object {
|
||||
val DIRENV_KEY = KeyWithDefaultValue.create<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.process.ProcessOutput
|
||||
import com.intellij.util.io.awaitExit
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runInterruptible
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import java.nio.file.Path
|
||||
|
||||
|
@ -34,10 +36,14 @@ abstract class ZigTool(val toolchain: AbstractZigToolchain) {
|
|||
abstract val toolName: String
|
||||
|
||||
suspend fun callWithArgs(workingDirectory: Path?, vararg parameters: String, timeoutMillis: Long = Long.MAX_VALUE): ProcessOutput {
|
||||
val process = createBaseCommandLine(workingDirectory, *parameters).createProcess()
|
||||
val cli = createBaseCommandLine(workingDirectory, *parameters)
|
||||
|
||||
val exitCode = withTimeoutOrNull(timeoutMillis) {
|
||||
process.awaitExit()
|
||||
val (process, exitCode) = withContext(Dispatchers.IO) {
|
||||
val process = cli.createProcess()
|
||||
val exit = withTimeoutOrNull(timeoutMillis) {
|
||||
process.awaitExit()
|
||||
}
|
||||
process to exit
|
||||
}
|
||||
return runInterruptible {
|
||||
ProcessOutput(
|
||||
|
@ -50,8 +56,10 @@ abstract class ZigTool(val toolchain: AbstractZigToolchain) {
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun createBaseCommandLine(workingDirectory: Path?,
|
||||
vararg parameters: String): GeneralCommandLine {
|
||||
private suspend fun createBaseCommandLine(
|
||||
workingDirectory: Path?,
|
||||
vararg parameters: String
|
||||
): GeneralCommandLine {
|
||||
val cli = GeneralCommandLine()
|
||||
.withExePath(toolchain.pathToExecutable(toolName).toString())
|
||||
.withWorkDirectory(workingDirectory?.toString())
|
||||
|
|
|
@ -22,13 +22,17 @@
|
|||
|
||||
package com.falsepattern.zigbrains.shared.coroutine
|
||||
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.application.ModalityState
|
||||
import com.intellij.openapi.application.asContextElement
|
||||
import com.intellij.platform.ide.progress.ModalTaskOwner
|
||||
import com.intellij.platform.ide.progress.TaskCancellation
|
||||
import com.intellij.platform.ide.progress.runWithModalProgressBlocking
|
||||
import com.intellij.platform.ide.progress.withModalProgress
|
||||
import com.intellij.platform.util.progress.withProgressText
|
||||
import com.intellij.util.SuspendingLazy
|
||||
import com.intellij.util.application
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
inline fun <T> runModalOrBlocking(taskOwnerFactory: () -> ModalTaskOwner, titleFactory: () -> String, cancellationFactory: () -> TaskCancellation = TaskCancellation::cancellable, noinline action: suspend CoroutineScope.() -> T): T {
|
||||
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.zig-toolchain=Path to the Zig Toolchain
|
||||
dialog.title.zig-std=Path to the Standard Library
|
||||
exec.type.run.label=Zig Run
|
||||
exec.type.test.label=Zig Test
|
||||
exec.type.build.label=Zig Build
|
||||
exec.option.label.working-directory=&Working directory:
|
||||
exec.option.label.colored-terminal=Colored terminal
|
||||
exec.option.label.direnv=Use direnv
|
||||
|
@ -84,6 +87,7 @@ exec.option.label.build.steps=Build steps
|
|||
exec.option.label.build.args=Extra command line arguments
|
||||
exec.option.label.build.exe-args-debug=Output program command line arguments (debug only)
|
||||
exec.option.label.build.exe-path-debug=Output executable created by the build (debug only, autodetect if empty)
|
||||
exception.zig.empty-file-path=Empty file path
|
||||
exception.translate-command-line.unbalanced-quotes=Unbalanced quotes in {0}
|
||||
exception.zig-profile-state.start-process.no-toolchain=Failed to get zig toolchain from project
|
||||
exception.zig-build.debug.test-not-supported=Debugging "zig build test" is not yet supported
|
||||
|
|
|
@ -3,7 +3,7 @@ plugins {
|
|||
}
|
||||
rootProject.name = "ZigBrains"
|
||||
|
||||
for (module in arrayOf("core")) {
|
||||
for (module in arrayOf("core", "cidr")) {
|
||||
include(module)
|
||||
project(":$module").projectDir = file("modules/$module")
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
<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-debugger.xml">com.intellij.modules.cidr.debugger</depends>
|
||||
|
||||
<resource-bundle>zigbrains.Bundle</resource-bundle>
|
||||
|
||||
|
@ -24,5 +25,10 @@
|
|||
dynamic="true"
|
||||
name="featureProvider"
|
||||
/>
|
||||
<extensionPoint
|
||||
interface="com.falsepattern.zigbrains.debugbridge.ZigDebuggerDriverConfigurationProvider"
|
||||
dynamic="true"
|
||||
name="debuggerDriverProvider"
|
||||
/>
|
||||
</extensionPoints>
|
||||
</idea-plugin>
|
Loading…
Add table
Reference in a new issue