PROJECT STUFF!
This commit is contained in:
parent
4a132be408
commit
a7e3f3e161
99 changed files with 4533 additions and 180 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -60,3 +60,4 @@ gradle-app.setting
|
||||||
.intellijPlatform
|
.intellijPlatform
|
||||||
jbr
|
jbr
|
||||||
secrets
|
secrets
|
||||||
|
!modules/**/src/**/build/
|
|
@ -5,6 +5,7 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm") version "1.9.24" apply false
|
kotlin("jvm") version "1.9.24" apply false
|
||||||
|
kotlin("plugin.serialization") version "1.9.24" apply false
|
||||||
id("org.jetbrains.intellij.platform") version "2.1.0"
|
id("org.jetbrains.intellij.platform") version "2.1.0"
|
||||||
id("org.jetbrains.changelog") version "2.2.1"
|
id("org.jetbrains.changelog") version "2.2.1"
|
||||||
id("org.jetbrains.grammarkit") version "2022.3.2.2" apply false
|
id("org.jetbrains.grammarkit") version "2022.3.2.2" apply false
|
||||||
|
@ -81,7 +82,6 @@ dependencies {
|
||||||
}
|
}
|
||||||
|
|
||||||
implementation(project(":core"))
|
implementation(project(":core"))
|
||||||
implementation(project(":lsp"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
intellijPlatform {
|
intellijPlatform {
|
||||||
|
|
|
@ -4,12 +4,21 @@ import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("org.jetbrains.grammarkit")
|
id("org.jetbrains.grammarkit")
|
||||||
|
kotlin("plugin.serialization")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val lsp4ijVersion: String by project
|
||||||
|
val lsp4jVersion: String by project
|
||||||
|
val lsp4ijNightly = property("lsp4ijNightly").toString().toBoolean()
|
||||||
|
val lsp4ijDepString = "${if (lsp4ijNightly) "nightly." else ""}com.jetbrains.plugins:com.redhat.devtools.lsp4ij:$lsp4ijVersion"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
intellijPlatform {
|
intellijPlatform {
|
||||||
create(IntelliJPlatformType.IntellijIdeaCommunity, providers.gradleProperty("ideaCommunityVersion"))
|
create(IntelliJPlatformType.IntellijIdeaCommunity, providers.gradleProperty("ideaCommunityVersion"))
|
||||||
}
|
}
|
||||||
|
intellijPlatformPluginDependency(lsp4ijDepString)
|
||||||
|
compileOnly("org.eclipse.lsp4j:org.eclipse.lsp4j:$lsp4jVersion")
|
||||||
|
compileOnly("org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3")
|
||||||
}
|
}
|
||||||
|
|
||||||
//region grammars
|
//region grammars
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.lsp
|
package com.falsepattern.zigbrains.lsp
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||||
import com.intellij.openapi.components.service
|
import com.intellij.openapi.components.service
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
|
@ -68,7 +69,7 @@ class ZigLanguageServerFactory: LanguageServerFactory, LanguageServerEnablementS
|
||||||
|
|
||||||
class ZLSStarter: LanguageServerStarter {
|
class ZLSStarter: LanguageServerStarter {
|
||||||
override fun startLSP(project: Project, restart: Boolean) {
|
override fun startLSP(project: Project, restart: Boolean) {
|
||||||
project.service<ZigLSPProjectService>().cs.launch {
|
project.zigCoroutineScope.launch {
|
||||||
val manager = project.service<LanguageServerManager>()
|
val manager = project.service<LanguageServerManager>()
|
||||||
val status = manager.getServerStatus("ZigBrains")
|
val status = manager.getServerStatus("ZigBrains")
|
||||||
if ((status == ServerStatus.started || status == ServerStatus.starting) && !restart)
|
if ((status == ServerStatus.started || status == ServerStatus.starting) && !restart)
|
|
@ -25,8 +25,10 @@
|
||||||
package com.falsepattern.zigbrains.lsp.config
|
package com.falsepattern.zigbrains.lsp.config
|
||||||
|
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import org.jetbrains.annotations.NonNls
|
import org.jetbrains.annotations.NonNls
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class ZLSConfig(
|
data class ZLSConfig(
|
||||||
@SerialName("zig_exe_path") val zigExePath: @NonNls String? = null,
|
@SerialName("zig_exe_path") val zigExePath: @NonNls String? = null,
|
||||||
@SerialName("zig_lib_path") val zigLibPath: @NonNls String? = null,
|
@SerialName("zig_lib_path") val zigLibPath: @NonNls String? = null,
|
|
@ -24,17 +24,16 @@ package com.falsepattern.zigbrains.lsp.settings
|
||||||
|
|
||||||
import org.jetbrains.annotations.NonNls
|
import org.jetbrains.annotations.NonNls
|
||||||
|
|
||||||
@JvmRecord
|
|
||||||
data class ZLSSettings(
|
data class ZLSSettings(
|
||||||
val direnv: Boolean = true,
|
var direnv: Boolean = true,
|
||||||
val zlsPath: @NonNls String = "",
|
var zlsPath: @NonNls String = "",
|
||||||
val zlsConfigPath: @NonNls String = "",
|
var zlsConfigPath: @NonNls String = "",
|
||||||
val debug: Boolean = false,
|
var debug: Boolean = false,
|
||||||
val messageTrace: Boolean = false,
|
var messageTrace: Boolean = false,
|
||||||
val buildOnSave: Boolean = false,
|
var buildOnSave: Boolean = false,
|
||||||
val buildOnSaveStep: @NonNls String = "install",
|
var buildOnSaveStep: @NonNls String = "install",
|
||||||
val globalVarDeclarations: Boolean = false,
|
var globalVarDeclarations: Boolean = false,
|
||||||
val comptimeInterpreter: Boolean = false,
|
var comptimeInterpreter: Boolean = false,
|
||||||
val inlayHints: Boolean = true,
|
var inlayHints: Boolean = true,
|
||||||
val inlayHintsCompact: Boolean = true
|
var inlayHintsCompact: Boolean = true
|
||||||
)
|
)
|
|
@ -22,19 +22,16 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.lsp.settings
|
package com.falsepattern.zigbrains.lsp.settings
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.lsp.ZLSBundle
|
|
||||||
import com.falsepattern.zigbrains.lsp.startLSP
|
import com.falsepattern.zigbrains.lsp.startLSP
|
||||||
import com.falsepattern.zigbrains.shared.NestedConfigurable
|
import com.falsepattern.zigbrains.shared.SubConfigurable
|
||||||
import com.intellij.openapi.components.service
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.util.Disposer
|
||||||
import com.intellij.ui.dsl.builder.Panel
|
import com.intellij.ui.dsl.builder.Panel
|
||||||
import com.intellij.ui.dsl.builder.panel
|
|
||||||
import javax.swing.JComponent
|
|
||||||
|
|
||||||
class ZLSSettingsConfigurable(private val project: Project): NestedConfigurable {
|
class ZLSSettingsConfigurable(private val project: Project): SubConfigurable {
|
||||||
private var appSettingsComponent: ZLSSettingsPanel? = null
|
private var appSettingsComponent: ZLSSettingsPanel? = null
|
||||||
override fun createComponent(panel: Panel) {
|
override fun createComponent(panel: Panel) {
|
||||||
appSettingsComponent = ZLSSettingsPanel(project).apply { attach(panel) }
|
appSettingsComponent = ZLSSettingsPanel(project).apply { attach(panel) }.also { Disposer.register(this, it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isModified(): Boolean {
|
override fun isModified(): Boolean {
|
||||||
|
@ -56,12 +53,7 @@ class ZLSSettingsConfigurable(private val project: Project): NestedConfigurable
|
||||||
appSettingsComponent?.data = project.zlsSettings.state
|
appSettingsComponent?.data = project.zlsSettings.state
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun disposeUIResources() {
|
override fun dispose() {
|
||||||
appSettingsComponent?.dispose()
|
|
||||||
appSettingsComponent = null
|
appSettingsComponent = null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getDisplayName(): String {
|
|
||||||
return ZLSBundle.message("configurable.name.zls.settings")
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -24,12 +24,12 @@ package com.falsepattern.zigbrains.lsp.settings
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.direnv.*
|
import com.falsepattern.zigbrains.direnv.*
|
||||||
import com.falsepattern.zigbrains.lsp.ZLSBundle
|
import com.falsepattern.zigbrains.lsp.ZLSBundle
|
||||||
import com.falsepattern.zigbrains.lsp.ZigLSPApplicationService
|
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||||
import com.falsepattern.zigbrains.lsp.ZigLSPProjectService
|
|
||||||
import com.intellij.openapi.Disposable
|
import com.intellij.openapi.Disposable
|
||||||
import com.intellij.openapi.components.service
|
import com.intellij.openapi.components.service
|
||||||
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
|
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.util.Disposer
|
||||||
import com.intellij.ui.components.JBCheckBox
|
import com.intellij.ui.components.JBCheckBox
|
||||||
import com.intellij.ui.components.fields.ExtendableTextField
|
import com.intellij.ui.components.fields.ExtendableTextField
|
||||||
import com.intellij.ui.components.textFieldWithBrowseButton
|
import com.intellij.ui.components.textFieldWithBrowseButton
|
||||||
|
@ -44,12 +44,12 @@ class ZLSSettingsPanel(private val project: Project?) : Disposable {
|
||||||
project,
|
project,
|
||||||
ZLSBundle.message("settings.zls-path.browse.title"),
|
ZLSBundle.message("settings.zls-path.browse.title"),
|
||||||
FileChooserDescriptorFactory.createSingleFileDescriptor(),
|
FileChooserDescriptorFactory.createSingleFileDescriptor(),
|
||||||
)
|
).also { Disposer.register(this, it) }
|
||||||
private val zlsConfigPath = textFieldWithBrowseButton(
|
private val zlsConfigPath = textFieldWithBrowseButton(
|
||||||
project,
|
project,
|
||||||
ZLSBundle.message("settings.zls-config-path.browse.title"),
|
ZLSBundle.message("settings.zls-config-path.browse.title"),
|
||||||
FileChooserDescriptorFactory.createSingleFileDescriptor()
|
FileChooserDescriptorFactory.createSingleFileDescriptor()
|
||||||
)
|
).also { Disposer.register(this, it) }
|
||||||
|
|
||||||
private val buildOnSave = JBCheckBox().apply { toolTipText = ZLSBundle.message("settings.build-on-save.tooltip") }
|
private val buildOnSave = JBCheckBox().apply { toolTipText = ZLSBundle.message("settings.build-on-save.tooltip") }
|
||||||
private val buildOnSaveStep = ExtendableTextField().apply { toolTipText = ZLSBundle.message("settings.build-on-save-step.tooltip") }
|
private val buildOnSaveStep = ExtendableTextField().apply { toolTipText = ZLSBundle.message("settings.build-on-save-step.tooltip") }
|
||||||
|
@ -69,7 +69,11 @@ class ZLSSettingsPanel(private val project: Project?) : Disposable {
|
||||||
if (DirenvCmd.direnvInstalled() && project != null) {
|
if (DirenvCmd.direnvInstalled() && project != null) {
|
||||||
cell(direnv)
|
cell(direnv)
|
||||||
}
|
}
|
||||||
button(ZLSBundle.message("settings.zls-path.autodetect.label")) { autodetect() }
|
button(ZLSBundle.message("settings.zls-path.autodetect.label")) {
|
||||||
|
project.zigCoroutineScope.launch {
|
||||||
|
autodetect()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
row(ZLSBundle.message("settings.zls-config-path.label")) { cell(zlsConfigPath).align(AlignX.FILL) }
|
row(ZLSBundle.message("settings.zls-config-path.label")) { cell(zlsConfigPath).align(AlignX.FILL) }
|
||||||
row(ZLSBundle.message("settings.inlay-hints.label")) { cell(inlayHints) }
|
row(ZLSBundle.message("settings.inlay-hints.label")) { cell(inlayHints) }
|
||||||
|
@ -113,15 +117,11 @@ class ZLSSettingsPanel(private val project: Project?) : Disposable {
|
||||||
inlayHintsCompact.isSelected = value.inlayHintsCompact
|
inlayHintsCompact.isSelected = value.inlayHintsCompact
|
||||||
}
|
}
|
||||||
|
|
||||||
fun autodetect() {
|
suspend fun autodetect() {
|
||||||
(project?.service<ZigLSPProjectService>()?.cs ?: application.service<ZigLSPApplicationService>().cs).launch {
|
getDirenv().findExecutableOnPATH("zls")?.let { zlsPath.text = it.pathString }
|
||||||
getDirenv().findExecutableOnPATH("zls")?.let { zlsPath.text = it.pathString }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
zlsPath.dispose()
|
|
||||||
zlsConfigPath.dispose()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getDirenv(): Env {
|
private suspend fun getDirenv(): Env {
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* 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.project.actions
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.Icons
|
||||||
|
import com.intellij.ide.actions.CreateFileFromTemplateAction
|
||||||
|
import com.intellij.ide.actions.CreateFileFromTemplateDialog
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiDirectory
|
||||||
|
|
||||||
|
class ZigNewFileAction: CreateFileFromTemplateAction() {
|
||||||
|
override fun buildDialog(project: Project, directory: PsiDirectory, builder: CreateFileFromTemplateDialog.Builder) {
|
||||||
|
builder.setTitle("Zig File")
|
||||||
|
.addKind("Empty file", Icons.ZIG, "blank_zig_file")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getActionName(directory: PsiDirectory?, newName: String, templateName: String?): String {
|
||||||
|
return "Zig File"
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.project.console
|
||||||
|
|
||||||
|
import com.intellij.execution.filters.ConsoleFilterProvider
|
||||||
|
import com.intellij.execution.filters.Filter
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
|
||||||
|
class ZigConsoleFilterProvider: ConsoleFilterProvider {
|
||||||
|
override fun getDefaultFilters(project: Project): Array<Filter> {
|
||||||
|
return arrayOf(ZigSourceFileFilter(project))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* 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.project.console
|
||||||
|
|
||||||
|
import com.intellij.execution.filters.Filter
|
||||||
|
import com.intellij.execution.filters.Filter.ResultItem
|
||||||
|
import com.intellij.execution.filters.OpenFileHyperlinkInfo
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.project.guessProjectDir
|
||||||
|
import com.intellij.openapi.util.io.toNioPathOrNull
|
||||||
|
import com.intellij.openapi.vfs.refreshAndFindVirtualFile
|
||||||
|
import com.intellij.openapi.vfs.toNioPathOrNull
|
||||||
|
import java.nio.file.InvalidPathException
|
||||||
|
import java.nio.file.Path
|
||||||
|
import kotlin.io.path.isRegularFile
|
||||||
|
import kotlin.io.path.notExists
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
|
|
||||||
|
class ZigSourceFileFilter(private val project: Project): Filter {
|
||||||
|
override fun applyFilter(line: String, entireLength: Int): Filter.Result? {
|
||||||
|
val lineStart = entireLength - line.length
|
||||||
|
val projectPath = project.guessProjectDir()?.toNioPathOrNull()
|
||||||
|
val results = ArrayList<ResultItem>()
|
||||||
|
val matcher = LEN_REGEX.findAll(line)
|
||||||
|
for (match in matcher) {
|
||||||
|
val start = match.range.first
|
||||||
|
val pair = findLongestParsablePathFromOffset(line, start, projectPath)
|
||||||
|
val path = pair?.first ?: return null
|
||||||
|
val file = path.refreshAndFindVirtualFile() ?: return null
|
||||||
|
val lineNumber = max(match.groups[1]!!.value.toInt() - 1, 0)
|
||||||
|
val lineOffset = max(match.groups[2]!!.value.toInt() - 1, 0)
|
||||||
|
results.add(ResultItem(lineStart + pair.second, lineStart + match.range.last + 1, OpenFileHyperlinkInfo(project, file, lineNumber, lineOffset)))
|
||||||
|
}
|
||||||
|
return Filter.Result(results)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findLongestParsablePathFromOffset(line: String, end: Int, projectPath: Path?): Pair<Path, Int>? {
|
||||||
|
var longestStart = -1
|
||||||
|
var longest: Path? = null
|
||||||
|
for (i in end - 1 downTo 0) {
|
||||||
|
try {
|
||||||
|
val pathStr = line.substring(i, end)
|
||||||
|
var path: Path = pathStr.toNioPathOrNull() ?: continue
|
||||||
|
if ((path.notExists() || !path.isRegularFile()) && projectPath != null) {
|
||||||
|
path = projectPath.resolve(pathStr)
|
||||||
|
if (path.notExists() || !path.isRegularFile())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
longest = path
|
||||||
|
longestStart = i
|
||||||
|
} catch (ignored: InvalidPathException) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
longest ?: return null
|
||||||
|
return Pair(longest, longestStart)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val LEN_REGEX = Regex(":(\\d+):(\\d+)")
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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.project.execution
|
||||||
|
|
||||||
|
import com.intellij.execution.configurations.ConfigurationFactory
|
||||||
|
import com.intellij.execution.configurations.ConfigurationTypeBase
|
||||||
|
import com.intellij.execution.configurations.ConfigurationTypeUtil
|
||||||
|
import com.intellij.execution.configurations.runConfigurationType
|
||||||
|
|
||||||
|
inline fun <reified T: ConfigurationTypeBase> firstConfigFactory(): ConfigurationFactory {
|
||||||
|
return runConfigurationType<T>().configurationFactories.first()
|
||||||
|
}
|
|
@ -0,0 +1,390 @@
|
||||||
|
/*
|
||||||
|
* 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.project.execution.base
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||||
|
import com.falsepattern.zigbrains.project.execution.base.ZigConfigurable.ZigConfigModule
|
||||||
|
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
||||||
|
import com.falsepattern.zigbrains.shared.cli.translateCommandline
|
||||||
|
import com.falsepattern.zigbrains.shared.element.*
|
||||||
|
import com.intellij.openapi.Disposable
|
||||||
|
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
|
||||||
|
import com.intellij.openapi.options.SettingsEditor
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.ui.ComboBox
|
||||||
|
import com.intellij.openapi.ui.TextBrowseFolderListener
|
||||||
|
import com.intellij.openapi.ui.TextFieldWithBrowseButton
|
||||||
|
import com.intellij.openapi.util.Disposer
|
||||||
|
import com.intellij.openapi.util.io.toNioPathOrNull
|
||||||
|
import com.intellij.ui.components.JBCheckBox
|
||||||
|
import com.intellij.ui.components.JBTextField
|
||||||
|
import com.intellij.ui.dsl.builder.AlignX
|
||||||
|
import com.intellij.ui.dsl.builder.Panel
|
||||||
|
import com.intellij.ui.dsl.builder.panel
|
||||||
|
import org.jdom.Element
|
||||||
|
import org.jetbrains.annotations.Nls
|
||||||
|
import java.io.Serializable
|
||||||
|
import java.nio.file.Path
|
||||||
|
import javax.swing.JComponent
|
||||||
|
import kotlin.io.path.pathString
|
||||||
|
|
||||||
|
class ZigConfigEditor<T : ZigExecConfig<T>>(private val state: ZigExecConfig<T>) : SettingsEditor<T>() {
|
||||||
|
private val configModules = ArrayList<ZigConfigModule<*>>()
|
||||||
|
|
||||||
|
override fun resetEditorFrom(s: T) {
|
||||||
|
outer@ for (cfg in s.getConfigurables()) {
|
||||||
|
for (module in configModules) {
|
||||||
|
if (module.tryReset(cfg))
|
||||||
|
continue@outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun applyEditorTo(s: T) {
|
||||||
|
outer@ for (cfg in s.getConfigurables()) {
|
||||||
|
for (module in configModules) {
|
||||||
|
if (module.tryApply(cfg)) {
|
||||||
|
continue@outer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createEditor(): JComponent {
|
||||||
|
configModules.clear()
|
||||||
|
configModules.addAll(state.getConfigurables().map { it.createEditor() })
|
||||||
|
return panel {
|
||||||
|
for (module in configModules) {
|
||||||
|
module.construct(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun disposeEditor() {
|
||||||
|
for (module in configModules) {
|
||||||
|
module.dispose()
|
||||||
|
}
|
||||||
|
configModules.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ZigConfigurable<T : ZigConfigurable<T>> : Serializable, Cloneable {
|
||||||
|
fun readExternal(element: Element)
|
||||||
|
fun writeExternal(element: Element)
|
||||||
|
fun createEditor(): ZigConfigModule<T>
|
||||||
|
public override fun clone(): T
|
||||||
|
|
||||||
|
interface ZigConfigModule<T : ZigConfigurable<T>> : Disposable {
|
||||||
|
fun tryMatch(cfg: ZigConfigurable<*>): T?
|
||||||
|
fun apply(configurable: T): Boolean
|
||||||
|
fun reset(configurable: T)
|
||||||
|
fun tryApply(cfg: ZigConfigurable<*>): Boolean {
|
||||||
|
val x = tryMatch(cfg)
|
||||||
|
if (x != null) {
|
||||||
|
return apply(x)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tryReset(cfg: ZigConfigurable<*>): Boolean {
|
||||||
|
val x = tryMatch(cfg)
|
||||||
|
if (x != null) {
|
||||||
|
reset(x)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun construct(p: Panel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class PathConfigurable<T : PathConfigurable<T>> : ZigConfigurable<T> {
|
||||||
|
var path: Path? = null
|
||||||
|
|
||||||
|
override fun readExternal(element: Element) {
|
||||||
|
path = element.readString(serializedName)?.ifBlank { null }?.toNioPathOrNull() ?: return
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeExternal(element: Element) {
|
||||||
|
element.writeString(serializedName, path?.pathString ?: "")
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract val serializedName: String
|
||||||
|
|
||||||
|
abstract class PathConfigModule<T : PathConfigurable<T>> : ZigConfigModule<T> {
|
||||||
|
override fun apply(configurable: T): Boolean {
|
||||||
|
val str = stringValue
|
||||||
|
if (str.isBlank()) {
|
||||||
|
configurable.path = null
|
||||||
|
} else {
|
||||||
|
configurable.path = str.toNioPathOrNull() ?: return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reset(configurable: T) {
|
||||||
|
stringValue = configurable.path?.pathString ?: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract var stringValue: String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WorkDirectoryConfigurable(@Transient override val serializedName: String) : PathConfigurable<WorkDirectoryConfigurable>(), Cloneable {
|
||||||
|
override fun createEditor(): ZigConfigModule<WorkDirectoryConfigurable> {
|
||||||
|
return WorkDirectoryConfigModule(serializedName)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clone(): WorkDirectoryConfigurable {
|
||||||
|
return super<Cloneable>.clone() as WorkDirectoryConfigurable
|
||||||
|
}
|
||||||
|
|
||||||
|
class WorkDirectoryConfigModule(private val serializedName: String) : PathConfigModule<WorkDirectoryConfigurable>() {
|
||||||
|
private val field = TextFieldWithBrowseButton(
|
||||||
|
TextBrowseFolderListener(
|
||||||
|
FileChooserDescriptorFactory.createSingleFolderDescriptor().withTitle(ZigBrainsBundle.message("dialog.title.working-directory"))
|
||||||
|
),
|
||||||
|
this
|
||||||
|
)
|
||||||
|
|
||||||
|
override var stringValue by field::text
|
||||||
|
|
||||||
|
override fun tryMatch(cfg: ZigConfigurable<*>): WorkDirectoryConfigurable? {
|
||||||
|
return if (cfg is WorkDirectoryConfigurable && cfg.serializedName == serializedName) cfg else null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun construct(p: Panel): Unit = with(p) {
|
||||||
|
row(ZigBrainsBundle.message("exec.option.label.working-directory")) {
|
||||||
|
cell(field).resizableColumn().align(AlignX.FILL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
field.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FilePathConfigurable(
|
||||||
|
@Transient override val serializedName: String,
|
||||||
|
@Transient @Nls private val guiLabel: String
|
||||||
|
) : PathConfigurable<FilePathConfigurable>(), Cloneable {
|
||||||
|
|
||||||
|
override fun createEditor(): ZigConfigModule<FilePathConfigurable> {
|
||||||
|
return FilePathConfigModule(serializedName, guiLabel)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clone(): FilePathConfigurable {
|
||||||
|
return super<Cloneable>.clone() as FilePathConfigurable
|
||||||
|
}
|
||||||
|
|
||||||
|
class FilePathConfigModule(private val serializedName: String, @Nls private val label: String) : PathConfigModule<FilePathConfigurable>() {
|
||||||
|
private val field = TextFieldWithBrowseButton(
|
||||||
|
TextBrowseFolderListener(FileChooserDescriptorFactory.createSingleFileDescriptor()),
|
||||||
|
this
|
||||||
|
)
|
||||||
|
|
||||||
|
override var stringValue by field::text
|
||||||
|
|
||||||
|
override fun tryMatch(cfg: ZigConfigurable<*>): FilePathConfigurable? {
|
||||||
|
return if (cfg is FilePathConfigurable && cfg.serializedName == serializedName) cfg else null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun construct(p: Panel): Unit = with(p) {
|
||||||
|
row(label) {
|
||||||
|
cell(field).resizableColumn().align(AlignX.FILL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
Disposer.dispose(field)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CheckboxConfigurable(
|
||||||
|
@Transient private val serializedName: String,
|
||||||
|
@Transient @Nls private val label: String,
|
||||||
|
var value: Boolean
|
||||||
|
) : ZigConfigurable<CheckboxConfigurable>, Cloneable {
|
||||||
|
override fun readExternal(element: Element) {
|
||||||
|
value = element.readBoolean(serializedName) ?: return
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeExternal(element: Element) {
|
||||||
|
element.writeBoolean(serializedName, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createEditor(): ZigConfigModule<CheckboxConfigurable> {
|
||||||
|
return CheckboxConfigModule(serializedName, label)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clone(): CheckboxConfigurable {
|
||||||
|
return super<Cloneable>.clone() as CheckboxConfigurable
|
||||||
|
}
|
||||||
|
|
||||||
|
class CheckboxConfigModule(
|
||||||
|
private val serializedName: String,
|
||||||
|
@Nls private val label: String
|
||||||
|
) : ZigConfigModule<CheckboxConfigurable> {
|
||||||
|
private val checkBox = JBCheckBox()
|
||||||
|
|
||||||
|
override fun tryMatch(cfg: ZigConfigurable<*>): CheckboxConfigurable? {
|
||||||
|
return if (cfg is CheckboxConfigurable && cfg.serializedName == serializedName) cfg else null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun apply(configurable: CheckboxConfigurable): Boolean {
|
||||||
|
configurable.value = checkBox.isSelected
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reset(configurable: CheckboxConfigurable) {
|
||||||
|
checkBox.isSelected = configurable.value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun construct(p: Panel): Unit = with(p) {
|
||||||
|
row(label) {
|
||||||
|
cell(checkBox)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ColoredConfigurable(serializedName: String) = CheckboxConfigurable(serializedName, ZigBrainsBundle.message("exec.option.label.colored-terminal"), true)
|
||||||
|
|
||||||
|
fun DirenvConfigurable(serializedName: String, project: Project) =
|
||||||
|
CheckboxConfigurable(serializedName, ZigBrainsBundle.message("exec.option.label.direnv"), project.zigProjectSettings.state.direnv)
|
||||||
|
|
||||||
|
class OptimizationConfigurable(
|
||||||
|
@Transient private val serializedName: String,
|
||||||
|
var level: OptimizationLevel = OptimizationLevel.Debug,
|
||||||
|
var forced: Boolean = false
|
||||||
|
) : ZigConfigurable<OptimizationConfigurable>, Cloneable {
|
||||||
|
override fun readExternal(element: Element) {
|
||||||
|
element.readChild(serializedName)?.apply {
|
||||||
|
readEnum<OptimizationLevel>("level")?.let { level = it }
|
||||||
|
readBoolean("forced")?.let { forced = it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeExternal(element: Element) {
|
||||||
|
element.writeChild(serializedName).apply {
|
||||||
|
writeEnum("level", level)
|
||||||
|
writeBoolean("forced", forced)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createEditor(): ZigConfigModule<OptimizationConfigurable> {
|
||||||
|
return OptimizationConfigModule(serializedName)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clone(): OptimizationConfigurable {
|
||||||
|
return super<Cloneable>.clone() as OptimizationConfigurable
|
||||||
|
}
|
||||||
|
|
||||||
|
class OptimizationConfigModule(private val serializedName: String) : ZigConfigModule<OptimizationConfigurable> {
|
||||||
|
private val levels = ComboBox(OptimizationLevel.entries.toTypedArray())
|
||||||
|
private val forced = JBCheckBox(ZigBrainsBundle.message("exec.option.label.optimization.force"))
|
||||||
|
override fun tryMatch(cfg: ZigConfigurable<*>): OptimizationConfigurable? {
|
||||||
|
return if (cfg is OptimizationConfigurable && cfg.serializedName == serializedName) cfg else null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun apply(configurable: OptimizationConfigurable): Boolean {
|
||||||
|
configurable.level = levels.item
|
||||||
|
configurable.forced = forced.isSelected
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reset(configurable: OptimizationConfigurable) {
|
||||||
|
levels.item = configurable.level
|
||||||
|
forced.isSelected = configurable.forced
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun construct(p: Panel): Unit = with(p) {
|
||||||
|
row(ZigBrainsBundle.message("exec.option.label.optimization")) {
|
||||||
|
cell(levels)
|
||||||
|
cell(forced)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ArgsConfigurable(
|
||||||
|
@Transient private val serializedName: String,
|
||||||
|
@Transient @Nls private val guiName: String
|
||||||
|
) : ZigConfigurable<ArgsConfigurable>, Cloneable {
|
||||||
|
var args: List<String> = emptyList()
|
||||||
|
|
||||||
|
override fun readExternal(element: Element) {
|
||||||
|
args = element.readStrings(serializedName) ?: return
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeExternal(element: Element) {
|
||||||
|
element.writeStrings(serializedName, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createEditor(): ZigConfigModule<ArgsConfigurable> {
|
||||||
|
return ArgsConfigModule(serializedName, guiName)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clone(): ArgsConfigurable {
|
||||||
|
return super<Cloneable>.clone() as ArgsConfigurable
|
||||||
|
}
|
||||||
|
|
||||||
|
class ArgsConfigModule(
|
||||||
|
private val serializedName: String,
|
||||||
|
@Nls private val guiName: String
|
||||||
|
) : ZigConfigModule<ArgsConfigurable> {
|
||||||
|
private val argsField = JBTextField()
|
||||||
|
|
||||||
|
override fun tryMatch(cfg: ZigConfigurable<*>): ArgsConfigurable? {
|
||||||
|
return if (cfg is ArgsConfigurable && cfg.serializedName == serializedName) cfg else null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun apply(configurable: ArgsConfigurable): Boolean {
|
||||||
|
configurable.args = translateCommandline(argsField.text)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reset(configurable: ArgsConfigurable) {
|
||||||
|
argsField.text = configurable.args.joinToString(separator = " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun construct(p: Panel): Unit = with(p) {
|
||||||
|
row(guiName) {
|
||||||
|
cell(argsField).resizableColumn().align(AlignX.FILL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,17 +20,11 @@
|
||||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.lsp
|
package com.falsepattern.zigbrains.project.execution.base
|
||||||
|
|
||||||
import com.intellij.openapi.components.Service
|
enum class OptimizationLevel {
|
||||||
import kotlinx.coroutines.CoroutineScope
|
Debug,
|
||||||
|
ReleaseSafe,
|
||||||
@Service(Service.Level.PROJECT)
|
ReleaseFast,
|
||||||
class ZigLSPProjectService(
|
ReleaseSmall
|
||||||
val cs: CoroutineScope
|
}
|
||||||
)
|
|
||||||
|
|
||||||
@Service
|
|
||||||
class ZigLSPApplicationService(
|
|
||||||
val cs: CoroutineScope
|
|
||||||
)
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* 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.project.execution.base
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.zig.psi.ZigFile
|
||||||
|
import com.intellij.execution.actions.ConfigurationContext
|
||||||
|
import com.intellij.execution.actions.ConfigurationFromContext
|
||||||
|
import com.intellij.execution.actions.LazyRunConfigurationProducer
|
||||||
|
import com.intellij.execution.configurations.ConfigurationFactory
|
||||||
|
import com.intellij.openapi.util.Ref
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.openapi.vfs.toNioPathOrNull
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
abstract class ZigConfigProducer<T: ZigExecConfig<T>>: LazyRunConfigurationProducer<T>() {
|
||||||
|
abstract override fun getConfigurationFactory(): ConfigurationFactory
|
||||||
|
|
||||||
|
override fun setupConfigurationFromContext(configuration: T, context: ConfigurationContext, sourceElement: Ref<PsiElement>): Boolean {
|
||||||
|
val element = context.location?.psiElement ?: return false
|
||||||
|
val psiFile = element.containingFile as? ZigFile ?: return false
|
||||||
|
val theFile = psiFile.virtualFile ?: return false
|
||||||
|
val filePath = theFile.toNioPathOrNull() ?: return false
|
||||||
|
return setupConfigurationFromContext(configuration, element, filePath, theFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isConfigurationFromContext(configuration: T, context: ConfigurationContext): Boolean {
|
||||||
|
val element = context.location?.psiElement ?: return false
|
||||||
|
val psiFile = element.containingFile as? ZigFile ?: return false
|
||||||
|
val theFile = psiFile.virtualFile ?: return false
|
||||||
|
val filePath = theFile.toNioPathOrNull() ?: return false
|
||||||
|
return isConfigurationFromContext(configuration, element, filePath, theFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO implement these
|
||||||
|
@Override
|
||||||
|
protected boolean setupConfigurationFromContext(@NotNull ZigExecConfigRun configuration, PsiElement element, String filePath, VirtualFile theFile) {
|
||||||
|
if (PsiUtil.getElementType(element) == ZigTypes.KEYWORD_TEST) {
|
||||||
|
configuration.command = "test " + filePath;
|
||||||
|
configuration.setName("Test " + theFile.getPresentableName());
|
||||||
|
} else if ("build.zig".equals(theFile.getName())) {
|
||||||
|
configuration.command = "build";
|
||||||
|
configuration.setName("Build");
|
||||||
|
} else {
|
||||||
|
configuration.extraArgs = filePath;
|
||||||
|
configuration.setName(theFile.getPresentableName());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isConfigurationFromContext(@NotNull ZigExecConfigRun configuration, String filePath, VirtualFile vFile, PsiElement element) {
|
||||||
|
if (!configuration.command.contains(filePath)) {
|
||||||
|
return configuration.command.startsWith("build") && vFile.getName().equals("build.zig");
|
||||||
|
}
|
||||||
|
return (PsiUtil.getElementType(element) == ZigTypes.KEYWORD_TEST) == configuration.command.startsWith("test ");
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
protected abstract fun setupConfigurationFromContext(configuration: T, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean
|
||||||
|
protected abstract fun isConfigurationFromContext(configuration: T, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean
|
||||||
|
abstract override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean
|
||||||
|
}
|
|
@ -22,7 +22,68 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project.execution.base
|
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.Executor
|
||||||
|
import com.intellij.execution.configurations.ConfigurationFactory
|
||||||
|
import com.intellij.execution.configurations.GeneralCommandLine
|
||||||
import com.intellij.execution.configurations.LocatableConfigurationBase
|
import com.intellij.execution.configurations.LocatableConfigurationBase
|
||||||
|
import com.intellij.execution.configurations.RunConfiguration
|
||||||
|
import com.intellij.execution.runners.ExecutionEnvironment
|
||||||
|
import com.intellij.openapi.options.SettingsEditor
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.project.guessProjectDir
|
||||||
|
import com.intellij.openapi.util.NlsActions.ActionText
|
||||||
|
import com.intellij.openapi.vfs.toNioPathOrNull
|
||||||
|
import org.jdom.Element
|
||||||
|
|
||||||
abstract class ZigExecConfig<T: ZigExecConfig<T>>: LocatableConfigurationBase {
|
abstract class ZigExecConfig<T: ZigExecConfig<T>>(project: Project, factory: ConfigurationFactory, 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)
|
||||||
|
private set
|
||||||
|
var direnv = DirenvConfigurable("direnv", project)
|
||||||
|
private set
|
||||||
|
|
||||||
|
abstract val suggestedName: @ActionText String
|
||||||
|
abstract suspend fun buildCommandLineArgs(debug: Boolean): List<String>
|
||||||
|
abstract override fun getState(executor: Executor, environment: ExecutionEnvironment): ZigProfileState<T>
|
||||||
|
|
||||||
|
override fun getConfigurationEditor(): SettingsEditor<out RunConfiguration> {
|
||||||
|
return ZigConfigEditor(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun readExternal(element: Element) {
|
||||||
|
super.readExternal(element)
|
||||||
|
getConfigurables().forEach { it.readExternal(element) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeExternal(element: Element) {
|
||||||
|
super.writeExternal(element)
|
||||||
|
getConfigurables().forEach { it.writeExternal(element) }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
suspend fun patchCommandLine(commandLine: GeneralCommandLine, toolchain: AbstractZigToolchain): GeneralCommandLine {
|
||||||
|
if (direnv.value) {
|
||||||
|
commandLine.withEnvironment(DirenvCmd.importDirenv(project).env)
|
||||||
|
}
|
||||||
|
return commandLine
|
||||||
|
}
|
||||||
|
|
||||||
|
fun emulateTerminal(): Boolean {
|
||||||
|
return pty.value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clone(): T {
|
||||||
|
val myClone = super.clone() as ZigExecConfig<*>
|
||||||
|
myClone.workingDirectory = workingDirectory.clone()
|
||||||
|
myClone.pty = pty.clone()
|
||||||
|
myClone.direnv = direnv.clone()
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return myClone as T
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun getConfigurables(): List<ZigConfigurable<*>> = listOf(workingDirectory, pty, direnv)
|
||||||
}
|
}
|
|
@ -22,12 +22,68 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project.execution.base
|
package com.falsepattern.zigbrains.project.execution.base
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||||
|
import com.falsepattern.zigbrains.project.run.ZigProcessHandler
|
||||||
|
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
||||||
|
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
|
||||||
|
import com.falsepattern.zigbrains.shared.coroutine.runModalOrBlocking
|
||||||
|
import com.intellij.build.BuildTextConsoleView
|
||||||
|
import com.intellij.execution.DefaultExecutionResult
|
||||||
|
import com.intellij.execution.ExecutionException
|
||||||
import com.intellij.execution.configurations.CommandLineState
|
import com.intellij.execution.configurations.CommandLineState
|
||||||
|
import com.intellij.execution.configurations.GeneralCommandLine
|
||||||
|
import com.intellij.execution.configurations.PtyCommandLine
|
||||||
|
import com.intellij.execution.process.ProcessHandler
|
||||||
|
import com.intellij.execution.process.ProcessTerminatedListener
|
||||||
import com.intellij.execution.runners.ExecutionEnvironment
|
import com.intellij.execution.runners.ExecutionEnvironment
|
||||||
|
import com.intellij.platform.ide.progress.ModalTaskOwner
|
||||||
|
import kotlin.io.path.pathString
|
||||||
|
|
||||||
abstract class ZigProfileState<T: ZigExecConfig<T>>(
|
abstract class ZigProfileState<T: ZigExecConfig<T>> (
|
||||||
environment: ExecutionEnvironment,
|
environment: ExecutionEnvironment,
|
||||||
protected val configuration: T
|
val configuration: T
|
||||||
): CommandLineState(environment) {
|
): CommandLineState(environment) {
|
||||||
|
|
||||||
|
@Throws(ExecutionException::class)
|
||||||
|
override fun startProcess(): ProcessHandler {
|
||||||
|
return runModalOrBlocking({ModalTaskOwner.project(environment.project)}, {"ZigProfileState.startProcess"}) {
|
||||||
|
startProcessSuspend()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(ExecutionException::class)
|
||||||
|
suspend fun startProcessSuspend(): ProcessHandler {
|
||||||
|
val toolchain = environment.project.zigProjectSettings.state.toolchain ?: throw ExecutionException(ZigBrainsBundle.message("exception.zig-profile-state.start-process.no-toolchain"))
|
||||||
|
return ZigProcessHandler(getCommandLine(toolchain, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(ExecutionException::class)
|
||||||
|
suspend fun getCommandLine(toolchain: AbstractZigToolchain, debug: Boolean): GeneralCommandLine {
|
||||||
|
val workingDir = configuration.workingDirectory
|
||||||
|
val zigExePath = toolchain.zig.path()
|
||||||
|
|
||||||
|
// TODO remove this check once JetBrains implements colored terminal in the debugger
|
||||||
|
// https://youtrack.jetbrains.com/issue/CPP-11622/ANSI-color-codes-not-honored-in-Debug-Run-Configuration-output-window
|
||||||
|
val cli = if (configuration.emulateTerminal() && !debug) PtyCommandLine() else GeneralCommandLine()
|
||||||
|
cli.exePath = zigExePath.pathString
|
||||||
|
workingDir.path?.let { cli.withWorkingDirectory(it) }
|
||||||
|
cli.charset = Charsets.UTF_8
|
||||||
|
cli.addParameters(configuration.buildCommandLineArgs(debug))
|
||||||
|
return configuration.patchCommandLine(cli, toolchain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(ExecutionException::class)
|
||||||
|
fun executeCommandLine(commandLine: GeneralCommandLine, environment: ExecutionEnvironment): DefaultExecutionResult {
|
||||||
|
val handler = startProcess(commandLine)
|
||||||
|
val console = BuildTextConsoleView(environment.project, false, emptyList())
|
||||||
|
console.attachToProcess(handler)
|
||||||
|
return DefaultExecutionResult(console, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(ExecutionException::class)
|
||||||
|
fun startProcess(commandLine: GeneralCommandLine): ProcessHandler {
|
||||||
|
val handler = ZigProcessHandler(commandLine)
|
||||||
|
ProcessTerminatedListener.attach(handler)
|
||||||
|
return handler
|
||||||
}
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* 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.project.execution.build
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||||
|
import com.falsepattern.zigbrains.project.execution.base.ZigConfigProducer
|
||||||
|
import com.falsepattern.zigbrains.project.execution.firstConfigFactory
|
||||||
|
import com.intellij.execution.actions.ConfigurationFromContext
|
||||||
|
import com.intellij.execution.configurations.ConfigurationFactory
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
class ZigConfigProducerBuild: ZigConfigProducer<ZigExecConfigBuild>() {
|
||||||
|
override fun getConfigurationFactory(): ConfigurationFactory {
|
||||||
|
return firstConfigFactory<ZigConfigTypeBuild>()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupConfigurationFromContext(configuration: ZigExecConfigBuild, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean {
|
||||||
|
if (LINE_MARKER.elementMatches(element)) {
|
||||||
|
configuration.name = ZigBrainsBundle.message("configuration.build.marker-name")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isConfigurationFromContext(configuration: ZigExecConfigBuild, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean {
|
||||||
|
return filePath.parent == (configuration.workingDirectory.path ?: return false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean {
|
||||||
|
return self.configurationType is ZigConfigTypeBuild
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val LINE_MARKER = ZigLineMarkerBuild()
|
|
@ -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.project.execution.build
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.Icons
|
||||||
|
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||||
|
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 ZigConfigTypeBuild : ConfigurationTypeBase(
|
||||||
|
IDENTIFIER,
|
||||||
|
ZigBrainsBundle.message("configuration.build.name"),
|
||||||
|
ZigBrainsBundle.message("configuration.build.description"),
|
||||||
|
Icons.ZIG
|
||||||
|
) {
|
||||||
|
init {
|
||||||
|
addFactory(ConfigFactoryRun())
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class ConfigFactoryRun: ConfigurationFactory(this@ZigConfigTypeBuild) {
|
||||||
|
override fun createTemplateConfiguration(project: Project): RunConfiguration {
|
||||||
|
return ZigExecConfigBuild(project, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getId(): String {
|
||||||
|
return IDENTIFIER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val IDENTIFIER = "ZIGBRAINS_BUILD"
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* 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.project.execution.build
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||||
|
import com.falsepattern.zigbrains.project.execution.base.*
|
||||||
|
import com.falsepattern.zigbrains.shared.ZBFeatures
|
||||||
|
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
|
||||||
|
|
||||||
|
class ZigExecConfigBuild(project: Project, factory: ConfigurationFactory): ZigExecConfig<ZigExecConfigBuild>(project, factory, "Zig Run") {
|
||||||
|
var buildSteps = ArgsConfigurable("buildSteps", ZigBrainsBundle.message("exec.option.label.build.steps"))
|
||||||
|
private set
|
||||||
|
var extraArgs = ArgsConfigurable("compilerArgs", ZigBrainsBundle.message("exec.option.label.build.args"))
|
||||||
|
private set
|
||||||
|
var colored = ColoredConfigurable("colored")
|
||||||
|
private set
|
||||||
|
var exePath = FilePathConfigurable("exePath", ZigBrainsBundle.message("exec.option.label.build.exe-path-debug"))
|
||||||
|
private set
|
||||||
|
var exeArgs = ArgsConfigurable("exeArgs", ZigBrainsBundle.message("exec.option.label.build.exe-args-debug"))
|
||||||
|
private set
|
||||||
|
|
||||||
|
override suspend fun buildCommandLineArgs(debug: Boolean): List<String> {
|
||||||
|
val result = ArrayList<String>()
|
||||||
|
result.add("build")
|
||||||
|
var steps = buildSteps.args
|
||||||
|
if (debug) {
|
||||||
|
val truncatedSteps = ArrayList<String>()
|
||||||
|
for (step in steps) {
|
||||||
|
if (step == "run")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if (step == "test")
|
||||||
|
throw ExecutionException(ZigBrainsBundle.message("exception.zig-build.debug.test-not-supported"))
|
||||||
|
|
||||||
|
truncatedSteps.add(step)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.addAll(steps)
|
||||||
|
result.addAll(coloredCliFlags(colored.value, debug))
|
||||||
|
result.addAll(extraArgs.args)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override val suggestedName: String
|
||||||
|
get() = ZigBrainsBundle.message("configuration.build.suggested-name")
|
||||||
|
|
||||||
|
override fun clone(): ZigExecConfigBuild {
|
||||||
|
val clone = super.clone()
|
||||||
|
clone.buildSteps = buildSteps.clone()
|
||||||
|
clone.exeArgs = exeArgs.clone()
|
||||||
|
clone.colored = colored.clone()
|
||||||
|
clone.exePath = exePath.clone()
|
||||||
|
clone.exeArgs = exeArgs.clone()
|
||||||
|
return clone
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getConfigurables(): List<ZigConfigurable<*>> {
|
||||||
|
val baseCfg = super.getConfigurables() + listOf(buildSteps, extraArgs, colored)
|
||||||
|
if (ZBFeatures.debug()) {
|
||||||
|
return baseCfg + listOf(exePath, exeArgs)
|
||||||
|
} else {
|
||||||
|
return baseCfg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getState(executor: Executor, environment: ExecutionEnvironment): ZigProfileState<ZigExecConfigBuild> {
|
||||||
|
return ZigProfileStateBuild(environment, this)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* 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.project.execution.build
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.execution.base.ZigTopLevelLineMarker
|
||||||
|
import com.falsepattern.zigbrains.zig.psi.ZigTypes
|
||||||
|
import com.intellij.icons.AllIcons.RunConfigurations.TestState
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.util.elementType
|
||||||
|
import javax.swing.Icon
|
||||||
|
|
||||||
|
class ZigLineMarkerBuild: ZigTopLevelLineMarker() {
|
||||||
|
override fun getDeclaration(element: PsiElement): PsiElement? {
|
||||||
|
if (element.elementType != ZigTypes.IDENTIFIER)
|
||||||
|
return null
|
||||||
|
|
||||||
|
if (!element.textMatches("build"))
|
||||||
|
return null
|
||||||
|
|
||||||
|
val parent = element.parent ?: return null
|
||||||
|
if (parent.elementType != ZigTypes.FN_PROTO)
|
||||||
|
return null
|
||||||
|
|
||||||
|
val file = element.containingFile ?: return null
|
||||||
|
|
||||||
|
val fileName = file.virtualFile.name
|
||||||
|
if (fileName != "build.zig")
|
||||||
|
return null
|
||||||
|
|
||||||
|
return parent.parent
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getIcon(element: PsiElement): Icon {
|
||||||
|
return TestState.Run
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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.project.execution.build
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
||||||
|
import com.intellij.execution.runners.ExecutionEnvironment
|
||||||
|
|
||||||
|
class ZigProfileStateBuild(environment: ExecutionEnvironment, configuration: ZigExecConfigBuild) : ZigProfileState<ZigExecConfigBuild>(environment, configuration) {
|
||||||
|
}
|
|
@ -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.project.execution.run
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.project.execution.base.ZigConfigProducer
|
||||||
|
import com.falsepattern.zigbrains.project.execution.firstConfigFactory
|
||||||
|
import com.intellij.execution.actions.ConfigurationFromContext
|
||||||
|
import com.intellij.execution.configurations.ConfigurationFactory
|
||||||
|
import com.intellij.execution.configurations.ConfigurationTypeUtil
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
class ZigConfigProducerRun: ZigConfigProducer<ZigExecConfigRun>() {
|
||||||
|
override fun getConfigurationFactory(): ConfigurationFactory {
|
||||||
|
return firstConfigFactory<ZigConfigTypeRun>()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupConfigurationFromContext(configuration: ZigExecConfigRun, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean {
|
||||||
|
if (LINE_MARKER.elementMatches(element)) {
|
||||||
|
configuration.filePath.path = filePath
|
||||||
|
configuration.name = theFile.presentableName
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isConfigurationFromContext(configuration: ZigExecConfigRun, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean {
|
||||||
|
return filePath == configuration.filePath.path
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean {
|
||||||
|
return self.configurationType is ZigConfigTypeRun
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val LINE_MARKER = ZigLineMarkerRun()
|
|
@ -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.project.execution.run
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.Icons
|
||||||
|
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||||
|
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 ZigConfigTypeRun : ConfigurationTypeBase(
|
||||||
|
IDENTIFIER,
|
||||||
|
ZigBrainsBundle.message("configuration.run.name"),
|
||||||
|
ZigBrainsBundle.message("configuration.run.description"),
|
||||||
|
Icons.ZIG
|
||||||
|
) {
|
||||||
|
init {
|
||||||
|
addFactory(ConfigFactoryRun())
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class ConfigFactoryRun: ConfigurationFactory(this@ZigConfigTypeRun) {
|
||||||
|
override fun createTemplateConfiguration(project: Project): RunConfiguration {
|
||||||
|
return ZigExecConfigRun(project, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getId(): String {
|
||||||
|
return IDENTIFIER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val IDENTIFIER = "ZIGBRAINS_RUN"
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* 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.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.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") {
|
||||||
|
var filePath = FilePathConfigurable("filePath", ZigBrainsBundle.message("exec.option.label.file-path"))
|
||||||
|
private set
|
||||||
|
var colored = ColoredConfigurable("colored")
|
||||||
|
private set
|
||||||
|
var optimization = OptimizationConfigurable("optimization")
|
||||||
|
private set
|
||||||
|
var compilerArgs = ArgsConfigurable("compilerArgs", ZigBrainsBundle.message("exec.option.label.compiler-args"))
|
||||||
|
private set
|
||||||
|
var exeArgs = ArgsConfigurable("exeArgs", ZigBrainsBundle.message("exec.option.label.exe-args"))
|
||||||
|
private set
|
||||||
|
|
||||||
|
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!"))
|
||||||
|
if (!debug || optimization.forced) {
|
||||||
|
result.addAll(listOf("-O", optimization.level.name))
|
||||||
|
}
|
||||||
|
result.addAll(compilerArgs.args)
|
||||||
|
if (!debug) {
|
||||||
|
result.add("--")
|
||||||
|
result.addAll(exeArgs.args)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override val suggestedName: String
|
||||||
|
get() = ZigBrainsBundle.message("configuration.run.suggested-name")
|
||||||
|
|
||||||
|
override fun clone(): ZigExecConfigRun {
|
||||||
|
val clone = super.clone()
|
||||||
|
clone.filePath = filePath.clone()
|
||||||
|
clone.colored = colored.clone()
|
||||||
|
clone.compilerArgs = compilerArgs.clone()
|
||||||
|
clone.optimization = optimization.clone()
|
||||||
|
clone.exeArgs = exeArgs.clone()
|
||||||
|
return clone
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getConfigurables(): List<ZigConfigurable<*>> {
|
||||||
|
return super.getConfigurables() + listOf(filePath, optimization, colored, compilerArgs, exeArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getState(executor: Executor, environment: ExecutionEnvironment): ZigProfileState<ZigExecConfigRun> {
|
||||||
|
return ZigProfileStateRun(environment, this)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* 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.project.execution.run
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.execution.base.ZigTopLevelLineMarker
|
||||||
|
import com.falsepattern.zigbrains.zig.psi.ZigTypes
|
||||||
|
import com.intellij.icons.AllIcons.RunConfigurations.TestState
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.util.elementType
|
||||||
|
import javax.swing.Icon
|
||||||
|
|
||||||
|
class ZigLineMarkerRun: ZigTopLevelLineMarker() {
|
||||||
|
override fun getDeclaration(element: PsiElement): PsiElement? {
|
||||||
|
if (element.elementType != ZigTypes.IDENTIFIER)
|
||||||
|
return null
|
||||||
|
|
||||||
|
if (!element.textMatches("main"))
|
||||||
|
return null
|
||||||
|
|
||||||
|
val parent = element.parent
|
||||||
|
if (parent.elementType != ZigTypes.FN_PROTO)
|
||||||
|
return null
|
||||||
|
|
||||||
|
return parent.parent
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getIcon(element: PsiElement): Icon {
|
||||||
|
return TestState.Run
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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.project.execution.run
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
||||||
|
import com.intellij.execution.runners.ExecutionEnvironment
|
||||||
|
|
||||||
|
class ZigProfileStateRun(environment: ExecutionEnvironment, configuration: ZigExecConfigRun) : ZigProfileState<ZigExecConfigRun>(environment, configuration) {
|
||||||
|
}
|
|
@ -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.project.execution.test
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||||
|
import com.falsepattern.zigbrains.project.execution.base.ZigConfigProducer
|
||||||
|
import com.falsepattern.zigbrains.project.execution.firstConfigFactory
|
||||||
|
import com.intellij.execution.actions.ConfigurationFromContext
|
||||||
|
import com.intellij.execution.configurations.ConfigurationFactory
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
class ZigConfigProducerTest: ZigConfigProducer<ZigExecConfigTest>() {
|
||||||
|
override fun getConfigurationFactory(): ConfigurationFactory {
|
||||||
|
return firstConfigFactory<ZigConfigTypeTest>()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupConfigurationFromContext(configuration: ZigExecConfigTest, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean {
|
||||||
|
if (LINE_MARKER.elementMatches(element)) {
|
||||||
|
configuration.filePath.path = filePath
|
||||||
|
configuration.name = ZigBrainsBundle.message("configuration.test.marker-name", theFile.presentableName)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isConfigurationFromContext(configuration: ZigExecConfigTest, element: PsiElement, filePath: Path, theFile: VirtualFile): Boolean {
|
||||||
|
return filePath == configuration.filePath.path
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun shouldReplace(self: ConfigurationFromContext, other: ConfigurationFromContext): Boolean {
|
||||||
|
return self.configurationType is ZigConfigTypeTest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val LINE_MARKER = ZigLineMarkerTest()
|
|
@ -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.project.execution.test
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.Icons
|
||||||
|
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||||
|
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 ZigConfigTypeTest : ConfigurationTypeBase(
|
||||||
|
IDENTIFIER,
|
||||||
|
ZigBrainsBundle.message("configuration.test.name"),
|
||||||
|
ZigBrainsBundle.message("configuration.test.description"),
|
||||||
|
Icons.ZIG
|
||||||
|
) {
|
||||||
|
init {
|
||||||
|
addFactory(ConfigFactoryRun())
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class ConfigFactoryRun: ConfigurationFactory(this@ZigConfigTypeTest) {
|
||||||
|
override fun createTemplateConfiguration(project: Project): RunConfiguration {
|
||||||
|
return ZigExecConfigTest(project, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getId(): String {
|
||||||
|
return IDENTIFIER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val IDENTIFIER = "ZIGBRAINS_TEST"
|
|
@ -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.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.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") {
|
||||||
|
var filePath = FilePathConfigurable("filePath", ZigBrainsBundle.message("exec.option.label.file-path"))
|
||||||
|
private set
|
||||||
|
var colored = ColoredConfigurable("colored")
|
||||||
|
private set
|
||||||
|
var optimization = OptimizationConfigurable("optimization")
|
||||||
|
private set
|
||||||
|
var compilerArgs = ArgsConfigurable("compilerArgs", ZigBrainsBundle.message("exec.option.label.compiler-args"))
|
||||||
|
private set
|
||||||
|
|
||||||
|
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!"))
|
||||||
|
if (!debug || optimization.forced) {
|
||||||
|
result.addAll(listOf("-O", optimization.level.name))
|
||||||
|
}
|
||||||
|
result.addAll(compilerArgs.args)
|
||||||
|
if (debug) {
|
||||||
|
result.add("--test-no-exec")
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override val suggestedName: String
|
||||||
|
get() = ZigBrainsBundle.message("configuration.test.suggested-name")
|
||||||
|
|
||||||
|
override fun clone(): ZigExecConfigTest {
|
||||||
|
val clone = super.clone()
|
||||||
|
clone.filePath = filePath.clone()
|
||||||
|
clone.colored = colored.clone()
|
||||||
|
clone.compilerArgs = compilerArgs.clone()
|
||||||
|
clone.optimization = optimization.clone()
|
||||||
|
return clone
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getConfigurables(): List<ZigConfigurable<*>> {
|
||||||
|
return super.getConfigurables() + listOf(filePath, optimization, colored, compilerArgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getState(executor: Executor, environment: ExecutionEnvironment): ZigProfileState<ZigExecConfigTest> {
|
||||||
|
return ZigProfileStateTest(environment, this)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* 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.project.execution.test
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.execution.base.ZigTopLevelLineMarker
|
||||||
|
import com.falsepattern.zigbrains.zig.psi.ZigTypes
|
||||||
|
import com.intellij.icons.AllIcons.RunConfigurations.TestState
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.util.elementType
|
||||||
|
import javax.swing.Icon
|
||||||
|
|
||||||
|
class ZigLineMarkerTest: ZigTopLevelLineMarker() {
|
||||||
|
override fun getDeclaration(element: PsiElement): PsiElement? {
|
||||||
|
if (element.elementType != ZigTypes.KEYWORD_TEST)
|
||||||
|
return null
|
||||||
|
|
||||||
|
val parent = element.parent
|
||||||
|
if (parent.elementType != ZigTypes.TEST_DECL)
|
||||||
|
return null
|
||||||
|
|
||||||
|
return parent
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getIcon(element: PsiElement): Icon {
|
||||||
|
return TestState.Run_run
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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.project.execution.test
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
||||||
|
import com.intellij.execution.runners.ExecutionEnvironment
|
||||||
|
|
||||||
|
class ZigProfileStateTest(environment: ExecutionEnvironment, configuration: ZigExecConfigTest) : ZigProfileState<ZigExecConfigTest>(environment, configuration) {
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* 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.project.module
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.project.newproject.ZigProjectConfigurationData
|
||||||
|
import com.falsepattern.zigbrains.project.newproject.ZigProjectGeneratorPeer
|
||||||
|
import com.intellij.ide.util.projectWizard.ModuleBuilder
|
||||||
|
import com.intellij.ide.util.projectWizard.ModuleWizardStep
|
||||||
|
import com.intellij.ide.util.projectWizard.WizardContext
|
||||||
|
import com.intellij.openapi.Disposable
|
||||||
|
import com.intellij.openapi.application.EDT
|
||||||
|
import com.intellij.openapi.application.Experiments
|
||||||
|
import com.intellij.openapi.module.ModuleType
|
||||||
|
import com.intellij.openapi.roots.ModifiableRootModel
|
||||||
|
import com.intellij.openapi.util.Disposer
|
||||||
|
import com.intellij.util.ui.JBUI
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import javax.swing.JComponent
|
||||||
|
|
||||||
|
class ZigModuleBuilder: ModuleBuilder() {
|
||||||
|
var configurationData: ZigProjectConfigurationData? = null
|
||||||
|
var forceGitignore = false
|
||||||
|
|
||||||
|
override fun getModuleType(): ModuleType<*> {
|
||||||
|
return ZigModuleType
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupRootModel(modifiableRootModel: ModifiableRootModel) {
|
||||||
|
super.setupRootModel(modifiableRootModel)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCustomOptionsStep(context: WizardContext?, parentDisposable: Disposable?): ModuleWizardStep? {
|
||||||
|
val step = ZigModuleWizardStep()
|
||||||
|
parentDisposable?.let { Disposer.register(it, step.peer) }
|
||||||
|
return step
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun createProject(rootModel: ModifiableRootModel) {
|
||||||
|
val contentEntry = doAddContentEntry(rootModel) ?: return
|
||||||
|
val root = contentEntry.file ?: return
|
||||||
|
val config = configurationData ?: return
|
||||||
|
config.generateProject(this, rootModel.project, root, forceGitignore)
|
||||||
|
withContext(Dispatchers.EDT) {
|
||||||
|
root.refresh(false, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class ZigModuleWizardStep: ModuleWizardStep() {
|
||||||
|
internal val peer = ZigProjectGeneratorPeer(true)
|
||||||
|
|
||||||
|
override fun getComponent(): JComponent {
|
||||||
|
return peer.component.withBorder()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun disposeUIResources() {
|
||||||
|
Disposer.dispose(peer)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateDataModel() {
|
||||||
|
this@ZigModuleBuilder.configurationData = peer.settings
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T: JComponent> T.withBorder(): T {
|
||||||
|
border = JBUI.Borders.empty(14, 20)
|
||||||
|
return this
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* 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.project.module
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.Icons
|
||||||
|
import com.intellij.openapi.module.ModuleType
|
||||||
|
import javax.swing.Icon
|
||||||
|
|
||||||
|
object ZigModuleType: ModuleType<ZigModuleBuilder>("com.falsepattern.zigbrains.zigModuleType") {
|
||||||
|
override fun createModuleBuilder(): ZigModuleBuilder {
|
||||||
|
return ZigModuleBuilder()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getName(): String {
|
||||||
|
return "Zig"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getDescription(): String {
|
||||||
|
return "Zig module"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getNodeIcon(isOpened: Boolean): Icon {
|
||||||
|
return Icons.ZIG
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* 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.project.newproject
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.Icons
|
||||||
|
import com.falsepattern.zigbrains.shared.coroutine.runModalOrBlocking
|
||||||
|
import com.intellij.execution.runners.ExecutionUtil
|
||||||
|
import com.intellij.facet.ui.ValidationResult
|
||||||
|
import com.intellij.ide.util.projectWizard.AbstractNewProjectStep
|
||||||
|
import com.intellij.ide.util.projectWizard.CustomStepProjectGenerator
|
||||||
|
import com.intellij.openapi.module.Module
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.openapi.wm.impl.welcomeScreen.AbstractActionWithPanel
|
||||||
|
import com.intellij.platform.DirectoryProjectGenerator
|
||||||
|
import com.intellij.platform.ProjectGeneratorPeer
|
||||||
|
import com.intellij.platform.ide.progress.ModalTaskOwner
|
||||||
|
import javax.swing.Icon
|
||||||
|
|
||||||
|
class ZigDirectoryProjectGenerator: DirectoryProjectGenerator<ZigProjectConfigurationData>, CustomStepProjectGenerator<ZigProjectConfigurationData> {
|
||||||
|
override fun getName(): String {
|
||||||
|
return "Zig"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLogo(): Icon {
|
||||||
|
return Icons.ZIG
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createPeer(): ProjectGeneratorPeer<ZigProjectConfigurationData> {
|
||||||
|
return ZigProjectGeneratorPeer(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun validate(baseDirPath: String): ValidationResult {
|
||||||
|
return ValidationResult.OK
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateProject(project: Project, baseDir: VirtualFile, settings: ZigProjectConfigurationData, module: Module) {
|
||||||
|
runModalOrBlocking({ ModalTaskOwner.project(project)}, {"ZigDirectoryProjectGenerator.generateProject"}) {
|
||||||
|
settings.generateProject(this, project, baseDir, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createStep(
|
||||||
|
projectGenerator: DirectoryProjectGenerator<ZigProjectConfigurationData>?,
|
||||||
|
callback: AbstractNewProjectStep.AbstractCallback<ZigProjectConfigurationData>?
|
||||||
|
): AbstractActionWithPanel {
|
||||||
|
return ZigProjectSettingsStep(projectGenerator!!, callback)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
* 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.project.newproject
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.lsp.settings.ZLSSettingsPanel
|
||||||
|
import com.falsepattern.zigbrains.project.settings.ZigProjectSettingsPanel
|
||||||
|
import com.falsepattern.zigbrains.project.template.ZigExecutableTemplate
|
||||||
|
import com.falsepattern.zigbrains.project.template.ZigInitTemplate
|
||||||
|
import com.falsepattern.zigbrains.project.template.ZigLibraryTemplate
|
||||||
|
import com.falsepattern.zigbrains.project.template.ZigProjectTemplate
|
||||||
|
import com.intellij.openapi.Disposable
|
||||||
|
import com.intellij.openapi.actionSystem.ActionToolbarPosition
|
||||||
|
import com.intellij.openapi.util.Disposer
|
||||||
|
import com.intellij.ui.ColoredListCellRenderer
|
||||||
|
import com.intellij.ui.ToolbarDecorator
|
||||||
|
import com.intellij.ui.components.JBCheckBox
|
||||||
|
import com.intellij.ui.components.JBList
|
||||||
|
import com.intellij.ui.dsl.builder.AlignX
|
||||||
|
import com.intellij.ui.dsl.builder.AlignY
|
||||||
|
import com.intellij.ui.dsl.builder.Panel
|
||||||
|
import com.intellij.util.ui.JBUI
|
||||||
|
import javax.swing.JList
|
||||||
|
import javax.swing.ListSelectionModel
|
||||||
|
|
||||||
|
class ZigNewProjectPanel(private var handleGit: Boolean): Disposable {
|
||||||
|
private val git = JBCheckBox()
|
||||||
|
private val projConf = ZigProjectSettingsPanel(null).also { Disposer.register(this, it) }
|
||||||
|
private val zlsConf = ZLSSettingsPanel(null).also { Disposer.register(this, it) }
|
||||||
|
private val templateList = JBList(JBList.createDefaultListModel(defaultTemplates)).apply {
|
||||||
|
selectionMode = ListSelectionModel.SINGLE_SELECTION
|
||||||
|
selectedIndex = 0
|
||||||
|
cellRenderer = object : ColoredListCellRenderer<ZigProjectTemplate>() {
|
||||||
|
override fun customizeCellRenderer(list: JList<out ZigProjectTemplate>, value: ZigProjectTemplate?, index: Int, selected: Boolean, hasFocus: Boolean) {
|
||||||
|
value?.let {
|
||||||
|
icon = it.icon
|
||||||
|
append(it.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val templateToolbar get() = ToolbarDecorator.createDecorator(templateList)
|
||||||
|
.setToolbarPosition(ActionToolbarPosition.BOTTOM)
|
||||||
|
.setPreferredSize(JBUI.size(0, 125))
|
||||||
|
.disableUpDownActions()
|
||||||
|
.disableAddAction()
|
||||||
|
.disableRemoveAction()
|
||||||
|
|
||||||
|
fun getData(): ZigProjectConfigurationData {
|
||||||
|
val selectedTemplate = templateList.selectedValue
|
||||||
|
return ZigProjectConfigurationData(handleGit && git.isSelected, projConf.data, zlsConf.data, selectedTemplate)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun attach(p: Panel): Unit = with(p) {
|
||||||
|
if (handleGit) {
|
||||||
|
row("Create Git repository") {
|
||||||
|
cell(git)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
group("Zig Project Template") {
|
||||||
|
row {
|
||||||
|
resizableRow()
|
||||||
|
cell(templateToolbar.createPanel())
|
||||||
|
.align(AlignX.FILL)
|
||||||
|
.align(AlignY.FILL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
projConf.attach(p)
|
||||||
|
zlsConf.attach(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun autodetect() {
|
||||||
|
projConf.autodetect()
|
||||||
|
zlsConf.autodetect()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private val defaultTemplates get() = listOf(
|
||||||
|
ZigExecutableTemplate(),
|
||||||
|
ZigLibraryTemplate(),
|
||||||
|
ZigInitTemplate()
|
||||||
|
)
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* 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.project.newproject
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.Icons
|
||||||
|
import com.falsepattern.zigbrains.project.module.ZigModuleBuilder
|
||||||
|
import com.intellij.ide.wizard.AbstractNewProjectWizardStep
|
||||||
|
import com.intellij.ide.wizard.GitNewProjectWizardData.Companion.gitData
|
||||||
|
import com.intellij.ide.wizard.NewProjectWizardStep
|
||||||
|
import com.intellij.ide.wizard.language.LanguageGeneratorNewProjectWizard
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.ui.dsl.builder.AlignX
|
||||||
|
import com.intellij.ui.dsl.builder.Panel
|
||||||
|
import javax.swing.Icon
|
||||||
|
|
||||||
|
class ZigNewProjectWizard: LanguageGeneratorNewProjectWizard {
|
||||||
|
override val name: String
|
||||||
|
get() = "Zig"
|
||||||
|
override val icon: Icon
|
||||||
|
get() = Icons.ZIG
|
||||||
|
override val ordinal: Int
|
||||||
|
get() = 900
|
||||||
|
|
||||||
|
override fun createStep(parent: NewProjectWizardStep): NewProjectWizardStep {
|
||||||
|
return ZigNewProjectWizardStep(parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ZigNewProjectWizardStep(parentStep: NewProjectWizardStep): AbstractNewProjectWizardStep(parentStep) {
|
||||||
|
private val peer = ZigProjectGeneratorPeer(false)
|
||||||
|
|
||||||
|
override fun setupUI(builder: Panel): Unit = with(builder) {
|
||||||
|
row {
|
||||||
|
cell(peer.component).align(AlignX.FILL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupProject(project: Project) {
|
||||||
|
val builder = ZigModuleBuilder()
|
||||||
|
builder.configurationData = peer.settings
|
||||||
|
val gitData = gitData
|
||||||
|
builder.forceGitignore = gitData != null && gitData.git
|
||||||
|
builder.commit(project)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,142 @@
|
||||||
|
/*
|
||||||
|
* 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.project.newproject
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.lsp.settings.ZLSSettings
|
||||||
|
import com.falsepattern.zigbrains.lsp.settings.zlsSettings
|
||||||
|
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.intellij.notification.Notification
|
||||||
|
import com.intellij.notification.NotificationType
|
||||||
|
import com.intellij.openapi.GitRepositoryInitializer
|
||||||
|
import com.intellij.openapi.application.EDT
|
||||||
|
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.util.ResourceUtil
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
@JvmRecord
|
||||||
|
data class ZigProjectConfigurationData(
|
||||||
|
val git: Boolean,
|
||||||
|
val projConf: ZigProjectSettings,
|
||||||
|
val zlsConf: ZLSSettings,
|
||||||
|
val selectedTemplate: ZigProjectTemplate
|
||||||
|
) {
|
||||||
|
suspend fun generateProject(requestor: Any, project: Project, baseDir: VirtualFile, forceGitignore: Boolean): Boolean {
|
||||||
|
withContext(Dispatchers.EDT) {
|
||||||
|
project.zigProjectSettings.loadState(projConf)
|
||||||
|
project.zlsSettings.loadState(zlsConf)
|
||||||
|
}
|
||||||
|
|
||||||
|
val template = selectedTemplate
|
||||||
|
|
||||||
|
if (template is ZigInitTemplate) {
|
||||||
|
val toolchain = projConf.toolchain ?: run {
|
||||||
|
Notification(
|
||||||
|
"zigbrains",
|
||||||
|
"Tried to generate project with zig init, but zig toolchain is invalid",
|
||||||
|
NotificationType.ERROR
|
||||||
|
).notify(project)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
val zig = toolchain.zig
|
||||||
|
val workDir = baseDir.toNioPathOrNull() ?: run {
|
||||||
|
Notification(
|
||||||
|
"zigbrains",
|
||||||
|
"Tried to generate project with zig init, but base directory is invalid",
|
||||||
|
NotificationType.ERROR
|
||||||
|
).notify(project)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
val result = zig.callWithArgs(workDir, "init")
|
||||||
|
if (result.exitCode != 0) {
|
||||||
|
Notification(
|
||||||
|
"zigbrains",
|
||||||
|
"\"zig init\" failed with exit code ${result.exitCode}! Check the IDE log files!",
|
||||||
|
NotificationType.ERROR
|
||||||
|
)
|
||||||
|
System.err.println(result.stderr)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val projectName = project.name
|
||||||
|
for (fileTemplate in template.fileTemplates()) {
|
||||||
|
val (fileName, parentDir) = fileTemplate.key.let {
|
||||||
|
if (it.contains("/")) {
|
||||||
|
val slashIndex = it.indexOf("/")
|
||||||
|
val parentDir = withContext(Dispatchers.EDT) {
|
||||||
|
baseDir.createChildDirectory(requestor, it.substring(0, slashIndex))
|
||||||
|
}
|
||||||
|
Pair(it.substring(slashIndex + 1), parentDir)
|
||||||
|
} else {
|
||||||
|
Pair(it, baseDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val templateDir = fileTemplate.value
|
||||||
|
val resourceData = getResourceString("project-gen/$templateDir/$fileName.template")
|
||||||
|
?.replace("@@PROJECT_NAME@@", projectName)
|
||||||
|
?: continue
|
||||||
|
withContext(Dispatchers.EDT) {
|
||||||
|
val targetFile = parentDir.createChildData(requestor, fileName)
|
||||||
|
VfsUtil.saveText(targetFile, resourceData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (git) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
GitRepositoryInitializer.getInstance()?.initRepository(project, baseDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (git || forceGitignore) {
|
||||||
|
createGitIgnoreFile(baseDir, requestor)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun createGitIgnoreFile(projectDir: VirtualFile, requestor: Any) {
|
||||||
|
if (projectDir.findChild(".gitignore") != null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
ZigProjectConfigurationData::class.java.getResourceAsStream("/fileTemplates/internal/gitignore")?.use {
|
||||||
|
val file = projectDir.createChildData(requestor, ".gitignore")
|
||||||
|
file.setCharset(Charsets.UTF_8)
|
||||||
|
file.setBinaryContent(it.readAllBytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getResourceString(path: String): String? {
|
||||||
|
return ResourceUtil.getResourceAsBytes(path, ZigProjectConfigurationData::class.java.classLoader)?.decodeToString()
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* 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.project.newproject
|
||||||
|
|
||||||
|
import com.intellij.ide.util.projectWizard.SettingsStep
|
||||||
|
import com.intellij.openapi.Disposable
|
||||||
|
import com.intellij.openapi.ui.ValidationInfo
|
||||||
|
import com.intellij.openapi.util.Disposer
|
||||||
|
import com.intellij.platform.ProjectGeneratorPeer
|
||||||
|
import com.intellij.ui.dsl.builder.panel
|
||||||
|
import javax.swing.JComponent
|
||||||
|
|
||||||
|
class ZigProjectGeneratorPeer(var handleGit: Boolean): ProjectGeneratorPeer<ZigProjectConfigurationData>, Disposable {
|
||||||
|
private val newProjectPanel: ZigNewProjectPanel = ZigNewProjectPanel(handleGit).also { Disposer.register(this, it) }
|
||||||
|
private val myComponent: JComponent by lazy {
|
||||||
|
panel {
|
||||||
|
newProjectPanel.attach(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun getComponent(): JComponent {
|
||||||
|
return myComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun buildUI(settingsStep: SettingsStep) {
|
||||||
|
myComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSettings(): ZigProjectConfigurationData {
|
||||||
|
return newProjectPanel.getData()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun validate(): ValidationInfo? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isBackgroundJobRunning(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* 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.project.newproject
|
||||||
|
|
||||||
|
import com.intellij.ide.util.projectWizard.AbstractNewProjectStep
|
||||||
|
import com.intellij.ide.util.projectWizard.ProjectSettingsStepBase
|
||||||
|
import com.intellij.platform.DirectoryProjectGenerator
|
||||||
|
|
||||||
|
class ZigProjectSettingsStep(
|
||||||
|
projectGenerator: DirectoryProjectGenerator<ZigProjectConfigurationData>,
|
||||||
|
callback: AbstractNewProjectStep.AbstractCallback<ZigProjectConfigurationData>?
|
||||||
|
): ProjectSettingsStepBase<ZigProjectConfigurationData>(projectGenerator, callback)
|
|
@ -20,9 +20,8 @@
|
||||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project.execution
|
package com.falsepattern.zigbrains.project.run
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.execution.VT100Util.translateVT100Escapes
|
|
||||||
import com.intellij.execution.configurations.GeneralCommandLine
|
import com.intellij.execution.configurations.GeneralCommandLine
|
||||||
import com.intellij.execution.configurations.PtyCommandLine
|
import com.intellij.execution.configurations.PtyCommandLine
|
||||||
import com.intellij.execution.process.AnsiEscapeDecoder.ColoredTextAcceptor
|
import com.intellij.execution.process.AnsiEscapeDecoder.ColoredTextAcceptor
|
||||||
|
@ -47,53 +46,51 @@ class ZigProcessHandler : KillableColoredProcessHandler, ColoredTextAcceptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object VT100Util {
|
private val VT100_CHARS = CharArray(256).apply {
|
||||||
private val VT100_CHARS = CharArray(256).apply {
|
this.fill(' ')
|
||||||
this.fill(' ')
|
this[0x6A] = '┘';
|
||||||
this[0x6A] = '┘';
|
this[0x6B] = '┐';
|
||||||
this[0x6B] = '┐';
|
this[0x6C] = '┌';
|
||||||
this[0x6C] = '┌';
|
this[0x6D] = '└';
|
||||||
this[0x6D] = '└';
|
this[0x6E] = '┼';
|
||||||
this[0x6E] = '┼';
|
this[0x71] = '─';
|
||||||
this[0x71] = '─';
|
this[0x74] = '├';
|
||||||
this[0x74] = '├';
|
this[0x75] = '┤';
|
||||||
this[0x75] = '┤';
|
this[0x76] = '┴';
|
||||||
this[0x76] = '┴';
|
this[0x77] = '┬';
|
||||||
this[0x77] = '┬';
|
this[0x78] = '│';
|
||||||
this[0x78] = '│';
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private const val VT100_BEGIN_SEQ = "\u001B(0"
|
private const val VT100_BEGIN_SEQ = "\u001B(0"
|
||||||
private const val VT100_END_SEQ = "\u001B(B"
|
private const val VT100_END_SEQ = "\u001B(B"
|
||||||
private const val VT100_BEGIN_SEQ_LENGTH: Int = VT100_BEGIN_SEQ.length
|
private const val VT100_BEGIN_SEQ_LENGTH: Int = VT100_BEGIN_SEQ.length
|
||||||
private const val VT100_END_SEQ_LENGTH: Int = VT100_END_SEQ.length
|
private const val VT100_END_SEQ_LENGTH: Int = VT100_END_SEQ.length
|
||||||
|
|
||||||
fun String.translateVT100Escapes(): String {
|
private fun String.translateVT100Escapes(): String {
|
||||||
var offset = 0
|
var offset = 0
|
||||||
val result = StringBuilder()
|
val result = StringBuilder()
|
||||||
val textLength = length
|
val textLength = length
|
||||||
while (offset < textLength) {
|
while (offset < textLength) {
|
||||||
val startIndex = indexOf(VT100_BEGIN_SEQ, offset)
|
val startIndex = indexOf(VT100_BEGIN_SEQ, offset)
|
||||||
if (startIndex < 0) {
|
if (startIndex < 0) {
|
||||||
result.append(substring(offset, textLength).replace(VT100_END_SEQ, ""))
|
result.append(substring(offset, textLength).replace(VT100_END_SEQ, ""))
|
||||||
break
|
break
|
||||||
}
|
|
||||||
result.append(this, offset, startIndex)
|
|
||||||
val blockOffset = startIndex + VT100_BEGIN_SEQ_LENGTH
|
|
||||||
var endIndex = indexOf(VT100_END_SEQ, blockOffset)
|
|
||||||
if (endIndex < 0) {
|
|
||||||
endIndex = textLength
|
|
||||||
}
|
|
||||||
for (i in blockOffset until endIndex) {
|
|
||||||
val c = this[i].code
|
|
||||||
if (c >= 256) {
|
|
||||||
result.append(c)
|
|
||||||
} else {
|
|
||||||
result.append(VT100_CHARS[c])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
offset = endIndex + VT100_END_SEQ_LENGTH
|
|
||||||
}
|
}
|
||||||
return result.toString()
|
result.append(this, offset, startIndex)
|
||||||
|
val blockOffset = startIndex + VT100_BEGIN_SEQ_LENGTH
|
||||||
|
var endIndex = indexOf(VT100_END_SEQ, blockOffset)
|
||||||
|
if (endIndex < 0) {
|
||||||
|
endIndex = textLength
|
||||||
|
}
|
||||||
|
for (i in blockOffset until endIndex) {
|
||||||
|
val c = this[i].code
|
||||||
|
if (c >= 256) {
|
||||||
|
result.append(c)
|
||||||
|
} else {
|
||||||
|
result.append(VT100_CHARS[c])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset = endIndex + VT100_END_SEQ_LENGTH
|
||||||
}
|
}
|
||||||
}
|
return result.toString()
|
||||||
|
}
|
|
@ -23,22 +23,27 @@
|
||||||
package com.falsepattern.zigbrains.project.run
|
package com.falsepattern.zigbrains.project.run
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
import com.falsepattern.zigbrains.project.execution.base.ZigProfileState
|
||||||
import com.falsepattern.zigbrains.project.zigService
|
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
||||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
|
||||||
|
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||||
import com.intellij.execution.configurations.RunProfileState
|
import com.intellij.execution.configurations.RunProfileState
|
||||||
import com.intellij.execution.configurations.RunnerSettings
|
import com.intellij.execution.configurations.RunnerSettings
|
||||||
import com.intellij.execution.runners.AsyncProgramRunner
|
import com.intellij.execution.runners.AsyncProgramRunner
|
||||||
import com.intellij.execution.runners.ExecutionEnvironment
|
import com.intellij.execution.runners.ExecutionEnvironment
|
||||||
import com.intellij.execution.ui.RunContentDescriptor
|
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.openapi.rd.util.toPromise
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import org.jetbrains.concurrency.Promise
|
import org.jetbrains.concurrency.Promise
|
||||||
|
|
||||||
abstract class ZigProgramRunner<ProfileState: ZigProfileState<*>>(protected val executorId: String): AsyncProgramRunner<RunnerSettings>() {
|
abstract class ZigProgramRunner<ProfileState: ZigProfileState<*>>(protected val executorId: String): AsyncProgramRunner<RunnerSettings>() {
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
override fun execute(environment: ExecutionEnvironment, state: RunProfileState): Promise<RunContentDescriptor?> {
|
override fun execute(environment: ExecutionEnvironment, state: RunProfileState): Promise<RunContentDescriptor?> {
|
||||||
return environment.project.zigService.cs.async {
|
return environment.project.zigCoroutineScope.async {
|
||||||
executeAsync(environment, state)
|
executeAsync(environment, state)
|
||||||
}.toPromise()
|
}.toPromise()
|
||||||
}
|
}
|
||||||
|
@ -49,10 +54,16 @@ abstract class ZigProgramRunner<ProfileState: ZigProfileState<*>>(protected val
|
||||||
|
|
||||||
val state = castProfileState(state) ?: return null
|
val state = castProfileState(state) ?: return null
|
||||||
|
|
||||||
execute(state, null, environment)
|
val toolchain = environment.project.zigProjectSettings.state.toolchain ?: return null
|
||||||
|
|
||||||
|
withContext(Dispatchers.EDT) {
|
||||||
|
FileDocumentManager.getInstance().saveAllDocuments()
|
||||||
|
}
|
||||||
|
|
||||||
|
return execute(state, toolchain, environment)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract fun castProfileState(state: ZigProfileState<*>): ProfileState?
|
protected abstract fun castProfileState(state: ZigProfileState<*>): ProfileState?
|
||||||
|
|
||||||
abstract suspend fun execute(state: ProfileState, toolchain: ZigToolchain, environment: ExecutionEnvironment)
|
abstract suspend fun execute(state: ProfileState, toolchain: AbstractZigToolchain, environment: ExecutionEnvironment): RunContentDescriptor?
|
||||||
}
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* 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.project.run
|
||||||
|
|
||||||
|
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.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.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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun castProfileState(state: ZigProfileState<*>): ZigProfileState<*>? {
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canRun(executorId: String, profile: RunProfile): Boolean {
|
||||||
|
return this.executorId == executorId && profile is ZigExecConfig<*>
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRunnerId(): String {
|
||||||
|
return "ZigRegularRunner"
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.project.settings
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.lsp.settings.ZLSSettingsConfigurable
|
||||||
|
import com.falsepattern.zigbrains.shared.MultiConfigurable
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
|
||||||
|
class ZigConfigurable(project: Project): MultiConfigurable(ZigProjectConfigurable(project), ZLSSettingsConfigurable(project)) {
|
||||||
|
override fun getDisplayName(): String {
|
||||||
|
return "Zig"
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.project.settings
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.lsp.startLSP
|
||||||
|
import com.falsepattern.zigbrains.shared.SubConfigurable
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.util.Disposer
|
||||||
|
import com.intellij.ui.dsl.builder.Panel
|
||||||
|
|
||||||
|
class ZigProjectConfigurable(private val project: Project): SubConfigurable {
|
||||||
|
private var settingsPanel: ZigProjectSettingsPanel? = null
|
||||||
|
override fun createComponent(panel: Panel) {
|
||||||
|
settingsPanel?.let { Disposer.dispose(it) }
|
||||||
|
settingsPanel = ZigProjectSettingsPanel(project).apply { attach(panel) }.also { Disposer.register(this, it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isModified(): Boolean {
|
||||||
|
return project.zigProjectSettings.isModified(settingsPanel?.data ?: return false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun apply() {
|
||||||
|
val service = project.zigProjectSettings
|
||||||
|
val data = settingsPanel?.data ?: return
|
||||||
|
val modified = service.isModified(data)
|
||||||
|
service.state = data
|
||||||
|
if (modified) {
|
||||||
|
startLSP(project, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reset() {
|
||||||
|
settingsPanel?.data = project.zigProjectSettings.state
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
settingsPanel = null
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,14 +22,22 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project.settings
|
package com.falsepattern.zigbrains.project.settings
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainConverter
|
import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain
|
||||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
import com.intellij.openapi.util.io.toNioPathOrNull
|
||||||
import com.intellij.util.xmlb.annotations.OptionTag
|
import com.intellij.util.xmlb.annotations.Transient
|
||||||
|
import kotlin.io.path.pathString
|
||||||
|
|
||||||
@JvmRecord
|
|
||||||
data class ZigProjectSettings(
|
data class ZigProjectSettings(
|
||||||
val direnv: Boolean = true,
|
var direnv: Boolean = true,
|
||||||
val overrideStdPath: Boolean = false,
|
var overrideStdPath: Boolean = false,
|
||||||
val explicitPathToStd: String? = null,
|
var explicitPathToStd: String? = null,
|
||||||
@OptionTag(converter = ZigToolchainConverter::class) val toolchain: ZigToolchain? = null
|
var toolchainPath: String? = null
|
||||||
)
|
) {
|
||||||
|
@get:Transient
|
||||||
|
@set:Transient
|
||||||
|
var toolchain: LocalZigToolchain?
|
||||||
|
get() = toolchainPath?.toNioPathOrNull()?.let { LocalZigToolchain(it) }
|
||||||
|
set(value) {
|
||||||
|
toolchainPath = value?.location?.pathString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
/*
|
||||||
|
* 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.project.settings
|
||||||
|
|
||||||
|
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.zigCoroutineScope
|
||||||
|
import com.intellij.openapi.Disposable
|
||||||
|
import com.intellij.openapi.application.EDT
|
||||||
|
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
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.ui.DocumentAdapter
|
||||||
|
import com.intellij.ui.JBColor
|
||||||
|
import com.intellij.ui.components.JBCheckBox
|
||||||
|
import com.intellij.ui.components.JBLabel
|
||||||
|
import com.intellij.ui.components.textFieldWithBrowseButton
|
||||||
|
import com.intellij.ui.dsl.builder.AlignX
|
||||||
|
import com.intellij.ui.dsl.builder.Panel
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import javax.swing.event.DocumentEvent
|
||||||
|
import kotlin.io.path.pathString
|
||||||
|
|
||||||
|
class ZigProjectSettingsPanel(private val project: Project?) : Disposable {
|
||||||
|
private val direnv = JBCheckBox(ZigBrainsBundle.message("settings.project.label.direnv"))
|
||||||
|
private val pathToToolchain = textFieldWithBrowseButton(
|
||||||
|
project,
|
||||||
|
ZigBrainsBundle.message("dialog.title.zig-toolchain"),
|
||||||
|
FileChooserDescriptorFactory.createSingleFolderDescriptor()
|
||||||
|
).also {
|
||||||
|
it.textField.document.addDocumentListener(object : DocumentAdapter() {
|
||||||
|
override fun textChanged(e: DocumentEvent) {
|
||||||
|
dispatchUpdateUI()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
Disposer.register(this, it)
|
||||||
|
}
|
||||||
|
private val toolchainVersion = JBLabel()
|
||||||
|
private val stdFieldOverride = JBCheckBox(ZigBrainsBundle.message("settings.project.label.override-std")).apply {
|
||||||
|
addChangeListener {
|
||||||
|
if (isSelected) {
|
||||||
|
pathToStd.isEnabled = true
|
||||||
|
} else {
|
||||||
|
pathToStd.isEnabled = false
|
||||||
|
updateUI()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private val pathToStd = textFieldWithBrowseButton(
|
||||||
|
project,
|
||||||
|
ZigBrainsBundle.message("dialog.title.zig-std"),
|
||||||
|
FileChooserDescriptorFactory.createSingleFolderDescriptor()
|
||||||
|
).also { Disposer.register(this, it) }
|
||||||
|
private var debounce: Job? = null
|
||||||
|
|
||||||
|
suspend fun autodetect() {
|
||||||
|
val data = UserDataHolderBase()
|
||||||
|
data.putUserData(LocalZigToolchain.DIRENV_KEY, direnv.isSelected)
|
||||||
|
val tc = ZigToolchainProvider.suggestToolchain(project, data) ?: return
|
||||||
|
if (tc !is LocalZigToolchain) {
|
||||||
|
TODO("Implement non-local zig toolchain in config")
|
||||||
|
}
|
||||||
|
pathToToolchain.text = tc.location.pathString
|
||||||
|
dispatchUpdateUI()
|
||||||
|
}
|
||||||
|
|
||||||
|
var data
|
||||||
|
get() = ZigProjectSettings(
|
||||||
|
direnv.isSelected,
|
||||||
|
stdFieldOverride.isSelected,
|
||||||
|
pathToStd.text,
|
||||||
|
pathToToolchain.text
|
||||||
|
)
|
||||||
|
set(value) {
|
||||||
|
direnv.isSelected = value.direnv
|
||||||
|
pathToToolchain.text = value.toolchainPath ?: ""
|
||||||
|
stdFieldOverride.isSelected = value.overrideStdPath
|
||||||
|
pathToStd.text = value.explicitPathToStd ?: ""
|
||||||
|
pathToStd.isEnabled = value.overrideStdPath
|
||||||
|
dispatchUpdateUI()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun attach(p: Panel): Unit = with(p) {
|
||||||
|
val project = project ?: ProjectManager.getInstance().defaultProject
|
||||||
|
data = project.zigProjectSettings.state
|
||||||
|
group(ZigBrainsBundle.message("settings.project.group.title")) {
|
||||||
|
row(ZigBrainsBundle.message("settings.project.label.toolchain")) {
|
||||||
|
cell(pathToToolchain).resizableColumn().align(AlignX.FILL)
|
||||||
|
if (DirenvCmd.direnvInstalled() && !project.isDefault) {
|
||||||
|
cell(direnv)
|
||||||
|
}
|
||||||
|
button(ZigBrainsBundle.message("settings.project.label.toolchain-autodetect")) {
|
||||||
|
this@ZigProjectSettingsPanel.project.zigCoroutineScope.launch {
|
||||||
|
autodetect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
row(ZigBrainsBundle.message("settings.project.label.toolchain-version")) {
|
||||||
|
cell(toolchainVersion)
|
||||||
|
}
|
||||||
|
row(ZigBrainsBundle.message("settings.project.label.std-location")) {
|
||||||
|
cell(pathToStd).resizableColumn().align(AlignX.FILL)
|
||||||
|
cell(stdFieldOverride)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dispatchUpdateUI() {
|
||||||
|
debounce?.cancel("New debounce")
|
||||||
|
debounce = project.zigCoroutineScope.launch {
|
||||||
|
updateUI()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private suspend fun updateUI() {
|
||||||
|
val pathToToolchain = this.pathToToolchain.text.toNioPathOrNull()
|
||||||
|
delay(200)
|
||||||
|
val toolchain = pathToToolchain?.let { LocalZigToolchain(it) }
|
||||||
|
val zig = toolchain?.zig
|
||||||
|
val env = zig?.getEnv(project)
|
||||||
|
val version = env?.version
|
||||||
|
val stdPath = env?.stdPath(toolchain)
|
||||||
|
withContext(Dispatchers.EDT) {
|
||||||
|
toolchainVersion.text = version ?: ""
|
||||||
|
toolchainVersion.foreground = JBColor.foreground()
|
||||||
|
|
||||||
|
if (!stdFieldOverride.isSelected) {
|
||||||
|
pathToStd.text = stdPath?.pathString ?: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
debounce?.cancel("Disposed")
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.project.steps.discovery
|
||||||
|
|
||||||
|
import com.intellij.openapi.actionSystem.AnAction
|
||||||
|
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||||
|
|
||||||
|
class ZigDiscoverStepsAction: AnAction() {
|
||||||
|
override fun actionPerformed(e: AnActionEvent) {
|
||||||
|
val project = e.project ?: return
|
||||||
|
project.zigStepDiscovery.triggerReload()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.project.steps.discovery
|
||||||
|
|
||||||
|
interface ZigStepDiscoveryListener {
|
||||||
|
suspend fun preReload() {}
|
||||||
|
suspend fun postReload(steps: List<Pair<String, String?>>) {}
|
||||||
|
suspend fun errorReload(type: ErrorType, details: String?) {}
|
||||||
|
suspend fun timeoutReload(seconds: Int) {}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class ErrorType {
|
||||||
|
MissingToolchain,
|
||||||
|
MissingBuildZig,
|
||||||
|
GeneralError
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,160 @@
|
||||||
|
/*
|
||||||
|
* 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.project.steps.discovery
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
||||||
|
import com.falsepattern.zigbrains.project.steps.discovery.ZigStepDiscoveryListener.ErrorType
|
||||||
|
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||||
|
import com.intellij.openapi.Disposable
|
||||||
|
import com.intellij.openapi.application.EDT
|
||||||
|
import com.intellij.openapi.components.Service
|
||||||
|
import com.intellij.openapi.components.service
|
||||||
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
|
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.project.guessProjectDir
|
||||||
|
import com.intellij.openapi.vfs.toNioPathOrNull
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
||||||
|
@Service(Service.Level.PROJECT)
|
||||||
|
class ZigStepDiscoveryService(private val project: Project) {
|
||||||
|
private val reloading = AtomicBoolean(false)
|
||||||
|
private val reloadScheduled = AtomicBoolean(false)
|
||||||
|
private val reloadMutex = Mutex()
|
||||||
|
private var CURRENT_TIMEOUT_SEC = DEFAULT_TIMEOUT_SEC
|
||||||
|
private val listeners = ArrayList<ZigStepDiscoveryListener>()
|
||||||
|
private val listenerMutex = Mutex()
|
||||||
|
|
||||||
|
suspend fun register(listener: ZigStepDiscoveryListener): Disposable {
|
||||||
|
return listenerMutex.withLock {
|
||||||
|
listeners.add(listener)
|
||||||
|
Disposable {
|
||||||
|
zigCoroutineScope.launch {
|
||||||
|
listenerMutex.withLock {
|
||||||
|
listeners.remove(listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun triggerReload() {
|
||||||
|
project.zigCoroutineScope.launch {
|
||||||
|
reloadMutex.withLock {
|
||||||
|
if (reloading.getAndSet(true)) {
|
||||||
|
reloadScheduled.set(true)
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dispatchReload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private tailrec suspend fun doReload() {
|
||||||
|
preReload()
|
||||||
|
val toolchain = project.zigProjectSettings.state.toolchain ?: run {
|
||||||
|
errorReload(ErrorType.MissingToolchain)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val zig = toolchain.zig
|
||||||
|
val result = zig.callWithArgs(
|
||||||
|
project.guessProjectDir()?.toNioPathOrNull(),
|
||||||
|
"build", "-l",
|
||||||
|
timeoutMillis = CURRENT_TIMEOUT_SEC * 1000L
|
||||||
|
)
|
||||||
|
if (result.checkSuccess(LOG)) {
|
||||||
|
CURRENT_TIMEOUT_SEC = DEFAULT_TIMEOUT_SEC
|
||||||
|
val lines = result.stdoutLines
|
||||||
|
val steps = ArrayList<Pair<String, String?>>()
|
||||||
|
for (line in lines) {
|
||||||
|
val parts = line.trim().split(SPACES, 2)
|
||||||
|
if (parts.size == 2) {
|
||||||
|
steps.add(Pair(parts[0], parts[1]))
|
||||||
|
} else {
|
||||||
|
steps.add(Pair(parts[0], null))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
postReload(steps)
|
||||||
|
} else if (result.isTimeout) {
|
||||||
|
timeoutReload(CURRENT_TIMEOUT_SEC)
|
||||||
|
CURRENT_TIMEOUT_SEC *= 2
|
||||||
|
} else if (result.stderrLines.any { it.contains("error: no build.zig file found, in the current directory or any parent directories") }) {
|
||||||
|
errorReload(ErrorType.MissingBuildZig, result.stderr)
|
||||||
|
} else {
|
||||||
|
errorReload(ErrorType.GeneralError, result.stderr)
|
||||||
|
}
|
||||||
|
if (reloadMutex.withLock {
|
||||||
|
if (reloadScheduled.getAndSet(false)) {
|
||||||
|
return@withLock true
|
||||||
|
}
|
||||||
|
reloading.set(false)
|
||||||
|
return@withLock false
|
||||||
|
}) {
|
||||||
|
doReload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun dispatchReload() {
|
||||||
|
withContext(Dispatchers.EDT) {
|
||||||
|
FileDocumentManager.getInstance().saveAllDocuments()
|
||||||
|
}
|
||||||
|
doReload()
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun preReload() {
|
||||||
|
listenerMutex.withLock {
|
||||||
|
listeners.forEach { it.preReload() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun postReload(steps: List<Pair<String, String?>>) {
|
||||||
|
listenerMutex.withLock {
|
||||||
|
listeners.forEach { it.postReload(steps) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun errorReload(type: ErrorType, details: String? = null) {
|
||||||
|
listenerMutex.withLock {
|
||||||
|
listeners.forEach { it.errorReload(type, details) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun timeoutReload(seconds: Int) {
|
||||||
|
listenerMutex.withLock {
|
||||||
|
listeners.forEach { it.timeoutReload(seconds) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val Project.zigStepDiscovery get() = service<ZigStepDiscoveryService>()
|
||||||
|
|
||||||
|
private val SPACES = Regex("\\s+")
|
||||||
|
|
||||||
|
private const val DEFAULT_TIMEOUT_SEC = 10
|
||||||
|
|
||||||
|
private val LOG = Logger.getInstance(ZigStepDiscoveryService::class.java)
|
|
@ -20,23 +20,28 @@
|
||||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType
|
package com.falsepattern.zigbrains.project.steps.ui
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
|
||||||
|
|
||||||
val lsp4ijVersion: String by project
|
import com.intellij.ide.projectView.PresentationData
|
||||||
val lsp4jVersion: String by project
|
import com.intellij.ide.util.treeView.PresentableNodeDescriptor
|
||||||
val lsp4ijNightly = property("lsp4ijNightly").toString().toBoolean()
|
import com.intellij.openapi.project.Project
|
||||||
val lsp4ijDepString = "${if (lsp4ijNightly) "nightly." else ""}com.jetbrains.plugins:com.redhat.devtools.lsp4ij:$lsp4ijVersion"
|
import com.intellij.ui.SimpleTextAttributes
|
||||||
tasks.withType<KotlinCompile> {
|
import javax.swing.Icon
|
||||||
kotlinOptions {
|
|
||||||
freeCompilerArgs += "-Xcontext-receivers"
|
open class BaseNodeDescriptor<T>(project: Project?, displayName: String, displayIcon: Icon, private var description: String? = null): PresentableNodeDescriptor<T>(project, null) {
|
||||||
|
init {
|
||||||
|
icon = displayIcon
|
||||||
|
myName = displayName
|
||||||
|
update()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
dependencies {
|
override fun update(presentation: PresentationData) {
|
||||||
intellijPlatform {
|
presentation.setIcon(icon)
|
||||||
create(IntelliJPlatformType.IntellijIdeaCommunity, providers.gradleProperty("ideaCommunityVersion"))
|
presentation.addText(myName, SimpleTextAttributes.REGULAR_ATTRIBUTES)
|
||||||
|
presentation.tooltip = description
|
||||||
}
|
}
|
||||||
intellijPlatformPluginDependency(lsp4ijDepString)
|
|
||||||
compileOnly("org.eclipse.lsp4j:org.eclipse.lsp4j:$lsp4jVersion")
|
override fun getElement(): T? {
|
||||||
implementation(project(":core"))
|
return null
|
||||||
}
|
}
|
||||||
|
}
|
|
@ -0,0 +1,229 @@
|
||||||
|
/*
|
||||||
|
* 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.project.steps.ui
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.Icons
|
||||||
|
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||||
|
import com.falsepattern.zigbrains.project.execution.build.ZigConfigTypeBuild
|
||||||
|
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.intellij.execution.ProgramRunnerUtil
|
||||||
|
import com.intellij.execution.RunManager
|
||||||
|
import com.intellij.execution.RunnerAndConfigurationSettings
|
||||||
|
import com.intellij.execution.executors.DefaultRunExecutor
|
||||||
|
import com.intellij.icons.AllIcons
|
||||||
|
import com.intellij.openapi.Disposable
|
||||||
|
import com.intellij.openapi.actionSystem.ActionManager
|
||||||
|
import com.intellij.openapi.actionSystem.DefaultActionGroup
|
||||||
|
import com.intellij.openapi.application.EDT
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.ui.SimpleToolWindowPanel
|
||||||
|
import com.intellij.openapi.util.Disposer
|
||||||
|
import com.intellij.openapi.util.Key
|
||||||
|
import com.intellij.openapi.wm.ToolWindow
|
||||||
|
import com.intellij.openapi.wm.ToolWindowManager
|
||||||
|
import com.intellij.ui.AnimatedIcon
|
||||||
|
import com.intellij.ui.components.JBLabel
|
||||||
|
import com.intellij.ui.components.JBScrollPane
|
||||||
|
import com.intellij.ui.components.JBTextArea
|
||||||
|
import com.intellij.ui.content.Content
|
||||||
|
import com.intellij.ui.content.ContentFactory
|
||||||
|
import com.intellij.ui.treeStructure.Tree
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.intellij.lang.annotations.JdkConstants.BoxLayoutAxis
|
||||||
|
import java.awt.GridBagConstraints
|
||||||
|
import java.awt.GridBagLayout
|
||||||
|
import java.awt.event.MouseAdapter
|
||||||
|
import java.awt.event.MouseEvent
|
||||||
|
import javax.swing.BoxLayout
|
||||||
|
import javax.swing.JPanel
|
||||||
|
import javax.swing.SwingConstants
|
||||||
|
import javax.swing.tree.DefaultMutableTreeNode
|
||||||
|
import javax.swing.tree.DefaultTreeModel
|
||||||
|
import javax.swing.tree.TreePath
|
||||||
|
|
||||||
|
|
||||||
|
class BuildToolWindowContext(private val project: Project): Disposable {
|
||||||
|
val rootNode: DefaultMutableTreeNode = DefaultMutableTreeNode(BaseNodeDescriptor<Any>(project, project.name, AllIcons.Actions.ProjectDirectory))
|
||||||
|
private val buildZig: DefaultMutableTreeNode = DefaultMutableTreeNode(BaseNodeDescriptor<Any>(project, ZigBrainsBundle.message("build.tool.window.tree.steps.label"), Icons.ZIG))
|
||||||
|
init {
|
||||||
|
rootNode.add(buildZig)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setViewportTree(viewport: JBScrollPane) {
|
||||||
|
val model = DefaultTreeModel(rootNode)
|
||||||
|
val tree = Tree(model)
|
||||||
|
tree.expandPath(TreePath(model.getPathToRoot(buildZig)))
|
||||||
|
viewport.setViewportView(tree)
|
||||||
|
tree.addMouseListener(object : MouseAdapter() {
|
||||||
|
override fun mouseClicked(e: MouseEvent) {
|
||||||
|
if (e.clickCount == 2) {
|
||||||
|
val node = tree.lastSelectedPathComponent as? DefaultMutableTreeNode ?: return
|
||||||
|
val step = node.userObject as? StepNodeDescriptor ?: return
|
||||||
|
|
||||||
|
val stepName = step.element?.name ?: return
|
||||||
|
val manager = RunManager.getInstance(project)
|
||||||
|
val config = getExistingRunConfig(manager, stepName) ?: run {
|
||||||
|
val factory = firstConfigFactory<ZigConfigTypeBuild>()
|
||||||
|
val newConfig = manager.createConfiguration("zig build $stepName", factory)
|
||||||
|
val config = newConfig.configuration as ZigExecConfigBuild
|
||||||
|
config.buildSteps.args = listOf(stepName)
|
||||||
|
manager.addConfiguration(newConfig)
|
||||||
|
return@run newConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.selectedConfiguration = config
|
||||||
|
ProgramRunnerUtil.executeConfiguration(config, DefaultRunExecutor.getRunExecutorInstance())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createContentPanel(): Content {
|
||||||
|
val contentPanel = SimpleToolWindowPanel(false)
|
||||||
|
val body = JPanel(GridBagLayout())
|
||||||
|
contentPanel.setLayout(GridBagLayout())
|
||||||
|
val c = GridBagConstraints()
|
||||||
|
c.fill = GridBagConstraints.BOTH
|
||||||
|
c.weightx = 1.0
|
||||||
|
c.weighty = 1.0
|
||||||
|
contentPanel.add(body, c)
|
||||||
|
c.fill = GridBagConstraints.HORIZONTAL
|
||||||
|
c.anchor = GridBagConstraints.NORTHWEST
|
||||||
|
c.weightx = 1.0
|
||||||
|
c.weighty = 0.0
|
||||||
|
val toolbar = ActionManager.getInstance().createActionToolbar("ZigToolbar", DefaultActionGroup(ActionManager.getInstance().getAction("zigbrains.discover.steps")), true)
|
||||||
|
toolbar.targetComponent = null
|
||||||
|
body.add(toolbar.component, c)
|
||||||
|
c.gridwidth = 1
|
||||||
|
c.gridy = 1
|
||||||
|
c.weighty = 1.0
|
||||||
|
c.fill = GridBagConstraints.BOTH
|
||||||
|
val viewport = JBScrollPane()
|
||||||
|
viewport.setViewportNoContent()
|
||||||
|
body.add(viewport, c)
|
||||||
|
val content = ContentFactory.getInstance().createContent(contentPanel, "", false)
|
||||||
|
content.putUserData(VIEWPORT, viewport)
|
||||||
|
return content
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
suspend fun create(project: Project, window: ToolWindow) {
|
||||||
|
withContext(Dispatchers.EDT) {
|
||||||
|
val context = BuildToolWindowContext(project)
|
||||||
|
Disposer.register(context, project.zigStepDiscovery.register(context.BuildReloadListener()))
|
||||||
|
Disposer.register(window.disposable, context)
|
||||||
|
window.contentManager.addContent(context.createContentPanel())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class BuildReloadListener: ZigStepDiscoveryListener {
|
||||||
|
override suspend fun preReload() {
|
||||||
|
getViewport(project)?.setViewportLoading()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun postReload(steps: List<Pair<String, String?>>) {
|
||||||
|
buildZig.removeAllChildren()
|
||||||
|
for ((task, description) in steps) {
|
||||||
|
val icon = when(task) {
|
||||||
|
"install" -> AllIcons.Actions.Install
|
||||||
|
"uninstall" -> AllIcons.Actions.Uninstall
|
||||||
|
else -> AllIcons.RunConfigurations.TestState.Run
|
||||||
|
}
|
||||||
|
buildZig.add(DefaultMutableTreeNode(StepNodeDescriptor(project, task, icon, description)))
|
||||||
|
}
|
||||||
|
withContext(Dispatchers.EDT) {
|
||||||
|
getViewport(project)?.let { setViewportTree(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun errorReload(type: ZigStepDiscoveryListener.ErrorType, details: String?) {
|
||||||
|
withContext(Dispatchers.EDT) {
|
||||||
|
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"
|
||||||
|
ZigStepDiscoveryListener.ErrorType.GeneralError -> "build.tool.window.status.error.general"
|
||||||
|
}), details)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun timeoutReload(seconds: Int) {
|
||||||
|
withContext(Dispatchers.EDT) {
|
||||||
|
getViewport(project)?.setViewportError(ZigBrainsBundle.message("build.tool.window.status.timeout", seconds), null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun JBScrollPane.setViewportLoading() {
|
||||||
|
setViewportView(JBLabel(ZigBrainsBundle.message("build.tool.window.status.loading"), AnimatedIcon.Default(), SwingConstants.CENTER))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun JBScrollPane.setViewportNoContent() {
|
||||||
|
setViewportView(JBLabel(ZigBrainsBundle.message("build.tool.window.status.not-scanned"), AllIcons.General.Information, SwingConstants.CENTER))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun JBScrollPane.setViewportError(msg: String, details: String?) {
|
||||||
|
val result = JPanel()
|
||||||
|
result.layout = BoxLayout(result, BoxLayout.Y_AXIS)
|
||||||
|
result.add(JBLabel(msg, AllIcons.General.Error, SwingConstants.CENTER))
|
||||||
|
if (details != null) {
|
||||||
|
val code = JBTextArea()
|
||||||
|
code.isEditable = false
|
||||||
|
code.text = details
|
||||||
|
val scroll = JBScrollPane(code)
|
||||||
|
result.add(scroll)
|
||||||
|
}
|
||||||
|
setViewportView(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getViewport(project: Project): JBScrollPane? {
|
||||||
|
val toolWindow = ToolWindowManager.getInstance(project).getToolWindow("zigbrains.build") ?: return null
|
||||||
|
val cm = toolWindow.contentManager
|
||||||
|
val content = cm.getContent(0) ?: return null
|
||||||
|
return content.getUserData(VIEWPORT)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getExistingRunConfig(manager: RunManager, stepName: String): RunnerAndConfigurationSettings? {
|
||||||
|
for (config in manager.getConfigurationSettingsList(ZigConfigTypeBuild::class.java)) {
|
||||||
|
val build = config.configuration as? ZigExecConfigBuild ?: continue
|
||||||
|
val steps = build.buildSteps.args
|
||||||
|
if (steps.size != 1)
|
||||||
|
continue
|
||||||
|
if (steps[0] != stepName)
|
||||||
|
continue
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private val VIEWPORT = Key.create<JBScrollPane>("MODEL")
|
|
@ -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.project.steps.ui
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.shared.coroutine.runModalOrBlocking
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.wm.ToolWindow
|
||||||
|
import com.intellij.openapi.wm.ToolWindowFactory
|
||||||
|
import com.intellij.platform.ide.progress.ModalTaskOwner
|
||||||
|
|
||||||
|
class BuildToolWindowFactory: ToolWindowFactory {
|
||||||
|
override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
|
||||||
|
runModalOrBlocking({ModalTaskOwner.project(project)}, {"BuildToolWindowFactory.createToolWindowContent"}) {
|
||||||
|
BuildToolWindowContext.create(project, toolWindow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* 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.project.steps.ui
|
||||||
|
|
||||||
|
@JvmRecord
|
||||||
|
data class StepDetails(val name: String)
|
|
@ -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.project.steps.ui
|
||||||
|
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import javax.swing.Icon
|
||||||
|
|
||||||
|
class StepNodeDescriptor(project: Project?, private val stepName: String, displayIcon: Icon, description: String? = null) :
|
||||||
|
BaseNodeDescriptor<StepDetails>(project, stepName, displayIcon, description) {
|
||||||
|
override fun getElement(): StepDetails? {
|
||||||
|
return StepDetails(stepName)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.project.template
|
||||||
|
|
||||||
|
class ZigExecutableTemplate: ZigProjectTemplate("Executable (application)", true) {
|
||||||
|
override fun fileTemplates(): Map<String, String> {
|
||||||
|
return mapOf(
|
||||||
|
"src/main.zig" to "application",
|
||||||
|
"build.zig" to "application",
|
||||||
|
"build.zig.zon" to "shared"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* 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.project.template
|
||||||
|
|
||||||
|
class ZigInitTemplate: ZigProjectTemplate("Generate using \"zig init\"", true) {
|
||||||
|
override fun fileTemplates(): Map<String, String> {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.project.template
|
||||||
|
|
||||||
|
class ZigLibraryTemplate: ZigProjectTemplate("Library (static)", true) {
|
||||||
|
override fun fileTemplates(): Map<String, String> {
|
||||||
|
return mapOf(
|
||||||
|
"src/root.zig" to "static",
|
||||||
|
"build.zig" to "static",
|
||||||
|
"build.zig.zon" to "shared"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.project.template
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.Icons
|
||||||
|
import com.intellij.openapi.util.NlsContexts.ListItem
|
||||||
|
import javax.swing.Icon
|
||||||
|
|
||||||
|
sealed class ZigProjectTemplate(
|
||||||
|
@ListItem val name: String,
|
||||||
|
val isBinary: Boolean,
|
||||||
|
val icon: Icon = Icons.ZIG
|
||||||
|
) {
|
||||||
|
abstract fun fileTemplates(): Map<String, String>
|
||||||
|
}
|
|
@ -22,12 +22,18 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project.toolchain
|
package com.falsepattern.zigbrains.project.toolchain
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.project.toolchain.tools.ZigCompilerTool
|
||||||
|
import com.intellij.execution.configurations.GeneralCommandLine
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.util.Key
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
abstract class AbstractZigToolchain(
|
abstract class AbstractZigToolchain {
|
||||||
val location: Path,
|
val zig: ZigCompilerTool by lazy { ZigCompilerTool(this) }
|
||||||
val project: Project?
|
|
||||||
) {
|
abstract fun workingDirectory(project: Project? = null): Path?
|
||||||
abstract fun pathToExecutable(toolName: String): Path
|
|
||||||
|
abstract suspend fun patchCommandLine(commandLine: GeneralCommandLine, project: Project? = null): GeneralCommandLine
|
||||||
|
|
||||||
|
abstract fun pathToExecutable(toolName: String, project: Project? = null): Path
|
||||||
}
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* 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.project.toolchain
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
||||||
|
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
||||||
|
import com.intellij.execution.configurations.GeneralCommandLine
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.project.guessProjectDir
|
||||||
|
import com.intellij.openapi.util.Key
|
||||||
|
import com.intellij.openapi.util.KeyWithDefaultValue
|
||||||
|
import com.intellij.openapi.util.SystemInfo
|
||||||
|
import com.intellij.openapi.vfs.toNioPathOrNull
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
class LocalZigToolchain(val location: Path): AbstractZigToolchain() {
|
||||||
|
override fun workingDirectory(project: Project?): Path? {
|
||||||
|
return project?.guessProjectDir()?.toNioPathOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun patchCommandLine(commandLine: GeneralCommandLine, project: Project?): GeneralCommandLine {
|
||||||
|
if (project != null && (commandLine.getUserData(DIRENV_KEY) ?: project.zigProjectSettings.state.direnv)) {
|
||||||
|
commandLine.withEnvironment(DirenvCmd.importDirenv(project).env)
|
||||||
|
}
|
||||||
|
return commandLine
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun pathToExecutable(toolName: String, project: Project?): Path {
|
||||||
|
val exeName = if (SystemInfo.isWindows) "$toolName.exe" else toolName
|
||||||
|
return location.resolve(exeName)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val DIRENV_KEY = KeyWithDefaultValue.create<Boolean>("ZIG_LOCAL_DIRENV")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* 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.project.toolchain
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.direnv.DirenvCmd
|
||||||
|
import com.falsepattern.zigbrains.direnv.emptyEnv
|
||||||
|
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.util.UserDataHolder
|
||||||
|
import com.intellij.openapi.util.io.toNioPathOrNull
|
||||||
|
import kotlinx.serialization.json.*
|
||||||
|
import kotlin.io.path.pathString
|
||||||
|
|
||||||
|
class LocalZigToolchainProvider: ZigToolchainProvider<LocalZigToolchain> {
|
||||||
|
override suspend fun suggestToolchain(project: Project?, extraData: UserDataHolder): LocalZigToolchain? {
|
||||||
|
val env = if (project != null && (extraData.getUserData(LocalZigToolchain.DIRENV_KEY) ?: project.zigProjectSettings.state.direnv)) {
|
||||||
|
DirenvCmd.importDirenv(project)
|
||||||
|
} else {
|
||||||
|
emptyEnv
|
||||||
|
}
|
||||||
|
val zigExePath = env.findExecutableOnPATH("zig") ?: return null
|
||||||
|
return LocalZigToolchain(zigExePath.parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val serialMarker: String
|
||||||
|
get() = "local"
|
||||||
|
|
||||||
|
override fun deserialize(data: JsonElement): LocalZigToolchain? {
|
||||||
|
if (data !is JsonObject)
|
||||||
|
return null
|
||||||
|
|
||||||
|
val loc = data["location"] as? JsonPrimitive ?: return null
|
||||||
|
val path = loc.content.toNioPathOrNull() ?: return null
|
||||||
|
return LocalZigToolchain(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canSerialize(toolchain: AbstractZigToolchain): Boolean {
|
||||||
|
return toolchain is LocalZigToolchain
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun serialize(toolchain: LocalZigToolchain): JsonElement {
|
||||||
|
return buildJsonObject {
|
||||||
|
put("location", toolchain.location.pathString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* 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.project.toolchain
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.lsp.config.SuspendingZLSConfigProvider
|
||||||
|
import com.falsepattern.zigbrains.lsp.config.ZLSConfig
|
||||||
|
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
||||||
|
import com.intellij.notification.Notification
|
||||||
|
import com.intellij.notification.NotificationType
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.util.UserDataHolderBase
|
||||||
|
import com.intellij.openapi.util.io.toNioPathOrNull
|
||||||
|
import kotlin.io.path.notExists
|
||||||
|
import kotlin.io.path.pathString
|
||||||
|
|
||||||
|
class ToolchainZLSConfigProvider: SuspendingZLSConfigProvider {
|
||||||
|
override suspend fun getEnvironment(project: Project, previous: ZLSConfig): ZLSConfig {
|
||||||
|
val svc = project.zigProjectSettings
|
||||||
|
var state = svc.state
|
||||||
|
val toolchain = state.toolchain ?: ZigToolchainProvider.suggestToolchain(project, UserDataHolderBase()) ?: return previous
|
||||||
|
|
||||||
|
val env = toolchain.zig.getEnv(project)
|
||||||
|
|
||||||
|
val exe = env.zigExecutable.toNioPathOrNull() ?: run {
|
||||||
|
Notification(
|
||||||
|
"zigbrains-lsp",
|
||||||
|
"Invalid zig executable path: ${env.zigExecutable}",
|
||||||
|
NotificationType.ERROR
|
||||||
|
).notify(project)
|
||||||
|
return previous
|
||||||
|
}
|
||||||
|
if (exe.notExists()) {
|
||||||
|
Notification(
|
||||||
|
"zigbrains-lsp",
|
||||||
|
"Zig executable does not exiust: $exe",
|
||||||
|
NotificationType.ERROR
|
||||||
|
).notify(project)
|
||||||
|
return previous
|
||||||
|
}
|
||||||
|
var lib = if (state.overrideStdPath && state.explicitPathToStd != null) {
|
||||||
|
state.explicitPathToStd?.toNioPathOrNull() ?: run {
|
||||||
|
Notification(
|
||||||
|
"zigbrains-lsp",
|
||||||
|
"Invalid zig standard library path override: ${state.explicitPathToStd}",
|
||||||
|
NotificationType.ERROR
|
||||||
|
).notify(project)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} else null
|
||||||
|
|
||||||
|
if (lib == null) {
|
||||||
|
lib = env.libDirectory.toNioPathOrNull() ?: run {
|
||||||
|
Notification(
|
||||||
|
"zigbrains-lsp",
|
||||||
|
"Invalid zig standard library path: ${env.libDirectory}",
|
||||||
|
NotificationType.ERROR
|
||||||
|
).notify(project)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lib == null)
|
||||||
|
return previous
|
||||||
|
|
||||||
|
return previous.copy(zigExePath = exe.pathString, zigLibPath = lib.pathString)
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,10 +23,12 @@ package com.falsepattern.zigbrains.project.toolchain
|
||||||
|
|
||||||
import com.intellij.openapi.util.io.toNioPathOrNull
|
import com.intellij.openapi.util.io.toNioPathOrNull
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
|
||||||
@JvmRecord
|
@JvmRecord
|
||||||
|
@Serializable
|
||||||
data class ZigToolchainEnvironmentSerializable(
|
data class ZigToolchainEnvironmentSerializable(
|
||||||
@SerialName("zig_exe") val zigExecutable: String,
|
@SerialName("zig_exe") val zigExecutable: String,
|
||||||
@SerialName("std_dir") val stdDirectory: String,
|
@SerialName("std_dir") val stdDirectory: String,
|
||||||
|
@ -35,7 +37,7 @@ data class ZigToolchainEnvironmentSerializable(
|
||||||
@SerialName("version") val version: String,
|
@SerialName("version") val version: String,
|
||||||
@SerialName("target") val target: String
|
@SerialName("target") val target: String
|
||||||
) {
|
) {
|
||||||
fun stdPath(toolchain: AbstractZigToolchain): Path? {
|
fun stdPath(toolchain: LocalZigToolchain): Path? {
|
||||||
val path = stdDirectory.toNioPathOrNull() ?: return null
|
val path = stdDirectory.toNioPathOrNull() ?: return null
|
||||||
if (path.isAbsolute)
|
if (path.isAbsolute)
|
||||||
return path
|
return path
|
||||||
|
|
|
@ -23,31 +23,34 @@
|
||||||
package com.falsepattern.zigbrains.project.toolchain
|
package com.falsepattern.zigbrains.project.toolchain
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainProvider.Companion.EXTENSION_POINT_NAME
|
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainProvider.Companion.EXTENSION_POINT_NAME
|
||||||
import com.falsepattern.zigbrains.project.toolchain.base.ZigToolchain
|
|
||||||
import com.intellij.openapi.extensions.ExtensionPointName
|
import com.intellij.openapi.extensions.ExtensionPointName
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.util.UserDataHolder
|
||||||
import com.intellij.util.xmlb.Converter
|
import com.intellij.util.xmlb.Converter
|
||||||
import kotlinx.serialization.json.*
|
import kotlinx.serialization.json.*
|
||||||
|
|
||||||
sealed interface ZigToolchainProvider {
|
sealed interface ZigToolchainProvider<in T: AbstractZigToolchain> {
|
||||||
suspend fun getToolchain(project: Project?): ZigToolchain?
|
suspend fun suggestToolchain(project: Project?, extraData: UserDataHolder): AbstractZigToolchain?
|
||||||
|
|
||||||
val serialMarker: String
|
val serialMarker: String
|
||||||
fun deserialize(data: JsonElement): ZigToolchain?
|
fun deserialize(data: JsonElement): AbstractZigToolchain?
|
||||||
fun canSerialize(toolchain: ZigToolchain): Boolean
|
fun canSerialize(toolchain: AbstractZigToolchain): Boolean
|
||||||
fun serialize(toolchain: ZigToolchain): JsonElement
|
fun serialize(toolchain: T): JsonElement
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val EXTENSION_POINT_NAME = ExtensionPointName.create<ZigToolchainProvider>("com.falsepattern.zigbrains.toolchainProvider")
|
val EXTENSION_POINT_NAME = ExtensionPointName.create<ZigToolchainProvider<*>>("com.falsepattern.zigbrains.toolchainProvider")
|
||||||
|
|
||||||
suspend fun findToolchains(project: Project?): ZigToolchain? {
|
suspend fun suggestToolchain(project: Project?, extraData: UserDataHolder): AbstractZigToolchain? {
|
||||||
return EXTENSION_POINT_NAME.extensionList.firstNotNullOfOrNull { it.getToolchain(project) }
|
return EXTENSION_POINT_NAME.extensionList.firstNotNullOfOrNull { it.suggestToolchain(project, extraData) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ZigToolchainConverter: Converter<ZigToolchain>() {
|
@Suppress("UNCHECKED_CAST")
|
||||||
override fun fromString(value: String): ZigToolchain? {
|
private fun <T: AbstractZigToolchain> ZigToolchainProvider<T>.serialize(toolchain: AbstractZigToolchain) = serialize(toolchain as T)
|
||||||
|
|
||||||
|
class ZigToolchainConverter: Converter<AbstractZigToolchain>() {
|
||||||
|
override fun fromString(value: String): AbstractZigToolchain? {
|
||||||
val json = Json.parseToJsonElement(value) as? JsonObject ?: return null
|
val json = Json.parseToJsonElement(value) as? JsonObject ?: return null
|
||||||
val marker = (json["marker"] as? JsonPrimitive)?.contentOrNull ?: return null
|
val marker = (json["marker"] as? JsonPrimitive)?.contentOrNull ?: return null
|
||||||
val data = json["data"] ?: return null
|
val data = json["data"] ?: return null
|
||||||
|
@ -55,7 +58,7 @@ class ZigToolchainConverter: Converter<ZigToolchain>() {
|
||||||
return provider.deserialize(data)
|
return provider.deserialize(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(value: ZigToolchain): String? {
|
override fun toString(value: AbstractZigToolchain): String? {
|
||||||
val provider = EXTENSION_POINT_NAME.extensionList.find { it.canSerialize(value) } ?: return null
|
val provider = EXTENSION_POINT_NAME.extensionList.find { it.canSerialize(value) } ?: return null
|
||||||
return buildJsonObject {
|
return buildJsonObject {
|
||||||
put("marker", provider.serialMarker)
|
put("marker", provider.serialMarker)
|
||||||
|
|
|
@ -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.project.toolchain.stdlib
|
||||||
|
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.roots.AdditionalLibraryRootsProvider
|
||||||
|
import com.intellij.openapi.roots.SyntheticLibrary
|
||||||
|
|
||||||
|
class ZigLibraryRootProvider: AdditionalLibraryRootsProvider() {
|
||||||
|
override fun getAdditionalProjectLibraries(project: Project): Collection<SyntheticLibrary> {
|
||||||
|
return setOf(ZigSyntheticLibrary(project))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
/*
|
||||||
|
* 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.project.toolchain.stdlib
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.Icons
|
||||||
|
import com.falsepattern.zigbrains.project.settings.ZigProjectSettings
|
||||||
|
import com.falsepattern.zigbrains.project.settings.zigProjectSettings
|
||||||
|
import com.falsepattern.zigbrains.shared.coroutine.getOrAwaitModalOrBlocking
|
||||||
|
import com.falsepattern.zigbrains.shared.coroutine.runModalOrBlocking
|
||||||
|
import com.falsepattern.zigbrains.shared.zigCoroutineScope
|
||||||
|
import com.intellij.navigation.ItemPresentation
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.roots.SyntheticLibrary
|
||||||
|
import com.intellij.openapi.util.io.toNioPathOrNull
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.openapi.vfs.refreshAndFindVirtualDirectory
|
||||||
|
import com.intellij.platform.ide.progress.ModalTaskOwner
|
||||||
|
import com.intellij.util.suspendingLazy
|
||||||
|
import kotlinx.coroutines.async
|
||||||
|
import java.util.*
|
||||||
|
import javax.swing.Icon
|
||||||
|
|
||||||
|
class ZigSyntheticLibrary(val project: Project) : SyntheticLibrary(), ItemPresentation {
|
||||||
|
private val roots = project.zigCoroutineScope.suspendingLazy {
|
||||||
|
getRoots(project.zigProjectSettings.state, project)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val name = project.zigCoroutineScope.suspendingLazy {
|
||||||
|
getName(project.zigProjectSettings.state, project)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (other !is ZigSyntheticLibrary)
|
||||||
|
return false
|
||||||
|
|
||||||
|
return roots == other.roots
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return Objects.hash(roots)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getPresentableText(): String {
|
||||||
|
return name.getOrAwaitModalOrBlocking({ModalTaskOwner.project(project)}, {"ZigSyntheticLibrary.getPresentableText"})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getIcon(unused: Boolean): Icon {
|
||||||
|
return Icons.ZIG
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSourceRoots(): Collection<VirtualFile> {
|
||||||
|
return roots.getOrAwaitModalOrBlocking({ ModalTaskOwner.project(project)}, {"ZigSyntheticLibrary.getSourceRoots"})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private suspend fun getName(
|
||||||
|
state: ZigProjectSettings,
|
||||||
|
project: Project
|
||||||
|
): String {
|
||||||
|
val tc = state.toolchain ?: return "Zig"
|
||||||
|
val version = tc.zig.getEnv(project).version
|
||||||
|
return "Zig $version"
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun getRoots(
|
||||||
|
state: ZigProjectSettings,
|
||||||
|
project: Project
|
||||||
|
): Set<VirtualFile> {
|
||||||
|
val toolchain = state.toolchain
|
||||||
|
run {
|
||||||
|
val ePathStr = state.explicitPathToStd ?: return@run
|
||||||
|
val ePath = ePathStr.toNioPathOrNull() ?: return@run
|
||||||
|
if (ePath.isAbsolute) {
|
||||||
|
val roots = ePath.refreshAndFindVirtualDirectory() ?: return@run
|
||||||
|
return setOf(roots)
|
||||||
|
} else if (toolchain != null) {
|
||||||
|
val stdPath = toolchain.location.resolve(ePath)
|
||||||
|
if (stdPath.isAbsolute) {
|
||||||
|
val roots = stdPath.refreshAndFindVirtualDirectory() ?: return@run
|
||||||
|
return setOf(roots)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (toolchain != null) {
|
||||||
|
val stdPath = toolchain.zig.getEnv(project).stdPath(toolchain) ?: return emptySet()
|
||||||
|
val roots = stdPath.refreshAndFindVirtualDirectory() ?: return emptySet()
|
||||||
|
return setOf(roots)
|
||||||
|
}
|
||||||
|
return emptySet()
|
||||||
|
}
|
|
@ -24,13 +24,23 @@ package com.falsepattern.zigbrains.project.toolchain.tools
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
|
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
|
||||||
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainEnvironmentSerializable
|
import com.falsepattern.zigbrains.project.toolchain.ZigToolchainEnvironmentSerializable
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
class ZigCompilerTool(toolchain: AbstractZigToolchain): ZigTool(toolchain) {
|
class ZigCompilerTool(toolchain: AbstractZigToolchain) : ZigTool(toolchain) {
|
||||||
override val toolName: String
|
override val toolName: String
|
||||||
get() = "zig"
|
get() = "zig"
|
||||||
|
|
||||||
suspend fun getEnv(): ZigToolchainEnvironmentSerializable {
|
fun path(): Path {
|
||||||
return Json.decodeFromString<ZigToolchainEnvironmentSerializable>(callWithArgs(toolchain.location, "env").stdout)
|
return toolchain.pathToExecutable(toolName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getEnv(project: Project?): ZigToolchainEnvironmentSerializable {
|
||||||
|
return envJson.decodeFromString<ZigToolchainEnvironmentSerializable>(callWithArgs(toolchain.workingDirectory(project), "env").stdout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val envJson = Json {
|
||||||
|
ignoreUnknownKeys = true
|
||||||
}
|
}
|
|
@ -26,35 +26,37 @@ import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain
|
||||||
import com.intellij.execution.configurations.GeneralCommandLine
|
import com.intellij.execution.configurations.GeneralCommandLine
|
||||||
import com.intellij.execution.process.ProcessOutput
|
import com.intellij.execution.process.ProcessOutput
|
||||||
import com.intellij.util.io.awaitExit
|
import com.intellij.util.io.awaitExit
|
||||||
import com.intellij.util.io.readLineAsync
|
|
||||||
import kotlinx.coroutines.runInterruptible
|
import kotlinx.coroutines.runInterruptible
|
||||||
import kotlinx.coroutines.withTimeout
|
import kotlinx.coroutines.withTimeoutOrNull
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.time.Duration
|
|
||||||
|
|
||||||
abstract class ZigTool(val toolchain: AbstractZigToolchain) {
|
abstract class ZigTool(val toolchain: AbstractZigToolchain) {
|
||||||
abstract val toolName: String
|
abstract val toolName: String
|
||||||
|
|
||||||
suspend fun callWithArgs(workingDirectory: Path?, vararg parameters: String): ProcessOutput {
|
suspend fun callWithArgs(workingDirectory: Path?, vararg parameters: String, timeoutMillis: Long = Long.MAX_VALUE): ProcessOutput {
|
||||||
val process = createBaseCommandLine(workingDirectory, *parameters).createProcess()
|
val process = createBaseCommandLine(workingDirectory, *parameters).createProcess()
|
||||||
val exitCode = process.awaitExit()
|
|
||||||
|
val exitCode = withTimeoutOrNull(timeoutMillis) {
|
||||||
|
process.awaitExit()
|
||||||
|
}
|
||||||
return runInterruptible {
|
return runInterruptible {
|
||||||
ProcessOutput(
|
ProcessOutput(
|
||||||
process.inputStream.bufferedReader().use { it.readText() },
|
process.inputStream.bufferedReader().use { it.readText() },
|
||||||
process.errorStream.bufferedReader().use { it.readText() },
|
process.errorStream.bufferedReader().use { it.readText() },
|
||||||
exitCode,
|
exitCode ?: -1,
|
||||||
false,
|
exitCode == null,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected suspend fun createBaseCommandLine(workingDirectory: Path?,
|
private suspend fun createBaseCommandLine(workingDirectory: Path?,
|
||||||
vararg parameters: String): GeneralCommandLine {
|
vararg parameters: String): GeneralCommandLine {
|
||||||
return GeneralCommandLine()
|
val cli = GeneralCommandLine()
|
||||||
.withExePath(toolchain.pathToExecutable(toolName).toString())
|
.withExePath(toolchain.pathToExecutable(toolName).toString())
|
||||||
.withWorkDirectory(workingDirectory?.toString())
|
.withWorkDirectory(workingDirectory?.toString())
|
||||||
.withParameters(*parameters)
|
.withParameters(*parameters)
|
||||||
.withCharset(Charsets.UTF_8)
|
.withCharset(Charsets.UTF_8)
|
||||||
|
return toolchain.patchCommandLine(cli)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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.shared
|
||||||
|
|
||||||
|
import com.intellij.openapi.options.Configurable
|
||||||
|
import com.intellij.openapi.util.Disposer
|
||||||
|
import com.intellij.ui.dsl.builder.panel
|
||||||
|
import javax.swing.JComponent
|
||||||
|
|
||||||
|
abstract class MultiConfigurable(private vararg val configurables: SubConfigurable): Configurable {
|
||||||
|
override fun createComponent(): JComponent? {
|
||||||
|
return panel {
|
||||||
|
for (configurable in configurables) {
|
||||||
|
configurable.createComponent(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isModified(): Boolean {
|
||||||
|
return configurables.any { it.isModified() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun apply() {
|
||||||
|
configurables.forEach { it.apply() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun reset() {
|
||||||
|
configurables.forEach { it.reset() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun disposeUIResources() {
|
||||||
|
configurables.forEach { Disposer.dispose(it) }
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,15 +22,14 @@
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.shared
|
package com.falsepattern.zigbrains.shared
|
||||||
|
|
||||||
import com.intellij.openapi.options.Configurable
|
import com.intellij.openapi.Disposable
|
||||||
|
import com.intellij.openapi.options.ConfigurationException
|
||||||
import com.intellij.ui.dsl.builder.Panel
|
import com.intellij.ui.dsl.builder.Panel
|
||||||
import com.intellij.ui.dsl.builder.panel
|
|
||||||
import javax.swing.JComponent
|
|
||||||
|
|
||||||
interface NestedConfigurable: Configurable {
|
|
||||||
override fun createComponent() = panel {
|
|
||||||
createComponent(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
interface SubConfigurable: Disposable {
|
||||||
fun createComponent(panel: Panel)
|
fun createComponent(panel: Panel)
|
||||||
|
fun isModified(): Boolean
|
||||||
|
@Throws(ConfigurationException::class)
|
||||||
|
fun apply()
|
||||||
|
fun reset()
|
||||||
}
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* 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.shared
|
||||||
|
|
||||||
|
import com.intellij.openapi.extensions.ExtensionPointName
|
||||||
|
|
||||||
|
interface ZBFeatures {
|
||||||
|
fun getDebug(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val EXTENSION_POINT_NAME = ExtensionPointName.create<ZBFeatures>("com.falsepattern.zigbrains.featureProvider")
|
||||||
|
|
||||||
|
fun debug(): Boolean {
|
||||||
|
val extensions = EXTENSION_POINT_NAME.extensionList
|
||||||
|
return extensions.any { it.getDebug() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,14 +20,24 @@
|
||||||
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
* along with ZigBrains. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.falsepattern.zigbrains.project
|
package com.falsepattern.zigbrains.shared
|
||||||
|
|
||||||
import com.intellij.openapi.components.Service
|
import com.intellij.openapi.components.Service
|
||||||
import com.intellij.openapi.components.service
|
import com.intellij.openapi.components.service
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.util.application
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
||||||
@Service(Service.Level.PROJECT)
|
@Service(Service.Level.PROJECT)
|
||||||
class ZigProjectService(val cs: CoroutineScope)
|
class ZigProjectService(val cs: CoroutineScope)
|
||||||
|
|
||||||
val Project.zigService get() = service<ZigProjectService>()
|
@Service
|
||||||
|
class ZigAppService(val cs: CoroutineScope)
|
||||||
|
|
||||||
|
val Project?.zigCoroutineScope get() =
|
||||||
|
if (this == null || this.isDefault)
|
||||||
|
application.service<ZigAppService>().cs
|
||||||
|
else
|
||||||
|
this.service<ZigProjectService>().cs
|
||||||
|
|
||||||
|
val zigCoroutineScope get() = application.service<ZigAppService>().cs
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* 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.shared.cli
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.ZigBrainsBundle
|
||||||
|
import com.intellij.openapi.options.ConfigurationException
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
|
|
||||||
|
//From Apache Ant
|
||||||
|
/**
|
||||||
|
* Crack a command line.
|
||||||
|
* @param toProcess the command line to process.
|
||||||
|
* @return the command line broken into strings.
|
||||||
|
* An empty or null toProcess parameter results in a zero sized array.
|
||||||
|
*/
|
||||||
|
@Throws(ConfigurationException::class)
|
||||||
|
fun translateCommandline(toProcess: String): List<String> {
|
||||||
|
if (toProcess.isEmpty()) {
|
||||||
|
//no command? no string
|
||||||
|
return listOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse with a simple finite state machine
|
||||||
|
val normal = 0
|
||||||
|
val inQuote = 1
|
||||||
|
val inDoubleQuote = 2
|
||||||
|
var state = normal
|
||||||
|
val tok = StringTokenizer(toProcess, "\"' ", true)
|
||||||
|
val result = ArrayList<String>()
|
||||||
|
val current = StringBuilder()
|
||||||
|
var lastTokenHasBeenQuoted = false
|
||||||
|
|
||||||
|
while (tok.hasMoreTokens()) {
|
||||||
|
val nextTok: String = tok.nextToken()
|
||||||
|
when (state) {
|
||||||
|
inQuote -> if ("'" == nextTok) {
|
||||||
|
lastTokenHasBeenQuoted = true
|
||||||
|
state = normal
|
||||||
|
} else {
|
||||||
|
current.append(nextTok)
|
||||||
|
}
|
||||||
|
|
||||||
|
inDoubleQuote -> if ("\"" == nextTok) {
|
||||||
|
lastTokenHasBeenQuoted = true
|
||||||
|
state = normal
|
||||||
|
} else {
|
||||||
|
current.append(nextTok)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
if ("'" == nextTok) {
|
||||||
|
state = inQuote
|
||||||
|
} else if ("\"" == nextTok) {
|
||||||
|
state = inDoubleQuote
|
||||||
|
} else if (" " == nextTok) {
|
||||||
|
if (lastTokenHasBeenQuoted || current.isNotEmpty()) {
|
||||||
|
result.add(current.toString())
|
||||||
|
current.setLength(0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
current.append(nextTok)
|
||||||
|
}
|
||||||
|
lastTokenHasBeenQuoted = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastTokenHasBeenQuoted || current.isNotEmpty()) {
|
||||||
|
result.add(current.toString())
|
||||||
|
}
|
||||||
|
if (state == inQuote || state == inDoubleQuote) {
|
||||||
|
throw ConfigurationException(ZigBrainsBundle.message("exception.translate-command-line.unbalanced-quotes", toProcess))
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun coloredCliFlags(colored: Boolean, debug: Boolean): List<String> {
|
||||||
|
return if (debug) {
|
||||||
|
emptyList()
|
||||||
|
} else {
|
||||||
|
listOf("--color", if (colored) "on" else "off")
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.shared.coroutine
|
||||||
|
|
||||||
|
import com.intellij.platform.ide.progress.ModalTaskOwner
|
||||||
|
import com.intellij.platform.ide.progress.TaskCancellation
|
||||||
|
import com.intellij.platform.ide.progress.runWithModalProgressBlocking
|
||||||
|
import com.intellij.util.SuspendingLazy
|
||||||
|
import com.intellij.util.application
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
|
||||||
|
inline fun <T> runModalOrBlocking(taskOwnerFactory: () -> ModalTaskOwner, titleFactory: () -> String, cancellationFactory: () -> TaskCancellation = TaskCancellation::cancellable, noinline action: suspend CoroutineScope.() -> T): T {
|
||||||
|
return if (application.isDispatchThread) {
|
||||||
|
runWithModalProgressBlocking(taskOwnerFactory(), titleFactory(), cancellationFactory(), action)
|
||||||
|
} else {
|
||||||
|
runBlocking(block = action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <T> SuspendingLazy<T>.getOrAwaitModalOrBlocking(taskOwnerFactory: () -> ModalTaskOwner, titleFactory: () -> String, cancellationFactory: () -> TaskCancellation = TaskCancellation::cancellable): T {
|
||||||
|
if (isInitialized()) {
|
||||||
|
return getInitialized()
|
||||||
|
} else {
|
||||||
|
return runModalOrBlocking(taskOwnerFactory, titleFactory, cancellationFactory) {
|
||||||
|
getValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* 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.shared.element
|
||||||
|
|
||||||
|
import org.jdom.Element
|
||||||
|
|
||||||
|
|
||||||
|
fun Element.readString(name: String): String? {
|
||||||
|
return children
|
||||||
|
.firstOrNull { it.name == "ZigBrainsOption" && it.getAttributeValue("name") == name }
|
||||||
|
?.getAttributeValue("value")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Element.readBoolean(name: String): Boolean? {
|
||||||
|
return readString(name)?.toBooleanStrictOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T: Enum<T>> Element.readEnum(name: String): T? {
|
||||||
|
return readEnum(name, T::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T: Enum<T>> Element.readEnum(name: String, klass: Class<T>): T? {
|
||||||
|
return readString(name)?.let { valueOf(it, klass) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Element.readChild(name: String): Element? {
|
||||||
|
return children
|
||||||
|
.firstOrNull { it.name == "ZigBrainsNestedOption" && it.getAttributeValue("name") == name }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Element.readStrings(name: String): List<String>? {
|
||||||
|
return children
|
||||||
|
.firstOrNull { it.name == "ZigBrainsArrayOption" && it.getAttributeValue("name") == name }
|
||||||
|
?.children
|
||||||
|
?.mapNotNull { if (it.name == "ZigBrainsArrayEntry") it.getAttributeValue("value") else null }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Element.writeString(name: String, value: String) {
|
||||||
|
val option = Element("ZigBrainsOption")
|
||||||
|
option.setAttribute("name", name)
|
||||||
|
option.setAttribute("value", value)
|
||||||
|
|
||||||
|
addContent(option)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Element.writeBoolean(name: String, value: Boolean) {
|
||||||
|
writeString(name, value.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T: Enum<T>> Element.writeEnum(name: String, value: T) {
|
||||||
|
writeString(name, value.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Element.writeStrings(name: String, values: List<String>) {
|
||||||
|
val arr = Element("ZigBrainsArrayOption")
|
||||||
|
arr.setAttribute("name", name)
|
||||||
|
for (value in values) {
|
||||||
|
val subElem = Element("ZigBrainsArrayEntry")
|
||||||
|
subElem.setAttribute("value", value)
|
||||||
|
arr.addContent(subElem)
|
||||||
|
}
|
||||||
|
addContent(arr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Element.writeChild(name: String): Element {
|
||||||
|
val child = Element("ZigBrainsNestedOption")
|
||||||
|
child.setAttribute("name", name)
|
||||||
|
addContent(child)
|
||||||
|
return child
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T: Enum<T>> valueOf(type: String, klass: Class<T>): T? {
|
||||||
|
return try {
|
||||||
|
java.lang.Enum.valueOf(klass, type)
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,9 +26,7 @@ package com.falsepattern.zigbrains.zig.util
|
||||||
|
|
||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap
|
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap
|
||||||
import org.jetbrains.annotations.NonNls
|
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
import java.util.stream.Collectors
|
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<idea-plugin>
|
<idea-plugin>
|
||||||
|
<resource-bundle>zigbrains.Bundle</resource-bundle>
|
||||||
<!-- region Zig -->
|
<!-- region Zig -->
|
||||||
<extensions defaultExtensionNs="com.intellij">
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
<colorSettingsPage
|
<colorSettingsPage
|
||||||
|
@ -90,6 +91,111 @@
|
||||||
</extensions>
|
</extensions>
|
||||||
<!-- endregion Zon -->
|
<!-- endregion Zon -->
|
||||||
|
|
||||||
|
<!-- region Project -->
|
||||||
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
|
<configurationType
|
||||||
|
implementation="com.falsepattern.zigbrains.project.execution.run.ZigConfigTypeRun"
|
||||||
|
/>
|
||||||
|
<runConfigurationProducer
|
||||||
|
implementation="com.falsepattern.zigbrains.project.execution.run.ZigConfigProducerRun"
|
||||||
|
/>
|
||||||
|
<runLineMarkerContributor
|
||||||
|
language="Zig"
|
||||||
|
implementationClass="com.falsepattern.zigbrains.project.execution.run.ZigLineMarkerRun"
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
<configurationType
|
||||||
|
implementation="com.falsepattern.zigbrains.project.execution.test.ZigConfigTypeTest"
|
||||||
|
/>
|
||||||
|
<runConfigurationProducer
|
||||||
|
implementation="com.falsepattern.zigbrains.project.execution.test.ZigConfigProducerTest"
|
||||||
|
/>
|
||||||
|
<runLineMarkerContributor
|
||||||
|
language="Zig"
|
||||||
|
implementationClass="com.falsepattern.zigbrains.project.execution.test.ZigLineMarkerTest"
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
<configurationType
|
||||||
|
implementation="com.falsepattern.zigbrains.project.execution.build.ZigConfigTypeBuild"
|
||||||
|
/>
|
||||||
|
<runConfigurationProducer
|
||||||
|
implementation="com.falsepattern.zigbrains.project.execution.build.ZigConfigProducerBuild"
|
||||||
|
/>
|
||||||
|
<runLineMarkerContributor
|
||||||
|
language="Zig"
|
||||||
|
implementationClass="com.falsepattern.zigbrains.project.execution.build.ZigLineMarkerBuild"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<directoryProjectGenerator
|
||||||
|
implementation="com.falsepattern.zigbrains.project.newproject.ZigDirectoryProjectGenerator"
|
||||||
|
/>
|
||||||
|
<newProjectWizard.languageGenerator
|
||||||
|
implementation="com.falsepattern.zigbrains.project.newproject.ZigNewProjectWizard"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<moduleBuilder
|
||||||
|
builderClass="com.falsepattern.zigbrains.project.module.ZigModuleBuilder"
|
||||||
|
/>
|
||||||
|
<projectConfigurable
|
||||||
|
parentId="language"
|
||||||
|
instance="com.falsepattern.zigbrains.project.settings.ZigConfigurable"
|
||||||
|
id="ZigConfigurable"
|
||||||
|
displayName="Zig"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<programRunner
|
||||||
|
implementation="com.falsepattern.zigbrains.project.run.ZigRegularRunner"
|
||||||
|
id="ZigRegularRunner"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<consoleFilterProvider
|
||||||
|
implementation="com.falsepattern.zigbrains.project.console.ZigConsoleFilterProvider"
|
||||||
|
/>
|
||||||
|
<analyzeStacktraceFilter
|
||||||
|
implementation="com.falsepattern.zigbrains.project.console.ZigSourceFileFilter"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<additionalLibraryRootsProvider
|
||||||
|
implementation="com.falsepattern.zigbrains.project.toolchain.stdlib.ZigLibraryRootProvider"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<toolWindow
|
||||||
|
factoryClass="com.falsepattern.zigbrains.project.steps.ui.BuildToolWindowFactory"
|
||||||
|
anchor="right"
|
||||||
|
icon="/icons/zig_build_tool.svg"
|
||||||
|
id="zigbrains.build"
|
||||||
|
/>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<extensions defaultExtensionNs="com.falsepattern.zigbrains">
|
||||||
|
<zlsConfigProvider
|
||||||
|
implementation="com.falsepattern.zigbrains.project.toolchain.ToolchainZLSConfigProvider"
|
||||||
|
/>
|
||||||
|
<toolchainProvider
|
||||||
|
implementation="com.falsepattern.zigbrains.project.toolchain.LocalZigToolchainProvider"
|
||||||
|
/>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<actions>
|
||||||
|
<action
|
||||||
|
id="zigbrains.discover.steps"
|
||||||
|
class="com.falsepattern.zigbrains.project.steps.discovery.ZigDiscoverStepsAction"
|
||||||
|
text="Reload Zig Build Steps"
|
||||||
|
description="Scan the project and detect build.zig steps using the current toolchain"
|
||||||
|
icon="AllIcons.Actions.Refresh"
|
||||||
|
/>
|
||||||
|
<action
|
||||||
|
id="zigbrains.file.new"
|
||||||
|
class="com.falsepattern.zigbrains.project.actions.ZigNewFileAction"
|
||||||
|
text="New Zig File"
|
||||||
|
>
|
||||||
|
<add-to-group group-id="NewGroup" anchor="before" relative-to-action="NewFile"/>
|
||||||
|
</action>
|
||||||
|
</actions>
|
||||||
|
<!-- endregion Project -->
|
||||||
|
|
||||||
<!-- region direnv -->
|
<!-- region direnv -->
|
||||||
<extensions defaultExtensionNs="com.intellij">
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
<notificationGroup displayType="BALLOON"
|
<notificationGroup displayType="BALLOON"
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
zig-cache/
|
||||||
|
zig-out/
|
||||||
|
build/
|
||||||
|
build-*/
|
||||||
|
docgen_tmp/
|
21
modules/core/src/main/resources/icons/zig_build_tool.svg
Normal file
21
modules/core/src/main/resources/icons/zig_build_tool.svg
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 154 140">
|
||||||
|
<g fill="#AFB1B3">
|
||||||
|
<g>
|
||||||
|
<polygon points="46,22 28,44 19,30"/>
|
||||||
|
<polygon points="46,22 33,33 28,44 22,44 22,95 31,95 20,100 12,117 0,117 0,22" shape-rendering="crispEdges"/>
|
||||||
|
<polygon points="31,95 12,117 4,106"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<polygon points="56,22 62,36 37,44"/>
|
||||||
|
<polygon points="56,22 111,22 111,44 37,44 56,32" shape-rendering="crispEdges"/>
|
||||||
|
<polygon points="116,95 97,117 90,104"/>
|
||||||
|
<polygon points="116,95 100,104 97,117 42,117 42,95" shape-rendering="crispEdges"/>
|
||||||
|
<polygon points="150,0 52,117 3,140 101,22"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<polygon points="141,22 140,40 122,45"/>
|
||||||
|
<polygon points="153,22 153,117 106,117 120,105 125,95 131,95 131,45 122,45 132,36 141,22" shape-rendering="crispEdges"/>
|
||||||
|
<polygon points="125,95 130,110 106,117"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 850 B |
|
@ -0,0 +1,66 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
// Although this function looks imperative, note that its job is to
|
||||||
|
// declaratively construct a build graph that will be executed by an external
|
||||||
|
// runner.
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
// Standard target options allows the person running `zig build` to choose
|
||||||
|
// what target to build for. Here we do not override the defaults, which
|
||||||
|
// means any target is allowed, and the default is native. Other options
|
||||||
|
// for restricting supported target set are available.
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
|
||||||
|
// Standard optimization options allow the person running `zig build` to select
|
||||||
|
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
|
||||||
|
// set a preferred release mode, allowing the user to decide how to optimize.
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
|
const exe = b.addExecutable(.{
|
||||||
|
.name = "@@PROJECT_NAME@@",
|
||||||
|
.root_source_file = b.path("src/main.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
|
// This declares intent for the executable to be installed into the
|
||||||
|
// standard location when the user invokes the "install" step (the default
|
||||||
|
// step when running `zig build`).
|
||||||
|
b.installArtifact(exe);
|
||||||
|
|
||||||
|
// This *creates* a Run step in the build graph, to be executed when another
|
||||||
|
// step is evaluated that depends on it. The next line below will establish
|
||||||
|
// such a dependency.
|
||||||
|
const run_cmd = b.addRunArtifact(exe);
|
||||||
|
|
||||||
|
// By making the run step depend on the install step, it will be run from the
|
||||||
|
// installation directory rather than directly from within the cache directory.
|
||||||
|
// This is not necessary, however, if the application depends on other installed
|
||||||
|
// files, this ensures they will be present and in the expected location.
|
||||||
|
run_cmd.step.dependOn(b.getInstallStep());
|
||||||
|
|
||||||
|
// This allows the user to pass arguments to the application in the build
|
||||||
|
// command itself, like this: `zig build run -- arg1 arg2 etc`
|
||||||
|
if (b.args) |args| {
|
||||||
|
run_cmd.addArgs(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This creates a build step. It will be visible in the `zig build --help` menu,
|
||||||
|
// and can be selected like this: `zig build run`
|
||||||
|
// This will evaluate the `run` step rather than the default, which is "install".
|
||||||
|
const run_step = b.step("run", "Run the app");
|
||||||
|
run_step.dependOn(&run_cmd.step);
|
||||||
|
|
||||||
|
const exe_unit_tests = b.addTest(.{
|
||||||
|
.root_source_file = b.path("src/main.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
|
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
|
||||||
|
|
||||||
|
// Similar to creating the run step earlier, this exposes a `test` step to
|
||||||
|
// the `zig build --help` menu, providing a way for the user to request
|
||||||
|
// running the unit tests.
|
||||||
|
const test_step = b.step("test", "Run unit tests");
|
||||||
|
test_step.dependOn(&run_exe_unit_tests.step);
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub fn main() !void {
|
||||||
|
// Prints to stderr (it's a shortcut based on `std.io.getStdErr()`)
|
||||||
|
std.debug.print("All your {s} are belong to us.\n", .{"codebase"});
|
||||||
|
|
||||||
|
// stdout is for the actual output of your application, for example if you
|
||||||
|
// are implementing gzip, then only the compressed bytes should be sent to
|
||||||
|
// stdout, not any debugging messages.
|
||||||
|
const stdout_file = std.io.getStdOut().writer();
|
||||||
|
var bw = std.io.bufferedWriter(stdout_file);
|
||||||
|
const stdout = bw.writer();
|
||||||
|
|
||||||
|
try stdout.print("Run `zig build test` to run the tests.\n", .{});
|
||||||
|
|
||||||
|
try bw.flush(); // don't forget to flush!
|
||||||
|
}
|
||||||
|
|
||||||
|
test "simple test" {
|
||||||
|
var list = std.ArrayList(i32).init(std.testing.allocator);
|
||||||
|
defer list.deinit(); // try commenting this out and see if zig detects the memory leak!
|
||||||
|
try list.append(42);
|
||||||
|
try std.testing.expectEqual(@as(i32, 42), list.pop());
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
.{
|
||||||
|
.name = "@@PROJECT_NAME@@",
|
||||||
|
// This is a [Semantic Version](https://semver.org/).
|
||||||
|
// In a future version of Zig it will be used for package deduplication.
|
||||||
|
.version = "0.0.0",
|
||||||
|
|
||||||
|
// This field is optional.
|
||||||
|
// This is currently advisory only; Zig does not yet do anything
|
||||||
|
// with this value.
|
||||||
|
//.minimum_zig_version = "0.11.0",
|
||||||
|
|
||||||
|
// This field is optional.
|
||||||
|
// Each dependency must either provide a `url` and `hash`, or a `path`.
|
||||||
|
// `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
|
||||||
|
// Once all dependencies are fetched, `zig build` no longer requires
|
||||||
|
// internet connectivity.
|
||||||
|
.dependencies = .{
|
||||||
|
// See `zig fetch --save <url>` for a command-line interface for adding dependencies.
|
||||||
|
//.example = .{
|
||||||
|
// // When updating this field to a new URL, be sure to delete the corresponding
|
||||||
|
// // `hash`, otherwise you are communicating that you expect to find the old hash at
|
||||||
|
// // the new URL.
|
||||||
|
// .url = "https://example.com/foo.tar.gz",
|
||||||
|
//
|
||||||
|
// // This is computed from the file contents of the directory of files that is
|
||||||
|
// // obtained after fetching `url` and applying the inclusion rules given by
|
||||||
|
// // `paths`.
|
||||||
|
// //
|
||||||
|
// // This field is the source of truth; packages do not come from a `url`; they
|
||||||
|
// // come from a `hash`. `url` is just one of many possible mirrors for how to
|
||||||
|
// // obtain a package matching this `hash`.
|
||||||
|
// //
|
||||||
|
// // Uses the [multihash](https://multiformats.io/multihash/) format.
|
||||||
|
// .hash = "...",
|
||||||
|
//
|
||||||
|
// // When this is provided, the package is found in a directory relative to the
|
||||||
|
// // build root. In this case the package's hash is irrelevant and therefore not
|
||||||
|
// // computed. This field and `url` are mutually exclusive.
|
||||||
|
// .path = "foo",
|
||||||
|
|
||||||
|
// // When this is set to `true`, a package is declared to be lazily
|
||||||
|
// // fetched. This makes the dependency only get fetched if it is
|
||||||
|
// // actually used.
|
||||||
|
// .lazy = false,
|
||||||
|
//},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Specifies the set of files and directories that are included in this package.
|
||||||
|
// Only files and directories listed here are included in the `hash` that
|
||||||
|
// is computed for this package.
|
||||||
|
// Paths are relative to the build root. Use the empty string (`""`) to refer to
|
||||||
|
// the build root itself.
|
||||||
|
// A directory listed here means that all files within, recursively, are included.
|
||||||
|
.paths = .{
|
||||||
|
// This makes *all* files, recursively, included in this package. It is generally
|
||||||
|
// better to explicitly list the files and directories instead, to insure that
|
||||||
|
// fetching from tarballs, file system paths, and version control all result
|
||||||
|
// in the same contents hash.
|
||||||
|
"",
|
||||||
|
// For example...
|
||||||
|
//"build.zig",
|
||||||
|
//"build.zig.zon",
|
||||||
|
//"src",
|
||||||
|
//"LICENSE",
|
||||||
|
//"README.md",
|
||||||
|
},
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
// Although this function looks imperative, note that its job is to
|
||||||
|
// declaratively construct a build graph that will be executed by an external
|
||||||
|
// runner.
|
||||||
|
pub fn build(b: *std.Build) void {
|
||||||
|
// Standard target options allows the person running `zig build` to choose
|
||||||
|
// what target to build for. Here we do not override the defaults, which
|
||||||
|
// means any target is allowed, and the default is native. Other options
|
||||||
|
// for restricting supported target set are available.
|
||||||
|
const target = b.standardTargetOptions(.{});
|
||||||
|
|
||||||
|
// Standard optimization options allow the person running `zig build` to select
|
||||||
|
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
|
||||||
|
// set a preferred release mode, allowing the user to decide how to optimize.
|
||||||
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
|
const lib = b.addStaticLibrary(.{
|
||||||
|
.name = "@@PROJECT_NAME@@",
|
||||||
|
// In this case the main source file is merely a path, however, in more
|
||||||
|
// complicated build scripts, this could be a generated file.
|
||||||
|
.root_source_file = b.path("src/root.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
|
// This declares intent for the library to be installed into the standard
|
||||||
|
// location when the user invokes the "install" step (the default step when
|
||||||
|
// running `zig build`).
|
||||||
|
b.installArtifact(lib);
|
||||||
|
|
||||||
|
// Creates a step for unit testing. This only builds the test executable
|
||||||
|
// but does not run it.
|
||||||
|
const lib_unit_tests = b.addTest(.{
|
||||||
|
.root_source_file = b.path("src/root.zig"),
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
});
|
||||||
|
|
||||||
|
const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);
|
||||||
|
|
||||||
|
// Similar to creating the run step earlier, this exposes a `test` step to
|
||||||
|
// the `zig build --help` menu, providing a way for the user to request
|
||||||
|
// running the unit tests.
|
||||||
|
const test_step = b.step("test", "Run unit tests");
|
||||||
|
test_step.dependOn(&run_lib_unit_tests.step);
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
|
||||||
|
export fn add(a: i32, b: i32) i32 {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "basic add functionality" {
|
||||||
|
try testing.expect(add(3, 7) == 10);
|
||||||
|
}
|
|
@ -68,3 +68,47 @@ notification.title.native-debug=Zig native debugger
|
||||||
notification.content.native-debug=You need to install the "Native Debugging Support" plugin for Zig debugging in this IDE!
|
notification.content.native-debug=You need to install the "Native Debugging Support" plugin for Zig debugging in this IDE!
|
||||||
notification.content.native-debug.market=Install from Marketplace
|
notification.content.native-debug.market=Install from Marketplace
|
||||||
notification.content.native-debug.browser=Open in Browser
|
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.option.label.working-directory=&Working directory:
|
||||||
|
exec.option.label.colored-terminal=Colored terminal
|
||||||
|
exec.option.label.direnv=Use direnv
|
||||||
|
exec.option.label.optimization=Optimization level
|
||||||
|
exec.option.label.optimization.force=Force even in debug runs
|
||||||
|
exec.option.label.emulate-terminal=Emulate terminal
|
||||||
|
exec.option.label.file-path=File Path
|
||||||
|
exec.option.label.compiler-args=Extra compiler command line arguments
|
||||||
|
exec.option.label.exe-args=Output program command line arguments
|
||||||
|
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.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
|
||||||
|
configuration.run.name=Zig run
|
||||||
|
configuration.run.suggested-name=Run
|
||||||
|
configuration.run.description=Execute "zig run" on a specific file
|
||||||
|
configuration.test.name=Zig test
|
||||||
|
configuration.test.suggested-name=Test
|
||||||
|
configuration.test.description=Execute "zig test" on a specific file
|
||||||
|
configuration.test.marker-name=all tests in {0}
|
||||||
|
configuration.build.name=Zig build
|
||||||
|
configuration.build.suggested-name=Build
|
||||||
|
configuration.build.description=Execute "zig build" with custom steps
|
||||||
|
configuration.build.marker-name=Build and Run
|
||||||
|
settings.project.group.title=Zig Settings
|
||||||
|
settings.project.label.direnv=Use direnv
|
||||||
|
settings.project.label.toolchain=Toolchain location
|
||||||
|
settings.project.label.toolchain-autodetect=Autodetect
|
||||||
|
settings.project.label.toolchain-version=Toolchain version
|
||||||
|
settings.project.label.override-std=Override standard library
|
||||||
|
settings.project.label.std-location=Standard library location
|
||||||
|
build.tool.window.tree.steps.label=Steps
|
||||||
|
build.tool.window.status.not-scanned=Build steps not yet scanned. Click the refresh button.
|
||||||
|
build.tool.window.status.loading=Running zig build -l
|
||||||
|
build.tool.window.status.error.missing-build-zig=No build.zig file found
|
||||||
|
build.tool.window.status.error.missing-toolchain=No zig toolchain configured
|
||||||
|
build.tool.window.status.error.general=Error while running zig build -l
|
||||||
|
build.tool.window.status.timeout=zig build -l timed out after {0} seconds.
|
|
@ -3,7 +3,7 @@ plugins {
|
||||||
}
|
}
|
||||||
rootProject.name = "ZigBrains"
|
rootProject.name = "ZigBrains"
|
||||||
|
|
||||||
for (module in arrayOf("core", "lsp")) {
|
for (module in arrayOf("core")) {
|
||||||
include(module)
|
include(module)
|
||||||
project(":$module").projectDir = file("modules/$module")
|
project(":$module").projectDir = file("modules/$module")
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,13 +12,17 @@
|
||||||
<extensionPoint
|
<extensionPoint
|
||||||
interface="com.falsepattern.zigbrains.lsp.config.ZLSConfigProviderBase"
|
interface="com.falsepattern.zigbrains.lsp.config.ZLSConfigProviderBase"
|
||||||
dynamic="true"
|
dynamic="true"
|
||||||
name="zlsConfigProvider"/>
|
name="zlsConfigProvider"
|
||||||
</extensionPoints>
|
/>
|
||||||
<extensionPoints>
|
|
||||||
<extensionPoint
|
<extensionPoint
|
||||||
interface="com.falsepattern.zigbrains.project.toolchain.ZigToolchainProvider"
|
interface="com.falsepattern.zigbrains.project.toolchain.ZigToolchainProvider"
|
||||||
dynamic="true"
|
dynamic="true"
|
||||||
name="toolchainProvider"
|
name="toolchainProvider"
|
||||||
/>
|
/>
|
||||||
|
<extensionPoint
|
||||||
|
interface="com.falsepattern.zigbrains.shared.ZBFeatures"
|
||||||
|
dynamic="true"
|
||||||
|
name="featureProvider"
|
||||||
|
/>
|
||||||
</extensionPoints>
|
</extensionPoints>
|
||||||
</idea-plugin>
|
</idea-plugin>
|
Loading…
Add table
Reference in a new issue