feat: Actual, proper compiler run that doesn't freeze the IDE or spam errors

This commit is contained in:
FalsePattern 2024-05-13 21:00:00 +02:00
parent 6f78cab411
commit 21ed7d66e1
Signed by: falsepattern
GPG key ID: E930CDEC50C50E23
11 changed files with 263 additions and 88 deletions

View file

@ -17,6 +17,11 @@ Changelog structure reference:
## [Unreleased] ## [Unreleased]
### Fixed
- Debugging
- The debugger no longer freezes the IDE while zig is compiling
## [14.2.0] ## [14.2.0]
### Added ### Added

View file

@ -18,6 +18,9 @@ package com.falsepattern.zigbrains.debugger;
import com.falsepattern.zigbrains.debugbridge.DebuggerDriverProvider; import com.falsepattern.zigbrains.debugbridge.DebuggerDriverProvider;
import com.falsepattern.zigbrains.debugger.win.WinDebuggerDriverConfiguration; import com.falsepattern.zigbrains.debugger.win.WinDebuggerDriverConfiguration;
import com.falsepattern.zigbrains.project.util.CLIUtil;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.notification.Notification; import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType; import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications; import com.intellij.notification.Notifications;
@ -25,6 +28,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.util.system.OS; import com.intellij.util.system.OS;
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration; import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
import com.jetbrains.cidr.execution.debugger.backend.lldb.LLDBDriverConfiguration; import com.jetbrains.cidr.execution.debugger.backend.lldb.LLDBDriverConfiguration;
import lombok.RequiredArgsConstructor;
import lombok.val; import lombok.val;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -51,4 +55,23 @@ public class Utils {
return null; return null;
} }
} }
public static void executeCommandLineWithErrorChecks(GeneralCommandLine cli) throws ExecutionException, ProcessException {
val outputOpt = CLIUtil.execute(cli, Integer.MAX_VALUE);
if (outputOpt.isEmpty()) {
throw new ExecutionException("Failed to execute \"" + cli.getCommandLineString() + "\"!");
}
val output = outputOpt.get();
if (output.getExitCode() != 0) {
throw new ProcessException(cli.getCommandLineString(), output.getStdout(), output.getStderr(), output.getExitCode());
}
}
@RequiredArgsConstructor
public static class ProcessException extends Exception {
public final String command;
public final String stdout;
public final String stderr;
public final int exitCode;
}
} }

View file

