From db85b560848e9667b9697a7c563af0623e5ced3a Mon Sep 17 00:00:00 2001 From: FalsePattern Date: Thu, 27 Mar 2025 20:40:47 +0100 Subject: [PATCH] backport: 24.0.0 --- CHANGELOG.md | 24 ++++++++ ...lionDebuggerDriverConfigurationProvider.kt | 4 +- .../debugger/ZigLocalDebugProcess.kt | 3 +- .../runner/base/PreLaunchProcessListener.kt | 12 +--- .../base/ZigDebugEmitBinaryInstaller.kt | 3 +- .../runner/base/ZigDebugRunnerBase.kt | 6 +- .../runner/build/ZigDebugParametersBuild.kt | 2 +- .../ZigDebuggerToolchainConfigurableUi.kt | 7 ++- .../project/execution/ZigConsoleBuilder.kt | 38 ++++++++++++ .../project/execution/base/Configuration.kt | 26 ++++----- .../project/execution/base/ZigExecConfig.kt | 9 +-- .../project/execution/base/ZigProfileState.kt | 37 +++++------- .../execution/build/ZigExecConfigBuild.kt | 7 +-- .../project/execution/run/ZigExecConfigRun.kt | 7 +-- .../execution/test/ZigExecConfigTest.kt | 7 +-- .../project/module/ZigModuleBuilder.kt | 3 +- .../newproject/ZigProjectConfigurationData.kt | 6 +- .../project/run/ZigProcessHandler.kt | 58 +------------------ .../zigbrains/project/run/ZigRegularRunner.kt | 4 +- .../settings/ZigProjectSettingsPanel.kt | 2 +- .../discovery/ZigStepDiscoveryService.kt | 5 +- .../steps/ui/BuildToolWindowContext.kt | 56 +++++++++--------- .../zigbrains/shared/cli/CLIUtil.kt | 38 +++++++----- .../shared/coroutine/CoroutinesUtil.kt | 6 +- .../zigbrains/shared/ipc/IPCUtil.kt | 4 +- .../zigbrains/zon/formatter/ZonBlock.kt | 6 +- .../resources/zigbrains/Bundle.properties | 2 - gradle.properties | 2 +- .../lsp/settings/ZLSSettingsPanel.kt | 2 +- .../resources/zigbrains/lsp/Bundle.properties | 2 - 30 files changed, 179 insertions(+), 209 deletions(-) create mode 100644 core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/ZigConsoleBuilder.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 180174e8..4f41dcf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,30 @@ Changelog structure reference: ## [Unreleased] +## [24.0.0] + +### Added + +- Project, Debugging + - TTY support for zig processes + +### Removed + +- Project + - "Emulate terminal" and "colored output" config options have been removed from zig run/test/build tasks, as they are no longer required for ZigBrains to work. + +### Fixed + +- Debugger + - Build errors didn't get shown in the console + +- Project + - File path browse buttons in zig run configurations didn't work + - Occasional GUI deadlocks + +- Zig + - IPC wrapper wasn't passing exit code + ## [23.1.2] ### Fixed diff --git a/cidr/src/main/kotlin/com/falsepattern/zigbrains/clion/ZigClionDebuggerDriverConfigurationProvider.kt b/cidr/src/main/kotlin/com/falsepattern/zigbrains/clion/ZigClionDebuggerDriverConfigurationProvider.kt index 40e6563c..cf4ae4aa 100644 --- a/cidr/src/main/kotlin/com/falsepattern/zigbrains/clion/ZigClionDebuggerDriverConfigurationProvider.kt +++ b/cidr/src/main/kotlin/com/falsepattern/zigbrains/clion/ZigClionDebuggerDriverConfigurationProvider.kt @@ -57,8 +57,8 @@ class ZigClionDebuggerDriverConfigurationProvider: ZigDebuggerDriverConfiguratio } return when(toolchain.debuggerKind) { CPPDebugger.Kind.BUNDLED_GDB, - CPPDebugger.Kind.CUSTOM_GDB -> CLionGDBDriverConfiguration(project, toolchain) - CPPDebugger.Kind.BUNDLED_LLDB -> CLionLLDBDriverConfiguration(project, toolchain) + CPPDebugger.Kind.CUSTOM_GDB -> CLionGDBDriverConfiguration(project, toolchain, isEmulateTerminal = emulateTerminal) + CPPDebugger.Kind.BUNDLED_LLDB -> CLionLLDBDriverConfiguration(project, toolchain, isEmulateTerminal = emulateTerminal) } } } diff --git a/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigLocalDebugProcess.kt b/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigLocalDebugProcess.kt index fe9fcc31..cae89406 100644 --- a/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigLocalDebugProcess.kt +++ b/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/ZigLocalDebugProcess.kt @@ -22,9 +22,10 @@ package com.falsepattern.zigbrains.debugger +import com.intellij.execution.filters.Filter import com.intellij.execution.filters.TextConsoleBuilder import com.intellij.xdebugger.XDebugSession import com.jetbrains.cidr.execution.RunParameters import com.jetbrains.cidr.execution.debugger.CidrLocalDebugProcess -class ZigLocalDebugProcess(parameters: RunParameters, session: XDebugSession, consoleBuilder: TextConsoleBuilder) : CidrLocalDebugProcess(parameters, session, consoleBuilder) \ No newline at end of file +class ZigLocalDebugProcess(parameters: RunParameters, session: XDebugSession, consoleBuilder: TextConsoleBuilder) : CidrLocalDebugProcess(parameters, session, consoleBuilder, { Filter.EMPTY_ARRAY }, true) \ No newline at end of file diff --git a/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/PreLaunchProcessListener.kt b/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/PreLaunchProcessListener.kt index 953e91e7..92b64c96 100644 --- a/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/PreLaunchProcessListener.kt +++ b/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/PreLaunchProcessListener.kt @@ -23,6 +23,7 @@ package com.falsepattern.zigbrains.debugger.runner.base import com.falsepattern.zigbrains.project.run.ZigProcessHandler +import com.falsepattern.zigbrains.shared.cli.startIPCAwareProcess import com.falsepattern.zigbrains.shared.ipc.IPCUtil import com.falsepattern.zigbrains.shared.ipc.ipc import com.intellij.execution.ExecutionException @@ -48,12 +49,7 @@ class PreLaunchProcessListener(val console: ConsoleView) : ProcessListener { @Throws(ExecutionException::class) suspend fun executeCommandLineWithHook(project: Project, commandLine: GeneralCommandLine): Boolean { return withProgressText(commandLine.commandLineString) { - val ipc = IPCUtil.wrapWithIPC(commandLine) - val cli = ipc?.cli ?: commandLine - val processHandler = ZigProcessHandler(cli) - if (ipc != null) { - project.ipc?.launchWatcher(ipc, processHandler.process) - } + val processHandler = commandLine.startIPCAwareProcess(project) this@PreLaunchProcessListener.processHandler = processHandler hook(processHandler) processHandler.startNotify() @@ -74,10 +70,6 @@ class PreLaunchProcessListener(val console: ConsoleView) : ProcessListener { override fun processTerminated(event: ProcessEvent) { if (event.exitCode != 0) { - console.print( - "Process finished with exit code " + event.exitCode, - ConsoleViewContentType.NORMAL_OUTPUT - ) isBuildFailed = true } else { isBuildFailed = false diff --git a/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugEmitBinaryInstaller.kt b/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugEmitBinaryInstaller.kt index 6190c5c0..634172cc 100644 --- a/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugEmitBinaryInstaller.kt +++ b/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugEmitBinaryInstaller.kt @@ -26,6 +26,7 @@ import com.falsepattern.zigbrains.project.execution.base.ZigProfileState import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain import com.falsepattern.zigbrains.shared.zigCoroutineScope import com.intellij.execution.configurations.GeneralCommandLine +import com.intellij.execution.configurations.PtyCommandLine import com.jetbrains.cidr.execution.Installer import kotlinx.coroutines.async import kotlinx.coroutines.future.asCompletableFuture @@ -39,7 +40,7 @@ class ZigDebugEmitBinaryInstaller>( ): Installer { override fun install(): GeneralCommandLine { val cfg = profileState.configuration - val cli = GeneralCommandLine().withExePath(executableFile.absolutePath) + val cli = PtyCommandLine().withConsoleMode(false).withExePath(executableFile.absolutePath) cfg.workingDirectory.path?.let { x -> cli.withWorkDirectory(x.toFile()) } cli.addParameters(exeArgs) cli.withCharset(Charsets.UTF_8) diff --git a/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugRunnerBase.kt b/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugRunnerBase.kt index 4bb92371..7f176753 100644 --- a/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugRunnerBase.kt +++ b/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/base/ZigDebugRunnerBase.kt @@ -58,7 +58,7 @@ abstract class ZigDebugRunnerBase> : ZigProgra val project = environment.project val driverProviders = ZigDebuggerDriverConfigurationProviderBase.EXTENSION_POINT_NAME.extensionList for (provider in driverProviders) { - val driver = provider.getDebuggerConfiguration(project, isElevated = false, emulateTerminal = false, DebuggerDriverConfiguration::class.java) ?: continue + val driver = provider.getDebuggerConfiguration(project, isElevated = false, emulateTerminal = true, DebuggerDriverConfiguration::class.java) ?: continue return executeWithDriver(state, toolchain, environment, driver) ?: continue } return null @@ -93,12 +93,12 @@ abstract class ZigDebugRunnerBase> : ZigProgra } } } - return@reportProgress runInterruptibleEDT { + return@reportProgress runInterruptibleEDT(ModalityState.any()) { val debuggerManager = XDebuggerManager.getInstance(environment.project) debuggerManager.startSession(environment, object: XDebugProcessStarter() { override fun start(session: XDebugSession): XDebugProcess { val project = session.project - val textConsoleBuilder = SharedConsoleBuilder(console) + val textConsoleBuilder = state.consoleBuilder val debugProcess = ZigLocalDebugProcess(runParameters, session, textConsoleBuilder) ProcessTerminatedListener.attach(debugProcess.processHandler, project) debugProcess.start() diff --git a/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/build/ZigDebugParametersBuild.kt b/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/build/ZigDebugParametersBuild.kt index aa2741d4..aa9e2e38 100644 --- a/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/build/ZigDebugParametersBuild.kt +++ b/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/runner/build/ZigDebugParametersBuild.kt @@ -62,7 +62,7 @@ class ZigDebugParametersBuild( withContext(Dispatchers.IO) { val commandLine = profileState.getCommandLine(toolchain, true) if (listener.executeCommandLineWithHook(profileState.environment.project, commandLine)) - throw ExecutionException(ZigDebugBundle.message("debug.build.compile.failed.generic")) + return@withContext val cfg = profileState.configuration val workingDir = cfg.workingDirectory.path val exe = profileState.configuration.exePath.path ?: run { diff --git a/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/settings/ZigDebuggerToolchainConfigurableUi.kt b/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/settings/ZigDebuggerToolchainConfigurableUi.kt index a9a79879..66b534f9 100644 --- a/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/settings/ZigDebuggerToolchainConfigurableUi.kt +++ b/cidr/src/main/kotlin/com/falsepattern/zigbrains/debugger/settings/ZigDebuggerToolchainConfigurableUi.kt @@ -31,6 +31,7 @@ import com.falsepattern.zigbrains.shared.coroutine.launchWithEDT import com.falsepattern.zigbrains.shared.coroutine.runModalOrBlocking import com.falsepattern.zigbrains.shared.zigCoroutineScope import com.intellij.ide.plugins.PluginManager +import com.intellij.openapi.application.ModalityState import com.intellij.openapi.extensions.PluginId import com.intellij.openapi.observable.util.whenItemSelected import com.intellij.openapi.ui.ComboBox @@ -88,7 +89,7 @@ class ZigDebuggerToolchainConfigurableUi : ZigDebuggerUiComponent { row(ZigDebugBundle.message("settings.debugger.toolchain.debugger.label")) { comment = cell(debuggerKindComboBox) .comment("", DEFAULT_COMMENT_WIDTH) { - zigCoroutineScope.launchWithEDT { + zigCoroutineScope.launchWithEDT(ModalityState.any()) { withModalProgress(ModalTaskOwner.component(debuggerKindComboBox), "Downloading debugger", TaskCancellation.cancellable()) { downloadDebugger() } @@ -96,7 +97,7 @@ class ZigDebuggerToolchainConfigurableUi : ZigDebuggerUiComponent { } .applyToComponent { whenItemSelected(null) { - zigCoroutineScope.launchWithEDT { + zigCoroutineScope.launchWithEDT(ModalityState.any()) { this@ZigDebuggerToolchainConfigurableUi.update() } } @@ -111,7 +112,7 @@ class ZigDebuggerToolchainConfigurableUi : ZigDebuggerUiComponent { cell(useClion) } } - zigCoroutineScope.launchWithEDT { + zigCoroutineScope.launchWithEDT(ModalityState.any()) { update() } } diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/ZigConsoleBuilder.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/ZigConsoleBuilder.kt new file mode 100644 index 00000000..e46a415f --- /dev/null +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/ZigConsoleBuilder.kt @@ -0,0 +1,38 @@ +/* + * This file is part of ZigBrains. + * + * Copyright (C) 2023-2025 FalsePattern + * All Rights Reserved + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * ZigBrains is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, only version 3 of the License. + * + * ZigBrains is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with ZigBrains. If not, see . + */ + +package com.falsepattern.zigbrains.project.execution + +import com.intellij.execution.filters.TextConsoleBuilderImpl +import com.intellij.execution.ui.ConsoleView +import com.intellij.openapi.project.Project +import com.intellij.terminal.TerminalExecutionConsole +import java.nio.file.Path + +class ZigConsoleBuilder(private val project: Project, private val emulateTerminal: Boolean = false): TextConsoleBuilderImpl(project) { + override fun createConsole(): ConsoleView { + return if (emulateTerminal) + TerminalExecutionConsole(project, null) + else + super.createConsole() + } +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/Configuration.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/Configuration.kt index 913fe604..15e177a0 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/Configuration.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/Configuration.kt @@ -33,11 +33,11 @@ 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.components.textFieldWithBrowseButton import com.intellij.ui.dsl.builder.AlignX import com.intellij.ui.dsl.builder.Panel import com.intellij.ui.dsl.builder.panel @@ -161,12 +161,11 @@ class WorkDirectoryConfigurable(@Transient override val serializedName: String) } class WorkDirectoryConfigModule(private val serializedName: String) : PathConfigModule() { - private val field = TextFieldWithBrowseButton( - TextBrowseFolderListener( - FileChooserDescriptorFactory.createSingleFolderDescriptor().withTitle(ZigBrainsBundle.message("dialog.title.working-directory")) - ), - this - ) + private val field = textFieldWithBrowseButton( + null, + ZigBrainsBundle.message("dialog.title.working-directory"), + FileChooserDescriptorFactory.createSingleFolderDescriptor().withTitle(ZigBrainsBundle.message("dialog.title.working-directory")) + ).also { Disposer.register(this, it) } override var stringValue by field::text @@ -201,9 +200,10 @@ class FilePathConfigurable( } class FilePathConfigModule(private val serializedName: String, @Nls private val label: String) : PathConfigModule() { - private val field = TextFieldWithBrowseButton( - TextBrowseFolderListener(FileChooserDescriptorFactory.createSingleFileDescriptor()), - this + private val field = textFieldWithBrowseButton( + null, + null, + FileChooserDescriptorFactory.createSingleFileDescriptor(), ) override var stringValue by field::text @@ -274,12 +274,6 @@ open class CheckboxConfigurable( } } -class ColoredConfigurable(serializedName: String): CheckboxConfigurable(serializedName, ZigBrainsBundle.message("exec.option.label.colored-terminal"), true) { - override fun clone(): ColoredConfigurable { - return super.clone() as ColoredConfigurable - } -} - class OptimizationConfigurable( @Transient private val serializedName: String, var level: OptimizationLevel = OptimizationLevel.Debug, diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigExecConfig.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigExecConfig.kt index b03b16ad..ee148595 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigExecConfig.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigExecConfig.kt @@ -43,8 +43,6 @@ import org.jetbrains.annotations.Nls abstract class ZigExecConfig>(project: Project, factory: ConfigurationFactory, @Nls name: String): LocatableConfigurationBase>(project, factory, name) { var workingDirectory = WorkDirectoryConfigurable("workingDirectory").apply { path = project.guessProjectDir()?.toNioPathOrNull() } private set - var pty = CheckboxConfigurable("pty", ZigBrainsBundle.message("exec.option.label.emulate-terminal"), false) - private set abstract val suggestedName: @ActionText String @Throws(ExecutionException::class) @@ -73,17 +71,12 @@ abstract class ZigExecConfig>(project: Project, factory: Con 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() @Suppress("UNCHECKED_CAST") return myClone as T } - open fun getConfigurables(): List> = listOf(workingDirectory, pty) + open fun getConfigurables(): List> = listOf(workingDirectory) } \ No newline at end of file diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigProfileState.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigProfileState.kt index eee91c7d..053c1455 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigProfileState.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/base/ZigProfileState.kt @@ -23,9 +23,11 @@ package com.falsepattern.zigbrains.project.execution.base import com.falsepattern.zigbrains.ZigBrainsBundle +import com.falsepattern.zigbrains.project.execution.ZigConsoleBuilder 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.cli.startIPCAwareProcess import com.falsepattern.zigbrains.shared.coroutine.runModalOrBlocking import com.falsepattern.zigbrains.shared.ipc.IPCUtil import com.falsepattern.zigbrains.shared.ipc.ipc @@ -35,11 +37,15 @@ import com.intellij.execution.ExecutionException import com.intellij.execution.configurations.CommandLineState import com.intellij.execution.configurations.GeneralCommandLine import com.intellij.execution.configurations.PtyCommandLine +import com.intellij.execution.filters.TextConsoleBuilder import com.intellij.execution.process.ProcessHandler import com.intellij.execution.process.ProcessTerminatedListener import com.intellij.execution.runners.ExecutionEnvironment import com.intellij.openapi.project.Project import com.intellij.platform.ide.progress.ModalTaskOwner +import com.intellij.terminal.TerminalExecutionConsole +import com.intellij.util.system.OS +import kotlin.collections.contains import kotlin.io.path.pathString abstract class ZigProfileState> ( @@ -47,6 +53,10 @@ abstract class ZigProfileState> ( val configuration: T ): CommandLineState(environment) { + init { + consoleBuilder = ZigConsoleBuilder(environment.project, true) + } + @Throws(ExecutionException::class) override fun startProcess(): ProcessHandler { return runModalOrBlocking({ModalTaskOwner.project(environment.project)}, {"ZigProfileState.startProcess"}) { @@ -57,7 +67,7 @@ abstract class ZigProfileState> ( @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 startProcess(getCommandLine(toolchain, false), environment.project) + return getCommandLine(toolchain, false).startIPCAwareProcess(environment.project, emulateTerminal = true) } @Throws(ExecutionException::class) @@ -65,32 +75,11 @@ abstract class ZigProfileState> ( 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().withConsoleMode(true).withParentEnvironmentType(GeneralCommandLine.ParentEnvironmentType.CONSOLE) else GeneralCommandLine() + val cli = PtyCommandLine().withConsoleMode(false) cli.withExePath(zigExePath.pathString) workingDir.path?.let { cli.withWorkDirectory(it.toFile()) } cli.withCharset(Charsets.UTF_8) cli.addParameters(configuration.buildCommandLineArgs(debug)) return configuration.patchCommandLine(cli) } -} - -@Throws(ExecutionException::class) -suspend fun executeCommandLine(commandLine: GeneralCommandLine, environment: ExecutionEnvironment): DefaultExecutionResult { - val handler = startProcess(commandLine, environment.project) - val console = BuildTextConsoleView(environment.project, false, emptyList()) - console.attachToProcess(handler) - return DefaultExecutionResult(console, handler) -} - -@Throws(ExecutionException::class) -suspend fun startProcess(commandLine: GeneralCommandLine, project: Project): ProcessHandler { - val ipc = IPCUtil.wrapWithIPC(commandLine) - val handler = ZigProcessHandler(ipc?.cli ?: commandLine) - ProcessTerminatedListener.attach(handler) - if (ipc != null) { - project.ipc?.launchWatcher(ipc, handler.process) - } - return handler -} +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/build/ZigExecConfigBuild.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/build/ZigExecConfigBuild.kt index cf30dfce..75104231 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/build/ZigExecConfigBuild.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/build/ZigExecConfigBuild.kt @@ -25,7 +25,6 @@ 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 @@ -37,8 +36,6 @@ class ZigExecConfigBuild(project: Project, factory: ConfigurationFactory): ZigEx private set var extraArgs = ArgsConfigurable("compilerArgs", ZigBrainsBundle.message("exec.option.label.build.args")) private set - var colored = ColoredConfigurable("colored") - private set var debugBuildSteps = ArgsConfigurable("debugBuildSteps", ZigBrainsBundle.message("exec.option.label.build.steps-debug")) private set var debugExtraArgs = ArgsConfigurable("debugCompilerArgs", ZigBrainsBundle.message("exec.option.label.build.args-debug")) @@ -54,7 +51,6 @@ class ZigExecConfigBuild(project: Project, factory: ConfigurationFactory): ZigEx result.add("build") val steps = if (debug) debugBuildSteps.argsSplit() else buildSteps.argsSplit() result.addAll(steps) - result.addAll(coloredCliFlags(colored.value, debug)) result.addAll(if (debug) debugExtraArgs.argsSplit() else extraArgs.argsSplit()) return result } @@ -66,14 +62,13 @@ class ZigExecConfigBuild(project: Project, factory: ConfigurationFactory): ZigEx 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> { - val baseCfg = super.getConfigurables() + listOf(buildSteps, extraArgs, colored) + val baseCfg = super.getConfigurables() + listOf(buildSteps, extraArgs) return if (ZBFeatures.debug()) { baseCfg + listOf(debugBuildSteps, debugExtraArgs, exePath, exeArgs) } else { diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/run/ZigExecConfigRun.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/run/ZigExecConfigRun.kt index b399105d..0a863dad 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/run/ZigExecConfigRun.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/run/ZigExecConfigRun.kt @@ -24,7 +24,6 @@ package com.falsepattern.zigbrains.project.execution.run import com.falsepattern.zigbrains.ZigBrainsBundle import com.falsepattern.zigbrains.project.execution.base.* -import com.falsepattern.zigbrains.shared.cli.coloredCliFlags import com.intellij.execution.ExecutionException import com.intellij.execution.Executor import com.intellij.execution.configurations.ConfigurationFactory @@ -35,8 +34,6 @@ import kotlin.io.path.pathString class ZigExecConfigRun(project: Project, factory: ConfigurationFactory): ZigExecConfig(project, factory, ZigBrainsBundle.message("exec.type.run.label")) { var filePath = FilePathConfigurable("filePath", ZigBrainsBundle.message("exec.option.label.file-path")) private set - var colored = ColoredConfigurable("colored") - private set var optimization = OptimizationConfigurable("optimization") private set var compilerArgs = ArgsConfigurable("compilerArgs", ZigBrainsBundle.message("exec.option.label.compiler-args")) @@ -47,7 +44,6 @@ class ZigExecConfigRun(project: Project, factory: ConfigurationFactory): ZigExec override suspend fun buildCommandLineArgs(debug: Boolean): List { val result = ArrayList() result.add(if (debug) "build-exe" else "run") - result.addAll(coloredCliFlags(colored.value, debug)) result.add(filePath.path?.pathString ?: throw ExecutionException(ZigBrainsBundle.message("exception.zig.empty-file-path"))) if (!debug || optimization.forced) { result.addAll(listOf("-O", optimization.level.name)) @@ -66,7 +62,6 @@ class ZigExecConfigRun(project: Project, factory: ConfigurationFactory): ZigExec 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() @@ -74,7 +69,7 @@ class ZigExecConfigRun(project: Project, factory: ConfigurationFactory): ZigExec } override fun getConfigurables(): List> { - return super.getConfigurables() + listOf(filePath, optimization, colored, compilerArgs, exeArgs) + return super.getConfigurables() + listOf(filePath, optimization, compilerArgs, exeArgs) } override fun getState(executor: Executor, environment: ExecutionEnvironment): ZigProfileState { diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/test/ZigExecConfigTest.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/test/ZigExecConfigTest.kt index 4f37fee3..1ffd6370 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/test/ZigExecConfigTest.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/execution/test/ZigExecConfigTest.kt @@ -24,7 +24,6 @@ package com.falsepattern.zigbrains.project.execution.test import com.falsepattern.zigbrains.ZigBrainsBundle import com.falsepattern.zigbrains.project.execution.base.* -import com.falsepattern.zigbrains.shared.cli.coloredCliFlags import com.intellij.execution.ExecutionException import com.intellij.execution.Executor import com.intellij.execution.configurations.ConfigurationFactory @@ -35,8 +34,6 @@ import kotlin.io.path.pathString class ZigExecConfigTest(project: Project, factory: ConfigurationFactory): ZigExecConfig(project, factory, ZigBrainsBundle.message("exec.type.test.label")) { var filePath = FilePathConfigurable("filePath", ZigBrainsBundle.message("exec.option.label.file-path")) private set - var colored = ColoredConfigurable("colored") - private set var optimization = OptimizationConfigurable("optimization") private set var compilerArgs = ArgsConfigurable("compilerArgs", ZigBrainsBundle.message("exec.option.label.compiler-args")) @@ -46,7 +43,6 @@ class ZigExecConfigTest(project: Project, factory: ConfigurationFactory): ZigExe override suspend fun buildCommandLineArgs(debug: Boolean): List { val result = ArrayList() result.add("test") - result.addAll(coloredCliFlags(colored.value, debug)) result.add(filePath.path?.pathString ?: throw ExecutionException(ZigBrainsBundle.message("exception.zig.empty-file-path"))) if (!debug || optimization.forced) { result.addAll(listOf("-O", optimization.level.name)) @@ -64,14 +60,13 @@ class ZigExecConfigTest(project: Project, factory: ConfigurationFactory): ZigExe 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> { - return super.getConfigurables() + listOf(filePath, optimization, colored, compilerArgs) + return super.getConfigurables() + listOf(filePath, optimization, compilerArgs) } override fun getState(executor: Executor, environment: ExecutionEnvironment): ZigProfileState { diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/module/ZigModuleBuilder.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/module/ZigModuleBuilder.kt index f6d0d66e..0cce0af7 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/module/ZigModuleBuilder.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/module/ZigModuleBuilder.kt @@ -29,6 +29,7 @@ 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.ModalityState import com.intellij.openapi.module.ModuleType import com.intellij.openapi.roots.ModifiableRootModel import com.intellij.openapi.util.Disposer @@ -58,7 +59,7 @@ class ZigModuleBuilder: ModuleBuilder() { val root = contentEntry.file ?: return val config = configurationData ?: return config.generateProject(this, rootModel.project, root, forceGitignore) - withEDTContext { + withEDTContext(ModalityState.defaultModalityState()) { root.refresh(false, true) } } diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/newproject/ZigProjectConfigurationData.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/newproject/ZigProjectConfigurationData.kt index 5fa4133a..ab425caf 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/newproject/ZigProjectConfigurationData.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/newproject/ZigProjectConfigurationData.kt @@ -119,10 +119,10 @@ data class ZigProjectConfigurationData( if (git) { project.zigCoroutineScope.launch { GitRepositoryInitializer.getInstance()?.initRepository(project, baseDir) - createGitIgnoreFile(project, baseDir, requestor) + createGitIgnoreFile(baseDir, requestor) } } else if (forceGitignore) { - createGitIgnoreFile(project, baseDir, requestor) + createGitIgnoreFile(baseDir, requestor) } return@reportProgress true @@ -131,7 +131,7 @@ data class ZigProjectConfigurationData( } -private suspend fun createGitIgnoreFile(project: Project, projectDir: VirtualFile, requestor: Any) { +private suspend fun createGitIgnoreFile(projectDir: VirtualFile, requestor: Any) { if (projectDir.findChild(".gitignore") != null) { return } diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/run/ZigProcessHandler.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/run/ZigProcessHandler.kt index 125e595e..8753be03 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/run/ZigProcessHandler.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/run/ZigProcessHandler.kt @@ -26,11 +26,12 @@ import com.intellij.execution.configurations.GeneralCommandLine import com.intellij.execution.configurations.PtyCommandLine import com.intellij.execution.process.AnsiEscapeDecoder.ColoredTextAcceptor import com.intellij.execution.process.KillableColoredProcessHandler +import com.intellij.execution.process.KillableProcessHandler import com.intellij.openapi.util.Key import com.pty4j.PtyProcess import java.nio.charset.Charset -class ZigProcessHandler : KillableColoredProcessHandler, ColoredTextAcceptor { +class ZigProcessHandler : KillableProcessHandler { constructor(commandLine: GeneralCommandLine) : super(commandLine) { setHasPty(commandLine is PtyCommandLine) setShouldDestroyProcessRecursively(!hasPty()) @@ -40,57 +41,4 @@ class ZigProcessHandler : KillableColoredProcessHandler, ColoredTextAcceptor { setHasPty(process is PtyProcess) setShouldDestroyProcessRecursively(!hasPty()) } - - override fun coloredTextAvailable(text: String, attributes: Key<*>) { - super.coloredTextAvailable(text.translateVT100Escapes(), attributes) - } -} - -private val VT100_CHARS = CharArray(256).apply { - this.fill(' ') - this[0x6A] = '┘' - this[0x6B] = '┐' - this[0x6C] = '┌' - this[0x6D] = '└' - this[0x6E] = '┼' - this[0x71] = '─' - this[0x74] = '├' - this[0x75] = '┤' - this[0x76] = '┴' - this[0x77] = '┬' - this[0x78] = '│' -} - -private const val VT100_BEGIN_SEQ = "\u001B(0" -private const val VT100_END_SEQ = "\u001B(B" -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 fun String.translateVT100Escapes(): String { - var offset = 0 - val result = StringBuilder() - val textLength = length - while (offset < textLength) { - val startIndex = indexOf(VT100_BEGIN_SEQ, offset) - if (startIndex < 0) { - result.append(substring(offset, textLength).replace(VT100_END_SEQ, "")) - 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() -} +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/run/ZigRegularRunner.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/run/ZigRegularRunner.kt index 7dce5c9c..771e94d2 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/run/ZigRegularRunner.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/run/ZigRegularRunner.kt @@ -24,7 +24,6 @@ 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.coroutine.withEDTContext import com.intellij.execution.configurations.RunProfile @@ -36,8 +35,7 @@ import com.intellij.openapi.application.ModalityState class ZigRegularRunner: ZigProgramRunner>(DefaultRunExecutor.EXECUTOR_ID) { override suspend fun execute(state: ZigProfileState<*>, toolchain: AbstractZigToolchain, environment: ExecutionEnvironment): RunContentDescriptor? { - val cli = state.getCommandLine(toolchain, false) - val exec = executeCommandLine(cli, environment) + val exec = state.execute(environment.executor, this) return withEDTContext(ModalityState.any()) { val runContentBuilder = RunContentBuilder(exec, environment) runContentBuilder.showRunContent(null) diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectSettingsPanel.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectSettingsPanel.kt index 7a8fa6cc..b0f60ca6 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectSettingsPanel.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/settings/ZigProjectSettingsPanel.kt @@ -97,7 +97,7 @@ class ZigProjectSettingsPanel(private val holder: ZigProjectConfigurationProvide } private fun dispatchAutodetect(force: Boolean) { - project.zigCoroutineScope.launchWithEDT { + project.zigCoroutineScope.launchWithEDT(ModalityState.any()) { withModalProgress(ModalTaskOwner.component(pathToToolchain), "Detecting Zig...", TaskCancellation.cancellable()) { autodetect(force) } diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/steps/discovery/ZigStepDiscoveryService.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/steps/discovery/ZigStepDiscoveryService.kt index 86900d6f..320118ec 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/steps/discovery/ZigStepDiscoveryService.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/steps/discovery/ZigStepDiscoveryService.kt @@ -27,6 +27,7 @@ import com.falsepattern.zigbrains.project.steps.discovery.ZigStepDiscoveryListen import com.falsepattern.zigbrains.shared.coroutine.withEDTContext import com.falsepattern.zigbrains.shared.zigCoroutineScope import com.intellij.openapi.Disposable +import com.intellij.openapi.application.ModalityState import com.intellij.openapi.components.Service import com.intellij.openapi.components.service import com.intellij.openapi.diagnostic.Logger @@ -90,7 +91,7 @@ class ZigStepDiscoveryService(private val project: Project) { null } if (result == null) { - {} + } else if (result.checkSuccess(LOG)) { currentTimeoutSec = DEFAULT_TIMEOUT_SEC val lines = result.stdoutLines @@ -124,7 +125,7 @@ class ZigStepDiscoveryService(private val project: Project) { } private suspend fun dispatchReload() { - withEDTContext { + withEDTContext(ModalityState.defaultModalityState()) { FileDocumentManager.getInstance().saveAllDocuments() } doReload() diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/project/steps/ui/BuildToolWindowContext.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/project/steps/ui/BuildToolWindowContext.kt index 6c282fc6..e0813dbd 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/project/steps/ui/BuildToolWindowContext.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/project/steps/ui/BuildToolWindowContext.kt @@ -81,18 +81,18 @@ class BuildToolWindowContext(private val project: Project): Disposable { val tree = Tree(model).also { it.isRootVisible = false } } private val viewPanel = JPanel(VerticalLayout(0)) - private val steps = TreeBox() - private val build = if (IPCUtil.haveIPC) TreeBox() else null + private val stepsBox = TreeBox() + private val buildBox = if (IPCUtil.haveIPC) TreeBox() else null private var live = AtomicBoolean(true) init { viewPanel.add(JBLabel(ZigBrainsBundle.message("build.tool.window.tree.steps.label"))) - viewPanel.add(steps.panel) - steps.panel.setNotScanned() + viewPanel.add(stepsBox.panel) + stepsBox.panel.setNotScanned() - steps.tree.addMouseListener(object : MouseAdapter() { + stepsBox.tree.addMouseListener(object : MouseAdapter() { override fun mouseClicked(e: MouseEvent) { if (e.clickCount == 2) { - val node = steps.tree.lastSelectedPathComponent as? DefaultMutableTreeNode ?: return + val node = stepsBox.tree.lastSelectedPathComponent as? DefaultMutableTreeNode ?: return val step = node.userObject as? StepNodeDescriptor ?: return val stepName = step.element?.name ?: return @@ -112,10 +112,10 @@ class BuildToolWindowContext(private val project: Project): Disposable { } }) - if (build != null) { + if (buildBox != null) { viewPanel.add(JBLabel(ZigBrainsBundle.message("build.tool.window.tree.build.label"))) - viewPanel.add(build.panel) - build.panel.setNoBuilds() + viewPanel.add(buildBox.panel) + buildBox.panel.setNoBuilds() project.zigCoroutineScope.launch { while (!project.isDisposed && live.get()) { @@ -126,14 +126,14 @@ class BuildToolWindowContext(private val project: Project): Disposable { ipc.mutex.withLock { withEDTContext(ModalityState.any()) { if (ipc.nodes.isEmpty()) { - build.root.removeAllChildren() - build.panel.setNoBuilds() + buildBox.root.removeAllChildren() + buildBox.panel.setNoBuilds() return@withEDTContext } val allNodes = ArrayList(ipc.nodes) val existingNodes = ArrayList() val removedNodes = ArrayList() - build.root.children().iterator().forEach { child -> + buildBox.root.children().iterator().forEach { child -> if (child !is ZigIPCService.IPCTreeNode) { return@forEach } @@ -145,18 +145,18 @@ class BuildToolWindowContext(private val project: Project): Disposable { } val newNodes = ArrayList(allNodes) newNodes.removeAll(existingNodes) - removedNodes.forEach { build.root.remove(it) } - newNodes.forEach { build.root.add(it) } + removedNodes.forEach { buildBox.root.remove(it) } + newNodes.forEach { buildBox.root.add(it) } if (removedNodes.isNotEmpty() || newNodes.isNotEmpty()) { - build.model.reload(build.root) + buildBox.model.reload(buildBox.root) } - if (build.root.childCount == 0) { - build.panel.setNoBuilds() + if (buildBox.root.childCount == 0) { + buildBox.panel.setNoBuilds() } else { - build.panel.setViewportBody(build.tree) + buildBox.panel.setViewportBody(buildBox.tree) } for (bn in allNodes) { - expandRecursively(build, bn) + expandRecursively(buildBox, bn) } } } @@ -220,28 +220,28 @@ class BuildToolWindowContext(private val project: Project): Disposable { inner class BuildReloadListener: ZigStepDiscoveryListener { override suspend fun preReload() { - steps.panel.setRunningZigBuild() + stepsBox.panel.setRunningZigBuild() } - override suspend fun postReload(stepInfo: List>) { - steps.root.removeAllChildren() - for ((task, description) in stepInfo) { + override suspend fun postReload(steps: List>) { + stepsBox.root.removeAllChildren() + for ((task, description) in steps) { val icon = when(task) { "install" -> AllIcons.Actions.Install "uninstall" -> AllIcons.Actions.Uninstall else -> AllIcons.RunConfigurations.TestState.Run } - steps.root.add(DefaultMutableTreeNode(StepNodeDescriptor(project, task, icon, description))) + stepsBox.root.add(DefaultMutableTreeNode(StepNodeDescriptor(project, task, icon, description))) } withEDTContext(ModalityState.any()) { - steps.model.reload(steps.root) - steps.panel.setViewportBody(steps.tree) + stepsBox.model.reload(stepsBox.root) + stepsBox.panel.setViewportBody(stepsBox.tree) } } override suspend fun errorReload(type: ZigStepDiscoveryListener.ErrorType, details: String?) { withEDTContext(ModalityState.any()) { - steps.panel.setViewportError(ZigBrainsBundle.message(when(type) { + stepsBox.panel.setViewportError(ZigBrainsBundle.message(when(type) { ZigStepDiscoveryListener.ErrorType.MissingToolchain -> "build.tool.window.status.error.missing-toolchain" ZigStepDiscoveryListener.ErrorType.MissingZigExe -> "build.tool.window.status.error.missing-zig-exe" ZigStepDiscoveryListener.ErrorType.MissingBuildZig -> "build.tool.window.status.error.missing-build-zig" @@ -252,7 +252,7 @@ class BuildToolWindowContext(private val project: Project): Disposable { override suspend fun timeoutReload(seconds: Int) { withEDTContext(ModalityState.any()) { - steps.panel.setViewportError(ZigBrainsBundle.message("build.tool.window.status.timeout", seconds), null) + stepsBox.panel.setViewportError(ZigBrainsBundle.message("build.tool.window.status.timeout", seconds), null) } } } diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/shared/cli/CLIUtil.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/shared/cli/CLIUtil.kt index f0445f77..c7bcaf23 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/shared/cli/CLIUtil.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/shared/cli/CLIUtil.kt @@ -23,13 +23,18 @@ package com.falsepattern.zigbrains.shared.cli import com.falsepattern.zigbrains.ZigBrainsBundle +import com.falsepattern.zigbrains.project.run.ZigProcessHandler import com.falsepattern.zigbrains.shared.ipc.IPCUtil import com.falsepattern.zigbrains.shared.ipc.ipc +import com.intellij.execution.ExecutionException import com.intellij.execution.configurations.GeneralCommandLine +import com.intellij.execution.process.ProcessHandler import com.intellij.execution.process.ProcessOutput +import com.intellij.execution.process.ProcessTerminatedListener import com.intellij.openapi.options.ConfigurationException import com.intellij.openapi.project.Project import com.intellij.util.io.awaitExit +import com.intellij.util.system.OS import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runInterruptible import kotlinx.coroutines.withContext @@ -108,14 +113,6 @@ fun translateCommandline(toProcess: String): List { return result } -fun coloredCliFlags(colored: Boolean, debug: Boolean): List { - return if (debug) { - emptyList() - } else { - listOf("--color", if (colored) "on" else "off") - } -} - fun createCommandLineSafe( workingDirectory: Path?, exe: Path, @@ -133,14 +130,27 @@ fun createCommandLineSafe( return Result.success(cli) } -suspend fun GeneralCommandLine.call(timeoutMillis: Long = Long.MAX_VALUE, ipcProject: Project? = null): Result { - val ipc = if (ipcProject != null) IPCUtil.wrapWithIPC(this) else null +@Throws(ExecutionException::class) +suspend fun GeneralCommandLine.startIPCAwareProcess(project: Project?, emulateTerminal: Boolean = false): ZigProcessHandler { + val ipc = if (project != null && !emulateTerminal) IPCUtil.wrapWithIPC(this) else null val cli = ipc?.cli ?: this + if (emulateTerminal && OS.CURRENT != OS.Windows && !cli.environment.contains("TERM")) { + cli.withEnvironment("TERM", "xterm-256color") + } + val handler = ZigProcessHandler(cli) + ProcessTerminatedListener.attach(handler) + + if (ipc != null) { + project!!.ipc?.launchWatcher(ipc, handler.process) + } + return handler +} + + +suspend fun GeneralCommandLine.call(timeoutMillis: Long = Long.MAX_VALUE, ipcProject: Project? = null): Result { val (process, exitCode) = withContext(Dispatchers.IO) { - val process = cli.createProcess() - if (ipc != null) { - ipcProject!!.ipc?.launchWatcher(ipc, process) - } + val handler = startIPCAwareProcess(ipcProject) + val process = handler.process val exit = withTimeoutOrNull(timeoutMillis) { process.awaitExit() } diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/shared/coroutine/CoroutinesUtil.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/shared/coroutine/CoroutinesUtil.kt index 878525aa..b41f0f25 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/shared/coroutine/CoroutinesUtil.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/shared/coroutine/CoroutinesUtil.kt @@ -39,7 +39,7 @@ inline fun runModalOrBlocking(taskOwnerFactory: () -> ModalTaskOwner, titleF } } -suspend inline fun withEDTContext(state: ModalityState = ModalityState.defaultModalityState(), noinline block: suspend CoroutineScope.() -> T): T { +suspend inline fun withEDTContext(state: ModalityState, noinline block: suspend CoroutineScope.() -> T): T { return withContext(Dispatchers.EDT + state.asContextElement(), block = block) } @@ -49,10 +49,10 @@ suspend inline fun withCurrentEDTModalityContext(noinline block: suspend Cor } } -suspend inline fun runInterruptibleEDT(state: ModalityState = ModalityState.defaultModalityState(), noinline targetAction: () -> T): T { +suspend inline fun runInterruptibleEDT(state: ModalityState, noinline targetAction: () -> T): T { return runInterruptible(Dispatchers.EDT + state.asContextElement(), block = targetAction) } -fun CoroutineScope.launchWithEDT(state: ModalityState = ModalityState.defaultModalityState(), block: suspend CoroutineScope.() -> Unit): Job { +fun CoroutineScope.launchWithEDT(state: ModalityState, block: suspend CoroutineScope.() -> Unit): Job { return launch(Dispatchers.EDT + state.asContextElement(), block = block) } \ No newline at end of file diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/shared/ipc/IPCUtil.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/shared/ipc/IPCUtil.kt index 5f11d6ee..f826bf3e 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/shared/ipc/IPCUtil.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/shared/ipc/IPCUtil.kt @@ -74,7 +74,7 @@ object IPCUtil { val cli = GeneralCommandLine(it) val tmpFile = FileUtil.createTempFile("zigbrains-bash-detection", null, true).toPath() try { - cli.addParameters("-c", "exec {var}>${tmpFile.pathString}; echo foo >&\$var; exec {var}>&-") + cli.addParameters("-c", "exec {var}>${tmpFile.pathString}; echo foo >&\$var; ZB_EXIT=\$?; exec {var}>&-; exit \$ZB_EXIT") val process = cli.createProcess() val exitCode = process.awaitExit() if (exitCode != 0) { @@ -100,7 +100,7 @@ object IPCUtil { val (fifoFile, fifo) = info!!.mkfifo.createTemp() ?: return null //FIFO created, hack cli val exePath = cli.exePath - val args = "exec {var}>${fifoFile.pathString}; ZIG_PROGRESS=\$var $exePath ${cli.parametersList.parametersString}; exec {var}>&-" + val args = "exec {var}>${fifoFile.pathString}; ZIG_PROGRESS=\$var $exePath ${cli.parametersList.parametersString}; ZB_EXIT=\$?; exec {var}>&-; exit \$ZB_EXIT" cli.withExePath(info!!.bash) cli.parametersList.clearAll() cli.addParameters("-c", args) diff --git a/core/src/main/kotlin/com/falsepattern/zigbrains/zon/formatter/ZonBlock.kt b/core/src/main/kotlin/com/falsepattern/zigbrains/zon/formatter/ZonBlock.kt index fa17c49f..9569b7e3 100644 --- a/core/src/main/kotlin/com/falsepattern/zigbrains/zon/formatter/ZonBlock.kt +++ b/core/src/main/kotlin/com/falsepattern/zigbrains/zon/formatter/ZonBlock.kt @@ -55,18 +55,16 @@ class ZonBlock( override fun getChildIndent(): Indent { val node = this.node - return getIndentBasedOnParentType(node, null, node.elementType, PLACEHOLDER) + return getIndentBasedOnParentType(node.elementType, PLACEHOLDER) } override fun getIndent(): Indent { val node = this.node val parent = node.treeParent ?: return noneIndent - return getIndentBasedOnParentType(parent, node, parent.elementType, node.elementType) + return getIndentBasedOnParentType(parent.elementType, node.elementType) } } private fun getIndentBasedOnParentType( - parent: ASTNode, - child: ASTNode?, parentType: IElementType, childType: IElementType ): Indent { diff --git a/core/src/main/resources/zigbrains/Bundle.properties b/core/src/main/resources/zigbrains/Bundle.properties index 62f99988..48b56bf6 100644 --- a/core/src/main/resources/zigbrains/Bundle.properties +++ b/core/src/main/resources/zigbrains/Bundle.properties @@ -65,11 +65,9 @@ exec.type.run.label=Zig Run exec.type.test.label=Zig Test exec.type.build.label=Zig Build exec.option.label.working-directory=&Working directory: -exec.option.label.colored-terminal=Colored terminal exec.option.label.direnv=Use direnv 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 diff --git a/gradle.properties b/gradle.properties index c0005305..521ba663 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ pluginName=ZigBrains pluginRepositoryUrl=https://github.com/FalsePattern/ZigBrains -pluginVersion=23.1.2 +pluginVersion=24.0.0 pluginSinceBuild=241 pluginUntilBuild=241.* diff --git a/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsPanel.kt b/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsPanel.kt index 3aee3f5e..d44ba09f 100644 --- a/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsPanel.kt +++ b/lsp/src/main/kotlin/com/falsepattern/zigbrains/lsp/settings/ZLSSettingsPanel.kt @@ -279,7 +279,7 @@ class ZLSSettingsPanel(private val project: Project) : ZigProjectConfigurationPr } private fun dispatchAutodetect(force: Boolean) { - project.zigCoroutineScope.launchWithEDT { + project.zigCoroutineScope.launchWithEDT(ModalityState.any()) { withModalProgress(ModalTaskOwner.component(zlsPath), "Detecting ZLS...", TaskCancellation.cancellable()) { autodetect(force) } diff --git a/lsp/src/main/resources/zigbrains/lsp/Bundle.properties b/lsp/src/main/resources/zigbrains/lsp/Bundle.properties index 9582f4e9..3b76263f 100644 --- a/lsp/src/main/resources/zigbrains/lsp/Bundle.properties +++ b/lsp/src/main/resources/zigbrains/lsp/Bundle.properties @@ -6,7 +6,6 @@ settings.zls-version.label=Detected ZLS version settings.zls-config-path.label=Config path settings.zls-config-path.tooltip=Leave empty to use built-in config generated from the settings below settings.zls-config-path.browse.title=Path to the Custom ZLS Config File (Optional) -settings.zls-path.use-direnv.label=Use direnv settings.inlay-hints-group.label=Inlay Hints settings.inlay-hints-enable.label=Enable settings.inlay-hints-enable.tooltip=Toggle this to enable/disable all inlay hints @@ -50,7 +49,6 @@ settings.build_runner_path.label=Build runner path settings.build_runner_path.tooltip=Specify a custom build runner to resolve build system information. settings.global_cache_path.label=Global cache path settings.global_cache_path.tooltip=Path to a directory that will be used as zig's cache. Will default to `${KnownFolders.Cache}/zls`. -configurable.name.zls.settings=ZLS Settings notification.group.zigbrains-lsp=ZigBrains LSP Integration notification.message.could-not-detect.content=Could not detect ZLS binary, please configure it notification.message.zls-exe-path-invalid.content=ZLS executable path could not be parsed: {0}