backport: 14.1.0

This commit is contained in:
FalsePattern 2024-05-11 15:23:39 +02:00
parent a985dc18e9
commit 5328d6f498
Signed by: falsepattern
GPG key ID: E930CDEC50C50E23
19 changed files with 305 additions and 184 deletions

View file

@ -11,13 +11,26 @@ Changelog structure reference:
"Category" should be something that can be quickly recognized by readers ("Highlighting", "Code Completion", "Folding", etc.)
"Type" ALWAYS follows the order in the list above
"Category" ALWAYS alphabetically sorted
-->
# ZigBrains
## [Unreleased]
## [14.1.0]
### Fixed
- Debugging
- Huge rework for starting the various debugging runs, and more robust compilation error visualization instead of a tiny
popup
- LSP
- No more notification popup about zig env not being detected when not in a zig projects.
- Project
- ZLS should now be detected more reliably when creating new projects
## [14.0.1]
### Fixed

View file

@ -22,15 +22,17 @@ import lombok.val;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ApplicationUtil {
private final static ExecutorService EXECUTOR_SERVICE;
private final static ScheduledExecutorService EXECUTOR_SERVICE;
static {
// Single threaded executor is used to simulate a behavior of async sequencial execution.
// All runnables are executed asyncly but they are executed in the order of their submission.
EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor();
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
@ -48,6 +50,10 @@ public class ApplicationUtil {
EXECUTOR_SERVICE.submit(runnable);
}
public static void pool(Runnable runnable, long delay, TimeUnit timeUnit) {
EXECUTOR_SERVICE.schedule(runnable, delay, timeUnit);
}
static public <T> T computableReadAction(Computable<T> computable) {
return ApplicationManager.getApplication().runReadAction(computable);
}

View file

@ -18,8 +18,6 @@ package com.falsepattern.zigbrains.debugger.runner.base;
import com.falsepattern.zigbrains.project.execution.base.ProfileStateBase;
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
import com.falsepattern.zigbrains.project.util.CLIUtil;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.jetbrains.cidr.execution.Installer;
import lombok.RequiredArgsConstructor;
@ -27,61 +25,27 @@ import lombok.val;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@RequiredArgsConstructor
public abstract class ZigDebugEmitBinaryInstaller<ProfileState extends ProfileStateBase<?>> implements Installer {
protected final String kind;
public class ZigDebugEmitBinaryInstaller<ProfileState extends ProfileStateBase<?>> implements Installer {
protected final ProfileState profileState;
protected final AbstractZigToolchain toolchain;
private File executableFile;
private final File executableFile;
private final String[] exeArgs;
@Override
public @NotNull GeneralCommandLine install() throws ExecutionException {
val commandLine = profileState.getCommandLine(toolchain, true);
final Path tmpDir;
try {
tmpDir = Files.createTempDirectory("zigbrains_debug").toAbsolutePath();
} catch (IOException e) {
throw new ExecutionException("Failed to create temporary directory for " + kind + " binary", e);
}
val exe = tmpDir.resolve("executable").toFile();
commandLine.addParameters("-femit-bin=" + exe.getAbsolutePath());
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());
}
//Find our binary
try (val stream = Files.list(tmpDir)){
executableFile = stream.filter(file -> !file.getFileName().toString().endsWith(".o"))
.map(Path::toFile)
.filter(File::canExecute)
.findFirst()
.orElseThrow(() -> new IOException("No executable file present in temporary directory \"" +
tmpDir + "\""));
} catch (Exception e) {
throw new ExecutionException("Failed to find compiled binary", e);
}
public @NotNull GeneralCommandLine install() {
//Construct new command line
val cfg = profileState.configuration();
val cli = new GeneralCommandLine().withExePath(executableFile.getAbsolutePath());
cfg.getWorkingDirectory().getPath().ifPresent(x -> cli.setWorkDirectory(x.toFile()));
cli.addParameters(getExeArgs());
cli.addParameters(exeArgs);
cli.withCharset(StandardCharsets.UTF_8);
cli.withRedirectErrorStream(true);
return cli;
}
public abstract String[] getExeArgs();
@Override
public @NotNull File getExecutableFile() {
return executableFile;

View file

@ -0,0 +1,64 @@
/*
* 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 com.falsepattern.zigbrains.project.execution.base.ProfileStateBase;
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
import com.falsepattern.zigbrains.project.util.CLIUtil;
import com.intellij.execution.ExecutionException;
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
import lombok.val;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public abstract class ZigDebugParametersEmitBinaryBase<ProfileState extends ProfileStateBase<?>> extends ZigDebugParametersBase<ProfileState> {
protected final File executableFile;
public ZigDebugParametersEmitBinaryBase(DebuggerDriverConfiguration driverConfiguration, AbstractZigToolchain toolchain, ProfileState profileState, String kind) throws ExecutionException {
super(driverConfiguration, toolchain, profileState);
val commandLine = profileState.getCommandLine(toolchain, true);
final Path tmpDir;
try {
tmpDir = Files.createTempDirectory("zigbrains_debug").toAbsolutePath();
} catch (IOException e) {
throw new ExecutionException("Failed to create temporary directory for " + kind + " binary", e);
}
val exe = tmpDir.resolve("executable").toFile();
commandLine.addParameters("-femit-bin=" + exe.getAbsolutePath());
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());
}
//Find our binary
try (val stream = Files.list(tmpDir)){
executableFile = stream.filter(file -> !file.getFileName().toString().endsWith(".o"))
.map(Path::toFile)
.filter(File::canExecute)
.findFirst()
.orElseThrow(() -> new IOException("No executable file present in temporary directory \"" +
tmpDir + "\""));
} catch (Exception e) {
throw new ExecutionException("Failed to find compiled binary! " + e.getMessage(), e);
}
}
}

View file

@ -22,28 +22,47 @@ import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
import com.falsepattern.zigbrains.debugger.Utils;
import com.falsepattern.zigbrains.debugger.ZigLocalDebugProcess;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.executors.DefaultDebugExecutor;
import com.intellij.execution.filters.Filter;
import com.intellij.execution.filters.TextConsoleBuilder;
import com.intellij.execution.process.ProcessTerminatedListener;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.ui.ConsoleView;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.xdebugger.XDebugProcess;
import com.intellij.xdebugger.XDebugProcessStarter;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XDebuggerManager;
import com.jetbrains.cidr.execution.Installer;
import com.jetbrains.cidr.execution.TrivialRunParameters;
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
public abstract class ZigDebugRunnerBase<ProfileState extends ProfileStateBase<?>> extends ZigProgramRunnerBase<ProfileState> {
public ZigDebugRunnerBase() {
super(DefaultDebugExecutor.EXECUTOR_ID);
}
private static RunContentDescriptor startSession(ExecutionEnvironment environment, XDebugProcessStarter starter)
throws ExecutionException {
return XDebuggerManager.getInstance(environment.getProject())
.startSession(environment, starter)
.getRunContentDescriptor();
}
@Override
protected RunContentDescriptor doExecute(ProfileState state, AbstractZigToolchain toolchain, ExecutionEnvironment environment)
throws ExecutionException {
@ -53,26 +72,97 @@ 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));
return null;
}
val runParameters = getDebugParameters(state, environment, debuggerDriver, toolchain);
Either<ZigDebugParametersBase<ProfileState>, ExecutionException> runParameters;
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) {
//Assume that getDebugParameters reports the bug in a notification already
return null;
}
val manager = XDebuggerManager.getInstance(project);
return manager.startSession(environment,
new XDebugProcessStarter() {
@Override
public @NotNull XDebugProcess start(@NotNull XDebugSession session) throws ExecutionException {
val process = new ZigLocalDebugProcess(runParameters, session, state.getConsoleBuilder());
ProcessTerminatedListener.attach(process.getProcessHandler(), environment.getProject());
process.start();
return process;
}
}).getRunContentDescriptor();
if (runParameters.isRight()) {
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
public abstract boolean canRun(@NotNull String executorId, @NotNull RunProfile profile);
protected abstract @Nullable ZigDebugParametersBase<ProfileState> getDebugParameters(ProfileState state, ExecutionEnvironment environment, DebuggerDriverConfiguration debuggerDriver, AbstractZigToolchain toolchain);
protected abstract @Nullable ZigDebugParametersBase<ProfileState> getDebugParameters(ProfileState state, ExecutionEnvironment environment, DebuggerDriverConfiguration debuggerDriver, AbstractZigToolchain toolchain) throws ExecutionException;
@RequiredArgsConstructor
private class ZigLocalDebugProcessStarter extends XDebugProcessStarter {
private final ZigDebugParametersBase<ProfileState> params;
private final ProfileState state;
private final ExecutionEnvironment environment;
@Override
public @NotNull XDebugProcess start(@NotNull XDebugSession session) throws ExecutionException {
val process = new ZigLocalDebugProcess(params, session, state.getConsoleBuilder());
ProcessTerminatedListener.attach(process.getProcessHandler(), environment.getProject());
process.start();
return process;
}
}
@RequiredArgsConstructor
private class ErrorProcessStarter extends XDebugProcessStarter {
private final ProfileState state;
private final ExecutionException exception;
private final DebuggerDriverConfiguration debuggerDriver;
@Override
public @NotNull XDebugProcess start(@NotNull XDebugSession session) throws ExecutionException {
val cb = state.getConsoleBuilder();
val wrappedBuilder = new TextConsoleBuilder() {
@Override
public @NotNull ConsoleView getConsole() {
val console = cb.getConsole();
console.print(exception.getMessage(), ConsoleViewContentType.ERROR_OUTPUT);
return console;
}
@Override
public void addFilter(@NotNull Filter filter) {
cb.addFilter(filter);
}
@Override
public void setViewer(boolean isViewer) {
cb.setViewer(isViewer);
}
};
val process = new ZigLocalDebugProcess(new TrivialRunParameters(debuggerDriver, new Installer() {
@Override
public @NotNull GeneralCommandLine install() throws ExecutionException {
throw new ExecutionException("Failed to start debugging");
}
@Override
public @NotNull File getExecutableFile() {
return null;
}
}), session, wrappedBuilder);
process.start();
return process;
}
}
}

View file

@ -16,6 +16,7 @@
package com.falsepattern.zigbrains.debugger.runner.binary;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugEmitBinaryInstaller;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase;
import com.falsepattern.zigbrains.debugger.execution.binary.ProfileStateBinary;
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
@ -29,25 +30,14 @@ import org.jetbrains.annotations.NotNull;
import java.io.File;
public class ZigDebugParametersBinary extends ZigDebugParametersBase<ProfileStateBinary> {
public ZigDebugParametersBinary(DebuggerDriverConfiguration driverConfiguration, AbstractZigToolchain toolchain, ProfileStateBinary profileStateBinary) {
private final File executableFile;
public ZigDebugParametersBinary(DebuggerDriverConfiguration driverConfiguration, AbstractZigToolchain toolchain, ProfileStateBinary profileStateBinary) throws ExecutionException {
super(driverConfiguration, toolchain, profileStateBinary);
executableFile = profileState.configuration().getExePath().getPathOrThrow().toFile();
}
@Override
public @NotNull Installer getInstaller() {
return new Installer() {
private File executableFile;
@Override
public @NotNull GeneralCommandLine install() throws ExecutionException {
val cli = profileState.getCommandLine(toolchain, true);
executableFile = profileState.configuration().getExePath().getPathOrThrow().toFile();
return cli;
}
@Override
public @NotNull File getExecutableFile() {
return executableFile;
}
};
return new ZigDebugEmitBinaryInstaller<>(profileState, toolchain, executableFile, profileState.configuration().getArgs().args);
}
}

View file

@ -23,6 +23,7 @@ import com.falsepattern.zigbrains.debugger.execution.binary.ProfileStateBinary;
import com.falsepattern.zigbrains.debugger.execution.binary.ZigExecConfigBinary;
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.notification.Notification;
@ -46,12 +47,8 @@ public class ZigDebugRunnerBinary extends ZigDebugRunnerBase<ProfileStateBinary>
}
@Override
protected @Nullable ZigDebugParametersBase<ProfileStateBinary> getDebugParameters(ProfileStateBinary profileStateBinary, ExecutionEnvironment environment, DebuggerDriverConfiguration debuggerDriver, AbstractZigToolchain toolchain$) {
if (!(toolchain$ instanceof LocalZigToolchain toolchain)) {
Notifications.Bus.notify(new Notification("ZigBrains.Debugger.Error", "The debugger only supports local zig toolchains!", NotificationType.ERROR));
return null;
}
return new ZigDebugParametersBinary(debuggerDriver, toolchain, profileStateBinary);
protected @Nullable ZigDebugParametersBase<ProfileStateBinary> getDebugParameters(ProfileStateBinary profileStateBinary, ExecutionEnvironment environment, DebuggerDriverConfiguration debuggerDriver, AbstractZigToolchain toolchain) throws ExecutionException {
return new ZigDebugParametersBinary(debuggerDriver, LocalZigToolchain.ensureLocal(toolchain), profileStateBinary);
}
@Override

View file

@ -16,6 +16,7 @@
package com.falsepattern.zigbrains.debugger.runner.build;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugEmitBinaryInstaller;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase;
import com.falsepattern.zigbrains.project.execution.build.ProfileStateBuild;
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
@ -37,74 +38,57 @@ import java.util.Arrays;
public class ZigDebugParametersBuild extends ZigDebugParametersBase<ProfileStateBuild> {
private static final String BoilerplateNotice = "\nPlease edit this intellij build configuration and specify the path of the executable created by \"zig build\" directly!";
public ZigDebugParametersBuild(DebuggerDriverConfiguration driverConfiguration, AbstractZigToolchain toolchain, ProfileStateBuild profileStateBuild) {
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());
}
val cfg = profileState.configuration();
val workingDir = cfg.getWorkingDirectory().getPath().orElse(null);
val exePath = profileState.configuration().getExePath().getPath();
Path exe;
if (exePath.isEmpty()) {
//Attempt autodetect, should work for trivial cases, and make basic users happy, while advanced
// users can use manual executable paths.
if (workingDir == null) {
throw new ExecutionException("Cannot find working directory to run debugged executable!" + BoilerplateNotice);
}
val expectedOutputDir = workingDir.resolve(Path.of("zig-out", "bin"));
if (!Files.exists(expectedOutputDir)) {
throw new ExecutionException("Could not auto-detect default executable output directory \"zig-out/bin\"!" + BoilerplateNotice);
}
try (val filesInOutput = Files.list(expectedOutputDir)) {
val executables = filesInOutput.filter(Files::isRegularFile).filter(Files::isExecutable).toList();
if (executables.size() > 1) {
throw new ExecutionException("Multiple executables found!" + BoilerplateNotice);
}
exe = executables.get(0);
} catch (IOException e) {
throw new ExecutionException("Could not scan output directory \"" + expectedOutputDir + "\"!" + BoilerplateNotice);
}
} else {
exe = exePath.get();
}
if (!Files.exists(exe)) {
throw new ExecutionException("File " + exe + " does not exist!");
} else if (!Files.isExecutable(exe)) {
throw new ExecutionException("File " + exe + " is not executable!");
}
executableFile = exe.toFile();
}
@Override
public @NotNull Installer getInstaller() {
return new Installer() {
private File executableFile;
@Override
public @NotNull GeneralCommandLine install() throws ExecutionException {
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());
}
val cfg = profileState.configuration();
val workingDir = cfg.getWorkingDirectory().getPath().orElse(null);
val exePath = profileState.configuration().getExePath().getPath();
Path exe;
if (exePath.isEmpty()) {
//Attempt autodetect, should work for trivial cases, and make basic users happy, while advanced
// users can use manual executable paths.
if (workingDir == null) {
throw new ExecutionException("Cannot find working directory to run debugged executable!" + BoilerplateNotice);
}
val expectedOutputDir = workingDir.resolve(Path.of("zig-out", "bin"));
if (!Files.exists(expectedOutputDir)) {
throw new ExecutionException("Could not auto-detect default executable output directory \"zig-out/bin\"!" + BoilerplateNotice);
}
try (val filesInOutput = Files.list(expectedOutputDir)) {
val executables = filesInOutput.filter(Files::isRegularFile).filter(Files::isExecutable).toList();
if (executables.size() > 1) {
throw new ExecutionException("Multiple executables found!" + BoilerplateNotice);
}
exe = executables.get(0);
} catch (IOException e) {
throw new ExecutionException("Could not scan output directory \"" + expectedOutputDir + "\"!" + BoilerplateNotice);
}
} else {
exe = exePath.get();
}
if (!Files.exists(exe)) {
throw new ExecutionException("File " + exe + " does not exist!");
} else if (!Files.isExecutable(exe)) {
throw new ExecutionException("File " + exe + " is not executable!");
}
executableFile = exe.toFile();
//Construct new command line
val cli = new GeneralCommandLine().withExePath(executableFile.getAbsolutePath());
cfg.getWorkingDirectory().getPath().ifPresent(x -> cli.setWorkDirectory(x.toFile()));
cli.addParameters(cfg.getExeArgs().args);
cli.withCharset(StandardCharsets.UTF_8);
cli.withRedirectErrorStream(true);
return cli;
}
@Override
public @NotNull File getExecutableFile() {
return executableFile;
}
};
return new ZigDebugEmitBinaryInstaller<>(profileState, toolchain, executableFile, profileState.configuration().getExeArgs().args);
}
}

View file

@ -23,12 +23,14 @@ import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugRunnerBase;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
import lombok.val;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -46,12 +48,9 @@ public class ZigDebugRunnerBuild extends ZigDebugRunnerBase<ProfileStateBuild> {
}
@Override
protected @Nullable ZigDebugParametersBase<ProfileStateBuild> getDebugParameters(ProfileStateBuild profileStateBuild, ExecutionEnvironment environment, DebuggerDriverConfiguration debuggerDriver, AbstractZigToolchain toolchain$) {
if (!(toolchain$ instanceof LocalZigToolchain toolchain)) {
Notifications.Bus.notify(new Notification("ZigBrains.Debugger.Error", "The debugger only supports local zig toolchains!", NotificationType.ERROR));
return null;
}
return new ZigDebugParametersBuild(debuggerDriver, toolchain, profileStateBuild);
protected @Nullable ZigDebugParametersBase<ProfileStateBuild> getDebugParameters(ProfileStateBuild profileStateBuild, ExecutionEnvironment environment, DebuggerDriverConfiguration debuggerDriver, AbstractZigToolchain toolchain) throws
ExecutionException {
return new ZigDebugParametersBuild(debuggerDriver, LocalZigToolchain.ensureLocal(toolchain), profileStateBuild);
}
@Override

View file

@ -18,24 +18,22 @@ package com.falsepattern.zigbrains.debugger.runner.run;
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.project.execution.run.ProfileStateRun;
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
import com.intellij.execution.ExecutionException;
import com.jetbrains.cidr.execution.Installer;
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
import org.jetbrains.annotations.NotNull;
public class ZigDebugParametersRun extends ZigDebugParametersBase<ProfileStateRun> {
public ZigDebugParametersRun(DebuggerDriverConfiguration driverConfiguration, AbstractZigToolchain toolchain, ProfileStateRun profileState) {
super(driverConfiguration, toolchain, profileState);
public class ZigDebugParametersRun extends ZigDebugParametersEmitBinaryBase<ProfileStateRun> {
public ZigDebugParametersRun(DebuggerDriverConfiguration driverConfiguration, AbstractZigToolchain toolchain, ProfileStateRun profileState)
throws ExecutionException {
super(driverConfiguration, toolchain, profileState, "run");
}
@Override
public @NotNull Installer getInstaller() {
return new ZigDebugEmitBinaryInstaller<>("run", profileState, toolchain) {
@Override
public String[] getExeArgs() {
return profileState.configuration().getExeArgs().args;
}
};
return new ZigDebugEmitBinaryInstaller<>(profileState, toolchain, executableFile, profileState.configuration().getExeArgs().args);
}
}

View file

@ -16,12 +16,14 @@
package com.falsepattern.zigbrains.debugger.runner.run;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugRunnerBase;
import com.falsepattern.zigbrains.project.execution.base.ProfileStateBase;
import com.falsepattern.zigbrains.project.execution.run.ProfileStateRun;
import com.falsepattern.zigbrains.project.execution.run.ZigExecConfigRun;
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.notification.Notification;
@ -45,12 +47,9 @@ public class ZigDebugRunnerRun extends ZigDebugRunnerBase<ProfileStateRun> {
}
@Override
protected ZigDebugParametersRun getDebugParameters(ProfileStateRun profileStateRun, ExecutionEnvironment environment, DebuggerDriverConfiguration debuggerDriver, AbstractZigToolchain toolchain$) {
if (!(toolchain$ instanceof LocalZigToolchain toolchain)) {
Notifications.Bus.notify(new Notification("ZigBrains.Debugger.Error", "The debugger only supports local zig toolchains!", NotificationType.ERROR));
return null;
}
return new ZigDebugParametersRun(debuggerDriver, toolchain, profileStateRun);
protected ZigDebugParametersRun getDebugParameters(ProfileStateRun profileStateRun, ExecutionEnvironment environment, DebuggerDriverConfiguration debuggerDriver, AbstractZigToolchain toolchain) throws
ExecutionException {
return new ZigDebugParametersRun(debuggerDriver, LocalZigToolchain.ensureLocal(toolchain), profileStateRun);
}
@Override

View file

@ -16,26 +16,24 @@
package com.falsepattern.zigbrains.debugger.runner.test;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersEmitBinaryBase;
import com.falsepattern.zigbrains.project.execution.test.ProfileStateTest;
import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
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.debugger.backend.DebuggerDriverConfiguration;
import org.jetbrains.annotations.NotNull;
public class ZigDebugParametersTest extends ZigDebugParametersBase<ProfileStateTest> {
public ZigDebugParametersTest(DebuggerDriverConfiguration driverConfiguration, AbstractZigToolchain toolchain, ProfileStateTest profileState) {
super(driverConfiguration, toolchain, profileState);
public class ZigDebugParametersTest extends ZigDebugParametersEmitBinaryBase<ProfileStateTest> {
public ZigDebugParametersTest(DebuggerDriverConfiguration driverConfiguration, AbstractZigToolchain toolchain, ProfileStateTest profileState)
throws ExecutionException {
super(driverConfiguration, toolchain, profileState, "test");
}
@Override
public @NotNull Installer getInstaller() {
return new ZigDebugEmitBinaryInstaller<>("test", profileState, toolchain) {
@Override
public String[] getExeArgs() {
return new String[0];
}
};
return new ZigDebugEmitBinaryInstaller<>(profileState, toolchain, executableFile, new String[0]);
}
}

View file

@ -23,6 +23,7 @@ import com.falsepattern.zigbrains.project.toolchain.AbstractZigToolchain;
import com.falsepattern.zigbrains.project.toolchain.LocalZigToolchain;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugParametersBase;
import com.falsepattern.zigbrains.debugger.runner.base.ZigDebugRunnerBase;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.notification.Notification;
@ -46,12 +47,9 @@ public class ZigDebugRunnerTest extends ZigDebugRunnerBase<ProfileStateTest> {
}
@Override
protected @Nullable ZigDebugParametersBase<ProfileStateTest> getDebugParameters(ProfileStateTest profileStateTest, ExecutionEnvironment environment, DebuggerDriverConfiguration debuggerDriver, AbstractZigToolchain toolchain$) {
if (!(toolchain$ instanceof LocalZigToolchain toolchain)) {
Notifications.Bus.notify(new Notification("ZigBrains.Debugger.Error", "The debugger only supports local zig toolchains!", NotificationType.ERROR));
return null;
}
return new ZigDebugParametersTest(debuggerDriver, toolchain, profileStateTest);
protected @Nullable ZigDebugParametersBase<ProfileStateTest> getDebugParameters(ProfileStateTest profileStateTest, ExecutionEnvironment environment, DebuggerDriverConfiguration debuggerDriver, AbstractZigToolchain toolchain) throws
ExecutionException {
return new ZigDebugParametersTest(debuggerDriver, LocalZigToolchain.ensureLocal(toolchain), profileStateTest);
}
@Override

View file

@ -64,7 +64,7 @@ public class ZigExecConfigBuild extends ZigExecConfigBase<ZigExecConfigBuild> {
steps = truncatedSteps;
}
result.addAll(steps);
result.addAll(CLIUtil.colored(colored.value));
result.addAll(CLIUtil.colored(colored.value, debug));
result.addAll(List.of(extraArgs.args));
return result;
}

View file

@ -46,7 +46,7 @@ public class ZigExecConfigRun extends ZigExecConfigBase<ZigExecConfigRun> {
public List<String> buildCommandLineArgs(boolean debug) {
val result = new ArrayList<String>();
result.add("run");
result.addAll(CLIUtil.colored(colored.value));
result.addAll(CLIUtil.colored(colored.value, debug));
result.add(filePath.getPathOrThrow().toString());
if (!debug || optimization.forced) {
result.addAll(List.of("-O", optimization.level.name()));

View file

@ -46,7 +46,7 @@ public class ZigExecConfigTest extends ZigExecConfigBase<ZigExecConfigTest> {
public List<String> buildCommandLineArgs(boolean debug) {
val result = new ArrayList<String>();
result.add("test");
result.addAll(CLIUtil.colored(colored.value));
result.addAll(CLIUtil.colored(colored.value, debug));
result.add(filePath.getPathOrThrow().toString());
if (!debug || optimization.forced) {
result.addAll(List.of("-O", optimization.level.name()));

View file

@ -17,6 +17,7 @@
package com.falsepattern.zigbrains.project.toolchain;
import com.falsepattern.zigbrains.common.util.PathUtil;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import java.nio.file.Path;
@ -40,4 +41,11 @@ public class LocalZigToolchain extends AbstractZigToolchain{
public Path pathToExecutable(String toolName) {
return PathUtil.pathToExecutable(getLocation(), toolName);
}
public static LocalZigToolchain ensureLocal(AbstractZigToolchain toolchain) throws ExecutionException {
if (!(toolchain instanceof LocalZigToolchain $toolchain)) {
throw new ExecutionException("The debugger only supports local zig toolchains!");
}
return $toolchain;
}
}

View file

@ -27,6 +27,7 @@ import lombok.val;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.StringTokenizer;
@ -121,7 +122,13 @@ public class CLIUtil {
return result.toArray(new String[0]);
}
public static List<String> colored(boolean colored) {
return List.of("--color", colored ? "on" : "off");
public static List<String> colored(boolean colored, boolean debug) {
// 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
if (debug) {
return Collections.emptyList();
} else {
return List.of("--color", colored ? "on" : "off");
}
}
}

View file

@ -16,6 +16,7 @@
package com.falsepattern.zigbrains.zig.lsp;
import com.falsepattern.zigbrains.common.util.ApplicationUtil;
import com.falsepattern.zigbrains.common.util.StringUtil;
import com.falsepattern.zigbrains.lsp.IntellijLanguageClient;
import com.falsepattern.zigbrains.lsp.utils.FileUtils;
@ -40,6 +41,7 @@ import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class ZLSStartupActivity implements ProjectActivity {
@ -76,7 +78,8 @@ public class ZLSStartupActivity implements ProjectActivity {
val tmpFile = Files.createTempFile("zigbrains-zls-autoconf", ".json");
val config = ZLSConfigProvider.findEnvironment(project);
if (StringUtil.isEmpty(config.zig_exe_path()) && StringUtil.isEmpty(config.zig_lib_path())) {
Notifications.Bus.notify(new Notification("ZigBrains.ZLS", "(ZLS) Failed to detect zig path from project toolchain", NotificationType.WARNING));
// TODO this generates unnecessary noise in non-zig projects, find an alternative.
// Notifications.Bus.notify(new Notification("ZigBrains.ZLS", "(ZLS) Failed to detect zig path from project toolchain", NotificationType.WARNING));
configOK = false;
break blk;
}
@ -172,6 +175,9 @@ public class ZLSStartupActivity implements ProjectActivity {
if (zlsPath == null) {
//Project creation
ApplicationUtil.pool(() -> {
initZLS(project);
}, 5, TimeUnit.SECONDS);
return null;
}