@ -19,14 +19,121 @@ package com.falsepattern.zigbrains.debugger;
import com.intellij.execution.ExecutionException; import com.intellij.execution.ExecutionException;
import com.intellij.execution.filters.Filter; import com.intellij.execution.filters.Filter;
import com.intellij.execution.filters.TextConsoleBuilder; import com.intellij.execution.filters.TextConsoleBuilder;
import com.intellij.openapi.util.Expirable;
import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebugSession;
import com.jetbrains.cidr.execution.RunParameters; import com.jetbrains.cidr.execution.RunParameters;
import com.jetbrains.cidr.execution.debugger.CidrDebugProcess;
import com.jetbrains.cidr.execution.debugger.CidrLocalDebugProcess; import com.jetbrains.cidr.execution.debugger.CidrLocalDebugProcess;
import lombok.val;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Supplier;
public class ZigLocalDebugProcess extends CidrLocalDebugProcess { public class ZigLocalDebugProcess extends CidrLocalDebugProcess {
private final ReentrantLock lock = new ReentrantLock();
public enum SuppressionLevel {
PreStart,
PostStart,
Unsuppressed
}
private volatile SuppressionLevel suppressionLevel = SuppressionLevel.PreStart;
private final List<Runnable> preStart = new ArrayList<>();
private final List<Runnable> postStart = new ArrayList<>();
public ZigLocalDebugProcess(@NotNull RunParameters parameters, @NotNull XDebugSession session, @NotNull TextConsoleBuilder consoleBuilder) public ZigLocalDebugProcess(@NotNull RunParameters parameters, @NotNull XDebugSession session, @NotNull TextConsoleBuilder consoleBuilder)
throws ExecutionException { throws ExecutionException {
super(parameters, session, consoleBuilder, (project) -> Filter.EMPTY_ARRAY, false); super(parameters, session, consoleBuilder, (project) -> Filter.EMPTY_ARRAY, false);
} }
public void doStart() {
start();
lock.lock();
try {
suppressionLevel = SuppressionLevel.PostStart;
} finally {
lock.unlock();
}
}
public void unSuppress(boolean runPreStart) {
lock.lock();
try {
suppressionLevel = SuppressionLevel.Unsuppressed;
if (runPreStart) {
for (val r: preStart)
r.run();
}
for (val r: postStart)
r.run();
preStart.clear();
postStart.clear();
} finally {
lock.unlock();
}
}
private <T> CompletableFuture<T> suppressedFuture(Supplier<CompletableFuture<T>> original) {
if (suppressionLevel == SuppressionLevel.Unsuppressed)
return original.get();
lock.lock();
try {
if (suppressionLevel == SuppressionLevel.Unsuppressed)
return original.get();
val bypass = new CompletableFuture<T>();
val task = (Runnable)() ->
original.get()
.thenAccept(bypass::complete)
.exceptionally((ex) -> {
bypass.completeExceptionally(ex);
return null;
});
switch (suppressionLevel) {
case PreStart -> preStart.add(task);
case PostStart -> postStart.add(task);
}
return bypass;
} finally {
lock.unlock();
}
}
@Override
public @NotNull CompletableFuture<Void> postCommand(@NotNull CidrDebugProcess.VoidDebuggerCommand command) {
return suppressedFuture(() -> super.postCommand(command));
}
@Override
public @NotNull CompletableFuture<Void> postCommand(
@Nullable Expirable expirable, @NotNull CidrDebugProcess.VoidDebuggerCommand command) {
return suppressedFuture(() -> super.postCommand(expirable, command));
}
@Override
public @NotNull CompletableFuture<Void> postCommand(
@NotNull CidrDebugProcess.VoidDebuggerCommand command, boolean useAlternativeDispatcher) {
return suppressedFuture(() -> super.postCommand(command, useAlternativeDispatcher));
}
@Override
public @NotNull <T> CompletableFuture<T> postCommand(@NotNull CidrDebugProcess.DebuggerCommand<T> command) {
return suppressedFuture(() -> super.postCommand(command));
}
@Override
public @NotNull <T> CompletableFuture<T> postCommand(
@Nullable Expirable expirable, @NotNull CidrDebugProcess.DebuggerCommand<T> command) {
return suppressedFuture(() -> super.postCommand(expirable, command));
}
@Override
public @NotNull <T> CompletableFuture<T> postCommand(
@NotNull CidrDebugProcess.DebuggerCommand<T> command, boolean useAlternativeDispatcher) {
return suppressedFuture(() -> super.postCommand(command, useAlternativeDispatcher));
}
} }

View file

@ -0,0 +1,23 @@
/*
* Copyright 2023-2024 FalsePattern
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.falsepattern.zigbrains.debugger.runner.base;
import java.util.concurrent.CompletableFuture;
public interface PreLaunchAware {
void preLaunch() throws Exception;
}

View file

@ -16,8 +16,10 @@
package com.falsepattern.zigbrains.debugger.runner.base; package com.falsepattern.zigbrains.debugger.runner.base;
import com.falsepattern.zigbrains.common.util.Lazy;
import com.falsepattern.zigbrains.project.execution.base.ProfileStateBase; import com.falsepattern.zigbrains.project.execution.base.ProfileStateBase;
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain; import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.configurations.GeneralCommandLine;
import com.jetbrains.cidr.execution.Installer; import com.jetbrains.cidr.execution.Installer;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;

View file

@ -23,9 +23,12 @@ import com.jetbrains.cidr.ArchitectureType;
import com.jetbrains.cidr.execution.RunParameters; import com.jetbrains.cidr.execution.RunParameters;
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration; import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.val;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.concurrent.CompletableFuture;
@RequiredArgsConstructor @RequiredArgsConstructor
public abstract class ZigDebugParametersBase<ProfileState extends ProfileStateBase<?>> extends RunParameters { public abstract class ZigDebugParametersBase<ProfileState extends ProfileStateBase<?>> extends RunParameters {

View file

@ -16,10 +16,12 @@
package com.falsepattern.zigbrains.debugger.runner.base; package com.falsepattern.zigbrains.debugger.runner.base;
import com.falsepattern.zigbrains.debugger.Utils;
import com.falsepattern.zigbrains.project.execution.base.ProfileStateBase; import com.falsepattern.zigbrains.project.execution.base.ProfileStateBase;
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain; import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
import com.falsepattern.zigbrains.project.util.CLIUtil;
import com.intellij.execution.ExecutionException; import com.intellij.execution.ExecutionException;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.io.FileUtil;
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration; import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
import lombok.val; import lombok.val;
@ -27,11 +29,19 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.concurrent.CompletableFuture;
public abstract class ZigDebugParametersEmitBinaryBase<ProfileState extends ProfileStateBase<?>> extends ZigDebugParametersBase<ProfileState> { public abstract class ZigDebugParametersEmitBinaryBase<ProfileState extends ProfileStateBase<?>> extends ZigDebugParametersBase<ProfileState> implements PreLaunchAware {
protected final File executableFile; protected volatile File executableFile;
public ZigDebugParametersEmitBinaryBase(DebuggerDriverConfiguration driverConfiguration, AbstractZigToolchain toolchain, ProfileState profileState, String kind) throws ExecutionException { private final String kind;
public ZigDebugParametersEmitBinaryBase(DebuggerDriverConfiguration driverConfiguration, AbstractZigToolchain toolchain, ProfileState profileState, String kind) {
super(driverConfiguration, toolchain, profileState); super(driverConfiguration, toolchain, profileState);
this.kind = kind;
}
private File compileExe()
throws ExecutionException, Utils.ProcessException {
final File executableFile;
val commandLine = profileState.getCommandLine(toolchain, true); val commandLine = profileState.getCommandLine(toolchain, true);
final Path tmpDir; final Path tmpDir;
try { try {
@ -41,14 +51,7 @@ public abstract class ZigDebugParametersEmitBinaryBase<ProfileState extends Prof
} }
val exe = tmpDir.resolve("executable").toFile(); val exe = tmpDir.resolve("executable").toFile();
commandLine.addParameters("-femit-bin=" + exe.getAbsolutePath()); commandLine.addParameters("-femit-bin=" + exe.getAbsolutePath());
val outputOpt = CLIUtil.execute(commandLine, Integer.MAX_VALUE); Utils.executeCommandLineWithErrorChecks(commandLine);
if (outputOpt.isEmpty()) {
throw new ExecutionException("Failed to execute \"zig " + commandLine.getParametersList().getParametersString() + "\"!");
}
val output = outputOpt.get();
if (output.getExitCode() != 0) {
throw new ExecutionException("Zig compilation failed with exit code " + output.getExitCode() + "\nError output:\n" + output.getStdout() + "\n" + output.getStderr());
}
//Find our binary //Find our binary
try (val stream = Files.list(tmpDir)){ try (val stream = Files.list(tmpDir)){
executableFile = stream.filter(file -> !file.getFileName().toString().endsWith(".o")) executableFile = stream.filter(file -> !file.getFileName().toString().endsWith(".o"))
@ -60,5 +63,12 @@ public abstract class ZigDebugParametersEmitBinaryBase<ProfileState extends Prof
} catch (Exception e) { } catch (Exception e) {
throw new ExecutionException("Failed to find compiled binary! " + e.getMessage(), e); throw new ExecutionException("Failed to find compiled binary! " + e.getMessage(), e);
} }
return executableFile;
} }
@Override
public void preLaunch() throws Exception {
this.executableFile = compileExe();
}
} }

View file

@ -16,13 +16,13 @@
package com.falsepattern.zigbrains.debugger.runner.base; package com.falsepattern.zigbrains.debugger.runner.base;
import com.falsepattern.zigbrains.common.util.ApplicationUtil;
import com.falsepattern.zigbrains.project.execution.base.ProfileStateBase; import com.falsepattern.zigbrains.project.execution.base.ProfileStateBase;
import com.falsepattern.zigbrains.project.runconfig.ZigProgramRunnerBase; import com.falsepattern.zigbrains.project.runconfig.ZigProgramRunnerBase;
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain; import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
import com.falsepattern.zigbrains.debugger.Utils; import com.falsepattern.zigbrains.debugger.Utils;
import com.falsepattern.zigbrains.debugger.ZigLocalDebugProcess; import com.falsepattern.zigbrains.debugger.ZigLocalDebugProcess;
import com.intellij.execution.ExecutionException; import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.configurations.RunProfile; import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.executors.DefaultDebugExecutor; import com.intellij.execution.executors.DefaultDebugExecutor;
import com.intellij.execution.filters.Filter; import com.intellij.execution.filters.Filter;
@ -40,16 +40,17 @@ import com.intellij.xdebugger.XDebugProcess;
import com.intellij.xdebugger.XDebugProcessStarter; import com.intellij.xdebugger.XDebugProcessStarter;
import com.intellij.xdebugger.XDebugSession; import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XDebuggerManager; import com.intellij.xdebugger.XDebuggerManager;
import com.jetbrains.cidr.execution.Installer; import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriver;
import com.jetbrains.cidr.execution.TrivialRunParameters;
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration; import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.val; import lombok.val;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.File; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public abstract class ZigDebugRunnerBase<ProfileState extends ProfileStateBase<?>> extends ZigProgramRunnerBase<ProfileState> { public abstract class ZigDebugRunnerBase<ProfileState extends ProfileStateBase<?>> extends ZigProgramRunnerBase<ProfileState> {
public ZigDebugRunnerBase() { public ZigDebugRunnerBase() {
@ -72,35 +73,12 @@ public abstract class ZigDebugRunnerBase<ProfileState extends ProfileStateBase<?
Notifications.Bus.notify(new Notification("ZigBrains.Debugger.Error", "Couldn't find a working GDB or LLDB debugger! Please check your Toolchains! (Settings | Build, Execution, Deployment | Toolchains)", NotificationType.ERROR)); Notifications.Bus.notify(new Notification("ZigBrains.Debugger.Error", "Couldn't find a working GDB or LLDB debugger! Please check your Toolchains! (Settings | Build, Execution, Deployment | Toolchains)", NotificationType.ERROR));
return null; return null;
} }
Either<ZigDebugParametersBase<ProfileState>, ExecutionException> runParameters; ZigDebugParametersBase<ProfileState> runParameters = getDebugParameters(state, environment, debuggerDriver, toolchain);
try {
runParameters = ApplicationManager.getApplication().executeOnPooledThread(() -> getDebugParametersSafe(state, environment, debuggerDriver, toolchain)).get();
} catch (InterruptedException | java.util.concurrent.ExecutionException e) {
e.printStackTrace();
Notifications.Bus.notify(new Notification("ZigBrains.Debugger.Error", e.getMessage(), NotificationType.ERROR));
return null;
}
if (runParameters == null) { if (runParameters == null) {
//Assume that getDebugParameters reports the bug in a notification already
return null; return null;
} }
if (runParameters.isRight()) { return startSession(environment, new ZigLocalDebugProcessStarter(runParameters, state, environment));
return startSession(environment, new ErrorProcessStarter(state, runParameters.getRight(), debuggerDriver));
} else if (runParameters.isLeft()) {
return startSession(environment, new ZigLocalDebugProcessStarter(runParameters.getLeft(), state, environment));
} else {
return null;
}
}
private Either<ZigDebugParametersBase<ProfileState>, ExecutionException> getDebugParametersSafe(ProfileState state, ExecutionEnvironment environment, DebuggerDriverConfiguration debuggerDriver, AbstractZigToolchain toolchain) {
try {
return Either.forLeft(getDebugParameters(state, environment, debuggerDriver, toolchain));
} catch (ExecutionException e) {
return Either.forRight(e);
}
} }
@Override @Override
@ -113,30 +91,33 @@ public abstract class ZigDebugRunnerBase<ProfileState extends ProfileStateBase<?
private final ZigDebugParametersBase<ProfileState> params; private final ZigDebugParametersBase<ProfileState> params;
private final ProfileState state; private final ProfileState state;
private final ExecutionEnvironment environment; private final ExecutionEnvironment environment;
private static class Carrier {
volatile ConsoleView console;
final Map<ConsoleViewContentType, List<String>> outputs = new HashMap<>();
@Override void handleOutput(String text, ConsoleViewContentType type) {
public @NotNull XDebugProcess start(@NotNull XDebugSession session) throws ExecutionException { if (console != null) {
val process = new ZigLocalDebugProcess(params, session, state.getConsoleBuilder()); console.print(text, type);
ProcessTerminatedListener.attach(process.getProcessHandler(), environment.getProject()); } else {
process.start(); outputs.computeIfAbsent(type, (ignored) -> new ArrayList<>()).add(text);
return process; }
}
} }
}
@RequiredArgsConstructor
private class ErrorProcessStarter extends XDebugProcessStarter {
private final ProfileState state;
private final ExecutionException exception;
private final DebuggerDriverConfiguration debuggerDriver;
@Override @Override
public @NotNull XDebugProcess start(@NotNull XDebugSession session) throws ExecutionException { public @NotNull XDebugProcess start(@NotNull XDebugSession session) throws ExecutionException {
val cb = state.getConsoleBuilder(); val cb = state.getConsoleBuilder();
val carrier = new Carrier();
val wrappedBuilder = new TextConsoleBuilder() { val wrappedBuilder = new TextConsoleBuilder() {
@Override @Override
public @NotNull ConsoleView getConsole() { public @NotNull ConsoleView getConsole() {
val console = cb.getConsole(); val console = cb.getConsole();
console.print(exception.getMessage(), ConsoleViewContentType.ERROR_OUTPUT); for (val output: carrier.outputs.entrySet()) {
for (val line: output.getValue()) {
console.print(line + "\n", output.getKey());
}
}
carrier.console = console;
return console; return console;
} }
@ -150,18 +131,35 @@ public abstract class ZigDebugRunnerBase<ProfileState extends ProfileStateBase<?
cb.setViewer(isViewer); cb.setViewer(isViewer);
} }
}; };
val process = new ZigLocalDebugProcess(new TrivialRunParameters(debuggerDriver, new Installer() { val process = new ZigLocalDebugProcess(params, session, wrappedBuilder);
@Override ApplicationManager.getApplication().executeOnPooledThread(() -> {
public @NotNull GeneralCommandLine install() throws ExecutionException { ProcessTerminatedListener.attach(process.getProcessHandler(), environment.getProject());
throw new ExecutionException("Failed to start debugging");
}
@Override if (params instanceof PreLaunchAware pla) {
public @NotNull File getExecutableFile() { try {
return null; pla.preLaunch();
} catch (Exception e) {
ApplicationUtil.invokeLater(() -> {
if (e instanceof Utils.ProcessException pe) {
carrier.handleOutput(pe.command + "\n", ConsoleViewContentType.SYSTEM_OUTPUT);
carrier.handleOutput("Compilation failure!\n", ConsoleViewContentType.SYSTEM_OUTPUT);
carrier.handleOutput(pe.stdout, ConsoleViewContentType.NORMAL_OUTPUT);
carrier.handleOutput(pe.stderr, ConsoleViewContentType.ERROR_OUTPUT);
process.handleTargetTerminated(new DebuggerDriver.ExitStatus(pe.exitCode));
} else {
carrier.handleOutput("Exception while compiling binary:\n", ConsoleViewContentType.SYSTEM_OUTPUT);
carrier.handleOutput(e.getMessage(), ConsoleViewContentType.ERROR_OUTPUT);
process.handleTargetTerminated(new DebuggerDriver.ExitStatus(-1));
}
process.stop();
ApplicationManager.getApplication().executeOnPooledThread(() -> process.unSuppress(false));
});
return;
}
} }
}), session, wrappedBuilder); process.unSuppress(true);
process.start(); });
process.doStart();
return process; return process;
} }
} }

View file

@ -16,6 +16,8 @@
package com.falsepattern.zigbrains.debugger.runner.build; package com.falsepattern.zigbrains.debugger.runner.build;
import com.falsepattern.zigbrains.debugger.Utils;
import com.falsepattern.zigbrains.debugger.runner.base.PreLaunchAware;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugEmitBinaryInstaller; import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugEmitBinaryInstaller;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase; import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase;
import com.falsepattern.zigbrains.project.execution.build.ProfileStateBuild; import com.falsepattern.zigbrains.project.execution.build.ProfileStateBuild;
@ -23,6 +25,7 @@ import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
import com.falsepattern.zigbrains.project.util.CLIUtil; import com.falsepattern.zigbrains.project.util.CLIUtil;
import com.intellij.execution.ExecutionException; import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.openapi.application.ApplicationManager;
import com.jetbrains.cidr.execution.Installer; import com.jetbrains.cidr.execution.Installer;
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration; import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
import lombok.Cleanup; import lombok.Cleanup;
@ -35,22 +38,21 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Arrays; import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
public class ZigDebugParametersBuild extends ZigDebugParametersBase<ProfileStateBuild> { public class ZigDebugParametersBuild extends ZigDebugParametersBase<ProfileStateBuild> implements PreLaunchAware {
private static final String BoilerplateNotice = "\nPlease edit this intellij build configuration and specify the path of the executable created by \"zig build\" directly!"; private static final String BoilerplateNotice = "\nPlease edit this intellij build configuration and specify the path of the executable created by \"zig build\" directly!";
private final File executableFile;
public ZigDebugParametersBuild(DebuggerDriverConfiguration driverConfiguration, AbstractZigToolchain toolchain, ProfileStateBuild profileStateBuild) throws ExecutionException {
super(driverConfiguration, toolchain, profileStateBuild);
val commandLine = profileState.getCommandLine(toolchain, true);
val outputOpt = CLIUtil.execute(commandLine, Integer.MAX_VALUE);
if (outputOpt.isEmpty()) {
throw new ExecutionException("Failed to execute \"zig " + commandLine.getParametersList().getParametersString() + "\"!");
}
val output = outputOpt.get();
if (output.getExitCode() != 0) {
throw new ExecutionException("Zig compilation failed with exit code " + output.getExitCode() + "\nError output:\n" + output.getStdout() + "\n" + output.getStderr());
}
private volatile File executableFile;
public ZigDebugParametersBuild(DebuggerDriverConfiguration driverConfiguration, AbstractZigToolchain toolchain, ProfileStateBuild profileStateBuild) {
super(driverConfiguration, toolchain, profileStateBuild);
}
private File compileExe() throws ExecutionException, Utils.ProcessException {
val commandLine = profileState.getCommandLine(toolchain, true);
Utils.executeCommandLineWithErrorChecks(commandLine);
val cfg = profileState.configuration(); val cfg = profileState.configuration();
val workingDir = cfg.getWorkingDirectory().getPath().orElse(null); val workingDir = cfg.getWorkingDirectory().getPath().orElse(null);
val exePath = profileState.configuration().getExePath().getPath(); val exePath = profileState.configuration().getExePath().getPath();
@ -84,11 +86,17 @@ public class ZigDebugParametersBuild extends ZigDebugParametersBase<ProfileState
throw new ExecutionException("File " + exe + " is not executable!"); throw new ExecutionException("File " + exe + " is not executable!");
} }
executableFile = exe.toFile(); return exe.toFile();
}
@Override
public void preLaunch() throws Exception {
this.executableFile = compileExe();
} }
@Override @Override
public @NotNull Installer getInstaller() { public @NotNull Installer getInstaller() {
assert executableFile != null;
return new ZigDebugEmitBinaryInstaller<>(profileState, toolchain, executableFile, profileState.configuration().getExeArgs().args); return new ZigDebugEmitBinaryInstaller<>(profileState, toolchain, executableFile, profileState.configuration().getExeArgs().args);
} }
} }

View file

@ -17,23 +17,21 @@
package com.falsepattern.zigbrains.debugger.runner.run; package com.falsepattern.zigbrains.debugger.runner.run;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugEmitBinaryInstaller; import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugEmitBinaryInstaller;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersEmitBinaryBase; import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersEmitBinaryBase;
import com.falsepattern.zigbrains.project.execution.run.ProfileStateRun; import com.falsepattern.zigbrains.project.execution.run.ProfileStateRun;
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain; import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
import com.intellij.execution.ExecutionException;
import com.jetbrains.cidr.execution.Installer; import com.jetbrains.cidr.execution.Installer;
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration; import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class ZigDebugParametersRun extends ZigDebugParametersEmitBinaryBase<ProfileStateRun> { public class ZigDebugParametersRun extends ZigDebugParametersEmitBinaryBase<ProfileStateRun> {
public ZigDebugParametersRun(DebuggerDriverConfiguration driverConfiguration, AbstractZigToolchain toolchain, ProfileStateRun profileState) public ZigDebugParametersRun(DebuggerDriverConfiguration driverConfiguration, AbstractZigToolchain toolchain, ProfileStateRun profileState) {
throws ExecutionException {
super(driverConfiguration, toolchain, profileState, "run"); super(driverConfiguration, toolchain, profileState, "run");
} }
@Override @Override
public @NotNull Installer getInstaller() { public @NotNull Installer getInstaller() {
assert executableFile != null;
return new ZigDebugEmitBinaryInstaller<>(profileState, toolchain, executableFile, profileState.configuration().getExeArgs().args); return new ZigDebugEmitBinaryInstaller<>(profileState, toolchain, executableFile, profileState.configuration().getExeArgs().args);
} }
} }

View file

@ -20,20 +20,18 @@ import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersEmitBin
import com.falsepattern.zigbrains.project.execution.test.ProfileStateTest; import com.falsepattern.zigbrains.project.execution.test.ProfileStateTest;
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain; import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugEmitBinaryInstaller; import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugEmitBinaryInstaller;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase;
import com.intellij.execution.ExecutionException;
import com.jetbrains.cidr.execution.Installer; import com.jetbrains.cidr.execution.Installer;
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration; import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class ZigDebugParametersTest extends ZigDebugParametersEmitBinaryBase<ProfileStateTest> { public class ZigDebugParametersTest extends ZigDebugParametersEmitBinaryBase<ProfileStateTest> {
public ZigDebugParametersTest(DebuggerDriverConfiguration driverConfiguration, AbstractZigToolchain toolchain, ProfileStateTest profileState) public ZigDebugParametersTest(DebuggerDriverConfiguration driverConfiguration, AbstractZigToolchain toolchain, ProfileStateTest profileState) {
throws ExecutionException {
super(driverConfiguration, toolchain, profileState, "test"); super(driverConfiguration, toolchain, profileState, "test");
} }
@Override @Override
public @NotNull Installer getInstaller() { public @NotNull Installer getInstaller() {
assert executableFile != null;
return new ZigDebugEmitBinaryInstaller<>(profileState, toolchain, executableFile, new String[0]); return new ZigDebugEmitBinaryInstaller<>(profileState, toolchain, executableFile, new String[0]);
} }
} }